diff options
| author | Chouser <chouser@n01se.net> | 2015-02-14 13:40:07 -0500 |
|---|---|---|
| committer | Chouser <chouser@n01se.net> | 2015-02-21 13:22:44 -0500 |
| commit | 69972a8399efe4abb8567526e90262e131f90d26 (patch) | |
| tree | 5e12e86da119a9c3f4372dab9e04777a746f90d0 | |
| parent | 9da223a35a176d94fbb75cbcc1000871ff5aff0b (diff) | |
| download | mal-69972a8399efe4abb8567526e90262e131f90d26.tar.gz mal-69972a8399efe4abb8567526e90262e131f90d26.zip | |
forth: Add step 3
| -rw-r--r-- | forth/env.fs | 45 | ||||
| -rw-r--r-- | forth/misc-tests.fs | 28 | ||||
| -rw-r--r-- | forth/printer.fs | 5 | ||||
| -rw-r--r-- | forth/reader.fs | 9 | ||||
| -rw-r--r-- | forth/step2_eval.fs | 14 | ||||
| -rw-r--r-- | forth/step3_env.fs | 160 | ||||
| -rw-r--r-- | forth/types.fs | 93 |
7 files changed, 316 insertions, 38 deletions
diff --git a/forth/env.fs b/forth/env.fs new file mode 100644 index 0000000..c1dc278 --- /dev/null +++ b/forth/env.fs @@ -0,0 +1,45 @@ +require types.fs + +MalType% + cell% field MalEnv/outer + cell% field MalEnv/data +deftype MalEnv + +: MalEnv. { outer -- env } + MalEnv new { env } + outer env MalEnv/outer ! + MalMap/Empty env MalEnv/data ! + env ; + +: env/set { key val env -- } + key val env MalEnv/data @ assoc + env MalEnv/data ! ; + +: env/find { key env -- env-or-0 } + env + begin ( env ) + dup 0 key rot MalEnv/data @ get ( env val-or-0 ) + 0= if ( env ) + MalEnv/outer @ dup 0= ( env-or-0 done-looping? ) + else + -1 \ found it! ( env -1 ) + endif + until ; + +MalEnv + extend get { not-found key env -- } + key env env/find ( env-or-0 ) + ?dup 0= if + not-found + else ( env ) + not-found key rot MalEnv/data @ get + endif ;; + extend pr-buf { env } + env MalEnv/data @ pr-buf + a-space s" outer: " str-append + env MalEnv/outer @ ?dup 0= if + s" <none>" str-append + else + pr-buf + endif ;; +drop
\ No newline at end of file diff --git a/forth/misc-tests.fs b/forth/misc-tests.fs index c428a12..ede5119 100644 --- a/forth/misc-tests.fs +++ b/forth/misc-tests.fs @@ -2,7 +2,7 @@ require printer.fs \ === basic testing util === / : test= - 2dup = if + 2dup m= if 2drop else cr ." assert failed on line " sourceline# . @@ -52,20 +52,38 @@ mal-nil 23 MalInt. mal-nil conj conj conj pr-str s" (nil (20 (42) 10) 23)" str= -1 test= +\ MalArray tests + +here 1 MalInt. , 2 MalInt. , 3 MalInt. , here>MalArray +4 MalInt. swap conj +5 MalInt. swap conj +pr-str s" (5 4 1 2 3)" str= -1 test= + \ map tests -s" one" MalString. s" one" MalString. mal= -1 test= -s" one" MalString. s" x" MalString. mal= 0 test= +s" one" MalString. s" one" MalString. test= +s" one" MalString. s" x" MalString. m= 0 test= + +MalMap/Empty +1000 MalInt. 1100 rot assoc +2000 MalInt. 2100 rot assoc +3000 MalInt. 3100 rot assoc + +dup 99 2000 MalInt. rot get 2100 test= +dup 99 4000 MalInt. rot get 99 test= +drop MalMap/Empty s" one" MalString. s" first" MalString. rot assoc s" two" MalString. s" second" MalString. rot assoc s" three" MalString. s" third" MalString. rot assoc -dup 99 s" two" MalString. rot get s" second" MalString. mal= -1 test= +dup 99 s" two" MalString. rot get s" second" MalString. test= dup 99 s" none" MalString. rot get 99 test= drop +99 MalInt. 10 MalInt. MalMap/Empty get 99 MalInt. test= + \ eval tests require step2_eval.fs @@ -74,8 +92,6 @@ mal-nil 1 MalInt. swap conj 2 MalInt. swap conj 3 MalInt. swap conj -~~ mal-eval -~~ bye diff --git a/forth/printer.fs b/forth/printer.fs index d85e38b..cc376e6 100644 --- a/forth/printer.fs +++ b/forth/printer.fs @@ -149,6 +149,11 @@ MalFn drop s" #<fn>" str-append ;; drop +SpecialOp + extend pr-buf + drop s" #<op>" str-append ;; +drop + MalSymbol extend pr-buf unpack-sym str-append ;; diff --git a/forth/reader.fs b/forth/reader.fs index edd99fc..8f7e3e3 100644 --- a/forth/reader.fs +++ b/forth/reader.fs @@ -135,9 +135,10 @@ defer read-form ( str-addr str-len -- str-addr str-len mal-obj ) ; : read-wrapped ( buf-addr buf-len quote-char sym-addr sym-len -- buf-addr buf-len char mal-list ) - MalSymbol. { sym } ( buf-addr buf-len char ) - read-form mal-nil conj ( buf-addr buf-len char mal-list ) - sym swap conj ; + here { old-here } + MalSymbol. , ( buf-addr buf-len char ) + read-form , ( buf-addr buf-len char ) + old-here here>MalArray ; : read-form2 ( str-addr str-len char -- str-addr str-len char mal-obj ) begin @@ -145,7 +146,7 @@ defer read-form ( str-addr str-len -- str-addr str-len mal-obj ) dup mal-digit? if read-int else dup [char] ( = if [char] ) read-array else dup [char] [ = if [char] ] read-array MalVector new tuck MalVector/list ! else - dup [char] { = if [char] } read-list MalMap new tuck MalMap/list ! else + dup [char] { = if [char] } read-array MalMap new tuck MalMap/list ! else dup [char] " = if read-string-literal else dup [char] ; = if read-comment else dup [char] : = if drop adv-str read-symbol-str MalKeyword. else diff --git a/forth/step2_eval.fs b/forth/step2_eval.fs index 51d1f6f..33ceb4e 100644 --- a/forth/step2_eval.fs +++ b/forth/step2_eval.fs @@ -15,9 +15,23 @@ value repl-env def-protocol-method mal-eval ( env ast -- val ) def-protocol-method mal-eval-ast ( env ast -- val ) +def-protocol-method invoke ( argv argc mal-fn -- ... ) MalDefault extend mal-eval nip ;; drop +MalKeyword + extend invoke { argv argc kw -- val } + argc 1 > if argv cell+ @ else mal-nil endif \ not-found + kw \ key + argv @ \ map + get ;; +drop + +MalFn + extend invoke ( ... mal-fn -- ... ) + MalFn/xt @ execute ;; +drop + MalSymbol extend mal-eval { env sym -- val } 0 sym env get diff --git a/forth/step3_env.fs b/forth/step3_env.fs new file mode 100644 index 0000000..4b76c4d --- /dev/null +++ b/forth/step3_env.fs @@ -0,0 +1,160 @@ +require reader.fs +require printer.fs +require env.fs + +: args-as-native { argv argc -- entry*argc... } + argc 0 ?do + argv i cells + @ as-native + loop ; + +0 MalEnv. constant repl-env +s" +" MalSymbol. :noname args-as-native + MalInt. ; MalFn. repl-env env/set +s" -" MalSymbol. :noname args-as-native - MalInt. ; MalFn. repl-env env/set +s" *" MalSymbol. :noname args-as-native * MalInt. ; MalFn. repl-env env/set +s" /" MalSymbol. :noname args-as-native / MalInt. ; MalFn. repl-env env/set + +def-protocol-method mal-eval ( env ast -- val ) +def-protocol-method mal-eval-ast ( env ast -- val ) +def-protocol-method invoke+ ( env arty -- ... ) +def-protocol-method invoke ( argv argc mal-fn -- ... ) + +MalDefault extend mal-eval nip ;; drop + +MalKeyword + extend invoke { argv argc kw -- val } + argc 1 > if argv cell+ @ else mal-nil endif \ not-found + kw \ key + argv @ \ map + get ;; +drop + +MalFn + extend invoke ( ... mal-fn -- ... ) + MalFn/xt @ execute ;; + + extend invoke+ { env ary this -- ary } + \ Pass args on dictionary stack (!) + \ TODO: consider allocate and free of a real MalArray instead + \ Normal list, evaluate and invoke + here { val-start } + ary MalArray/start @ { expr-start } + ary MalArray/count @ 1 ?do + env expr-start i cells + @ mal-eval , + loop + val-start here val-start - cell / this ( argv argc MalFn ) + invoke + val-start here - allot ;; +drop + +SpecialOp + extend invoke+ ( env ary this -- ary ) + SpecialOp/xt @ execute ;; +drop + +s" quote" MalSymbol. :noname ( env ary -- form ) + nip MalArray/start @ cell+ @ +; SpecialOp. repl-env env/set + +s" def!" MalSymbol. :noname { env ary -- } + ary MalArray/start @ cell+ { arg0 } + arg0 @ ( key ) + env arg0 cell+ @ mal-eval dup { val } ( key val ) + env env/set + val +; SpecialOp. repl-env env/set + +s" let*" MalSymbol. :noname { old-env ary -- } + old-env MalEnv. { env } + ary MalArray/start @ cell+ dup { arg0 } + @ to-array + dup MalArray/start @ { bindings-start } ( ary ) + MalArray/count @ 0 +do + bindings-start i cells + dup @ swap cell+ @ ( sym expr ) + env swap mal-eval + env env/set + 2 +loop + env arg0 cell+ @ mal-eval + \ TODO: dec refcount of env +; SpecialOp. repl-env env/set + +MalSymbol + extend mal-eval { env sym -- val } + 0 sym env get + dup 0= if + drop + ." Symbol '" + sym as-native safe-type + ." ' not found." cr + 1 throw + endif ;; +drop + +MalArray + extend mal-eval { env ary -- val } + env ary MalArray/start @ @ mal-eval + env ary rot invoke+ ;; + + extend mal-eval-ast { env ary -- ary } + here + ary MalArray/start @ { expr-start } + ary MalArray/count @ 0 ?do + env expr-start i cells + @ mal-eval , + loop + here>MalArray ;; +drop + +MalList + extend mal-eval-ast { env list -- ary } + here + list + begin ( list ) + dup mal-nil <> + while + env over MalList/car @ mal-eval , + MalList/cdr @ + repeat + drop here>MalArray ;; +drop + +MalVector + extend mal-eval ( env vector -- vector ) + MalVector/list @ mal-eval-ast + MalVector new swap over MalVector/list ! ;; +drop + +MalMap + extend mal-eval ( env map -- map ) + MalMap/list @ mal-eval-ast + MalMap new swap over MalMap/list ! ;; +drop + +: read read-str ; +: eval ( env obj ) mal-eval ; +: print + \ ." Type: " dup mal-type @ type-name safe-type cr + pr-str ; + +: rep ( str -- val ) + read + repl-env swap eval + print ; + +create buff 128 allot + +: read-lines + begin + ." user> " + 42042042042 + buff 128 stdin read-line throw + while + buff swap + ['] rep + execute safe-type + \ catch 0= if safe-type else ." Caught error" endif + cr + 42042042042 <> if ." --stack leak--" cr endif + repeat ; + +read-lines +cr +bye diff --git a/forth/types.fs b/forth/types.fs index 2c4d178..a8268a3 100644 --- a/forth/types.fs +++ b/forth/types.fs @@ -200,6 +200,20 @@ end-extend \ === Mal types and protocols === / +def-protocol-method conj ( obj this -- this ) +def-protocol-method assoc ( k v this -- this ) +def-protocol-method get ( not-found k this -- value ) +def-protocol-method mal= ( a b -- bool ) +def-protocol-method as-native ( obj -- ) +def-protocol-method to-array ( obj -- mal-array ) + +: m= ( a b -- bool ) + 2dup = if + 2drop -1 + else + mal= + endif ; + MalType% cell% field MalList/car cell% field MalList/cdr @@ -225,48 +239,63 @@ deftype MalArray 0 bytes - allot \ pop array contents from dictionary stack ; -def-protocol-method conj ( obj this -- this ) -def-protocol-method assoc ( k v this -- this ) -def-protocol-method get ( not-found k this -- value ) -def-protocol-method mal= ( a b -- bool ) -def-protocol-method as-native ( obj -- ) -def-protocol-method invoke ( argv argc mal-fn -- ... ) +MalArray + extend to-array ;; + extend conj { elem old-ary -- ary } + old-ary MalArray/count @ 1+ { new-count } + new-count cells allocate throw { new-start } + elem new-start ! + new-count 1 > if + old-ary MalArray/start @ new-start cell+ new-count 1- cells cmove + endif + + MalArray new + new-count over MalArray/count ! + new-start over MalArray/start ! ;; +drop + +MalArray new 0 over MalArray/count ! constant MalArray/Empty MalType% cell% field MalVector/list deftype MalVector +MalVector + extend to-array + MalVector/list @ to-array ;; +drop + MalType% cell% field MalMap/list deftype MalMap -MalMap new mal-nil over MalMap/list ! constant MalMap/Empty +MalMap new MalArray/Empty over MalMap/list ! constant MalMap/Empty MalMap extend conj ( kv map -- map ) MalMap/list @ \ get list - over MalList/cdr @ MalList/car @ conj \ add value - swap MalList/car @ conj \ add key - MalMap new MalMap/list ! \ put back in map + over MalArray/start @ cell+ @ swap conj \ add value + swap MalArray/start @ @ swap conj \ add key + MalMap new dup -rot MalMap/list ! \ put back in map ;; extend assoc ( k v map -- map ) MalMap/list @ \ get list - conj conj + conj conj MalMap new dup -rot MalMap/list ! \ put back in map ;; - extend get ( not-found k map -- value ) - -rot { not-found k } - MalMap/list @ \ get list + extend get { not-found k map -- value } + map MalMap/list @ + dup MalArray/start @ { start } + MalArray/count @ { count } + 0 begin - dup MalList/cdr @ - swap MalList/car @ k mal= if - MalList/car @ -1 \ found it + dup count >= if + drop not-found -1 else - MalList/cdr @ - dup mal-nil = if - not-found -1 + start over cells + @ k m= if + start swap cells + cell+ @ -1 \ found it ( value -1 ) else - 0 + 2 + 0 endif endif until ;; @@ -297,6 +326,13 @@ deftype MalInt MalInt new dup MalInt/int int swap ! ; MalInt + extend mal= ( other this -- bool ) + over mal-type @ MalInt = if + MalInt/int @ swap MalInt/int @ = + else + 2drop 0 + endif ;; + extend as-native ( mal-int -- int ) MalInt/int @ ;; drop @@ -345,11 +381,6 @@ MalKeyword 2drop 0 endif ;; ' as-native ' unpack-keyword extend-method* - extend invoke { argv argc kw -- val } - argc 1 > if argv cell+ @ else mal-nil endif \ not-found - kw \ key - argv @ \ map - get ;; drop : MalKeyword. { str-addr str-len -- mal-keyword } @@ -396,8 +427,14 @@ deftype MalFn mal-fn ; MalFn - extend invoke ( ... mal-fn -- ... ) - MalFn/xt @ execute ;; extend as-native MalFn/xt @ ;; drop + + +MalType% + cell% field SpecialOp/xt +deftype SpecialOp + +: SpecialOp. + SpecialOp new swap over SpecialOp/xt ! ; |
