;;; Sly ;;; Copyright (C) 2015 David Thompson ;;; ;;; This program is free software: you can redistribute it and/or ;;; modify it under the terms of the GNU General Public License as ;;; published by the Free Software Foundation, either version 3 of the ;;; License, or (at your option) any later version. ;;; ;;; This program is distributed in the hope that it will be useful, ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;; General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with this program. If not, see ;;; . ;;; Commentary: ;; ;; Immutable record type syntax with keyword argument constructor, ;; field inheritance, and default field values. ;; ;;; Code: (define-module (sly records) #:use-module (srfi srfi-4) #:use-module (srfi srfi-9) #:use-module (srfi srfi-9 gnu) #:use-module (rnrs bytevectors) #:export (define-record-type* define-packed-f64-record-type)) (define-syntax-rule (define-record-type* type constructor keyword-constructor predicate (field getter default) ...) "Define a new, immutable record type named TYPE. PREDICATE is the name of the procedure that tests if an object is of TYPE. A GETTER is the name of the accessor for its respective FIELD. CONSTRUCTOR is the name of the record type's low-level constructor that uses positional arguments corresponding to the order in which the fields are specified. KEYWORD-CONSTRUCTOR is the name of the high-level constructor that uses keyword arguments for each FIELD whose values correspond to the DEFAULT associated with that field. Additionally, a special keyword, #:inherit, can be used to copy values from another instance of TYPE and only change the fields that are explicitly overridden." (begin (define-record-type type (constructor field ...) predicate (field getter) ...) (define keyword-constructor (let ((default-record (constructor default ...))) (lambda* (#:key (inherit default-record) (field (getter inherit)) ...) (constructor field ...)))))) ;; A little hack until Guile can unbox fields in record types. ;) (define-syntax-rule (define-packed-f64-record-type constructor box unbox predicate? (field index getter setter) ...) (begin (define-record-type (box bv) predicate? (bv unbox)) (set-record-type-printer! (lambda (obj port) (display "<" port) (display ' port) (begin (display " " port) (display 'field port) (display ": " port) (display (getter obj) port)) ... (display " >" port))) (define constructor (let ((size (length (list 'field ...)))) (lambda (field ...) (let ((bv (make-f64vector size))) (f64vector-set! bv index field) ... (box bv))))) (define-inlinable (getter obj) (f64vector-ref (unbox obj) index)) ... (define-inlinable (setter obj value) (f64vector-set! (unbox obj) index value)) ...))