-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcogen-record.scm
76 lines (74 loc) · 2.45 KB
/
cogen-record.scm
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
;;; cogen-record.scm
;;; copyright © 1996, 1997, 1998 by Peter Thiemann
;;; non-commercial use is free as long as the original copright notice
;;; remains intact
;;; definitions that implement records
;;; example:
;;; (define-record type-name (sel1 ...) aform1 ... )
;;; aform ::= asel | (asel exp)
;;; defines a record type with one constructor, make-[type-name], with
;;; arguments sel1, ..., seln and additional fields asel1, ... aseln
;;; the additional fields can have initial values specified with [exp]
;;; (the argument fields of the constructors are in scope when eval [exp]
;;; selectors [type-name]->[sel1], ..., [type-name]->[asel1], ..., and
;;; update operations [type-name]->[sel1]! ... [type-name]->[asel1]!, ...
(define-syntax define-record
(lambda (x r c)
(let* ((%begin (r 'begin))
(%car (r 'car))
(%define (r 'define))
(%equal? (r 'equal?))
(%error (r 'error))
(%if (r 'if))
(%lambda (r 'lambda))
(%vector (r 'vector))
(%vector? (r 'vector?))
(%vector-ref (r 'vector-ref))
(%vector-set! (r 'vector-set!))
(type-name (cadr x))
(sel* (caddr x))
(rest (cdddr x))
(any->symbol
(lambda args
(string->symbol
(apply string-append
(map (lambda (arg)
(cond
((symbol? arg) (symbol->string arg))
((string? arg) arg)
((number? arg) (number->string arg))))
args)))))
(rest->sym
(lambda (arg)
(if (pair? arg) (car arg) arg)))
(rest->init
(lambda (arg)
(if (pair? arg) (cadr arg) #f)))
(a-sel* (map rest->sym rest))
(a-init* (map rest->init rest)))
`(,%begin
(,%define ,(any->symbol "make-" type-name)
(,%lambda ,sel*
(,%vector ',type-name ,@sel* ,@a-init*)))
(,%define ,(any->symbol type-name "?")
(,%lambda (rec)
(and (,%vector? rec)
(,%equal? (,%vector-ref rec 0) ',type-name))))
,@(let loop ((sel* (append sel* a-sel*)) (i 1))
(if (null? sel*)
'()
(cons
`(,%define ,(any->symbol type-name "->" (car sel*))
(,%lambda (rec)
(,%if (,(any->symbol type-name "?") rec)
(,%vector-ref rec ,i)
(,%error "error: select ~d->~d"
',type-name ',(car sel*)))))
(cons
`(,%define ,(any->symbol type-name "->" (car sel*) "!")
(,%lambda (rec arg)
(,%if (,(any->symbol type-name "?") rec)
(,%vector-set! rec ,i arg)
(,%error "error: set ~d->~d!"
',type-name ',(car sel*)))))
(loop (cdr sel*) (+ i 1))))))))))