forked from dbetz/xlisp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
crec.lsp
executable file
·87 lines (84 loc) · 4.16 KB
/
crec.lsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
(define-macro (define-crecord record-name fields)
(let* ((record-name-string (symbol->string record-name))
(constructor-name (intern (string-append "MAKE-" record-name-string)))
(indexer-name (intern (string-append record-name-string "-ADDRESS")))
(size-name (intern (string-append record-name-string "-SIZE")))
(field-macros '())
(field-offset 0)
(make-field-macros
(named-lambda make-field-macros (field-def)
(let* ((field-name (first field-def))
(field-name-string (symbol->string field-name))
(field-type-name (second field-def))
(field-type (crecord-type field-type-name))
(field-is-array? (not (null? (cddr field-def))))
(field-count (if field-is-array? (third field-def) 1))
(field-size (get-crecord-type-size field-type))
(getter-name (intern (string-append record-name-string "-" field-name-string)))
(get-addr-name (intern (string-append record-name-string "-" field-name-string "-ADDRESS")))
(setter-name (intern (string-append "SET-" record-name-string "-" field-name-string "!")))
(offset-name (intern (string-append record-name-string "-" field-name-string "-OFFSET"))))
(push! `(define-macro (,getter-name record &optional i)
(if i
`(get-crecord-field ,record ,(simplify-index ,field-offset ,field-size i) ,,field-type)
`(get-crecord-field ,record ,,field-offset ,,field-type))) field-macros)
(push! `(define-macro (,get-addr-name record &optional i)
(if i
`(get-crecord-field-address ,record ,(simplify-index ,field-offset ,field-size i) 'pointer)
`(get-crecord-field-address ,record ,,field-offset 'pointer))) field-macros)
(push! `(define-macro (,setter-name record value &optional i)
(if i
(let ((value i) ; looks better to have index before value
(i value))
`(set-crecord-field! ,record ,(simplify-index ,field-offset ,field-size i) ,,field-type ,value))
`(set-crecord-field! ,record ,,field-offset ,,field-type ,value))) field-macros)
(push! `(define ,offset-name ,field-offset) field-macros)
(+ field-offset (* field-size field-count))))))
(let loop ((fields fields))
(when fields
(let ((field-def (car fields)))
(if (atom? (car field-def))
(set! field-offset (make-field-macros field-def))
(let ((new-offset field-offset))
(let field-loop ((fields field-def))
(when fields
(let* ((field-def (car fields))
(this-offset (make-field-macros field-def)))
(when (> this-offset new-offset)
(set! new-offset this-offset))
(field-loop (cdr fields)))))
(set! field-offset new-offset)))
(loop (cdr fields)))))
(push! `',record-name field-macros)
`(begin
(define-macro (,constructor-name &optional size)
(if size
`(allocate-cmemory ',',record-name (* ,,field-offset ,size))
`(allocate-cmemory ',',record-name ,,field-offset)))
(define-macro (,indexer-name record i)
`(get-crecord-field-address ,record (* ,,field-offset ,i) 'pointer))
(define ,size-name ,field-offset)
,@(reverse field-macros))))
(define (simplify-index base size i)
(let ((offset (if (number? i)
(* size i)
(if (= size 1)
i
`(* ,size ,i)))))
(if (= base 0)
offset
(if (number? offset)
(+ base offset)
`(+ ,base ,offset)))))
(define (crecord-type name)
(case name
(char 1)
(uchar 2)
(short 3)
(ushort 4)
(int 5)
(uint 6)
(long 7)
(ulong 8)
(ptr 9)
(else (error "unknown type ~S" name))))