fn parse-input tokens: (addr stream cell), out: (addr handle cell), trace: (addr trace) { rewind-stream tokens var empty?/eax: boolean <- stream-empty? tokens compare empty?, 0/false { break-if-= error trace, "nothing to parse" return } var close-paren?/eax: boolean <- copy 0/false var dummy?/ecx: boolean <- copy 0/false close-paren?, dummy? <- parse-sexpression tokens, out, trace { compare close-paren?, 0/false break-if-= error trace, "')' is not a valid expression" return } { var empty?/eax: boolean <- stream-empty? tokens compare empty?, 0/false break-if-!= error trace, "unexpected tokens at end; only type in a single expression at a time" } } # return values: # 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, "parse", "parse" trace-lower trace var curr-token-storage: cell var curr-token/ecx: (addr cell) <- address curr-token-storage var empty?/eax: boolean <- stream-empty? tokens compare empty?, 0/false { break-if-= error trace, "end of stream; never found a balancing ')'" trace-higher trace return 1/true, 0/false } read-from-stream tokens, curr-token $parse-sexpression:type-check: { # single quote -> parse as list with a special car var quote-token?/eax: boolean <- quote-token? curr-token compare quote-token?, 0/false { break-if-= var out/edi: (addr handle cell) <- copy _out allocate-pair out var out-addr/eax: (addr cell) <- lookup *out var left-ah/edx: (addr handle cell) <- get out-addr, left new-symbol left-ah, "'" var right-ah/edx: (addr handle cell) <- get out-addr, right var close-paren?/eax: boolean <- copy 0/false var dot?/ecx: boolean <- copy 0/false close-paren?, dot? <- parse-sexpression tokens, right-ah, trace trace-higher trace return close-paren?, dot? } # backquote quote -> parse as list with a special car var backquote-token?/eax: boolean <- backquote-token? curr-token compare backquote-token?, 0/false { break-if-= var out/edi: (addr handle cell) <- copy _out allocate-pair out var out-addr/eax: (addr cell) <- lookup *out var left-ah/edx: (addr handle cell) <- get out-addr, left new-symbol left-ah, "`" var right-ah/edx: (addr handle cell) <- get out-addr, right var close-paren?/eax: boolean <- copy 0/false var dot?/ecx: boolean <- copy 0/false close-paren?, dot? <- parse-sexpression tokens, right-ah, trace trace-higher trace return close-paren?, dot? } # unquote -> parse as list with a special car var unquote-token?/eax: boolean <- unquote-token? curr-token compare unquote-token?, 0/false { break-if-= var out/edi: (addr handle cell) <- copy _out allocate-pair out var out-addr/eax: (addr cell) <- lookup *out var left-ah/edx: (addr handle cell) <- get out-addr, left new-symbol left-ah, "," var right-ah/edx: (addr handle cell) <- get out-addr, right var close-paren?/eax: boolean <- copy 0/false var dot?/ecx: boolean <- copy 0/false close-paren?, dot? <- parse-sexpression tokens, right-ah, trace trace-higher trace return close-paren?, dot? } # unquote-splice -> parse as list with a special car var unquote-splice-token?/eax: boolean <- unquote-splice-token? curr-token compare unquote-splice-token?, 0/false { break-if-= var out/edi: (addr handle cell) <- copy _out allocate-pair out var out-addr/eax: (addr cell) <- lookup *out var left-ah/edx: (addr handle cell) <- get out-addr, left new-symbol left-ah, ",@" var right-ah/edx: (addr handle cell) <- get out-addr, right var close-paren?/eax: boolean <- copy 0/false var dot?/ecx: boolean <- copy 0/false close-paren?, dot? <- parse-sexpression tokens, right-ah, trace trace-higher trace return close-paren?, dot? } # dot -> return var dot?/eax: boolean <- dot-token? curr-token compare dot?, 0/false { break-if-= trace-higher trace return 0/false, 1/true } # not bracket -> parse atom var bracket-token?/eax: boolean <- bracket-token? curr-token compare bracket-token?, 0/false { break-if-!= parse-atom curr-token, _out, trace break $parse-sexpression:type-check } # open paren -> parse list var open-paren?/eax: boolean <- open-paren-token? curr-token compare open-paren?, 0/false { break-if-= var curr/esi: (addr handle cell) <- copy _out allocate-pair curr var curr-addr/eax: (addr cell) <- lookup *curr var left/edx: (addr handle cell) <- get curr-addr, left { var close-paren?/eax: boolean <- copy 0/false var dot?/ecx: boolean <- copy 0/false close-paren?, dot? <- parse-sexpression tokens, left, trace { compare dot?, 0/false break-if-= error trace, "'.' cannot be at the start of a list" return 1/true, dot? } compare close-paren?, 0/false break-if-!= var curr-addr/eax: (addr cell) <- lookup *curr curr <- get curr-addr, right var tmp-storage: (handle cell) var tmp/edx: (addr handle cell) <- address tmp-storage $parse-sexpression:list-loop: { var close-paren?/eax: boolean <- copy 0/false var dot?/ecx: boolean <- copy 0/false close-paren?, dot? <- parse-sexpression tokens, tmp