Merge pull request #238 from prt2121/pt/haskell-7.10.1
[jackhill/mal.git] / forth / reader.fs
CommitLineData
59038a10
C
1require types.fs
2require printer.fs
3
4\ Drop a char off the front of string by advancing the addr and
5\ decrementing the length, and fetch next char
6: adv-str ( str-addr str-len -- str-addr str-len char )
7 swap 1+ swap 1-
8 dup 0= if 0 ( eof )
9 else over c@ endif ;
10
59038a10
C
11: mal-digit? ( char -- flag )
12 dup [char] 9 <= if
13 [char] 0 >=
14 else
15 drop 0
16 endif ;
17
18: char-in-str? ( char str-addr str-len )
19 rot { needle }
bf6a574e
C
20 false -rot
21 over + swap ?do
22 i c@ needle = if drop true leave endif
23 loop ;
24
25: sym-char? ( char -- flag )
26 s\" \n\r\t\000[]{}()'\"`,; " char-in-str? 0= ;
27
28: skip-spaces ( str-addr str-len char -- str-addr str-len non-space-char )
29 begin
30 begin
31 dup s\" \n\r\t, " char-in-str?
32 while ( str-addr str-len space-char )
33 drop adv-str
34 repeat
35 dup [char] ; = if
36 drop
37 begin
38 adv-str s\" \n\r\000" char-in-str?
39 until
40 adv-str false
59038a10 41 else
bf6a574e 42 true
59038a10
C
43 endif
44 until ;
45
59038a10
C
46defer read-form ( str-addr str-len -- str-addr str-len mal-obj )
47
48: read-int ( str-addr str-len digit-char -- str-addr str-len non-digit-char mal-int )
49 0 { int }
7412ebc6
JM
50 0 { neg }
51 dup [char] - = if drop adv-str 1 to neg endif
59038a10
C
52 begin ( str-addr str-len digit-char )
53 [char] 0 - int 10 * + to int ( str-addr str-len )
54 adv-str dup mal-digit? 0= ( str-addr str-len digit-char )
55 until
7412ebc6 56 neg if 0 int - to int endif
59038a10
C
57 int MalInt. ;
58
168fb5dc 59: read-symbol-str ( str-addr str-len sym-char -- str-addr str-len char sym-addr sym-len )
59038a10 60 new-str { sym-addr sym-len }
168fb5dc 61 begin ( str-addr str-len sym-char )
59038a10
C
62 sym-addr sym-len rot str-append-char to sym-len to sym-addr
63 adv-str dup sym-char? 0=
64 until
65 sym-addr sym-len ;
66
168fb5dc
C
67: read-string-literal ( in-addr in-len quote-char -- in-addr in-len mal-string )
68 new-str { out-addr out-len }
69 drop \ drop leading quote
70 begin ( in-addr in-len )
71 adv-str over 0= if
580c4eef 72 2drop 0 0 s\" expected '\"', got EOF" ...throw-str
168fb5dc
C
73 endif
74 dup [char] " <>
75 while
76 dup [char] \ = if
77 drop adv-str
78 dup [char] n = if drop 10 endif
79 dup [char] r = if drop 13 endif
80 endif
81 out-addr out-len rot str-append-char to out-len to out-addr
82 repeat
83 drop adv-str \ skip trailing quote
84 out-addr out-len MalString. ;
85
9da223a3 86: read-list ( str-addr str-len open-paren-char close-paren-char
c05d35e8 87 -- str-addr str-len non-paren-char mal-list )
9da223a3
C
88 here { close-char old-here }
89 drop adv-str
90 begin ( str-addr str-len char )
91 skip-spaces ( str-addr str-len non-space-char )
92 over 0= if
580c4eef
C
93 drop 2drop 0 0 s" ', got EOF"
94 close-char pad ! pad 1
95 s" expected '" ...throw-str
9da223a3
C
96 endif
97 dup close-char <>
98 while ( str-addr str-len non-space-non-paren-char )
99 read-form ,
100 repeat
101 drop adv-str
bf6a574e 102 old-here here>MalList ;
59038a10 103
794bfca1
C
104s" deref" MalSymbol. constant deref-sym
105s" quote" MalSymbol. constant quote-sym
106s" quasiquote" MalSymbol. constant quasiquote-sym
107s" splice-unquote" MalSymbol. constant splice-unquote-sym
108s" unquote" MalSymbol. constant unquote-sym
109
168fb5dc 110: read-wrapped ( buf-addr buf-len quote-char sym-addr sym-len -- buf-addr buf-len char mal-list )
69972a83 111 here { old-here }
794bfca1 112 , ( buf-addr buf-len char )
69972a83 113 read-form , ( buf-addr buf-len char )
c05d35e8 114 old-here here>MalList ;
168fb5dc
C
115
116: read-form2 ( str-addr str-len char -- str-addr str-len char mal-obj )
bf6a574e 117 skip-spaces
7412ebc6 118 dup [char] - = 3 pick 1 + c@ mal-digit? and if read-int else
bf6a574e
C
119 dup mal-digit? if read-int else
120 dup [char] ( = if [char] ) read-list else
121 dup [char] [ = if [char] ] read-list MalVector new tuck MalVector/list ! else
122 dup [char] { = if [char] } read-list MalMap new tuck MalMap/list ! else
123 dup [char] " = if read-string-literal else
124 dup [char] : = if drop adv-str read-symbol-str MalKeyword. else
794bfca1
C
125 dup [char] @ = if drop adv-str deref-sym read-wrapped else
126 dup [char] ' = if drop adv-str quote-sym read-wrapped else
127 dup [char] ` = if drop adv-str quasiquote-sym read-wrapped else
bf6a574e
C
128 dup [char] ~ = if
129 drop adv-str
794bfca1
C
130 dup [char] @ = if drop adv-str splice-unquote-sym read-wrapped
131 else unquote-sym read-wrapped
bf6a574e
C
132 endif
133 else
134 dup [char] ^ = if
135 drop adv-str
136 read-form { meta } read-form { obj }
137 meta mal-nil conj
138 obj swap conj
139 s" with-meta" MalSymbol. swap conj
140 else
141 read-symbol-str
142 2dup s" true" str= if 2drop mal-true
143 else 2dup s" false" str= if 2drop mal-false
144 else 2dup s" nil" str= if 2drop mal-nil
168fb5dc 145 else
bf6a574e 146 MalSymbol.
7412ebc6 147 endif endif endif endif endif endif endif endif endif endif endif endif endif endif endif ;
59038a10
C
148' read-form2 is read-form
149
150: read-str ( str-addr str-len - mal-obj )
168fb5dc 151 over c@ read-form { obj } drop 2drop obj ;