.
[mu.git] / shell / macroexpand.mu
blobb9e98f731682fb2cc24551ca75a839c5cb34e833
1 fn macroexpand expr-ah: (addr handle cell), globals: (addr global-table), trace: (addr trace) {
2   # trace "macroexpand " expr-ah {{{
3   {
4     var should-trace?/eax: boolean <- should-trace? trace
5     compare should-trace?, 0/false
6     break-if-=
7     var stream-storage: (stream byte 0x200)
8     var stream/ecx: (addr stream byte) <- address stream-storage
9     write stream, "macroexpand "
10     var nested-trace-storage: trace
11     var nested-trace/edi: (addr trace) <- address nested-trace-storage
12     initialize-trace nested-trace, 1/only-errors, 0x10/capacity, 0/visible
13     print-cell expr-ah, stream, nested-trace
14     trace trace, "mac", stream
15   }
16   # }}}
17   trace-lower trace
18 #?   clear-screen 0
19 #?   set-cursor-position 0, 0x20 0x20
20   # loop until convergence
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   # trace "=> " expr-ah {{{
31   {
32     var should-trace?/eax: boolean <- should-trace? trace
33     compare should-trace?, 0/false
34     break-if-=
35     var stream-storage: (stream byte 0x200)
36     var stream/ecx: (addr stream byte) <- address stream-storage
37     write stream, "=> "
38     var nested-trace-storage: trace
39     var nested-trace/edi: (addr trace) <- address nested-trace-storage
40     initialize-trace nested-trace, 1/only-errors, 0x10/capacity, 0/visible
41     print-cell expr-ah, stream, nested-trace
42     trace trace, "mac", stream
43   }
44   # }}}
47 # return true if we found any macros
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   # trace "macroexpand-iter " expr {{{
56   {
57     var should-trace?/eax: boolean <- should-trace? trace
58     compare should-trace?, 0/false
59     break-if-=
60     var stream-storage: (stream byte 0x200)
61     var stream/ecx: (addr stream byte) <- address stream-storage
62     write stream, "macroexpand-iter "
63     var nested-trace-storage: trace
64     var nested-trace/edi: (addr trace) <- address nested-trace-storage
65     initialize-trace nested-trace, 1/only-errors, 0x10/capacity, 0/visible
66     print-cell expr-ah, stream, nested-trace
67     trace trace, "mac", stream
68   }
69   # }}}
70   trace-lower trace
71   debug-print "a", 7/fg, 0/bg
72   # if expr is a non-pair, return
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     # nil is a literal
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     # non-pairs are literals
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   # if expr is a literal pair, return
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     # litfn is a literal
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     # litmac is a literal
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     # litimg is a literal
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   # for each builtin, expand only what will later be evaluated
135   $macroexpand-iter:anonymous-function: {
136     var fn?/eax: boolean <- fn? first
137     compare fn?, 0/false
138     break-if-=
139     # fn: expand every expression in the body
140     trace-text trace, "mac", "anonymous function"
141     # skip parameters
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     # trace "fn=> " _expr-ah {{{
165     {
166       var should-trace?/eax: boolean <- should-trace? trace
167       compare should-trace?, 0/false
168       break-if-=
169       var stream-storage: (stream byte 0x200)
170       var stream/ecx: (addr stream byte) <- address stream-storage
171       write stream, "fn=> "
172       var nested-trace-storage: trace
173       var nested-trace/edi: (addr trace) <- address nested-trace-storage
174       initialize-trace nested-trace, 1/only-errors, 0x10/capacity, 0/visible
175       print-cell _expr-ah, stream, nested-trace
176       trace trace, "mac", stream
177     }
178     # }}}
179     return result
180   }
181   debug-print "g", 7/fg, 0/bg
182   # builtins with "special" evaluation rules
183   $macroexpand-iter:quote: {
184     # trees starting with single quote create literals
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     # nested backquote not supported for now
196     var backquote?/eax: boolean <- symbol-equal? first, "`"
197     compare backquote?, 0/false
198     break-if-=
199     #
200 #?     set-cursor-position 0/screen, 0x40/x 0x10/y
201 #?     dump-cell-from-cursor-over-full-screen rest-ah
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     # nested backquote not supported for now
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     # nested backquote not supported for now
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     # trees starting with "define" define globals
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  # skip name
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     # trace "define=> " _expr-ah {{{
242     {
243       var should-trace?/eax: boolean <- should-trace? trace
244       compare should-trace?, 0/false
245       break-if-=
246       var stream-storage: (stream byte 0x200)
247       var stream/ecx: (addr stream byte) <- address stream-storage
248       write stream, "define=> "
249       var nested-trace-storage: trace
250       var nested-trace/edi: (addr trace) <- address nested-trace-storage
251       initialize-trace nested-trace, 1/only-errors, 0x10/capacity, 0/visible
252       print-cell _expr-ah, stream, nested-trace
253       trace trace, "mac", stream
254     }
255     # }}}
256     return macro-found?
257   }
258   debug-print "j", 7/fg, 0/bg
259   $macroexpand-iter:set: {
260     # trees starting with "set" mutate bindings
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  # skip name
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     # trace "set=> " _expr-ah {{{
273     {
274       var should-trace?/eax: boolean <- should-trace? trace
275       compare should-trace?, 0/false
276       break-if-=
277       var stream-storage: (stream byte 0x200)
278       var stream/ecx: (addr stream byte) <- address stream-storage
279       write stream, "set=> "
280       var nested-trace-storage: trace
281       var nested-trace/edi: (addr trace) <- address nested-trace-storage
282       initialize-trace nested-trace, 1/only-errors, 0x10/capacity, 0/visible
283       print-cell _expr-ah, stream, nested-trace
284       trace trace, "mac", stream
285     }
286     # }}}
287     return macro-found?
288   }
289   debug-print "k", 7/fg, 0/bg
290   # 'and' is like a function for macroexpansion purposes
291   # 'or' is like a function for macroexpansion purposes
292   # 'if' is like a function for macroexpansion purposes
293   # 'while' is like a function for macroexpansion purposes
294   # if car(expr) is a symbol defined as a macro, expand it
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     # definition found
303     {
304       var definition-type/eax: (addr int) <- get definition, type
305       compare *definition-type, 0/pair
306     }
307     break-if-!=
308     # definition is a pair
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     # definition is a macro
317     var macro-definition-ah/eax: (addr handle cell) <- get definition, right
318     # TODO: check car(macro-definition) is litfn
319 #?     turn-on-debug-print
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     # trace "1=> " _expr-ah {{{
323     {
324       var should-trace?/eax: boolean <- should-trace? trace
325       compare should-trace?, 0/false
326       break-if-=
327       var stream-storage: (stream byte 0x200)
328       var stream/ecx: (addr stream byte) <- address stream-storage
329       write stream, "1=> "
330       var nested-trace-storage: trace
331       var nested-trace/edi: (addr trace) <- address nested-trace-storage
332       initialize-trace nested-trace, 1/only-errors, 0x10/capacity, 0/visible
333       print-cell _expr-ah, stream, nested-trace
334       trace trace, "mac", stream
335     }
336     # }}}
337     return 1/true
338   }
339   # no macro found; process any macros within args
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 #?     clear-screen 0/screen
345 #?     dump-trace trace
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   # trace "=> " _expr-ah {{{
369   {
370     var should-trace?/eax: boolean <- should-trace? trace
371     compare should-trace?, 0/false
372     break-if-=
373     var stream-storage: (stream byte 0x200)
374     var stream/ecx: (addr stream byte) <- address stream-storage
375     write stream, "=> "
376     var nested-trace-storage: trace
377     var nested-trace/edi: (addr trace) <- address nested-trace-storage
378     initialize-trace nested-trace, 1/only-errors, 0x10/capacity, 0/visible
379     print-cell _expr-ah, stream, nested-trace
380     trace trace, "mac", stream
381   }
382   # }}}
383   return result
386 fn look-for-double-unquote _expr-ah: (addr handle cell) -> _/eax: boolean {
387   # if expr is a non-pair, return false
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   # if car is unquote or unquote-splice, check if cadr is unquote or
406   # unquote-splice.
407   $look-for-double-unquote:check: {
408     # if car is not an unquote, break
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     # if cdr is not a pair, break
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     # if cadr is not an unquote, break
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     # error
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
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   # new macro: m
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   # invoke macro
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 #?   dump-cell-from-cursor-over-full-screen result-ah, 4/fg 0/bg
475   var _result/eax: (addr cell) <- lookup *result-ah
476   var result/edi: (addr cell) <- copy _result
477   # expected
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 #?   dump-cell-from-cursor-over-full-screen expected-ah
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"
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   # new macro: m
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   # invoke macro
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 #?   dump-cell-from-cursor-over-full-screen result-ah
514   var _result/eax: (addr cell) <- lookup *result-ah
515   var result/edi: (addr cell) <- copy _result
516   # expected
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"
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   # new macro: m
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   # invoke macro
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 #?   dump-cell-from-cursor-over-full-screen result-ah
552   var _result/eax: (addr cell) <- lookup *result-ah
553   var result/edi: (addr cell) <- copy _result
554   # expected
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 #?   dump-cell-from-cursor-over-full-screen expected-ah
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"
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   # macroexpand an expression with a backquote but no macro
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     # we need space to display traces, so just stop rendering future tests on failure here
591     dump-trace trace
592     {
593       loop
594     }
595   }
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   # new macro: m
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   # invoke macro
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 #?   dump-cell-from-cursor-over-full-screen result-ah
621   var _result/eax: (addr cell) <- lookup *result-ah
622   var result/edi: (addr cell) <- copy _result
623   # expected
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"
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   # new macro: m
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   # invoke macro
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 #?   dump-cell-from-cursor-over-full-screen result-ah
659   var _result/eax: (addr cell) <- lookup *result-ah
660   var result/edi: (addr cell) <- copy _result
661   # expected
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 #?   dump-cell-from-cursor-over-full-screen expected-ah
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"
675 # TODO: unquote-splice, nested and unnested