Add field offsets specification for define-cstruct

This allows to define the offsets for each field instead
of relying on the calculated ones - useful when struct might
be defined differently across platforms.
This commit is contained in:
BartAdv 2015-02-10 03:51:12 +00:00 committed by Matthew Flatt
parent 2c506a2157
commit 7dfa02cc5f
2 changed files with 56 additions and 21 deletions

View File

@ -55,7 +55,36 @@
(test 500.0 quint-r kv)
(test 500.0 cadr (quint->list kv))
(test '((10 20 30 40.0) 500.0) quint->list* kv)
(test '((11 21 31 40.25) 500.25) quint->list* (list*->quint '((11 21 31 40.25) 500.25)))))
(test '((11 21 31 40.25) 500.25) quint->list* (list*->quint '((11 21 31 40.25) 500.25)))
(define-cstruct _due [(x _byte 0) (y _byte 1)])
(define cv (make-due 255 1))
(test 255 due-x cv)
(test 1 due-y cv)
(test '(255 1) due->list cv)
(set-due-x! cv 1)
(test 1 due-x cv)
(test 1 due-y cv)
(define-cstruct (_tre _due) [(z _short 2)])
(define dv (make-tre 255 1 20))
(test 255 due-x dv)
(test 1 due-y dv)
(test 20 tre-z dv)
(set-due-y! dv 255)
(test 255 due-y dv)
(test 20 tre-z dv)
(define-cstruct _quattro [(pre _tre 0) (v _int 4)])
(define qtv (make-quattro dv 50))
(test 255 due-x qtv)
(test 255 due-y qtv)
(test 20 tre-z qtv)
(test 50 quattro-v qtv)
(set-tre-z! qtv 255)
(test 255 tre-z qtv)
(test '((255 255 255) 50) quattro->list* qtv)
(test '((255 127 1) 2048) quattro->list* (list*->quattro '((255 127 1) 2048)))))
(make-test [] void
[] void)

View File

@ -1363,7 +1363,7 @@
;; type.
(provide define-cstruct)
(define-syntax (define-cstruct stx)
(define (make-syntax _TYPE-stx has-super? slot-names-stx slot-types-stx
(define (make-syntax _TYPE-stx has-super? slot-names-stx slot-types-stx slot-offsets-stx
alignment-stx malloc-mode-stx property-stxes property-binding-stxes
no-equal?)
(define name
@ -1389,6 +1389,7 @@
[struct-string (format "~a?" name)]
[(slot ...) slot-names-stx]
[(slot-type ...) slot-types-stx]
[(slot-offset ...) slot-offsets-stx]
[TYPE (id name)]
[cpointer:TYPE (id "cpointer:"name)]
[struct:cpointer:TYPE (if (null? property-stxes)
@ -1496,7 +1497,7 @@
(define-values (stype ...) (values slot-type ...))
(define types (list stype ...))
(define alignment-v alignment)
(define offsets (compute-offsets types alignment-v))
(define offsets (map (lambda (u c) (or u c)) (list slot-offset ...) (compute-offsets types alignment-v)))
(define-values (offset ...) (apply values offsets))
(define all-tags (cons TYPE-tag super-tags))
(define _TYPE*
@ -1596,9 +1597,9 @@
(if (list? what) (apply string-append what) what)
stx xs))
(syntax-case stx ()
[(_ type ([slot slot-type] ...) . more)
[(_ type (slot-def ...) . more)
(or (stx-pair? #'type)
(stx-pair? #'(slot ...)))
(stx-pair? #'(slot-def ...)))
(let-values ([(_TYPE _SUPER)
(syntax-case #'type ()
[(t s) (values #'t #'s)]
@ -1656,28 +1657,33 @@
_TYPE))
(unless (regexp-match? #rx"^_." (symbol->string (syntax-e _TYPE)))
(err "cstruct name must begin with a `_'" _TYPE))
(with-syntax
([((slot slot-type slot-offset) ...)
(syntax-case #'(slot-def ...) ()
[((slot slot-type) ...) #'((slot slot-type #f) ...)]
[((slot slot-type slot-offset) ...) #'((slot slot-type slot-offset) ...)]
[_ (err "bad field specification, expecting `[name ctype]' or `[name ctype offset]'" #'(slot-def ...))])])
(for ([s (in-list (syntax->list #'(slot ...)))])
(unless (identifier? s)
(err "bad field name, expecting an identifier" s)))
(if _SUPER
(make-syntax _TYPE #t
#`(#,(datum->syntax _TYPE 'super _TYPE) slot ...)
#`(#,_SUPER slot-type ...)
alignment
malloc-mode
properties
property-bindings
no-equal?)
(make-syntax _TYPE #f #'(slot ...) #`(slot-type ...)
alignment malloc-mode properties property-bindings no-equal?)))]
(if _SUPER
(make-syntax _TYPE #t
#`(#,(datum->syntax _TYPE 'super _TYPE) slot ...)
#`(#,_SUPER slot-type ...)
#'(0 slot-offset ...)
alignment
malloc-mode
properties
property-bindings
no-equal?)
(make-syntax _TYPE #f #'(slot ...) #`(slot-type ...) #`(slot-offset ...)
alignment malloc-mode properties property-bindings no-equal?))))]
[(_ type () . more)
(identifier? #'type)
(err "must have either a supertype or at least one field")]
;; specific errors for bad slot specs, leave the rest for a generic error
[(_ type (bad ...) . more)
(err "bad field specification, expecting `[name ctype]'"
(ormap (lambda (s) (syntax-case s () [[n ct] #t] [_ s]))
(syntax->list #'(bad ...))))]
[(_ type bad . more)
(err "bad field specification, expecting a sequence of `[name ctype]'"
#'bad)]))