Commit | Line | Data |
---|---|---|
69972a83 C |
1 | require reader.fs |
2 | require printer.fs | |
3 | require env.fs | |
4 | ||
5 | : args-as-native { argv argc -- entry*argc... } | |
6 | argc 0 ?do | |
7 | argv i cells + @ as-native | |
8 | loop ; | |
9 | ||
10 | 0 MalEnv. constant repl-env | |
136ce7c9 C |
11 | s" +" MalSymbol. :noname args-as-native + MalInt. ; MalNativeFn. repl-env env/set |
12 | s" -" MalSymbol. :noname args-as-native - MalInt. ; MalNativeFn. repl-env env/set | |
13 | s" *" MalSymbol. :noname args-as-native * MalInt. ; MalNativeFn. repl-env env/set | |
14 | s" /" MalSymbol. :noname args-as-native / MalInt. ; MalNativeFn. repl-env env/set | |
69972a83 | 15 | |
45c1894b C |
16 | : read read-str ; |
17 | : eval ( env obj ) mal-eval ; | |
18 | ||
19 | \ ." Type: " dup mal-type @ type-name safe-type cr | |
20 | pr-str ; | |
69972a83 | 21 | |
45c1894b | 22 | MalDefault extend mal-eval nip ;; drop \ By default, evalutate to yourself |
69972a83 C |
23 | |
24 | MalKeyword | |
45c1894b C |
25 | extend eval-invoke { env list kw -- val } |
26 | 0 kw env list MalList/start @ cell+ @ eval get | |
e6106d45 C |
27 | ?dup 0= if |
28 | \ compute not-found value | |
29 | list MalList/count @ 1 > if | |
45c1894b | 30 | env list MalList/start @ 2 cells + @ eval |
e6106d45 C |
31 | else |
32 | mal-nil | |
33 | endif | |
34 | endif ;; | |
69972a83 C |
35 | drop |
36 | ||
45c1894b C |
37 | \ eval all but the first item of list |
38 | : eval-rest { env list -- argv argc } | |
39 | list MalList/start @ cell+ { expr-start } | |
40 | list MalList/count @ 1- { argc } | |
41 | argc cells allocate throw { target } | |
42 | argc 0 ?do | |
43 | env expr-start i cells + @ eval | |
44 | target i cells + ! | |
69972a83 | 45 | loop |
45c1894b C |
46 | target argc ; |
47 | ||
48 | MalNativeFn | |
49 | extend eval-invoke ( env list this -- list ) | |
50 | MalNativeFn/xt @ { xt } | |
51 | eval-rest ( argv argc ) | |
52 | xt execute ( return-val ) ;; | |
69972a83 C |
53 | drop |
54 | ||
55 | SpecialOp | |
45c1894b | 56 | extend eval-invoke ( env list this -- list ) |
69972a83 C |
57 | SpecialOp/xt @ execute ;; |
58 | drop | |
59 | ||
79feb89f C |
60 | : install-special ( symbol xt ) |
61 | SpecialOp. repl-env env/set ; | |
69972a83 | 62 | |
79feb89f C |
63 | : defspecial |
64 | parse-allot-name MalSymbol. | |
65 | ['] install-special | |
66 | :noname | |
67 | ; | |
68 | ||
69 | defspecial quote ( env list -- form ) | |
70 | nip MalList/start @ cell+ @ ;; | |
71 | ||
45c1894b | 72 | defspecial def! { env list -- val } |
c05d35e8 | 73 | list MalList/start @ cell+ { arg0 } |
69972a83 | 74 | arg0 @ ( key ) |
45c1894b C |
75 | env arg0 cell+ @ eval dup { val } ( key val ) |
76 | env env/set val ;; | |
69972a83 | 77 | |
45c1894b | 78 | defspecial let* { old-env list -- val } |
69972a83 | 79 | old-env MalEnv. { env } |
c05d35e8 C |
80 | list MalList/start @ cell+ dup { arg0 } |
81 | @ to-list | |
82 | dup MalList/start @ { bindings-start } ( list ) | |
83 | MalList/count @ 0 +do | |
69972a83 | 84 | bindings-start i cells + dup @ swap cell+ @ ( sym expr ) |
45c1894b | 85 | env swap eval |
69972a83 C |
86 | env env/set |
87 | 2 +loop | |
45c1894b | 88 | env arg0 cell+ @ eval |
69972a83 | 89 | \ TODO: dec refcount of env |
79feb89f | 90 | ;; |
69972a83 C |
91 | |
92 | MalSymbol | |
93 | extend mal-eval { env sym -- val } | |
a631063f | 94 | sym env env/get-addr |
69972a83 C |
95 | dup 0= if |
96 | drop | |
9e2a4ab0 | 97 | 0 0 s" ' not found" sym pr-str s" '" ...throw-str |
a631063f C |
98 | else |
99 | @ | |
69972a83 C |
100 | endif ;; |
101 | drop | |
102 | ||
45c1894b | 103 | : eval-ast { env list -- list } |
69972a83 | 104 | here |
c05d35e8 C |
105 | list MalList/start @ { expr-start } |
106 | list MalList/count @ 0 ?do | |
45c1894b | 107 | env expr-start i cells + @ eval , |
69972a83 | 108 | loop |
e6106d45 C |
109 | here>MalList ; |
110 | ||
111 | MalList | |
112 | extend mal-eval { env list -- val } | |
4e258d3a DM |
113 | list MalList/count @ 0= if |
114 | list | |
115 | else | |
116 | env list MalList/start @ @ eval | |
117 | env list rot eval-invoke | |
118 | endif ;; | |
69972a83 C |
119 | drop |
120 | ||
121 | MalVector | |
122 | extend mal-eval ( env vector -- vector ) | |
45c1894b | 123 | MalVector/list @ eval-ast |
69972a83 C |
124 | MalVector new swap over MalVector/list ! ;; |
125 | drop | |
126 | ||
127 | MalMap | |
128 | extend mal-eval ( env map -- map ) | |
45c1894b | 129 | MalMap/list @ eval-ast |
69972a83 C |
130 | MalMap new swap over MalMap/list ! ;; |
131 | drop | |
132 | ||
45c1894b | 133 | : rep ( str-addr str-len -- str-addr str-len ) |
69972a83 C |
134 | read |
135 | repl-env swap eval | |
136 | print ; | |
137 | ||
138 | create buff 128 allot | |
45c1894b | 139 | 77777777777 constant stack-leak-detect |
69972a83 C |
140 | |
141 | : read-lines | |
142 | begin | |
143 | ." user> " | |
45c1894b | 144 | stack-leak-detect |
69972a83 | 145 | buff 128 stdin read-line throw |
45c1894b | 146 | while ( num-bytes-read ) |
9e2a4ab0 JMC |
147 | dup 0 <> if |
148 | buff swap ( str-addr str-len ) | |
149 | ['] rep | |
150 | \ execute ['] nop \ uncomment to see stack traces | |
151 | catch ?dup 0= if | |
152 | safe-type cr | |
153 | stack-leak-detect <> if ." --stack leak--" cr endif | |
154 | else { errno } | |
155 | begin stack-leak-detect = until | |
156 | errno 1 <> if | |
157 | s" forth-errno" MalKeyword. errno MalInt. MalMap/Empty assoc | |
158 | to exception-object | |
159 | endif | |
160 | ." Uncaught exception: " | |
161 | exception-object pr-str safe-type cr | |
162 | endif | |
163 | endif | |
69972a83 C |
164 | repeat ; |
165 | ||
166 | read-lines | |
167 | cr | |
168 | bye |