https://github.com/akkartik/mu/blob/main/shell/macroexpand.mu
1 fn macroexpand expr-ah: (addr handle cell), globals: (addr global-table), trace: (addr trace) {
2 +-- 15 lines: # trace "macroexpand " expr-ah --------------------------------------------------------------------------------------------------------------------------------------------
17 trace-lower trace
18
19
20
21 {
22 var error?/eax: boolean <- has-errors? trace
23 compare error?, 0/false
24 break-if-!=
25 var expanded?/eax: boolean <- macroexpand-iter expr-ah, globals, trace
26 compare expanded?, 0/false
27 loop-if-!=
28 }
29 trace-higher trace
30 +-- 15 lines: # trace "=> " expr-ah -----------------------------------------------------------------------------------------------------------------------------------------------------
45 }
46
47
48 fn macroexpand-iter _expr-ah: (addr handle cell), globals: (addr global-table), trace: (addr trace) -> _/eax: boolean {
49 var expr-ah/esi: (addr handle cell) <- copy _expr-ah
50 {
51 compare expr-ah, 0
52 break-if-!=
53 abort "macroexpand-iter: NULL expr-ah"
54 }
55 +-- 15 lines: # trace "macroexpand-iter " expr ------------------------------------------------------------------------------------------------------------------------------------------
70 trace-lower trace
71 debug-print "a", 7/fg, 0/bg
72
73 var expr/eax: (addr cell) <- lookup *expr-ah
74 {
75 compare expr, 0
76 break-if-!=
77 abort "macroexpand-iter: NULL expr"
78 }
79 {
80 var nil?/eax: boolean <- nil? expr
81 compare nil?, 0/false
82 break-if-=
83
84 trace-text trace, "mac", "nil"
85 trace-higher trace
86 return 0/false
87 }
88 debug-print "b", 7/fg, 0/bg
89 {
90 var expr-type/eax: (addr int) <- get expr, type
91 compare *expr-type, 0/pair
92 break-if-=
93
94 trace-text trace, "mac", "non-pair"
95 trace-higher trace
96 return 0/false
97 }
98 debug-print "c", 7/fg, 0/bg
99
100 var first-ah/ebx: (addr handle cell) <- get expr, left
101 var rest-ah/ecx: (addr handle cell) <- get expr, right
102 var first/eax: (addr cell) <- lookup *first-ah
103 {
104 var litfn?/eax: boolean <- litfn? first
105 compare litfn?, 0/false
106 break-if-=
107
108 trace-text trace, "mac", "literal function"
109 trace-higher trace
110 return 0/false
111 }
112 debug-print "d", 7/fg, 0/bg
113 {
114 var litmac?/eax: boolean <- litmac? first
115 compare litmac?, 0/false
116 break-if-=
117
118 trace-text trace, "mac", "literal macro"
119 trace-higher trace
120 return 0/false
121 }
122 debug-print "e", 7/fg, 0/bg
123 {
124 var litimg?/eax: boolean <- litimg? first
125 compare litimg?, 0/false
126 break-if-=
127
128 trace-text trace, "mac", "literal image"
129 trace-higher trace
130 return 0/false
131 }
132 debug-print "f", 7/fg, 0/bg
133 var result/edi: boolean <- copy 0/false
134
135 $macroexpand-iter:anonymous-function: {
136 var fn?/eax: boolean <- fn? first
137 compare fn?, 0/false
138 break-if-=
139
140 trace-text trace, "mac", "anonymous function"
141
142 var rest/eax: (addr cell) <- lookup *rest-ah
143 {
144 rest-ah <- get rest, right
145 rest <- lookup *rest-ah
146 {
147 var done?/eax: boolean <- nil? rest
148 compare done?, 0/false
149 }
150 break-if-!=
151 var curr-ah/eax: (addr handle cell) <- get rest, left
152 var macro-found?/eax: boolean <- macroexpand-iter curr-ah, globals, trace
153 result <- or macro-found?
154 {
155 var error?/eax: boolean <- has-errors? trace
156 compare error?, 0/false
157 break-if-=
158 trace-higher trace
159 return result
160 }
161 loop
162 }
163 trace-higher trace
164 +-- 15 lines: # trace "fn=> " _expr-ah --------------------------------------------------------------------------------------------------------------------------------------------------
179 return result
180 }
181 debug-print "g", 7/fg, 0/bg
182
183 $macroexpand-iter:quote: {
184
185 var quote?/eax: boolean <- symbol-equal? first, "'"
186 compare quote?, 0/false
187 break-if-=
188
189 trace-text trace, "mac", "quote"
190 trace-higher trace
191 return 0/false
192 }
193 debug-print "h", 7/fg, 0/bg
194 $macroexpand-iter:backquote: {
195
196 var backquote?/eax: boolean <- symbol-equal? first, "`"
197 compare backquote?, 0/false
198 break-if-=
199
200
201
202 var double-unquote-found?/eax: boolean <- look-for-double-unquote rest-ah
203 compare double-unquote-found?, 0/false
204 {
205 break-if-=
206 error trace, "double unquote not supported yet"
207 }
208 trace-higher trace
209 return 0/false
210 }
211 $macroexpand-iter:unquote: {
212
213 var unquote?/eax: boolean <- symbol-equal? first, ","
214 compare unquote?, 0/false
215 break-if-=
216 error trace, "unquote (,) must be within backquote (`)"
217 return 0/false
218 }
219 $macroexpand-iter:unquote-splice: {
220
221 var unquote-splice?/eax: boolean <- symbol-equal? first, ",@"
222 compare unquote-splice?, 0/false
223 break-if-=
224 error trace, "unquote (,@) must be within backquote (`)"
225 return 0/false
226 }
227 debug-print "i", 7/fg, 0/bg
228 $macroexpand-iter:define: {
229
230 var define?/eax: boolean <- symbol-equal? first, "define"
231 compare define?, 0/false
232 break-if-=
233
234 trace-text trace, "mac", "define"
235 var rest/eax: (addr cell) <- lookup *rest-ah
236 rest-ah <- get rest, right
237 rest <- lookup *rest-ah
238 var val-ah/edx: (addr handle cell) <- get rest, left
239 var macro-found?/eax: boolean <- macroexpand-iter val-ah, globals, trace
240 trace-higher trace
241 +-- 15 lines: # trace "define=> " _expr-ah ----------------------------------------------------------------------------------------------------------------------------------------------
256 return macro-found?
257 }
258 debug-print "j", 7/fg, 0/bg
259 $macroexpand-iter:set: {
260
261 var set?/eax: boolean <- symbol-equal? first, "set"
262 compare set?, 0/false
263 break-if-=
264
265 trace-text trace, "mac", "set"
266 var rest/eax: (addr cell) <- lookup *rest-ah
267 rest-ah <- get rest, right
268 rest <- lookup *rest-ah
269 var val-ah/edx: (addr handle cell) <- get rest, left
270 var macro-found?/eax: boolean <- macroexpand-iter val-ah, globals, trace
271 trace-higher trace
272 +-- 15 lines: # trace "set=> " _expr-ah -------------------------------------------------------------------------------------------------------------------------------------------------
287 return macro-found?
288 }
289 debug-print "k", 7/fg, 0/bg
290
291
292
293
294
295 {
296 var definition-h: (handle cell)
297 var definition-ah/edx: (addr handle cell) <- address definition-h
298 maybe-lookup-symbol-in-globals first, definition-ah, globals, trace
299 var definition/eax: (addr cell) <- lookup *definition-ah
300 compare definition, 0
301 break-if-=
302
303 {
304 var definition-type/eax: (addr int) <- get definition, type
305 compare *definition-type, 0/pair
306 }
307 break-if-!=
308
309 {
310 var definition-car-ah/eax: (addr handle cell) <- get definition, left
311 var definition-car/eax: (addr cell) <- lookup *definition-car-ah
312 var macro?/eax: boolean <- litmac? definition-car
313 compare macro?, 0/false
314 }
315 break-if-=
316
317 var macro-definition-ah/eax: (addr handle cell) <- get definition, right
318
319
320 apply macro-definition-ah, rest-ah, expr-ah, globals, trace, 0/no-screen, 0/no-keyboard, 0/definitions-created, 0/call-number
321 trace-higher trace
322 +-- 15 lines: # trace "1=> " _expr-ah ---------------------------------------------------------------------------------------------------------------------------------------------------
337 return 1/true
338 }
339
340 trace-text trace, "mac", "recursing into function definition"
341 var curr-ah/ebx: (addr handle cell) <- copy first-ah
342 $macroexpand-iter:loop: {
343 debug-print "l", 7/fg, 0/bg
344
345
346 {
347 var foo/eax: (addr cell) <- lookup *curr-ah
348 compare foo, 0
349 break-if-!=
350 abort "macroexpand-iter: NULL in loop"
351 }
352 var macro-found?/eax: boolean <- macroexpand-iter curr-ah, globals, trace
353 result <- or macro-found?
354 var error?/eax: boolean <- has-errors? trace
355 compare error?, 0/false
356 break-if-!=
357 var rest/eax: (addr cell) <- lookup *rest-ah
358 {
359 var nil?/eax: boolean <- nil? rest
360 compare nil?, 0/false
361 }
362 break-if-!=
363 curr-ah <- get rest, left
364 rest-ah <- get rest, right
365 loop
366 }
367 trace-higher trace
368 +-- 15 lines: # trace "=> " _expr-ah ----------------------------------------------------------------------------------------------------------------------------------------------------
383 return result
384 }
385
386 fn look-for-double-unquote _expr-ah: (addr handle cell) -> _/eax: boolean {
387
388 var expr-ah/eax: (addr handle cell) <- copy _expr-ah
389 var expr/eax: (addr cell) <- lookup *expr-ah
390 {
391 var nil?/eax: boolean <- nil? expr
392 compare nil?, 0/false
393 break-if-=
394 return 0/false
395 }
396 {
397 var expr-type/eax: (addr int) <- get expr, type
398 compare *expr-type, 0/pair
399 break-if-=
400 return 0/false
401 }
402 var cdr-ah/ecx: (addr handle cell) <- get expr, right
403 var car-ah/ebx: (addr handle cell) <- get expr, left
404 var car/eax: (addr cell) <- lookup *car-ah
405
406
407 $look-for-double-unquote:check: {
408
409 {
410 {
411 var unquote?/eax: boolean <- symbol-equal? car, ","
412 compare unquote?, 0/false
413 }
414 break-if-!=
415 var unquote-splice?/eax: boolean <- symbol-equal? car, ",@"
416 compare unquote-splice?, 0/false
417 break-if-!=
418 break $look-for-double-unquote:check
419 }
420
421 var cdr/eax: (addr cell) <- lookup *cdr-ah
422 var cdr-type/ecx: (addr int) <- get cdr, type
423 compare *cdr-type, 0/pair
424 break-if-!=
425
426 var cadr-ah/eax: (addr handle cell) <- get cdr, left
427 var cadr/eax: (addr cell) <- lookup *cadr-ah
428 {
429 {
430 var unquote?/eax: boolean <- symbol-equal? cadr, ","
431 compare unquote?, 0/false
432 }
433 break-if-!=
434 var unquote-splice?/eax: boolean <- symbol-equal? cadr, ",@"
435 compare unquote-splice?, 0/false
436 break-if-!=
437 break $look-for-double-unquote:check
438 }
439
440 return 1/true
441 }
442 var result/eax: boolean <- look-for-double-unquote car-ah
443 compare result, 0/false
444 {
445 break-if-=
446 return result
447 }
448 result <- look-for-double-unquote cdr-ah
449 return result
450 }
451
452 fn test-macroexpand {
453 var globals-storage: global-table
454 var globals/edx: (addr global-table) <- address globals-storage
455 initialize-globals globals
456
457 var sandbox-storage: sandbox
458 var sandbox/esi: (addr sandbox) <- address sandbox-storage
459 initialize-sandbox-with sandbox, "(define m (litmac litfn () (a b) `(+ ,a ,b)))"
460 edit-sandbox sandbox, 0x13/ctrl-s, globals, 0/no-disk
461
462 initialize-sandbox-with sandbox, "(m 3 4)"
463 var gap-ah/ecx: (addr handle gap-buffer) <- get sandbox, data
464 var gap/eax: (addr gap-buffer) <- lookup *gap-ah
465 var result-h: (handle cell)
466 var result-ah/ebx: (addr handle cell) <- address result-h
467 var trace-storage: trace
468 var trace/ecx: (addr trace) <- address trace-storage
469 initialize-trace trace, 1/only-errors, 0x10/capacity, 0/visible
470 read-cell gap, result-ah, trace
471 var dummy/eax: boolean <- macroexpand-iter result-ah, globals, trace
472 var error?/eax: boolean <- has-errors? trace
473 check-not error?, "F - test-macroexpand/error"
474
475 var _result/eax: (addr cell) <- lookup *result-ah
476 var result/edi: (addr cell) <- copy _result
477
478 initialize-sandbox-with sandbox, "(+ 3 4)"
479 var expected-gap-ah/edx: (addr handle gap-buffer) <- get sandbox, data
480 var expected-gap/eax: (addr gap-buffer) <- lookup *expected-gap-ah
481 var expected-h: (handle cell)
482 var expected-ah/edx: (addr handle cell) <- address expected-h
483 read-cell expected-gap, expected-ah, trace
484
485 var expected/eax: (addr cell) <- lookup *expected-ah
486
487 var assertion/eax: boolean <- cell-isomorphic? result, expected, trace
488 check assertion, "F - test-macroexpand"
489 }
490
491 fn test-macroexpand-inside-anonymous-fn {
492 var globals-storage: global-table
493 var globals/edx: (addr global-table) <- address globals-storage
494 initialize-globals globals
495
496 var sandbox-storage: sandbox
497 var sandbox/esi: (addr sandbox) <- address sandbox-storage
498 initialize-sandbox-with sandbox, "(define m (litmac litfn () (a b) `(+ ,a ,b)))"
499 edit-sandbox sandbox, 0x13/ctrl-s, globals, 0/no-disk
500
501 initialize-sandbox-with sandbox, "(fn() (m 3 4))"
502 var gap-ah/ecx: (addr handle gap-buffer) <- get sandbox, data
503 var gap/eax: (addr gap-buffer) <- lookup *gap-ah
504 var result-h: (handle cell)
505 var result-ah/ebx: (addr handle cell) <- address result-h
506 var trace-storage: trace
507 var trace/ecx: (addr trace) <- address trace-storage
508 initialize-trace trace, 1/only-errors, 0x10/capacity, 0/visible
509 read-cell gap, result-ah, trace
510 var dummy/eax: boolean <- macroexpand-iter result-ah, globals, trace
511 var error?/eax: boolean <- has-errors? trace
512 check-not error?, "F - test-macroexpand-inside-anonymous-fn/error"
513
514 var _result/eax: (addr cell) <- lookup *result-ah
515 var result/edi: (addr cell) <- copy _result
516
517 initialize-sandbox-with sandbox, "(fn() (+ 3 4))"
518 var expected-gap-ah/edx: (addr handle gap-buffer) <- get sandbox, data
519 var expected-gap/eax: (addr gap-buffer) <- lookup *expected-gap-ah
520 var expected-h: (handle cell)
521 var expected-ah/edx: (addr handle cell) <- address expected-h
522 read-cell expected-gap, expected-ah, trace
523 var expected/eax: (addr cell) <- lookup *expected-ah
524
525 var assertion/eax: boolean <- cell-isomorphic? result, expected, trace
526 check assertion, "F - test-macroexpand-inside-anonymous-fn"
527 }
528
529 fn test-macroexpand-inside-fn-call {
530 var globals-storage: global-table
531 var globals/edx: (addr global-table) <- address globals-storage
532 initialize-globals globals
533
534 var sandbox-storage: sandbox
535 var sandbox/esi: (addr sandbox) <- address sandbox-storage
536 initialize-sandbox-with sandbox, "(define m (litmac litfn () (a b) `(+ ,a ,b)))"
537 edit-sandbox sandbox, 0x13/ctrl-s, globals, 0/no-disk
538
539 initialize-sandbox-with sandbox, "((fn() (m 3 4)))"
540 var gap-ah/ecx: (addr handle gap-buffer) <- get sandbox, data
541 var gap/eax: (addr gap-buffer) <- lookup *gap-ah
542 var result-h: (handle cell)
543 var result-ah/ebx: (addr handle cell) <- address result-h
544 var trace-storage: trace
545 var trace/ecx: (addr trace) <- address trace-storage
546 initialize-trace trace, 1/only-errors, 0x10/capacity, 0/visible
547 read-cell gap, result-ah, trace
548 var dummy/eax: boolean <- macroexpand-iter result-ah, globals, trace
549 var error?/eax: boolean <- has-errors? trace
550 check-not error?, "F - test-macroexpand-inside-fn-call/error"
551
552 var _result/eax: (addr cell) <- lookup *result-ah
553 var result/edi: (addr cell) <- copy _result
554
555 initialize-sandbox-with sandbox, "((fn() (+ 3 4)))"
556 var expected-gap-ah/edx: (addr handle gap-buffer) <- get sandbox, data
557 var expected-gap/eax: (addr gap-buffer) <- lookup *expected-gap-ah
558 var expected-h: (handle cell)
559 var expected-ah/edx: (addr handle cell) <- address expected-h
560 read-cell expected-gap, expected-ah, trace
561
562 var expected/eax: (addr cell) <- lookup *expected-ah
563
564 var assertion/eax: boolean <- cell-isomorphic? result, expected, trace
565 check assertion, "F - test-macroexpand-inside-fn-call"
566 }
567
568 fn test-macroexpand-repeatedly-with-backquoted-arg {
569 var globals-storage: global-table
570 var globals/edx: (addr global-table) <- address globals-storage
571 initialize-globals globals
572
573 var sandbox-storage: sandbox
574 var sandbox/esi: (addr sandbox) <- address sandbox-storage
575 initialize-sandbox-with sandbox, "(cons 1 `(3))"
576 var gap-ah/ecx: (addr handle gap-buffer) <- get sandbox, data
577 var gap/eax: (addr gap-buffer) <- lookup *gap-ah
578 var result-h: (handle cell)
579 var result-ah/ebx: (addr handle cell) <- address result-h
580 var trace-storage: trace
581 var trace/ecx: (addr trace) <- address trace-storage
582 initialize-trace trace, 1/only-errors, 0x10/capacity, 0/visible
583 read-cell gap, result-ah, trace
584 var dummy/eax: boolean <- macroexpand-iter result-ah, globals, trace
585 var error?/eax: boolean <- has-errors? trace
586 check-not error?, "F - test-macroexpand-repeatedly-with-backquoted-arg"
587 {
588 compare error?, 0/false
589 break-if-=
590
591 dump-trace trace
592 {
593 loop
594 }
595 }
596 }
597
598 fn pending-test-macroexpand-inside-backquote-unquote {
599 var globals-storage: global-table
600 var globals/edx: (addr global-table) <- address globals-storage
601 initialize-globals globals
602
603 var sandbox-storage: sandbox
604 var sandbox/esi: (addr sandbox) <- address sandbox-storage
605 initialize-sandbox-with sandbox, "(define m (litmac litfn () (a b) `(+ ,a ,b)))"
606 edit-sandbox sandbox, 0x13/ctrl-s, globals, 0/no-disk
607
608 initialize-sandbox-with sandbox, "`(print [result is ] ,(m 3 4)))"
609 var gap-ah/ecx: (addr handle gap-buffer) <- get sandbox, data
610 var gap/eax: (addr gap-buffer) <- lookup *gap-ah
611 var result-h: (handle cell)
612 var result-ah/ebx: (addr handle cell) <- address result-h
613 var trace-storage: trace
614 var trace/ecx: (addr trace) <- address trace-storage
615 initialize-trace trace, 1/only-errors, 0x10/capacity, 0/visible
616 read-cell gap, result-ah, trace
617 var dummy/eax: boolean <- macroexpand-iter result-ah, globals, trace
618 var error?/eax: boolean <- has-errors? trace
619 check-not error?, "F - test-macroexpand-inside-backquote-unquote/error"
620
621 var _result/eax: (addr cell) <- lookup *result-ah
622 var result/edi: (addr cell) <- copy _result
623
624 initialize-sandbox-with sandbox, "`(print [result is ] ,(+ 3 4)))"
625 var expected-gap-ah/edx: (addr handle gap-buffer) <- get sandbox, data
626 var expected-gap/eax: (addr gap-buffer) <- lookup *expected-gap-ah
627 var expected-h: (handle cell)
628 var expected-ah/edx: (addr handle cell) <- address expected-h
629 read-cell expected-gap, expected-ah, trace
630 var expected/eax: (addr cell) <- lookup *expected-ah
631
632 var assertion/eax: boolean <- cell-isomorphic? result, expected, trace
633 check assertion, "F - test-macroexpand-inside-backquote-unquote"
634 }
635
636 fn pending-test-macroexpand-inside-nested-backquote-unquote {
637 var globals-storage: global-table
638 var globals/edx: (addr global-table) <- address globals-storage
639 initialize-globals globals
640
641 var sandbox-storage: sandbox
642 var sandbox/esi: (addr sandbox) <- address sandbox-storage
643 initialize-sandbox-with sandbox, "(define m (litmac litfn () (a b) `(+ ,a ,b)))"
644 edit-sandbox sandbox, 0x13/ctrl-s, globals, 0/no-disk
645
646 initialize-sandbox-with sandbox, "`(a ,(m 3 4) `(b ,(m 3 4) ,,(m 3 4)))"
647 var gap-ah/ecx: (addr handle gap-buffer) <- get sandbox, data
648 var gap/eax: (addr gap-buffer) <- lookup *gap-ah
649 var result-h: (handle cell)
650 var result-ah/ebx: (addr handle cell) <- address result-h
651 var trace-storage: trace
652 var trace/ecx: (addr trace) <- address trace-storage
653 initialize-trace trace, 1/only-errors, 0x10/capacity, 0/visible
654 read-cell gap, result-ah, trace
655 var dummy/eax: boolean <- macroexpand-iter result-ah, globals, trace
656 var error?/eax: boolean <- has-errors? trace
657 check-not error?, "F - test-macroexpand-inside-nested-backquote-unquote/error"
658
659 var _result/eax: (addr cell) <- lookup *result-ah
660 var result/edi: (addr cell) <- copy _result
661
662 initialize-sandbox-with sandbox, "`(a ,(+ 3 4) `(b ,(m 3 4) ,,(+ 3 4)))"
663 var expected-gap-ah/edx: (addr handle gap-buffer) <- get sandbox, data
664 var expected-gap/eax: (addr gap-buffer) <- lookup *expected-gap-ah
665 var expected-h: (handle cell)
666 var expected-ah/edx: (addr handle cell) <- address expected-h
667 read-cell expected-gap, expected-ah, trace
668
669 var expected/eax: (addr cell) <- lookup *expected-ah
670
671 var assertion/eax: boolean <- cell-isomorphic? result, expected, trace
672 check assertion, "F - test-macroexpand-inside-nested-backquote-unquote"
673 }
674
675