3 (define current-def-proc-id #f)
5 (define (form? keyword source)
7 (eq? (car source) keyword)))
9 (define (expect-form keyword source)
10 (if (not (form? keyword source))
11 (error "expected" keyword source)))
13 (define (get-id source)
14 (expect-form 'six.identifier source)
17 (define (define-variable source cte cont)
18 (let* ((id (get-id (cadr source)))
20 (dims (cadddr source))
21 (val (car (cddddr source))))
23 ;; variables which, when found in programs, have special meanings
24 ;; when any of these are encountered, its associated thunk is
26 (define special-variables
27 (list ;; TODO fit with the predefined variables in cte.scm ?
28 (cons 'SIXPIC_MEMORY_DIVIDE
30 (set! memory-divide (cadr val)) ; must be a literal
31 (expression val cte (lambda (ast cte)
32 (def (list ast) cte)))))))
35 (define (def asts cte)
37 (alloc-value type current-def-proc-id id))
40 asts id '() type value '() current-def-proc-id))
42 (cte-extend cte (list ast))))
45 ;; if it's a special variable, call its associated thunk instead
46 (let ((target (assq id special-variables)))
50 (expression val cte (lambda (ast cte) (def (list ast) cte)))
53 (define (define-procedure source cte cont)
54 (let* ((id (get-id (cadr source)))
55 (proc (caddr source)))
56 (expect-form 'six.procedure proc)
57 (set! current-def-proc-id id)
62 (let* ((var-id (get-id (car x)))
64 (value (alloc-value type id var-id)))
65 (new-def-variable '() var-id '() type value '() id))) ;; TODO allocate the value inside new-def-variable ?
69 (expect-form 'six.procedure-body body)
71 (alloc-value type id id))
73 (new-def-procedure '() id '() type value params))
75 (cte-extend cte (list ast))))
76 (multi-link-parent! params ast)
77 (let ((res (block body
78 (cte-extend cte params)
79 (lambda (body-ast body-cte)
80 (ast-subasts-set! ast (list body-ast))
81 (link-parent! body-ast ast)
84 (set! current-def-proc-id #f)
87 (define (block source cte cont)
88 (define (b source cte cont)
91 (let ((head (car source))
93 (if (or (form? 'six.label head) ; we complete the block with a list of named blocks
94 (form? 'six.case head))
95 (named-block-list source
97 cont) ; will return a list of named blocks
104 (cont (cons ast asts)
109 (cont (new-block asts)
112 ;; handles named blocks (implicit blocks delimited by labels)
113 ;; useful for switch and goto
114 (define (named-block-list source cte cont)
115 (define (b source cte cont name body-so-far)
117 (cont (list (new-named-block name body-so-far)) ; last block
119 (let ((curr (car source)))
120 (if (or (form? 'six.label curr) ; we reached another named block
121 (form? 'six.case curr))
122 (named-block-list source
124 (lambda (named-blocks cte)
125 (cont (cons (new-named-block name body-so-far)
135 (append body-so-far (list ast)))))))))
138 (statement (caddar source)
145 ;; the first statement is in the case/label form
148 (if (form? 'six.case (car source)) ; the label is a case
149 (literal (cadar source)
152 (new-cont (list 'case (literal-val name)) cte)))
153 (new-cont (cadar source) cte)))) ; ordinary label
155 (define (statement source cte cont)
156 (cond ((form? 'six.define-variable source)
157 (define-variable source cte cont))
158 ((form? 'six.if source)
159 (if (null? (cdddr source))
160 (if1 source cte cont)
161 (if2 source cte cont)))
162 ((form? 'six.switch source)
163 (switch source cte cont))
164 ((form? 'six.while source)
165 (while source cte cont))
166 ((form? 'six.do-while source)
167 (do-while source cte cont))
168 ((form? 'six.for source)
169 (for source cte cont))
170 ((form? 'six.return source)
171 (return source cte cont))
172 ((form? 'six.break source)
173 (break source cte cont))
174 ((form? 'six.continue source)
175 (continue source cte cont))
176 ((form? 'six.goto source)
177 (goto source cte cont))
178 ((form? 'six.compound source)
179 (block source cte cont))
181 (expression source cte cont))))
183 (define (return source cte cont)
185 (define (ret asts cte)
186 (cont (new-return asts)
189 (if (null? (cdr source))
191 (expression (cadr source)
194 (ret (list ast) cte)))))
196 (define (break source cte cont)
200 (define (continue source cte cont)
204 (define (goto source cte cont)
205 (cont (new-goto (cadadr source)) ; label
208 (define (if1 source cte cont)
209 (expression (cadr source)
212 (statement (caddr source)
215 (cont (new-if (list ast1 ast2))
218 (define (if2 source cte cont)
219 (expression (cadr source)
222 (statement (caddr source)
225 (statement (cadddr source)
228 (cont (new-if (list ast1 ast2 ast3))
231 (define (switch source cte cont)
232 (expression (cadr source)
234 (lambda (ast1 cte) ; we matched the paren expr
235 (expect-form 'six.compound (caddr source))
236 (block (caddr source)
239 (cont (new-switch (cons ast1 (ast-subasts ast2)))
242 (define (while source cte cont)
243 (expression (cadr source)
246 (statement (caddr source)
249 (cont (new-while (list ast1 ast2))
252 (define (do-while source cte cont)
253 (statement (cadr source)
256 (expression (caddr source)
259 (cont (new-do-while (list ast1 ast2))
262 (define (for source cte cont)
264 (define (opt-expr source cte cont)
266 (expression source cte cont)
269 (statement (cadr source)
272 (opt-expr (caddr source)
275 (opt-expr (cadddr source)
278 (statement (car (cddddr source))
284 (new-literal 'byte 1))
290 (define (expression source cte cont)
291 (cond ((form? 'six.literal source)
292 (literal source cte cont))
293 ((form? 'six.prefix source)
294 ;; this is a hack to support hexadecimal values
295 ;; SIX does not parse C-style hex values (0x...), but falls back on
296 ;; the regular parser when it encounters Scheme-style hex values
297 ;; (#x...) and wraps them in a six.prefix.
298 ;; TODO support C-style hex values
299 (literal `(six.literal ,(cadr source)) cte cont))
300 ((form? 'six.identifier source)
301 (ref source cte cont))
302 ((form? 'six.call source)
303 (call source cte cont))
307 (operation op source cte cont)))
309 (error "expected expression" source))))
311 (define (operation op source cte cont)
312 (define (continue ast cte)
313 (expr-type-set! ast ((op-type-rule op) ast))
314 (cont (if fold-constants? ((op-constant-fold op) ast) ast)
321 (continue (new-oper (list ast1) #f op) cte))))
331 (continue (new-oper (list ast1 ast2) #f op) cte))))))
332 (else ; ternary operator
345 (continue (new-oper (list ast1 ast2 ast3) #f op)
348 (define (call source cte cont)
349 (let* ((id (get-id (cadr source)))
350 (binding (cte-lookup cte id)))
351 (if (def-procedure? binding)
352 (expressions (cddr source)
355 (cont (new-call args (def-procedure-type binding) binding)
357 (error "expected procedure" source))))
359 (define (expressions source cte cont)
360 (cond ((null? source)
364 (let ((head (car source))
372 (cont (cons ast asts)
375 (define (literal source cte cont)
376 (let ((n (cadr source)))
377 ;; note: literals have the smallest type they can fit in.
378 ;; this is not standard, so more casts than usual might be needed to
379 ;; avoid unfortunate truncations
380 ;; this helps generate shorter code, and can be considered a domain
381 ;; specific optimization
382 (cont (new-literal (val->type n) n)
385 (define (ref source cte cont)
386 (let* ((id (cadr source))
387 (binding (cte-lookup cte id)))
388 (if (def-variable? binding)
389 (cont (new-ref (def-variable-type binding) binding)
391 (error "expected variable" source))))
393 (define (toplevel source cte cont) ;; TODO have an implicit main
394 (cond ((form? 'six.define-variable source)
395 (define-variable source cte cont))
396 ((form? 'six.define-procedure source)
397 (define-procedure source cte cont))
399 (statement source cte cont))))
401 (define (program source cte cont)
403 (define (p source cte cont)
404 (cond ((null? source)
408 (let ((head (car source))
416 (cont (cons ast asts)
422 (cont (new-program asts)