diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2021-05-31 07:29:33 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2021-05-31 08:00:26 -0700 |
commit | e9d2f00edb5b537ba5a0b88f737af5e487653d3b (patch) | |
tree | 4cd5a3c7de4cc90a52263c1111fa28b6288d7172 /shell | |
parent | f691782d113a98d5277e41a59268a937425f6aa2 (diff) | |
download | mu-e9d2f00edb5b537ba5a0b88f737af5e487653d3b.tar.gz |
multi-macroexpanding backquote != nested backquote
This was quite difficult to diagnose. The issue I noticed was that brline had stopped working. All the bugs in previous commits were hiding the cause. Once I cleaned them up, I realized the problem was that the `(,x0 ,y0) was triggering the nested-backquote check. The fix was fairly straightforward then (even though I didn't yet understand why). But how to write a test for this? I spent some time trying to do so without defining a macro using literal macros, before I realized: You can't call literal macros; we don't have first-class macros. Trying to insert literal macro support just breaks everything because we have no way to distinguish between a literal macro call and the stage in macroexpand where a symbol has been replaced with its macro definition. How do you explain stuff like this? I grow weary of Lisp. There's still some issue in loading the entire definition of brline from data.limg.
Diffstat (limited to 'shell')
-rw-r--r-- | shell/macroexpand.mu | 130 |
1 files changed, 129 insertions, 1 deletions
diff --git a/shell/macroexpand.mu b/shell/macroexpand.mu index 44602a4a..9b3686b6 100644 --- a/shell/macroexpand.mu +++ b/shell/macroexpand.mu @@ -166,7 +166,12 @@ fn macroexpand-iter _expr-ah: (addr handle cell), globals: (addr global-table), compare backquote?, 0/false break-if-= # - error trace, "nested backquote not supported yet" + var double-unquote-found?/eax: boolean <- look-for-double-unquote rest-ah + compare double-unquote-found?, 0/false + { + break-if-= + error trace, "double unquote not supported yet" + } trace-higher trace return 0/false } @@ -319,6 +324,68 @@ fn macroexpand-iter _expr-ah: (addr handle cell), globals: (addr global-table), return result } +fn look-for-double-unquote _expr-ah: (addr handle cell) -> _/eax: boolean { + # if expr is a non-pair, return false + var expr-ah/eax: (addr handle cell) <- copy _expr-ah + var expr/eax: (addr cell) <- lookup *expr-ah + { + var nil?/eax: boolean <- nil? expr + compare nil?, 0/false + break-if-= + return 0/false + } + { + var expr-type/eax: (addr int) <- get expr, type + compare *expr-type, 0/pair + break-if-= + return 0/false + } + var cdr-ah/ecx: (addr handle cell) <- get expr, right + var car-ah/ebx: (addr handle cell) <- get expr, left + var car/eax: (addr cell) <- lookup *car-ah + # if car is unquote or unquote-splice, check if cadr is unquote or + # unquote-splice. + $look-for-double-unquote:check: { + # if car is not an unquote, break + { + { + var unquote?/eax: boolean <- symbol-equal? car, "," + compare unquote?, 0/false + } + break-if-!= + var unquote-splice?/eax: boolean <- symbol-equal? car, ",@" + compare unquote-splice?, 0/false + break-if-!= + break $look-for-double-unquote:check + } + # if cadr is not an unquote, break + var cdr/eax: (addr cell) <- lookup *cdr-ah + var cadr-ah/eax: (addr handle cell) <- get cdr, left + var cadr/eax: (addr cell) <- lookup *cadr-ah + { + { + var unquote?/eax: boolean <- symbol-equal? cadr, "," + compare unquote?, 0/false + } + break-if-!= + var unquote-splice?/eax: boolean <- symbol-equal? cadr, ",@" + compare unquote-splice?, 0/false + break-if-!= + break $look-for-double-unquote:check + } + # error + return 1/true + } + var result/eax: boolean <- look-for-double-unquote car-ah + compare result, 0/false + { + break-if-= + return result + } + result <- look-for-double-unquote cdr-ah + return result +} + fn test-macroexpand { var globals-storage: global-table var globals/edx: (addr global-table) <- address globals-storage @@ -435,6 +502,67 @@ fn test-macroexpand-inside-fn-call { check assertion, "F - test-macroexpand-inside-fn-call" } +fn test-macroexpand-repeatedly-with-backquoted-arg { + var globals-storage: global-table + var globals/edx: (addr global-table) <- address globals-storage + initialize-globals globals + # new macro: m + var sandbox-storage: sandbox + var sandbox/esi: (addr sandbox) <- address sandbox-storage + initialize-sandbox-with sandbox, "(def m (litmac litfn () (a) `(cons 1 ,a)))" + edit-sandbox sandbox, 0x13/ctrl-s, globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen + # invoke macro + initialize-sandbox-with sandbox, "(m `(3))" +#? initialize-sandbox-with sandbox, "(m (m `(3)))" + var gap-ah/ecx: (addr handle gap-buffer) <- get sandbox, data + var gap/eax: (addr gap-buffer) <- lookup *gap-ah + var result-h: (handle cell) + var result-ah/ebx: (addr handle cell) <- address result-h + var trace-storage: trace + var trace/ecx: (addr trace) <- address trace-storage + initialize-trace trace, 1/only-errors, 0x10/capacity, 0/visible + read-cell gap, result-ah, trace + var dummy/eax: boolean <- macroexpand-iter result-ah, globals, trace + var error?/eax: boolean <- has-errors? trace + check-not error?, "F - test-macroexpand-repeatedly-with-backquoted-arg/error" + { + compare error?, 0/false + break-if-= + # we need space to display traces, so just stop rendering future tests on failure here + dump-trace trace + { + loop + } + } + var dummy/eax: boolean <- macroexpand-iter result-ah, globals, trace + var error?/eax: boolean <- has-errors? trace + check-not error?, "F - test-macroexpand-repeatedly-with-backquoted-arg/error2" + { + compare error?, 0/false + break-if-= + # we need space to display traces, so just stop rendering future tests on failure here + dump-trace trace + { + loop + } + } +#? dump-cell-from-cursor-over-full-screen result-ah + var _result/eax: (addr cell) <- lookup *result-ah + var result/edi: (addr cell) <- copy _result + # expected + initialize-sandbox-with sandbox, "(cons 1 `(3))" +#? initialize-sandbox-with sandbox, "(cons 1 (cons 1 `(3)))" + var expected-gap-ah/edx: (addr handle gap-buffer) <- get sandbox, data + var expected-gap/eax: (addr gap-buffer) <- lookup *expected-gap-ah + var expected-h: (handle cell) + var expected-ah/edx: (addr handle cell) <- address expected-h + read-cell expected-gap, expected-ah, trace + var expected/eax: (addr cell) <- lookup *expected-ah + # + var assertion/eax: boolean <- cell-isomorphic? result, expected, trace + check assertion, "F - test-macroexpand-repeatedly-with-backquoted-arg" +} + fn pending-test-macroexpand-inside-backquote-unquote { var globals-storage: global-table var globals/edx: (addr global-table) <- address globals-storage |