forked from mighty-gerbils/gerbil
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsugar.ss
More file actions
183 lines (165 loc) · 6.09 KB
/
sugar.ss
File metadata and controls
183 lines (165 loc) · 6.09 KB
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
;;; -*- Gerbil -*-
;;; (C) vyzo
;;; some standard sugar
package: std
(export #t)
(defrules catch ())
(defrules finally ())
(defsyntax (try stx)
(def (generate-thunk body)
(if (null? body)
(raise-syntax-error #f "Bad syntax; missing body" stx)
(with-syntax (((e ...) (reverse body)))
#'(lambda () e ...))))
(def (generate-fini thunk fini)
(with-syntax ((thunk thunk)
((e ...) fini))
#'(with-unwind-protect thunk (lambda () e ...))))
(def (generate-catch handlers thunk)
(with-syntax (($e (genident)))
(let lp ((rest handlers) (clauses []))
(match rest
([hd . rest]
(syntax-case hd (=>)
((pred => K)
(lp rest (cons #'(((? pred) $e) => K)
clauses)))
(((pred var) body ...)
(identifier? #'var)
(lp rest (cons #'(((? pred) $e) (let ((var $e)) body ...))
clauses)))
(((var) body ...)
(identifier? #'var)
(lp rest (cons #'(#t (let ((var $e)) body ...))
clauses)))
((us body ...)
(underscore? #'us)
(lp rest (cons #'(#t (begin body ...))
clauses)))))
(else
(with-syntax (((clause ...) clauses)
(thunk thunk))
#'(with-catch
(lambda ($e) (cond clause ... (else (raise $e))))
thunk)))))))
(syntax-case stx ()
((_ e ...)
(let lp ((rest #'(e ...)) (body []))
(syntax-case rest ()
((hd . rest)
(syntax-case #'hd (catch finally)
((finally fini ...)
(if (stx-null? #'rest)
(generate-fini (generate-thunk body) #'(fini ...))
(raise-syntax-error #f "Misplaced finally clause" stx)))
((catch handler ...)
(let lp ((rest #'rest) (handlers [#'(handler ...)]))
(syntax-case rest (catch finally)
(((catch handler ...) . rest)
(lp #'rest [#'(handler ...) . handlers]))
(((finally fini ...))
(with-syntax ((body (generate-catch handlers (generate-thunk body))))
(generate-fini #'(lambda () body) #'(fini ...))))
(()
(generate-catch handlers (generate-thunk body))))))
(_ (lp #'rest (cons #'hd body)))))
(() ; no clauses, just a begin
(cons 'begin (reverse body))))))))
(defrules with-destroy ()
((_ obj body ...)
(let ($obj obj)
(try body ... (finally {destroy $obj})))))
(defsyntax (defmethod/alias stx)
(syntax-case stx (@method)
((_ {method (alias ...) type} body ...)
(and (identifier? #'method)
(stx-andmap identifier? #'(alias ...))
(syntax-local-type-info? #'type))
(with-syntax* (((values klass) (syntax-local-value #'type))
(type::t (runtime-type-identifier klass))
(method-impl (stx-identifier #'method #'type "::" #'method)))
#'(begin
(defmethod {method type} body ...)
(bind-method! type::t 'alias method-impl) ...)))))
(defrules using ()
((_ obj method ...)
(begin (using-method obj method) ...)))
(defrules using-method ()
((_ obj method)
(identifier? #'method)
(def method (checked-bound-method-ref obj 'method)))
((_ obj (method method-id))
(and (identifier? #'method) (identifier? #'method-id))
(def method (checked-bound-method-ref obj 'method-id))))
(defrules assert! ()
((_ expr)
(unless expr
(error "Assertion failed" 'expr)))
((_ expr message)
(unless expr
(error "Assertion failed" message 'expr))))
(defrules while ()
((_ test body ...)
(let lp ()
(when test
body ...
(lp)))))
(defrules until ()
((_ test body ...)
(let lp ()
(unless test
body ...
(lp)))))
(defrules hash ()
((_ (key val) ...)
(~hash-table make-hash-table (key val) ...)))
(defrules hash-eq ()
((_ (key val) ...)
(~hash-table make-hash-table-eq (key val) ...)))
(defrules hash-eqv ()
((_ (key val) ...)
(~hash-table make-hash-table-eqv (key val) ...)))
(defsyntax (~hash-table stx)
(syntax-case stx ()
((_ make-ht clause ...)
(with-syntax* ((size (stx-length #'(clause ...)))
(((key val) ...) #'(clause ...)))
#'(let (ht (make-ht size: size))
(hash-put! ht `key val) ...
ht)))))
;; the hash deconstructor macro
;; usage: (let-hash a-hash body ...)
;; rebinds %%ref so that identifiers starting with a dot are looked up in the hash:
;; .x -> (hash-ref a-hash 'x) ; strong accessor
;; .?x -> (hash-get a-hash 'x) ; weak accessor
;; ..x -> (%%ref .x) ; escape
(defsyntax (let-hash stx)
(syntax-case stx ()
((macro expr body ...)
(with-syntax ((@ref (stx-identifier #'macro '%%ref)))
#'(let (ht expr)
(let-syntax
((var-ref
(syntax-rules ()
((_ id) (@ref id)))))
(let-syntax
((@ref
(lambda (stx)
(syntax-case stx ()
((_ id)
(let (str (symbol->string (stx-e #'id)))
(def (str->symbol start)
(string->symbol (substring str start (string-length str))))
(if (eq? (string-ref str 0) #\.) ; hash accessor?
(cond
((eq? (string-ref str 1) #\.) ; escape
(with-syntax ((sym (str->symbol 1)))
#'(var-ref sym)))
((eq? (string-ref str 1) #\?) ; weak
(with-syntax ((sym (str->symbol 2)))
#'(hash-get ht 'sym)))
(else
(with-syntax ((sym (str->symbol 1)))
#'(hash-ref ht 'sym))))
#'(var-ref id))))))))
body ...)))))))