3 ;; TODO: global warning
4 (global $token_buf (mut i32) 0)
5 (global $read_index (mut i32) 0)
7 (func $skip_spaces (param $str i32) (result i32)
9 $c (i32.load8_u (i32.add $str (global.get $read_index))))
12 ;;; while (c == ' ' || c == ',' || c == '\n')
13 (br_if $done (AND (i32.ne $c (CHR " "))
15 (i32.ne $c (CHR "\n"))))
18 (global.set $read_index (i32.add (global.get $read_index) 1))
19 (local.set $c (i32.load8_u (i32.add $str (global.get $read_index))))
23 ;; ($debug ">>> skip_spaces:" $found)
27 (func $skip_to_eol (param $str i32) (result i32)
29 $c (i32.load8_u (i32.add $str (global.get $read_index))))
30 (if (i32.eq $c (CHR ";"))
36 (global.set $read_index (i32.add (global.get $read_index) 1))
37 (local.set $c (i32.load8_u (i32.add $str
38 (global.get $read_index))))
39 ;;; while (c != '\0' && c != '\n')
40 (br_if $loop (AND (i32.ne $c (CHR "\x00"))
41 (i32.ne $c (CHR "\n"))))
44 ;; ($debug ">>> skip_to_eol:" $found)
48 (func $skip_spaces_comments (param $str i32)
51 (br_if $loop ($skip_spaces $str))
53 (br_if $loop ($skip_to_eol $str))
57 (func $read_token (param $str i32) (result i32)
64 ($skip_spaces_comments $str)
66 ;; read first character
68 (local.set $c (i32.load8_u (i32.add $str (global.get $read_index))))
69 (global.set $read_index (i32.add (global.get $read_index) 1))
70 ;; read first character
71 ;;; token[token_index++] = c
72 (i32.store8 (i32.add (global.get $token_buf) $token_index) $c)
73 (local.set $token_index (i32.add $token_index 1))
74 ;; single/double character token
75 (if (OR (i32.eq $c (CHR "("))
84 (AND (i32.eq $c (CHR "~"))
85 (i32.ne (i32.load8_u (i32.add $str (global.get $read_index)))
92 ;;; if (c == '"') isstring = true
93 (local.set $isstring (i32.eq $c (CHR "\"")))
94 (local.set $instring $isstring)
97 ;; peek at next character
99 (local.set $c (i32.load8_u
100 (i32.add $str (global.get $read_index))))
101 ;;; if (c == '\0') break
102 (br_if $done (i32.eq $c 0))
104 (if (i32.eqz $isstring)
106 ;; next character is token delimiter
107 (br_if $done (OR (i32.eq $c (CHR "("))
108 (i32.eq $c (CHR ")"))
109 (i32.eq $c (CHR "["))
110 (i32.eq $c (CHR "]"))
111 (i32.eq $c (CHR "{"))
112 (i32.eq $c (CHR "}"))
113 (i32.eq $c (CHR " "))
114 (i32.eq $c (CHR ","))
115 (i32.eq $c (CHR "\n"))))))
116 ;; read next character
117 ;;; token[token_index++] = str[(*index)++]
118 (i32.store8 (i32.add (global.get $token_buf) $token_index)
120 (i32.add $str (global.get $read_index))))
121 (local.set $token_index (i32.add $token_index 1))
122 (global.set $read_index (i32.add (global.get $read_index) 1))
123 ;;; if (token[0] == '~' && token[1] == '@') break
124 (br_if $done (AND (i32.eq (i32.load8_u
125 (i32.add (global.get $token_buf) 0))
128 (i32.add (global.get $token_buf) 1))
131 ;;; if ((!isstring) || escaped)
132 (if (OR (i32.eqz $isstring) $escaped)
134 (local.set $escaped 0)
136 (if (i32.eq $c (CHR "\\"))
137 (local.set $escaped 1))
138 (if (i32.eq $c (CHR "\""))
140 (local.set $instring 0)
146 (if (AND $isstring $instring)
148 ($THROW_STR_0 "expected '\"', got EOF")
151 ;;; token[token_index] = '\0'
152 (i32.store8 (i32.add (global.get $token_buf) $token_index) 0)
153 (global.get $token_buf)
156 (func $read_seq (param $str i32 $type i32 $end i32) (result i32)
157 (LET $res ($MAP_LOOP_START $type)
169 ($skip_spaces_comments $str)
171 ;; peek at next character
173 (local.set $c (i32.load8_u (i32.add $str (global.get $read_index))))
174 (if (i32.eq $c (CHR "\x00"))
176 ($THROW_STR_0 "unexpected EOF")
180 ;; read next character
181 ;;; c = str[(*index)++]
182 (local.set $c (i32.load8_u (i32.add $str (global.get $read_index))))
183 (global.set $read_index (i32.add (global.get $read_index) 1))
186 ;; value (or key for hash-maps)
187 (local.set $val2 ($read_form $str))
189 ;; if error, release the unattached element
190 (if (global.get $error_type)
195 ;; if this is a hash-map, READ_FORM again
196 (if (i32.eq $type (global.get $HASHMAP_T))
197 (local.set $val3 ($read_form $str)))
199 ;; update the return sequence structure
201 (local.set $res ($MAP_LOOP_UPDATE $type $empty $current $val2 $val3))
202 (if (i32.le_u $current (global.get $EMPTY_HASHMAP))
203 ;; if first element, set return to new element
204 (local.set $ret $res))
205 ;; update current to point to new element
206 (local.set $current $res)
216 (func $read_macro (param $str i32 $sym i32 $with_meta i32) (result i32)
217 (LET $first ($STRING (global.get $SYMBOL_T) $sym)
218 $second ($read_form $str)
221 (if (global.get $error_type) (return $res))
222 (if (i32.eqz $with_meta)
224 (local.set $res ($LIST2 $first $second)))
226 (local.set $third ($read_form $str))
227 (local.set $res ($LIST3 $first $third $second))
228 ;; release values, list has ownership
230 ;; release values, list has ownership
236 (func $read_form (param $str i32) (result i32)
237 (LET $tok 0 $c0 0 $c1 0 $res 0 $slen 0)
239 (if (global.get $error_type) (return 0))
241 (local.set $tok ($read_token $str))
243 (if (global.get $error_type) (return 0))
244 ;;($printf_1 ">>> read_form 1: %s\n" $tok)
246 (local.set $c0 (i32.load8_u $tok))
247 (local.set $c1 (i32.load8_u (i32.add $tok 1)))
251 (return ($INC_REF (global.get $NIL))))
252 (else (if (OR (AND (i32.ge_u $c0 (CHR "0"))
253 (i32.le_u $c0 (CHR "9")))
254 (AND (i32.eq $c0 (CHR "-"))
255 (i32.ge_u $c1 (CHR "0"))
256 (i32.le_u $c1 (CHR "9"))))
258 (return ($INTEGER ($atoi $tok))))
259 (else (if (i32.eq $c0 (CHR ":"))
261 (i32.store8 $tok (CHR "\x7f"))
262 (return ($STRING (global.get $STRING_T) $tok)))
263 (else (if (i32.eq $c0 (CHR "\""))
265 (local.set $slen ($strlen (i32.add $tok 1)))
266 (if (i32.ne (i32.load8_u (i32.add $tok $slen)) (CHR "\""))
268 ($THROW_STR_0 "expected '\"', got EOF")
271 ;; unescape backslashes, quotes, and newlines
272 ;; remove the trailing quote
273 (i32.store8 (i32.add $tok $slen) (CHR "\x00"))
274 (local.set $tok (i32.add $tok 1))
275 (drop ($REPLACE3 0 $tok
279 (return ($STRING (global.get $STRING_T) $tok)))))
280 (else (if (i32.eqz ($strcmp "nil" $tok))
281 (then (return ($INC_REF (global.get $NIL))))
282 (else (if (i32.eqz ($strcmp "false" $tok))
283 (then (return ($INC_REF (global.get $FALSE))))
284 (else (if (i32.eqz ($strcmp "true" $tok))
285 (then (return ($INC_REF (global.get $TRUE))))
286 (else (if (i32.eqz ($strcmp "'" $tok))
287 (then (return ($read_macro $str "quote" 0)))
288 (else (if (i32.eqz ($strcmp "`" $tok))
289 (then (return ($read_macro $str "quasiquote" 0)))
290 (else (if (i32.eqz ($strcmp "~@" $tok))
291 (then (return ($read_macro $str "splice-unquote" 0)))
292 (else (if (i32.eqz ($strcmp "~" $tok))
293 (then (return ($read_macro $str "unquote" 0)))
294 (else (if (i32.eqz ($strcmp "^" $tok))
295 (then (return ($read_macro $str "with-meta" 1)))
296 (else (if (i32.eqz ($strcmp "@" $tok))
297 (then (return ($read_macro $str "deref" 0)))
298 (else (if (i32.eq $c0 (CHR "("))
299 (then (return ($read_seq $str (global.get $LIST_T) (CHR ")"))))
300 (else (if (i32.eq $c0 (CHR "["))
301 (then (return ($read_seq $str (global.get $VECTOR_T) (CHR "]"))))
302 (else (if (i32.eq $c0 (CHR "{"))
303 (then (return ($read_seq $str (global.get $HASHMAP_T) (CHR "}"))))
304 (else (if (OR (i32.eq $c0 (CHR ")"))
305 (i32.eq $c0 (CHR "]"))
306 (i32.eq $c0 (CHR "}")))
308 ($THROW_STR_1 "unexpected '%c'" $c0)
311 (return ($STRING (global.get $SYMBOL_T) $tok))))
312 ))))))))))))))))))))))))))))))))
316 (func $read_str (param $str i32) (result i32)
317 (global.set $read_index 0)
321 (export "read_str" (func $read_str))