diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2021-05-06 21:24:34 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2021-05-06 21:38:02 -0700 |
commit | a1cfadc749e91abde00e56859b3d5122205a6ca4 (patch) | |
tree | dc8267cfc041b0ba5c4823ba79c3243a87630538 | |
parent | f882130c863d7ed05483a7ecc5e31a399aca241b (diff) | |
download | mu-a1cfadc749e91abde00e56859b3d5122205a6ca4.tar.gz |
first passing test for macroexpand
In the process I spent a long time tracking down a stray TODO in 108write.subx that I thought would abort but didn't since the switch to baremetal. Then after I reintroduced that assertion I had to go track down a bunch of buffer sizes. Stream sizes continue to be a huge mess.
-rw-r--r-- | 108write.subx | 10 | ||||
-rw-r--r-- | shell/gap-buffer.mu | 4 | ||||
-rw-r--r-- | shell/macroexpand.mu | 175 | ||||
-rw-r--r-- | shell/parse.mu | 16 | ||||
-rw-r--r-- | shell/tokenize.mu | 52 | ||||
-rw-r--r-- | shell/trace.mu | 33 |
6 files changed, 249 insertions, 41 deletions
diff --git a/108write.subx b/108write.subx index 43e9bf9b..88e05668 100644 --- a/108write.subx +++ b/108write.subx @@ -194,7 +194,7 @@ $_append-4:loop: 73/jump-if-addr>= $_append-4:end/disp8 # if (out >= outend) abort # just to catch test failures fast 39/compare 3/mod/direct 7/rm32/edi . . . 2/r32/edx . . # compare edi with edx - 73/jump-if-addr>= $_append-4:end/disp8 # TODO: abort + 0f 83/jump-if-addr>= $_append-4:abort/disp32 # *out = *in 8a/copy-byte 0/mod/indirect 6/rm32/esi . . . 3/r32/BL . . # copy byte at *esi to BL 88/copy-byte 0/mod/indirect 7/rm32/edi . . . 3/r32/BL . . # copy byte at BL to *edi @@ -217,4 +217,12 @@ $_append-4:end: 5d/pop-to-ebp c3/return +$_append-4:abort: + (draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0 "_append-4: stream full at " 3 0) # 3=cyan + (draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0 %eax 3 0) + { + eb/jump loop/disp8 + } + # never gets here + # . . vim:nowrap:textwidth=0 diff --git a/shell/gap-buffer.mu b/shell/gap-buffer.mu index fe6569d9..8dada84a 100644 --- a/shell/gap-buffer.mu +++ b/shell/gap-buffer.mu @@ -35,8 +35,8 @@ fn gap-buffer-capacity _gap: (addr gap-buffer) -> _/ecx: int { # just for tests fn initialize-gap-buffer-with self: (addr gap-buffer), s: (addr array byte) { - initialize-gap-buffer self, 0x10/capacity - var stream-storage: (stream byte 0x10/capacity) + initialize-gap-buffer self, 0x40/capacity + var stream-storage: (stream byte 0x40/capacity) var stream/ecx: (addr stream byte) <- address stream-storage write stream, s { diff --git a/shell/macroexpand.mu b/shell/macroexpand.mu index 8ab7d8e9..25fe5e0d 100644 --- a/shell/macroexpand.mu +++ b/shell/macroexpand.mu @@ -1,25 +1,118 @@ fn macroexpand expr-ah: (addr handle cell), globals: (addr global-table), trace: (addr trace) { + # trace "macroexpand " expr-ah {{{ + { + compare trace, 0 + break-if-= + var stream-storage: (stream byte 0x200) + var stream/ecx: (addr stream byte) <- address stream-storage + write stream, "macroexpand " + print-cell expr-ah, stream, 0/no-trace + trace trace, "mac", stream + } + # }}} # loop until convergence - var expanded?/eax: boolean <- macroexpand-iter expr-ah, globals, trace - compare expanded?, 0/false - loop-if-!= + { + var expanded?/eax: boolean <- macroexpand-iter expr-ah, globals, trace + compare expanded?, 0/false + loop-if-!= + } + # trace "=> " expr-ah {{{ + { + compare trace, 0 + break-if-= + var stream-storage: (stream byte 0x200) + var stream/ecx: (addr stream byte) <- address stream-storage + write stream, "=> " + print-cell expr-ah, stream, 0/no-trace + trace trace, "mac", stream + } + # }}} } # return true if we found any macros fn macroexpand-iter _expr-ah: (addr handle cell), globals: (addr global-table), trace: (addr trace) -> _/eax: boolean { - # if car(expr) is a symbol defined as a macro, expand it var expr-ah/esi: (addr handle cell) <- copy _expr-ah + # trace "macroexpand-iter " expr {{{ + { + compare trace, 0 + break-if-= + var stream-storage: (stream byte 0x200) + var stream/ecx: (addr stream byte) <- address stream-storage + write stream, "macroexpand-iter " + print-cell expr-ah, stream, 0/no-trace + trace trace, "mac", stream + } + # }}} + # if expr is a non-pair, return var expr/eax: (addr cell) <- lookup *expr-ah { + var nil?/eax: boolean <- nil? expr + compare nil?, 0/false + break-if-= + # nil is a literal + trace-text trace, "mac", "nil" + trace-higher trace + return 0/false + } + { var expr-type/eax: (addr int) <- get expr, type compare *expr-type, 0/pair break-if-= - # not a pair + # non-pairs are literals + trace-text trace, "mac", "non-pair" + trace-higher trace return 0/false } + # if expr is a literal pair, return var first-ah/ebx: (addr handle cell) <- get expr, left var rest-ah/ecx: (addr handle cell) <- get expr, right var first/eax: (addr cell) <- lookup *first-ah + { + var litfn?/eax: boolean <- litfn? first + compare litfn?, 0/false + break-if-= + # litfn is a literal + trace-text trace, "mac", "literal function" + trace-higher trace + return 0/false + } + { + var litmac?/eax: boolean <- litmac? first + compare litmac?, 0/false + break-if-= + # litmac is a literal + trace-text trace, "mac", "literal macro" + trace-higher trace + return 0/false + } + var result/edi: boolean <- copy 0/false + # for each builtin, expand only what will later be evaluated + macroexpand-iter:anonymous-function: { + var first/eax: (addr cell) <- lookup *first-ah + var fn?/eax: boolean <- fn? first + compare fn?, 0/false + break-if-= + # fn: expand every expression in the body + trace-text trace, "mac", "anonymous function" + # skip parameters + var rest/eax: (addr cell) <- lookup *rest-ah + { + rest-ah <- get rest, right + rest <- lookup *rest-ah + { + var done?/eax: boolean <- nil? rest + compare done?, 0/false + } + break-if-!= + var curr-ah/eax: (addr handle cell) <- get rest, left + var macro-found?/eax: boolean <- macroexpand-iter curr-ah, globals, trace + result <- or macro-found? + loop + } + trace-higher trace + return result + } + # if car(expr) is a symbol defined as a macro, expand it var definition-h: (handle cell) var definition-ah/ebx: (addr handle cell) <- address definition-h maybe-lookup-symbol-in-globals first, definition-ah, globals, trace @@ -51,3 +144,75 @@ fn macroexpand-iter _expr-ah: (addr handle cell), globals: (addr global-table), apply macro-definition-ah, rest-ah, expr-ah, globals, trace, 0/no-screen, 0/no-keyboard, 0/call-number return 1/true } + +fn test-macroexpand { + 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 b) `(+ ,a ,b)))" + edit-sandbox sandbox, 0x13/ctrl-s, globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen + var trace-ah/eax: (addr handle trace) <- get sandbox, trace + var trace/eax: (addr trace) <- lookup *trace-ah + # invoke macro + initialize-sandbox-with sandbox, "(m 3 4)" + 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 + read-cell gap, result-ah, 0/no-trace + var dummy/eax: boolean <- macroexpand-iter result-ah, globals, 0/no-trace +#? 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, "(+ 3 4)" + var expected-gap-ah/ecx: (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/ecx: (addr handle cell) <- address expected-h + read-cell expected-gap, expected-ah, 0/no-trace +#? dump-cell-from-cursor-over-full-screen expected-ah + var expected/eax: (addr cell) <- lookup *expected-ah + # + var assertion/eax: boolean <- cell-isomorphic? result, expected, 0/no-trace + check assertion, "F - test-macroexpand" +} + +fn test-macroexpand-inside-anonymous-fn { + 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 b) `(+ ,a ,b)))" + edit-sandbox sandbox, 0x13/ctrl-s, globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen + var trace-ah/eax: (addr handle trace) <- get sandbox, trace + var trace/eax: (addr trace) <- lookup *trace-ah + # invoke macro + initialize-sandbox-with sandbox, "(fn() (m 3 4))" + 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 + read-cell gap, result-ah, 0/no-trace + var dummy/eax: boolean <- macroexpand-iter result-ah, globals, 0/no-trace +#? 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, "(fn() (+ 3 4))" + var expected-gap-ah/ecx: (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/ecx: (addr handle cell) <- address expected-h + read-cell expected-gap, expected-ah, 0/no-trace +#? dump-cell-from-cursor-over-full-screen expected-ah + var expected/eax: (addr cell) <- lookup *expected-ah + # + var assertion/eax: boolean <- cell-isomorphic? result, expected, 0/no-trace + check assertion, "F - test-macroexpand-inside-anonymous-fn" +} diff --git a/shell/parse.mu b/shell/parse.mu index 283e1d49..eceebd7d 100644 --- a/shell/parse.mu +++ b/shell/parse.mu @@ -28,7 +28,7 @@ fn parse-input tokens: (addr stream cell), out: (addr handle cell), trace: (addr # unmatched close-paren encountered? # dot encountered? (only used internally by recursive calls) fn parse-sexpression tokens: (addr stream cell), _out: (addr handle cell), trace: (addr trace) -> _/eax: boolean, _/ecx: boolean { - trace-text trace, "read", "parse" + trace-text trace, "parse", "parse" trace-lower trace var curr-token-storage: cell var curr-token/ecx: (addr cell) <- address curr-token-storage @@ -180,7 +180,7 @@ fn parse-sexpression tokens: (addr stream cell), _out: (addr handle cell), trace return 1/true, 0/false } # otherwise abort - var stream-storage: (stream byte 0x40) + var stream-storage: (stream byte 0x400) var stream/edx: (addr stream byte) <- address stream-storage write stream, "unexpected token " var curr-token-data-ah/eax: (addr handle stream byte) <- get curr-token, text-data @@ -194,12 +194,12 @@ fn parse-sexpression tokens: (addr stream cell), _out: (addr handle cell), trace } fn parse-atom _curr-token: (addr cell), _out: (addr handle cell), trace: (addr trace) { - trace-text trace, "read", "parse atom" + trace-text trace, "parse", "parse atom" var curr-token/ecx: (addr cell) <- copy _curr-token var curr-token-data-ah/eax: (addr handle stream byte) <- get curr-token, text-data var _curr-token-data/eax: (addr stream byte) <- lookup *curr-token-data-ah var curr-token-data/esi: (addr stream byte) <- copy _curr-token-data - trace trace, "read", curr-token-data + trace trace, "parse", curr-token-data # number var number-token?/eax: boolean <- number-token? curr-token compare number-token?, 0/false @@ -215,11 +215,11 @@ fn parse-atom _curr-token: (addr cell), _out: (addr handle cell), trace: (addr t var dest/edi: (addr float) <- get out-addr, number-data copy-to *dest, val-float { - var stream-storage: (stream byte 0x40) + var stream-storage: (stream byte 0x400) var stream/ecx: (addr stream byte) <- address stream-storage write stream, "=> number " print-number out-addr, stream, 0/no-trace - trace trace, "read", stream + trace trace, "parse", stream } return } @@ -243,11 +243,11 @@ fn parse-atom _curr-token: (addr cell), _out: (addr handle cell), trace: (addr t var dest-ah/edx: (addr handle stream byte) <- get out-addr, text-data copy-object curr-token-data-ah, dest-ah { - var stream-storage: (stream byte 0x40) + var stream-storage: (stream byte 0x400) var stream/ecx: (addr stream byte) <- address stream-storage write stream, "=> symbol " print-symbol out-addr, stream, 0/no-trace - trace trace, "read", stream + trace trace, "parse", stream } } diff --git a/shell/tokenize.mu b/shell/tokenize.mu index 7572ffba..0ec4d57c 100644 --- a/shell/tokenize.mu +++ b/shell/tokenize.mu @@ -3,7 +3,7 @@ # they always have text-data. fn tokenize in: (addr gap-buffer), out: (addr stream cell), trace: (addr trace) { - trace-text trace, "read", "tokenize" + trace-text trace, "tokenize", "tokenize" trace-lower trace rewind-gap-buffer in var token-storage: cell @@ -19,7 +19,9 @@ fn tokenize in: (addr gap-buffer), out: (addr stream cell), trace: (addr trace) var dest-ah/eax: (addr handle stream byte) <- get token, text-data populate-stream dest-ah, 0x400/max-definition-size # +#? draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen "c", 7/fg 0/bg next-token in, token, trace +#? draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen "d", 7/fg 0/bg var skip?/eax: boolean <- comment-token? token compare skip?, 0/false loop-if-!= @@ -204,7 +206,7 @@ fn test-tokenize-stream-literal-in-tree { } fn next-token in: (addr gap-buffer), _out-cell: (addr cell), trace: (addr trace) { - trace-text trace, "read", "next-token" + trace-text trace, "tokenize", "next-token" trace-lower trace var out-cell/eax: (addr cell) <- copy _out-cell { @@ -217,13 +219,15 @@ fn next-token in: (addr gap-buffer), _out-cell: (addr cell), trace: (addr trace) $next-token:body: { clear-stream out var g/eax: grapheme <- peek-from-gap-buffer in +#? draw-grapheme-at-cursor 0/screen, g, 7/fg, 0/bg +#? move-cursor-rightward-and-downward 0/screen, 0, 0x80 { var stream-storage: (stream byte 0x40) var stream/esi: (addr stream byte) <- address stream-storage write stream, "next: " var gval/eax: int <- copy g write-int32-hex stream, gval - trace trace, "read", stream + trace trace, "tokenize", stream } # comment { @@ -317,16 +321,16 @@ fn next-token in: (addr gap-buffer), _out-cell: (addr cell), trace: (addr trace) } } trace-higher trace - var stream-storage: (stream byte 0x40) + var stream-storage: (stream byte 0x400) # maximum possible token size (next-stream-token) var stream/eax: (addr stream byte) <- address stream-storage write stream, "=> " rewind-stream out write-stream stream, out - trace trace, "read", stream + trace trace, "tokenize", stream } fn next-symbol-token in: (addr gap-buffer), out: (addr stream byte), trace: (addr trace) { - trace-text trace, "read", "looking for a symbol" + trace-text trace, "tokenize", "looking for a symbol" trace-lower trace $next-symbol-token:loop: { var done?/eax: boolean <- gap-buffer-scan-done? in @@ -339,14 +343,14 @@ fn next-symbol-token in: (addr gap-buffer), out: (addr stream byte), trace: (add write stream, "next: " var gval/eax: int <- copy g write-int32-hex stream, gval - trace trace, "read", stream + trace trace, "tokenize", stream } # if non-symbol, return { var symbol-grapheme?/eax: boolean <- symbol-grapheme? g compare symbol-grapheme?, 0/false break-if-!= - trace-text trace, "read", "stop" + trace-text trace, "tokenize", "stop" break $next-symbol-token:loop } var g/eax: grapheme <- read-from-gap-buffer in @@ -359,11 +363,11 @@ fn next-symbol-token in: (addr gap-buffer), out: (addr stream byte), trace: (add write stream, "=> " rewind-stream out write-stream stream, out - trace trace, "read", stream + trace trace, "tokenize", stream } fn next-operator-token in: (addr gap-buffer), out: (addr stream byte), trace: (addr trace) { - trace-text trace, "read", "looking for a operator" + trace-text trace, "tokenize", "looking for a operator" trace-lower trace $next-operator-token:loop: { var done?/eax: boolean <- gap-buffer-scan-done? in @@ -376,14 +380,14 @@ fn next-operator-token in: (addr gap-buffer), out: (addr stream byte), trace: (a write stream, "next: " var gval/eax: int <- copy g write-int32-hex stream, gval - trace trace, "read", stream + trace trace, "tokenize", stream } # if non-operator, return { var operator-grapheme?/eax: boolean <- operator-grapheme? g compare operator-grapheme?, 0/false break-if-!= - trace-text trace, "read", "stop" + trace-text trace, "tokenize", "stop" break $next-operator-token:loop } var g/eax: grapheme <- read-from-gap-buffer in @@ -396,11 +400,11 @@ fn next-operator-token in: (addr gap-buffer), out: (addr stream byte), trace: (a write stream, "=> " rewind-stream out write-stream stream, out - trace trace, "read", stream + trace trace, "tokenize", stream } fn next-number-token in: (addr gap-buffer), out: (addr stream byte), trace: (addr trace) { - trace-text trace, "read", "looking for a number" + trace-text trace, "tokenize", "looking for a number" trace-lower trace $next-number-token:loop: { var done?/eax: boolean <- gap-buffer-scan-done? in @@ -413,14 +417,14 @@ fn next-number-token in: (addr gap-buffer), out: (addr stream byte), trace: (add write stream, "next: " var gval/eax: int <- copy g write-int32-hex stream, gval - trace trace, "read", stream + trace trace, "tokenize", stream } # if not symbol grapheme, return { var symbol-grapheme?/eax: boolean <- symbol-grapheme? g compare symbol-grapheme?, 0/false break-if-!= - trace-text trace, "read", "stop" + trace-text trace, "tokenize", "stop" break $next-number-token:loop } # if not digit grapheme, abort @@ -431,7 +435,7 @@ fn next-number-token in: (addr gap-buffer), out: (addr stream byte), trace: (add error trace, "invalid number" return } - trace-text trace, "read", "append" + trace-text trace, "tokenize", "append" var g/eax: grapheme <- read-from-gap-buffer in write-grapheme out, g loop @@ -440,7 +444,7 @@ fn next-number-token in: (addr gap-buffer), out: (addr stream byte), trace: (add } fn next-stream-token in: (addr gap-buffer), out: (addr stream byte), trace: (addr trace) { - trace-text trace, "read", "stream" + trace-text trace, "tokenize", "stream" { var empty?/eax: boolean <- gap-buffer-scan-done? in compare empty?, 0/false @@ -455,27 +459,27 @@ fn next-stream-token in: (addr gap-buffer), out: (addr stream byte), trace: (add write-grapheme out, g loop } - var stream-storage: (stream byte 0x40) + var stream-storage: (stream byte 0x400) # max-definition-size var stream/esi: (addr stream byte) <- address stream-storage write stream, "=> " rewind-stream out write-stream stream, out - trace trace, "read", stream + trace trace, "tokenize", stream } fn next-bracket-token g: grapheme, out: (addr stream byte), trace: (addr trace) { - trace-text trace, "read", "bracket" + trace-text trace, "tokenize", "bracket" write-grapheme out, g var stream-storage: (stream byte 0x40) var stream/esi: (addr stream byte) <- address stream-storage write stream, "=> " rewind-stream out write-stream stream, out - trace trace, "read", stream + trace trace, "tokenize", stream } fn rest-of-line in: (addr gap-buffer), out: (addr stream byte), trace: (addr trace) { - trace-text trace, "read", "comment" + trace-text trace, "tokenize", "comment" { var empty?/eax: boolean <- gap-buffer-scan-done? in compare empty?, 0/false @@ -494,7 +498,7 @@ fn rest-of-line in: (addr gap-buffer), out: (addr stream byte), trace: (addr tra write stream, "=> " rewind-stream out write-stream stream, out - trace trace, "read", stream + trace trace, "tokenize", stream } fn symbol-grapheme? g: grapheme -> _/eax: boolean { diff --git a/shell/trace.mu b/shell/trace.mu index 12285704..dfe82638 100644 --- a/shell/trace.mu +++ b/shell/trace.mu @@ -300,9 +300,40 @@ fn dump-trace _self: (addr trace) { $dump-trace:iter: { var offset/ebx: (offset trace-line) <- compute-offset trace, i var curr/ebx: (addr trace-line) <- index trace, offset + y <- render-trace-line 0/screen, curr, 0, y, 0x80/width, 0x30/height, 7/fg, 0/bg + } + i <- increment + loop + } +} + +fn dump-trace-with-label _self: (addr trace), label: (addr array byte) { + var already-hiding-lines?: boolean + var y/ecx: int <- copy 0 + var self/esi: (addr trace) <- copy _self + compare self, 0 + { + break-if-!= + return + } + var trace-ah/eax: (addr handle array trace-line) <- get self, data + var _trace/eax: (addr array trace-line) <- lookup *trace-ah + var trace/edi: (addr array trace-line) <- copy _trace + var i/edx: int <- copy 0 + var max-addr/ebx: (addr int) <- get self, first-free + var max/ebx: int <- copy *max-addr + $dump-trace:loop: { + compare i, max + break-if->= + $dump-trace:iter: { + var offset/ebx: (offset trace-line) <- compute-offset trace, i + var curr/ebx: (addr trace-line) <- index trace, offset var curr-label-ah/eax: (addr handle array byte) <- get curr, label var curr-label/eax: (addr array byte) <- lookup *curr-label-ah - y <- render-trace-line 0/screen, curr, 0, y, 0x80/width, 0x30/height, 7/fg, 0xc5/bg=blue-bg + var show?/eax: boolean <- string-equal? curr-label, label + compare show?, 0/false + break-if-= + y <- render-trace-line 0/screen, curr, 0, y, 0x80/width, 0x30/height, 7/fg, 0/bg } i <- increment loop |