Refactor all words that depend on parsing to use parse+parseName+skip

This commit is contained in:
Remko Tronçon 2022-05-29 10:26:49 +02:00
parent 401c701579
commit 8f4c7b0999
2 changed files with 187 additions and 196 deletions

View file

@ -262,24 +262,15 @@
;; 6.1.0070 ;; 6.1.0070
(func $' (param $tos i32) (result i32) (func $' (param $tos i32) (result i32)
(local.get $tos) (i32.store (local.get $tos) (drop (call $find (call $parseName))))
(call $readWord (i32.const 0x20)) (i32.add (local.get $tos) (i32.const 4)))
(if (param i32) (result i32) (i32.eqz (i32.load8_u (call $wordBase)))
(then
(call $fail (i32.const 0x2001d (; = str("incomplete input") ;)))))
(call $FIND)
(drop (call $pop)))
(data (i32.const 0x200d8) "\cc\00\02\00" "\01" "' " "\14\00\00\00") (data (i32.const 0x200d8) "\cc\00\02\00" "\01" "' " "\14\00\00\00")
(elem (i32.const 0x14) $') (elem (i32.const 0x14) $')
;; 6.1.0080 ;; 6.1.0080
(func $paren (param $tos i32) (result i32) (func $paren (param $tos i32) (result i32)
(local $c i32) (drop (drop (call $parse (i32.const 0x29 (; = ')' ;)))))
(local.get $tos) (local.get $tos))
(loop $loop (param i32) (result i32)
(if (param i32) (result i32) (i32.lt_s (local.tee $c (call $readChar)) (i32.const 0))
(call $fail (i32.const 0x2002e (; = str("missing ')'") ;))))
(br_if $loop (i32.ne (local.get $c) (i32.const 41)))))
(data (i32.const 0x200e4) "\d8\00\02\00" "\81" (; F_IMMEDIATE ;) "( " "\15\00\00\00") (data (i32.const 0x200e4) "\d8\00\02\00" "\81" (; F_IMMEDIATE ;) "( " "\15\00\00\00")
(elem (i32.const 0x15) $paren) (elem (i32.const 0x15) $paren)
@ -773,9 +764,7 @@
;; 6.1.0705 ;; 6.1.0705
(func $ALIGN (param $tos i32) (result i32) (func $ALIGN (param $tos i32) (result i32)
(global.set $here (i32.and (global.set $here (call $aligned (global.get $here)))
(i32.add (global.get $here) (i32.const 3))
(i32.const -4 (; ~3 ;))))
(local.get $tos)) (local.get $tos))
(data (i32.const 0x20320) "\10\03\02\00" "\05" "ALIGN " "\3f\00\00\00") (data (i32.const 0x20320) "\10\03\02\00" "\05" "ALIGN " "\3f\00\00\00")
(elem (i32.const 0x3f) $ALIGN) (elem (i32.const 0x3f) $ALIGN)
@ -784,8 +773,7 @@
(func $ALIGNED (param $tos i32) (result i32) (func $ALIGNED (param $tos i32) (result i32)
(local $btos i32) (local $btos i32)
(i32.store (local.tee $btos (i32.sub (local.get $tos) (i32.const 4))) (i32.store (local.tee $btos (i32.sub (local.get $tos) (i32.const 4)))
(i32.and (i32.add (i32.load (local.get $btos)) (i32.const 3)) (call $aligned (i32.load (local.get $btos))))
(i32.const -4 (; ~3 ;))))
(local.get $tos)) (local.get $tos))
(data (i32.const 0x20330) "\20\03\02\00" "\07" "ALIGNED" "\40\00\00\00") (data (i32.const 0x20330) "\20\03\02\00" "\07" "ALIGNED" "\40\00\00\00")
(elem (i32.const 0x40) $ALIGNED) (elem (i32.const 0x40) $ALIGNED)
@ -874,12 +862,14 @@
;; 6.1.0895 ;; 6.1.0895
(func $CHAR (param $tos i32) (result i32) (func $CHAR (param $tos i32) (result i32)
(call $readWord (local.get $tos) (i32.const 0x20)) (local $addr i32)
(if (param i32) (result i32) (i32.eqz (i32.load8_u (call $wordBase))) (local $len i32)
(call $fail (i32.const 0x2001d (; = str("incomplete input") ;)))) (local.set $addr (local.set $len (call $parseName)))
(local.tee $tos) (if (i32.eqz (local.get $len))
(i32.store (i32.sub (local.get $tos) (i32.const 4)) (then
(i32.load8_u (i32.add (call $wordBase) (i32.const 1))))) (return (call $fail (local.get $tos) (i32.const 0x2001d (; = str("incomplete input") ;))))))
(i32.store (local.get $tos) (i32.load8_u (local.get $addr)))
(i32.add (local.get $tos) (i32.const 4)))
(data (i32.const 0x203d0) "\c0\03\02\00" "\04" "CHAR " "\4a\00\00\00") (data (i32.const 0x203d0) "\c0\03\02\00" "\04" "CHAR " "\4a\00\00\00")
(elem (i32.const 0x4a) $CHAR) (elem (i32.const 0x4a) $CHAR)
@ -927,34 +917,28 @@
;; 6.1.1000 ;; 6.1.1000
(func $CREATE (param $tos i32) (result i32) (func $CREATE (param $tos i32) (result i32)
(local $length i32) (local $addr i32)
(local $len i32)
(local $here i32) (local $here i32)
(i32.store (global.get $here) (global.get $latest)) (i32.store (global.get $here) (global.get $latest))
(global.set $latest (global.get $here)) (global.set $latest (global.get $here))
(global.set $here (i32.add (global.get $here) (i32.const 4))) (global.set $here (i32.add (global.get $here) (i32.const 4)))
(local.get $tos) (local.set $addr (local.set $len (call $parseName)))
(call $readWord (i32.const 0x20)) (if (i32.eqz (local.get $len))
(if (param i32) (result i32) (i32.eqz (local.tee $length (i32.load8_u (call $wordBase)))) (return (call $fail (local.get $tos) (i32.const 0x2001d (; = str("incomplete input") ;)))))
(call $fail (i32.const 0x2001d (; = str("incomplete input") ;)))) (i32.store8 (global.get $here) (local.get $len))
(drop (call $pop))
(i32.store8 (global.get $here) (local.get $length))
(memory.copy (memory.copy
(local.tee $here (i32.add (global.get $here) (i32.const 1))) (local.tee $here (i32.add (global.get $here) (i32.const 1)))
(i32.add (call $wordBase) (i32.const 1)) (local.get $addr)
(local.get $length)) (local.get $len))
(global.set $here (call $aligned (i32.add (local.get $here) (local.get $len))))
(global.set $here (i32.add (local.get $here) (local.get $length)))
(call $ALIGN)
(i32.store (global.get $here) (i32.const 0x3 (; = PUSH_DATA_ADDRESS_INDEX ;))) (i32.store (global.get $here) (i32.const 0x3 (; = PUSH_DATA_ADDRESS_INDEX ;)))
(global.set $here (i32.add (global.get $here) (i32.const 4))) (global.set $here (i32.add (global.get $here) (i32.const 4)))
(i32.store (global.get $here) (i32.const 0)) (i32.store (global.get $here) (i32.const 0))
(call $setFlag (i32.const 0x40 (; = F_DATA ;)))
(call $setFlag (i32.const 0x40 (; = F_DATA ;)))) (local.get $tos))
(data (i32.const 0x20430) "\24\04\02\00" "\06" "CREATE " "\50\00\00\00") (data (i32.const 0x20430) "\24\04\02\00" "\06" "CREATE " "\50\00\00\00")
(elem (i32.const 0x50) $CREATE) (elem (i32.const 0x50) $CREATE)
@ -1130,34 +1114,18 @@
;; 6.1.1550 ;; 6.1.1550
(func $FIND (param $tos i32) (result i32) (func $FIND (param $tos i32) (result i32)
(local $entryP i32) (local $caddr i32)
(local $entryLF i32) (local $xt i32)
(local $wordStart i32) (local $r i32)
(local $wordLength i32) (local.set $xt (local.set $r
(local.set $wordLength (i32.load8_u (local.tee $wordStart (i32.load (i32.sub (local.get $tos) (i32.const 4)))))) (call $find
(local.set $wordStart (i32.add (local.get $wordStart) (i32.const 1))) (i32.add (local.tee $caddr (i32.load (i32.sub (local.get $tos) (i32.const 4)))) (i32.const 1))
(local.set $entryP (global.get $latest)) (i32.load8_u (local.get $caddr)))))
(loop $loop (if (i32.eqz (local.get $r))
(if (then (i32.store (i32.sub (local.get $tos) (i32.const 4)) (local.get $caddr)))
(i32.and (else (i32.store (i32.sub (local.get $tos) (i32.const 4)) (local.get $xt))))
(i32.eqz (i32.store (local.get $tos) (local.get $r))
(i32.and (i32.add (local.get $tos) (i32.const 4)))
(local.tee $entryLF (i32.load (i32.add (local.get $entryP) (i32.const 4))))
(i32.const 0x20 (; = F_HIDDEN ;))))
(call $stringEqual
(local.get $wordStart) (local.get $wordLength)
(i32.add (local.get $entryP) (i32.const 5)) (i32.and (local.get $entryLF) (i32.const 0x1f (; = LENGTH_MASK ;)))))
(then
(i32.store (i32.sub (local.get $tos) (i32.const 4)) (local.get $entryP))
(call $push (local.get $tos)
(select
(i32.const -1)
(i32.const 1)
(i32.eqz (i32.and (local.get $entryLF) (i32.const 0x80 (; = F_IMMEDIATE ;))))))
(return)))
(local.set $entryP (i32.load (local.get $entryP)))
(br_if $loop (local.get $entryP)))
(call $push (local.get $tos) (i32.const 0)))
(data (i32.const 0x20534) "\24\05\02\00" "\04" "FIND " "\60\00\00\00") (data (i32.const 0x20534) "\24\05\02\00" "\04" "FIND " "\60\00\00\00")
(elem (i32.const 0x60) $FIND) (elem (i32.const 0x60) $FIND)
@ -1415,14 +1383,9 @@
(local $FINDResult i32) (local $FINDResult i32)
(local.get $tos) (local.get $tos)
(call $ensureCompiling) (call $ensureCompiling)
(call $readWord (i32.const 0x20)) (local.set $FINDToken (local.set $FINDResult (call $find (call $parseName))))
(if (param i32) (result i32) (i32.eqz (i32.load8_u (call $wordBase))) (if (param i32) (result i32) (i32.eqz (local.get $FINDResult))
(call $fail (i32.const 0x2001d (; = str("incomplete input") ;))))
(call $FIND)
(local.set $FINDResult (call $pop))
(if (param i32) (result i32) (i32.eqz (local.get $FINDResult))
(call $failUndefinedWord)) (call $failUndefinedWord))
(local.set $FINDToken (call $pop))
(if (param i32) (result i32) (i32.eq (local.get $FINDResult) (i32.const 1)) (if (param i32) (result i32) (i32.eq (local.get $FINDResult) (i32.const 1))
(then (then
(call $compileCall (local.get $FINDToken))) (call $compileCall (local.get $FINDToken)))
@ -1469,6 +1432,7 @@
(func $REFILL (param $tos i32) (result i32) (func $REFILL (param $tos i32) (result i32)
(local $char i32) (local $char i32)
(global.set $inputBufferSize (i32.const 0)) (global.set $inputBufferSize (i32.const 0))
(i32.store (i32.const 0x202a8 (; = body(>IN) ;)) (i32.const 0))
(local.get $tos) (local.get $tos)
(if (param i32) (result i32) (i32.eq (global.get $sourceID) (i32.const -1)) (if (param i32) (result i32) (i32.eq (global.get $sourceID) (i32.const -1))
(then (then
@ -1480,9 +1444,7 @@
(i32.const 0x700 (; = INPUT_BUFFER_SIZE ;)))) (i32.const 0x700 (; = INPUT_BUFFER_SIZE ;))))
(if (param i32) (result i32) (i32.eqz (global.get $inputBufferSize)) (if (param i32) (result i32) (i32.eqz (global.get $inputBufferSize))
(then (call $push (i32.const 0))) (then (call $push (i32.const 0)))
(else (else (call $push (i32.const -1)))))
(i32.store (i32.const 0x202a8 (; = body(>IN) ;)) (i32.const 0))
(call $push (i32.const -1)))))
(data (i32.const 0x206f8) "\e8\06\02\00" "\06" "REFILL " "\7f\00\00\00") (data (i32.const 0x206f8) "\e8\06\02\00" "\06" "REFILL " "\7f\00\00\00")
(elem (i32.const 0x7f) $REFILL) (elem (i32.const 0x7f) $REFILL)
@ -1524,21 +1486,16 @@
;; 6.1.2165 ;; 6.1.2165
(func $Sq (param $tos i32) (result i32) (func $Sq (param $tos i32) (result i32)
(local $c i32) (local $c i32)
(local $start i32) (local $addr i32)
(local $len i32)
(local.get $tos) (local.get $tos)
(call $ensureCompiling) (call $ensureCompiling)
(local.set $start (global.get $here)) (local.set $addr (local.set $len (call $parse (i32.const 0x22 (; = '"' ;)))))
(block $endLoop (param i32) (result i32) (memory.copy (global.get $here) (local.get $addr) (local.get $len))
(loop $loop (param i32) (result i32) (call $compilePushConst (global.get $here))
(if (param i32) (result i32) (i32.lt_s (local.tee $c (call $readChar)) (i32.const 0)) (call $compilePushConst (local.get $len))
(call $fail (i32.const 0x2003a (; = str("missing \"") ;)))) (global.set $here
(br_if $endLoop (i32.eq (local.get $c) (i32.const 0x22))) (call $aligned (i32.add (global.get $here) (local.get $len)))))
(i32.store8 (global.get $here) (local.get $c))
(global.set $here (i32.add (global.get $here) (i32.const 1)))
(br $loop)))
(call $compilePushConst (local.get $start))
(call $compilePushConst (i32.sub (global.get $here) (local.get $start)))
(call $ALIGN))
(data (i32.const 0x20734) "\24\07\02\00" "\82" (; F_IMMEDIATE ;) "S\22 " "\83\00\00\00") (data (i32.const 0x20734) "\24\07\02\00" "\82" (; F_IMMEDIATE ;) "S\22 " "\83\00\00\00")
(elem (i32.const 0x83) $Sq) (elem (i32.const 0x83) $Sq)
@ -1654,16 +1611,11 @@
(func $TO (param $tos i32) (result i32) (func $TO (param $tos i32) (result i32)
(local $v i32) (local $v i32)
(local $xt i32) (local $xt i32)
(local.get $tos) (local $btos i32)
(call $readWord (i32.const 0x20)) (local.set $xt (drop (call $find (call $parseName))))
(if (param i32) (result i32) (i32.eqz (i32.load8_u (call $wordBase))) (i32.store (i32.add (call $body (local.get $xt)) (i32.const 4))
(call $fail (i32.const 0x2001d (; = str("incomplete input") ;)))) (i32.load (local.tee $btos (i32.sub (local.get $tos) (i32.const 4)))))
(call $FIND) (local.get $btos))
(if (param i32) (result i32) (i32.eqz (call $pop))
(call $failUndefinedWord))
(local.set $xt (call $pop))
(local.set $v (call $pop))
(i32.store (i32.add (call $body (local.get $xt)) (i32.const 4)) (local.get $v)))
(data (i32.const 0x207f4) "\e4\07\02\00" "\02" "TO " "\8e\00\00\00") (data (i32.const 0x207f4) "\e4\07\02\00" "\02" "TO " "\8e\00\00\00")
(elem (i32.const 0x8e) $TO) (elem (i32.const 0x8e) $TO)
@ -1803,8 +1755,20 @@
;; 6.1.2450 ;; 6.1.2450
(func $WORD (param $tos i32) (result i32) (func $WORD (param $tos i32) (result i32)
(local $wordBase i32)
(local $addr i32)
(local $len i32)
(local $delimiter i32)
(local.get $tos) (local.get $tos)
(call $readWord (call $pop))) (local.set $delimiter (call $pop))
(call $skip (local.get $delimiter))
(local.set $addr (local.set $len (call $parse (local.get $delimiter))))
(memory.copy
(i32.add (local.tee $wordBase (call $wordBase)) (i32.const 1))
(local.get $addr)
(local.get $len))
(i32.store8 (local.get $wordBase) (local.get $len))
(call $push (local.get $wordBase)))
(data (i32.const 0x208d8) "\c8\08\02\00" "\04" "WORD " "\9c\00\00\00") (data (i32.const 0x208d8) "\c8\08\02\00" "\04" "WORD " "\9c\00\00\00")
(elem (i32.const 0x9c) $WORD) (elem (i32.const 0x9c) $WORD)
@ -1869,14 +1833,7 @@
;; 6.2.2535 ;; 6.2.2535
(func $\ (param $tos i32) (result i32) (func $\ (param $tos i32) (result i32)
(local $char i32) (drop (drop (call $parse (i32.const 0x0a (; '\n' ;)))))
(block $endSkipComments
(loop $skipComments
(local.set $char (call $readChar))
(br_if $endSkipComments (i32.eq (local.get $char)
(i32.const 0x0a (; '\n' ;))))
(br_if $endSkipComments (i32.eq (local.get $char) (i32.const -1)))
(br $skipComments)))
(local.get $tos)) (local.get $tos))
(data (i32.const 0x2092c) "\1c\09\02\00" "\81" (; F_IMMEDIATE ;) "\5c " "\a2\00\00\00") (data (i32.const 0x2092c) "\1c\09\02\00" "\81" (; F_IMMEDIATE ;) "\5c " "\a2\00\00\00")
(elem (i32.const 0xa2) $\) (elem (i32.const 0xa2) $\)
@ -1901,91 +1858,57 @@
(local $FINDToken i32) (local $FINDToken i32)
(local $error i32) (local $error i32)
(local $number i32) (local $number i32)
(local $wordAddr i32)
(local $wordLen i32)
(local.set $error (i32.const 0)) (local.set $error (i32.const 0))
(global.set $tors (i32.const 0x2000 (; = RETURN_STACK_BASE ;))) (global.set $tors (i32.const 0x2000 (; = RETURN_STACK_BASE ;)))
(local.get $tos) (block $endLoop
(block $endLoop (param i32) (result i32) (loop $loop
(loop $loop (param i32) (result i32) (local.set $wordAddr (local.set $wordLen (call $parseName)))
(call $readWord (i32.const 0x20)) (br_if $endLoop (i32.eqz (local.get $wordLen)))
(br_if $endLoop (i32.eqz (i32.load8_u (call $wordBase)))) (local.set $FINDToken (local.set $FINDResult
(call $FIND) (call $find (local.get $wordAddr) (local.get $wordLen))))
(local.set $FINDResult (call $pop)) (if (i32.eqz (local.get $FINDResult))
(local.set $FINDToken (call $pop))
(if (param i32) (result i32) (i32.eqz (local.get $FINDResult))
(then ;; Not in the dictionary. Is it a number? (then ;; Not in the dictionary. Is it a number?
(if (param i32 i32) (result i32) (i32.eqz (call $readNumber)) (if (param i32) (i32.eqz (call $readNumber (local.get $wordAddr) (local.get $wordLen)))
(then ;; It's a number. Are we compiling? (then ;; It's a number. Are we compiling?
(local.set $number) (local.set $number)
(if (param i32) (result i32) (i32.load (i32.const 0x207d0 (; = body(STATE) ;))) (if (i32.load (i32.const 0x207d0 (; = body(STATE) ;)))
(then (then
;; We're compiling. Pop it off the stack and ;; We're compiling. Pop it off the stack and
;; add it to the compiled list ;; add it to the compiled list
(call $compilePushConst (local.get $number))) (local.set $tos (call $compilePushConst (local.get $tos) (local.get $number))))
(else (else
;; We're not compiling. Put the number on the stack. ;; We're not compiling. Put the number on the stack.
(call $push (local.get $number))))) (local.set $tos (call $push (local.get $tos) (local.get $number))))))
(else ;; It's not a number. (else ;; It's not a number.
(drop) (drop)
(call $failUndefinedWord)))) (local.set $tos (call $failUndefinedWord (local.get $tos))))))
(else ;; Found the word. (else ;; Found the word.
;; Are we compiling or is it immediate? ;; Are we compiling or is it immediate?
(if (param i32) (result i32) (i32.or (i32.eqz (i32.load (i32.const 0x207d0 (; = body(STATE) ;)))) (if
(i32.eq (local.get $FINDResult) (i32.const 1))) (i32.or
(i32.eqz (i32.load (i32.const 0x207d0 (; = body(STATE) ;))))
(i32.eq (local.get $FINDResult) (i32.const 1)))
(then (then
(local.get $tos)
(call $push (local.get $FINDToken)) (call $push (local.get $FINDToken))
(call $EXECUTE)) (call $EXECUTE)
(local.set $tos))
(else (else
;; We're compiling a non-immediate ;; We're compiling a non-immediate
(call $compileCall (local.get $FINDToken)))))) (local.set $tos (call $compileCall (local.get $tos) (local.get $FINDToken)))))))
(br $loop))) (br $loop)))
;; 'WORD' left the address on the stack (local.get $tos)
(drop (call $pop))
(i32.load (i32.const 0x207d0 (; = body(STATE) ;)))) (i32.load (i32.const 0x207d0 (; = body(STATE) ;))))
(func $readWord (param $tos i32) (param $delimiter i32) (result i32) ;; Returns (number, unparsed length)
(local $char i32) (func $readNumber (param $addr i32) (param $len i32) (result i32 i32)
(local $stringPtr i32)
(local $wordBase i32)
;; Skip leading delimiters
(block $endSkipBlanks
(loop $skipBlanks
(local.set $char (call $readChar))
(br_if $skipBlanks (i32.eq (local.get $char) (local.get $delimiter)))
(br_if $skipBlanks (i32.eq (local.get $char) (i32.const 0x0a)))
(br $endSkipBlanks)))
(local.set $stringPtr (i32.add (local.tee $wordBase (call $wordBase)) (i32.const 1)))
(if (i32.ne (local.get $char) (i32.const -1))
(if (i32.ne (local.get $char) (i32.const 0x0a))
(then
;; Search for delimiter
(i32.store8 (i32.add (local.get $wordBase) (i32.const 1)) (local.get $char))
(local.set $stringPtr (i32.add (local.get $wordBase) (i32.const 2)))
(block $endReadChars
(loop $readChars
(local.set $char (call $readChar))
(br_if $endReadChars (i32.eq (local.get $char) (local.get $delimiter)))
(br_if $endReadChars (i32.eq (local.get $char) (i32.const 0x0a)))
(br_if $endReadChars (i32.eq (local.get $char) (i32.const -1)))
(i32.store8 (local.get $stringPtr) (local.get $char))
(local.set $stringPtr (i32.add (local.get $stringPtr) (i32.const 0x1)))
(br $readChars))))))
;; Write word length
(i32.store8 (local.get $wordBase)
(i32.sub (local.get $stringPtr) (i32.add (local.get $wordBase) (i32.const 1))))
(local.get $tos)
(call $push (local.get $wordBase)))
(func $readNumber (result i32 i32)
(local $length i32)
(local $restcount i32) (local $restcount i32)
(local $value i32) (local $value i32)
(if (i32.eqz (local.tee $length (i32.load8_u (call $wordBase)))) (if (i32.eqz (local.get $len))
(return (i32.const -1) (i32.const -1))) (return (i32.const -1) (i32.const -1)))
(call $number (i64.const 0) (i32.add (call $wordBase) (i32.const 1)) (local.get $length)) (call $number (i64.const 0) (local.get $addr) (local.get $len))
(local.set $restcount) (local.set $restcount)
(drop) (drop)
(i32.wrap_i64) (i32.wrap_i64)
@ -2611,14 +2534,7 @@
(br $loop)))) (br $loop))))
(func $failUndefinedWord (param $tos i32) (result i32) (func $failUndefinedWord (param $tos i32) (result i32)
(local $wordBase i32)
(call $type (i32.load8_u (i32.const 0x20000)) (i32.const 0x20001)) (call $type (i32.load8_u (i32.const 0x20000)) (i32.const 0x20001))
(call $shell_emit (i32.const 0x3a))
(call $shell_emit (i32.const 0x20))
(call $type
(i32.load8_u (local.tee $wordBase (call $wordBase)))
(i32.add (local.get $wordBase) (i32.const 1)))
(call $shell_emit (i32.const 0x0a))
(call $ABORT (local.get $tos))) (call $ABORT (local.get $tos)))
(func $setFlag (param $v i32) (func $setFlag (param $v i32)
@ -2699,28 +2615,100 @@
(i32.const 8 (; 4 + 1 + 3 ;))) (i32.const 8 (; 4 + 1 + 3 ;)))
(i32.const -4))) (i32.const -4)))
(func $readChar (result i32) (func $numberToChar (param $v i32) (result i32)
(local $n i32) (if (result i32) (i32.ge_u (local.get $v) (i32.const 10))
(local $in i32)
(if (result i32) (i32.ge_u (local.tee $in (i32.load (i32.const 0x202a8 (; = body(>IN) ;))))
(global.get $inputBufferSize))
(then (then
(i32.const -1)) (i32.add (local.get $v) (i32.const 0x37)))
(else (else
(local.set $n (i32.load8_s (i32.add (global.get $inputBufferBase) (local.get $in)))) (i32.add (local.get $v) (i32.const 0x30)))))
(i32.store (i32.const 0x202a8 (; = body(>IN) ;)) (i32.add (local.get $in) (i32.const 1)))
(local.get $n)))) ;; Returns address+length
(func $parseName (result i32 i32)
(call $skip (i32.const 0x20 (; = ' ' ;)))
(call $parse (i32.const 0x20 (; = ' ' ;))))
(func $numberToChar (param $v i32) (result i32) ;; Returns address+length
(if (result i32) (i32.ge_u (local.get $v) (i32.const 10)) (func $parse (param $delim i32) (result i32 i32)
(local $addr i32)
(local $p i32)
(local $end i32)
(local $c i32)
(local $delimited i32)
(local.set $p
(local.tee $addr (i32.add (global.get $inputBufferBase)
(i32.load (i32.const 0x202a8 (; = body(>IN) ;))))))
(local.set $end (i32.add (global.get $inputBufferBase) (global.get $inputBufferSize)))
(local.set $delimited (i32.const 0))
(block $endOfInput
(block $delimiter
(loop $read
(br_if $endOfInput (i32.eq (local.get $p) (local.get $end)))
(local.set $c (i32.load8_s (local.get $p)))
(local.set $p (i32.add (local.get $p) (i32.const 1)))
(br_if $delimiter (i32.eq (local.get $c) (i32.const 0xa)))
(br_if $read (i32.ne (local.get $c) (local.get $delim)))))
(local.set $delimited (i32.const 1)))
(i32.store (i32.const 0x202a8 (; = body(>IN) ;))
(i32.sub (local.get $p) (global.get $inputBufferBase)))
(local.get $addr)
(i32.sub
(i32.sub (local.get $p) (local.get $delimited))
(local.get $addr)))
(func $skip (param $delim i32)
(local $addr i32)
(local $p i32)
(local $end i32)
(local $c i32)
(local.set $p
(local.tee $addr (i32.add (global.get $inputBufferBase)
(i32.load (i32.const 0x202a8 (; = body(>IN) ;))))))
(local.set $end (i32.add (global.get $inputBufferBase) (global.get $inputBufferSize)))
(block $endLoop
(loop $loop
(br_if $endLoop (i32.eq (local.get $p) (local.get $end)))
(local.set $c (i32.load8_s (local.get $p)))
(br_if $endLoop (i32.ne (local.get $c) (local.get $delim)))
(local.set $p (i32.add (local.get $p) (i32.const 1)))
;; Eat up a newline
(br_if $loop (i32.ne (local.get $c) (i32.const 0xa)))))
(i32.store (i32.const 0x202a8 (; = body(>IN) ;))
(i32.sub (local.get $p) (global.get $inputBufferBase))))
;; Returns xt, type (0 = not found, 1 = immediate, -1 = non-immediate)
(func $find (param $addr i32) (param $len i32) (result i32) (result i32)
(local $entryP i32)
(local $entryLF i32)
(local.set $entryP (global.get $latest))
(loop $loop
(if
(i32.and
(i32.eqz
(i32.and
(local.tee $entryLF (i32.load (i32.add (local.get $entryP) (i32.const 4))))
(i32.const 0x20 (; = F_HIDDEN ;))))
(call $stringEqual
(local.get $addr) (local.get $len)
(i32.add (local.get $entryP) (i32.const 5)) (i32.and (local.get $entryLF) (i32.const 0x1f (; = LENGTH_MASK ;)))))
(then (then
(i32.add (local.get $v) (i32.const 0x37))) (return
(else (local.get $entryP)
(i32.add (local.get $v) (i32.const 0x30))))) (select
(i32.const -1)
(i32.const 1)
(i32.eqz (i32.and (local.get $entryLF) (i32.const 0x80 (; = F_IMMEDIATE ;))))))))
(local.set $entryP (i32.load (local.get $entryP)))
(br_if $loop (local.get $entryP)))
(i32.const 0) (i32.const 0))
(func $wordBase (result i32) (func $wordBase (result i32)
(i32.add (global.get $here) (i32.const 0x200 (; = WORD_OFFSET ;)))) (i32.add (global.get $here) (i32.const 0x200 (; = WORD_OFFSET ;))))
(func $aligned (param $addr i32) (result i32)
(i32.and
(i32.add (local.get $addr) (i32.const 3))
(i32.const -4 (; ~3 ;))))
(func $U._ (param $v i32) (param $base i32) (func $U._ (param $v i32) (param $base i32)
(local $m i32) (local $m i32)
(local.set $m (i32.rem_u (local.get $v) (local.get $base))) (local.set $m (i32.rem_u (local.get $v) (local.get $base)))

View file

@ -192,7 +192,8 @@ function loadTests() {
it("should return an error when word is not found", () => { it("should return an error when word is not found", () => {
forth.read("BADWORD"); forth.read("BADWORD");
expect(() => core.interpret()).to.throw(); expect(() => core.interpret()).to.throw();
expect(output.trim()).to.eql("undefined word: BADWORD"); // expect(output.trim()).to.eql("undefined word: BADWORD");
expect(output.trim()).to.eql("undefined word");
}); });
it("should interpret a positive number", () => { it("should interpret a positive number", () => {
@ -214,13 +215,15 @@ function loadTests() {
it("should not interpret hex in decimal mode", () => { it("should not interpret hex in decimal mode", () => {
forth.read("DF"); forth.read("DF");
expect(() => core.interpret()).to.throw(); expect(() => core.interpret()).to.throw();
expect(output.trim()).to.eql("undefined word: DF"); // expect(output.trim()).to.eql("undefined word: DF");
expect(output.trim()).to.eql("undefined word");
}); });
it("should fail on half a word", () => { it("should fail on half a word", () => {
forth.read("23FOO"); forth.read("23FOO");
expect(() => core.interpret()).to.throw(); expect(() => core.interpret()).to.throw();
expect(output.trim()).to.eql("undefined word: 23FOO"); // expect(output.trim()).to.eql("undefined word: 23FOO");
expect(output.trim()).to.eql("undefined word");
}); });
it("should interpret a long string", () => { it("should interpret a long string", () => {