aboutsummaryrefslogtreecommitdiff
path: root/forth/reader.fs
diff options
context:
space:
mode:
Diffstat (limited to 'forth/reader.fs')
-rw-r--r--forth/reader.fs147
1 files changed, 147 insertions, 0 deletions
diff --git a/forth/reader.fs b/forth/reader.fs
new file mode 100644
index 0000000..134749b
--- /dev/null
+++ b/forth/reader.fs
@@ -0,0 +1,147 @@
+require types.fs
+require printer.fs
+
+\ Drop a char off the front of string by advancing the addr and
+\ decrementing the length, and fetch next char
+: adv-str ( str-addr str-len -- str-addr str-len char )
+ swap 1+ swap 1-
+ dup 0= if 0 ( eof )
+ else over c@ endif ;
+
+: mal-digit? ( char -- flag )
+ dup [char] 9 <= if
+ [char] 0 >=
+ else
+ drop 0
+ endif ;
+
+: char-in-str? ( char str-addr str-len )
+ rot { needle }
+ false -rot
+ over + swap ?do
+ i c@ needle = if drop true leave endif
+ loop ;
+
+: sym-char? ( char -- flag )
+ s\" \n\r\t\000[]{}()'\"`,; " char-in-str? 0= ;
+
+: skip-spaces ( str-addr str-len char -- str-addr str-len non-space-char )
+ begin
+ begin
+ dup s\" \n\r\t, " char-in-str?
+ while ( str-addr str-len space-char )
+ drop adv-str
+ repeat
+ dup [char] ; = if
+ drop
+ begin
+ adv-str s\" \n\r\000" char-in-str?
+ until
+ adv-str false
+ else
+ true
+ endif
+ until ;
+
+defer read-form ( str-addr str-len -- str-addr str-len mal-obj )
+
+: read-int ( str-addr str-len digit-char -- str-addr str-len non-digit-char mal-int )
+ 0 { int }
+ begin ( str-addr str-len digit-char )
+ [char] 0 - int 10 * + to int ( str-addr str-len )
+ adv-str dup mal-digit? 0= ( str-addr str-len digit-char )
+ until
+ int MalInt. ;
+
+: read-symbol-str ( str-addr str-len sym-char -- str-addr str-len char sym-addr sym-len )
+ new-str { sym-addr sym-len }
+ begin ( str-addr str-len sym-char )
+ sym-addr sym-len rot str-append-char to sym-len to sym-addr
+ adv-str dup sym-char? 0=
+ until
+ sym-addr sym-len ;
+
+: read-string-literal ( in-addr in-len quote-char -- in-addr in-len mal-string )
+ new-str { out-addr out-len }
+ drop \ drop leading quote
+ begin ( in-addr in-len )
+ adv-str over 0= if
+ 2drop 0 0 s\" expected '\"', got EOF" ...throw-str
+ endif
+ dup [char] " <>
+ while
+ dup [char] \ = if
+ drop adv-str
+ dup [char] n = if drop 10 endif
+ dup [char] r = if drop 13 endif
+ endif
+ out-addr out-len rot str-append-char to out-len to out-addr
+ repeat
+ drop adv-str \ skip trailing quote
+ out-addr out-len MalString. ;
+
+: read-list ( str-addr str-len open-paren-char close-paren-char
+ -- str-addr str-len non-paren-char mal-list )
+ here { close-char old-here }
+ drop adv-str
+ begin ( str-addr str-len char )
+ skip-spaces ( str-addr str-len non-space-char )
+ over 0= if
+ drop 2drop 0 0 s" ', got EOF"
+ close-char pad ! pad 1
+ s" expected '" ...throw-str
+ endif
+ dup close-char <>
+ while ( str-addr str-len non-space-non-paren-char )
+ read-form ,
+ repeat
+ drop adv-str
+ old-here here>MalList ;
+
+s" deref" MalSymbol. constant deref-sym
+s" quote" MalSymbol. constant quote-sym
+s" quasiquote" MalSymbol. constant quasiquote-sym
+s" splice-unquote" MalSymbol. constant splice-unquote-sym
+s" unquote" MalSymbol. constant unquote-sym
+
+: read-wrapped ( buf-addr buf-len quote-char sym-addr sym-len -- buf-addr buf-len char mal-list )
+ here { old-here }
+ , ( buf-addr buf-len char )
+ read-form , ( buf-addr buf-len char )
+ old-here here>MalList ;
+
+: read-form2 ( str-addr str-len char -- str-addr str-len char mal-obj )
+ skip-spaces
+ dup mal-digit? if read-int else
+ dup [char] ( = if [char] ) read-list else
+ dup [char] [ = if [char] ] read-list MalVector new tuck MalVector/list ! else
+ dup [char] { = if [char] } read-list MalMap new tuck MalMap/list ! else
+ dup [char] " = if read-string-literal else
+ dup [char] : = if drop adv-str read-symbol-str MalKeyword. else
+ dup [char] @ = if drop adv-str deref-sym read-wrapped else
+ dup [char] ' = if drop adv-str quote-sym read-wrapped else
+ dup [char] ` = if drop adv-str quasiquote-sym read-wrapped else
+ dup [char] ~ = if
+ drop adv-str
+ dup [char] @ = if drop adv-str splice-unquote-sym read-wrapped
+ else unquote-sym read-wrapped
+ endif
+ else
+ dup [char] ^ = if
+ drop adv-str
+ read-form { meta } read-form { obj }
+ meta mal-nil conj
+ obj swap conj
+ s" with-meta" MalSymbol. swap conj
+ else
+ read-symbol-str
+ 2dup s" true" str= if 2drop mal-true
+ else 2dup s" false" str= if 2drop mal-false
+ else 2dup s" nil" str= if 2drop mal-nil
+ else
+ MalSymbol.
+ endif endif endif endif endif endif endif endif endif endif endif endif endif endif ;
+' read-form2 is read-form
+
+: read-str ( str-addr str-len - mal-obj )
+ over c@ read-form { obj } drop 2drop obj ;