-
Notifications
You must be signed in to change notification settings - Fork 2
/
defrectype.scm
120 lines (110 loc) · 4.77 KB
/
defrectype.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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
;;; -*- mode: scheme; scheme48-package: (config) -*-
;;;;;; Alternative record type definition macro
;;; This code is written by Taylor Campbell and placed in the Public
;;; Domain. All warranties are disclaimed.
(define (expand-define-record-type* form rename compare)
((call-with-current-continuation
(lambda (lose)
(lambda ()
(let-fluid $lose (lambda (message . irritants)
(lose
(lambda ()
;; SYNTAX-ERROR is silly in Scheme48.
(apply syntax-error
"invalid DEFINE-RECORD-TYPE form"
form
message irritants)
form)))
(lambda ()
(destructure (( (keyword type-name
(conser-name . conser-args)
other-fields)
form))
(receive (needs-conser-layer? arg-tags vars inits)
(compute-vars+inits conser-args other-fields)
(let ((real-conser
(if needs-conser-layer?
(rename (symbol-append '% conser-name))
conser-name)))
`(,(rename 'begin)
(,(rename 'define-record-type) ,type-name
;; Scheme48 convention
,(symbol-append ': type-name)
(,real-conser ,@arg-tags)
,(symbol-append type-name '?)
,@(generate-field-specs conser-args
other-fields
type-name))
,@(if needs-conser-layer?
`((,(rename 'define) (,conser-name ,@vars)
(,real-conser ,@inits)))
'()))))))))))))
(define $lose (make-fluid #f))
(define (lose msg . irritants) (apply (fluid $lose) msg irritants))
(define (compute-vars+inits conser-args other-fields)
(let ((vars (reverse-map
(lambda (x)
(cond ((symbol? x) x)
((and (pair? x)
(symbol? (car x))
(null? (cdr x)))
(car x))
(else (lose '(invalid maker argument specifier)
x))))
conser-args)))
(let loop ((fields other-fields)
(needs-conser-layer? #f)
(arg-tags vars)
(inits vars))
(if (null? fields)
(values needs-conser-layer?
(reverse arg-tags)
(reverse vars)
(reverse inits))
(let ((field (car fields)))
(cond ((symbol? field)
(loop (cdr fields)
needs-conser-layer?
arg-tags
inits))
((and (pair? field)
(symbol? (car field))
(pair? (cdr field))
(null? (cddr field)))
(loop (cdr fields)
#t
(cons (car field) arg-tags)
(cons (cadr field) inits)))
(else
(lose '(invalid field specifier)
field))))))))
(define (reverse-map proc list)
(let loop ((list list) (tail '()))
(if (null? list)
tail
(loop (cdr list) (cons (proc (car list)) tail)))))
(define (generate-field-specs conser-args other-fields type-name)
(append (map (lambda (x)
(receive (tag set?)
(if (pair? x)
(values (car x) #t)
(values x #f))
`(,tag ,(make-field-accessor type-name
tag)
,@(if set?
(list (make-field-setter
type-name
tag))
'()))))
conser-args)
(map (lambda (x)
(let ((tag (if (pair? x) (car x) x)))
`(,tag ,(make-field-accessor type-name tag)
,(make-field-setter type-name tag))))
other-fields)))
(define (make-field-accessor type-name tag)
(symbol-append type-name '- tag))
(define (make-field-setter type-name tag)
(symbol-append 'set- type-name '- tag '!))
(define (symbol-append . symbols)
(string->symbol (apply string-append (map symbol->string symbols))))