https://github.com/akkartik/mu/blob/main/shell/parse.mu
  1 fn parse-input tokens: (addr stream cell), out: (addr handle cell), trace: (addr trace) {
  2   rewind-stream tokens
  3   var empty?/eax: boolean <- stream-empty? tokens
  4   compare empty?, 0/false
  5   {
  6     break-if-=
  7     error trace, "nothing to parse"
  8     return
  9   }
 10   var close-paren?/eax: boolean <- parse-sexpression tokens, out, trace
 11   {
 12     compare close-paren?, 0/false
 13     break-if-=
 14     error trace, "')' is not a valid expression"
 15     return
 16   }
 17   {
 18     var empty?/eax: boolean <- stream-empty? tokens
 19     compare empty?, 0/false
 20     break-if-!=
 21     error trace, "unexpected tokens at end; only type in a single expression at a time"
 22   }
 23 }
 24 
 25 # return value: true if close-paren was encountered
 26 fn parse-sexpression tokens: (addr stream cell), _out: (addr handle cell), trace: (addr trace) -> _/eax: boolean {
 27   trace-text trace, "read", "parse"
 28   trace-lower trace
 29   var curr-token-storage: cell
 30   var curr-token/ecx: (addr cell) <- address curr-token-storage
 31   var empty?/eax: boolean <- stream-empty? tokens
 32   compare empty?, 0/false
 33   {
 34     break-if-=
 35     error trace, "end of stream; never found a balancing ')'"
 36     return 1/true
 37   }
 38   read-from-stream tokens, curr-token
 39   $parse-sexpression:type-check: {
 40     # not bracket -> parse atom
 41     var bracket-token?/eax: boolean <- bracket-token? curr-token
 42     compare bracket-token?, 0/false
 43     {
 44       break-if-!=
 45       parse-atom curr-token, _out, trace
 46       break $parse-sexpression:type-check
 47     }
 48     # open paren -> parse list
 49     var open-paren?/eax: boolean <- open-paren-token? curr-token
 50     compare open-paren?, 0/false
 51     {
 52       break-if-=
 53       var curr/esi: (addr handle cell) <- copy _out
 54       $parse-sexpression:list-loop: {
 55         allocate-pair curr
 56         var curr-addr/eax: (addr cell) <- lookup *curr
 57         var left/ecx: (addr handle cell) <- get curr-addr, left
 58         {
 59           var close-paren?/eax: boolean <- parse-sexpression tokens, left, trace
 60           compare close-paren?, 0/false
 61           break-if-!= $parse-sexpression:list-loop
 62         }
 63         #
 64         curr <- get curr-addr, right
 65         loop
 66       }
 67       break $parse-sexpression:type-check
 68     }
 69     # close paren -> parse list
 70     var close-paren?/eax: boolean <- close-paren-token? curr-token
 71     compare close-paren?, 0/false
 72     {
 73       break-if-=
 74       trace-higher trace
 75       return 1/true
 76     }
 77     # otherwise abort
 78     var stream-storage: (stream byte 0x40)
 79     var stream/edx: (addr stream byte) <- address stream-storage
 80     write stream, "unexpected token "
 81     var curr-token-data-ah/eax: (addr handle stream byte) <- get curr-token, text-data
 82     var curr-token-data/eax: (addr stream byte) <- lookup *curr-token-data-ah
 83     rewind-stream curr-token-data
 84     write-stream stream, curr-token-data
 85     trace trace, "error", stream
 86   }
 87   trace-higher trace
 88   return 0/false
 89 }
 90 
 91 fn parse-atom _curr-token: (addr cell), _out: (addr handle cell), trace: (addr trace) {
 92   trace-text trace, "read", "parse atom"
 93   var curr-token/ecx: (addr cell) <- copy _curr-token
 94   var curr-token-data-ah/eax: (addr handle stream byte) <- get curr-token, text-data
 95   var _curr-token-data/eax: (addr stream byte) <- lookup *curr-token-data-ah
 96   var curr-token-data/esi: (addr stream byte) <- copy _curr-token-data
 97   trace trace, "read", curr-token-data
 98   # number
 99   var number-token?/eax: boolean <- number-token? curr-token
100   compare number-token?, 0/false
101   {
102     break-if-=
103     rewind-stream curr-token-data
104     var _val/eax: int <- parse-decimal-int-from-stream curr-token-data
105     var val/ecx: int <- copy _val
106     var val-float/xmm0: float <- convert val
107     allocate-number _out
108     var out/eax: (addr handle cell) <- copy _out
109     var out-addr/eax: (addr cell) <- lookup *out
110     var dest/edi: (addr float) <- get out-addr, number-data
111     copy-to *dest, val-float
112     {
113       var stream-storage: (stream byte 0x40)
114       var stream/ecx: (addr stream byte) <- address stream-storage
115       write stream, "=> number "
116       print-number out-addr, stream, 0/no-trace
117       trace trace, "read", stream
118     }
119     return
120   }
121   # default: symbol
122   # just copy token data
123   allocate-symbol _out
124   var out/eax: (addr handle cell) <- copy _out
125   var out-addr/eax: (addr cell) <- lookup *out
126   var curr-token-data-ah/ecx: (addr handle stream byte) <- get curr-token, text-data
127   var dest-ah/edx: (addr handle stream byte) <- get out-addr, text-data
128   copy-object curr-token-data-ah, dest-ah
129   {
130     var stream-storage: (stream byte 0x40)
131     var stream/ecx: (addr stream byte) <- address stream-storage
132     write stream, "=> symbol "
133     print-symbol out-addr, stream, 0/no-trace
134     trace trace, "read", stream
135   }
136 }