5 core MalEnv. constant
repl-env
7 99999999 constant
TCO-eval
12 \
." eval-> " dup pr
-str safe
-type cr
19 \
." Type: " dup mal
-type @ type-name
safe-type cr
22 MalDefault extend mal
-eval
nip ;; drop \
By default, evalutate
to yourself
25 extend eval
-invoke
{ env list
kw -- val }
26 0 kw env list
MalList/start
@ cell
+ @ eval
get
28 \ compute
not-found value
29 list
MalList/count
@ 1 > if
30 env list
MalList/start
@ 2 cells
+ @ TCO-eval
35 extend invoke
{ argv argc
kw -- val }
46 \ eval
all but
the first
item of list
47 : eval
-rest
{ env list
-- argv argc
}
48 list
MalList/start
@ cell
+ { expr
-start
}
49 list
MalList/count
@ 1- { argc
}
50 argc cells
allocate throw
{ target
}
52 env expr
-start
i cells
+ @ eval
58 extend eval
-invoke
{ env list
this -- list
}
59 env list
eval-rest
( argv
argc )
61 extend invoke ( argv
argc this -- val )
62 MalNativeFn/xt
@ execute
;;
66 extend eval-invoke ( env list
this -- list
)
67 SpecialOp/xt
@ execute
;;
70 : install
-special
( symbol
xt )
71 SpecialOp. repl-env env
/set
;
74 parse
-allot
-name
MalSymbol.
79 : is-pair? ( obj -- bool )
82 defspecial quote ( env list -- form )
83 nip MalList/start @ cell+ @ ;;
85 s" concat" MalSymbol. constant concat-sym
86 s" cons" MalSymbol. constant cons-sym
89 : quasiquote0 { ast -- form }
91 here quote-sym , ast , here>MalList
93 ast to-list MalList/start @ { ast-start }
94 ast-start @ { ast[0] }
95 ast[0] unquote-sym m= if
99 ast[0] to-list MalList/start @ { ast[0]-start }
100 ast[0]-start @ splice-unquote-sym m= if
103 ast[0]-start cell+ @ ,
104 ast to-list MalList/rest quasiquote ,
113 ast to-list MalList/rest quasiquote ,
118 ' quasiquote0
is quasiquote
120 defspecial
quasiquote ( env list
)
121 MalList/start
@ cell+ @ ( ast
)
122 quasiquote TCO-eval ;;
124 defspecial
def! { env list
-- val }
125 list
MalList/start
@ cell+ { arg0
}
127 env arg0
cell+ @ eval dup { val } ( key
val )
130 defspecial
defmacro! { env list
-- val }
131 list
MalList/start
@ cell+ { arg0
}
133 env arg0
cell+ @ eval { val }
134 true val MalUserFn/is-macro
? !
138 defspecial
let* { old
-env list
-- val }
139 old
-env MalEnv. { env }
140 list
MalList/start
@ cell+ dup { arg0
}
142 dup MalList/start
@ { bindings
-start
} ( list
)
143 MalList/count
@ 0 +do
144 bindings
-start
i cells
+ dup @ swap
cell+ @ ( sym expr
)
148 env arg0
cell+ @ TCO-eval
149 \
TODO: dec refcount
of env
152 defspecial
do { env list
-- val }
153 list
MalList/start
@ { start
}
154 list
MalList/count
@ dup 1- { last
} 1 ?do
155 env start
i cells
+ @
163 defspecial
if { env list
-- val }
164 list
MalList/start
@ cell+ { arg0
}
165 env arg0
@ eval ( test
-val )
173 list
MalList/count
@ 3 > if
174 env arg0
cell+ cell+ @ TCO-eval
180 env arg0
cell+ @ TCO-eval
183 s
" &" MalSymbol. constant
&-sym
185 : new-user
-fn
-env { argv
argc mal
-fn
-- env }
186 mal
-fn
MalUserFn/formal
-args
@ { f
-args
-list
}
187 mal
-fn
MalUserFn/env @ MalEnv. { env }
189 f
-args
-list
MalList/start
@ { f
-args
}
190 f
-args
-list
MalList/count
@ ?dup 0= if else
191 \ pass
nil for last
arg, unless
overridden below
192 1- cells
f-args
+ @ mal
-nil env env/set
199 c cells
allocate throw
{ start
}
200 argv
i cells
+ start
c cells
cmove
201 f-args
i 1+ cells
+ @ ( more
-args
-symbol
)
202 start
c MalList. env env/set
211 extend eval-invoke { call
-env list
mal-fn
-- list
}
212 mal-fn
MalUserFn/is-macro
? @ if
213 list
MalList/start
@ cell+ \ argv
214 list
MalList/count
@ 1- \
argc
215 mal-fn
new-user
-fn
-env { env }
216 env mal-fn
MalUserFn/body
@ eval
217 call
-env swap
TCO-eval
219 call
-env list
eval-rest
223 extend invoke ( argv
argc mal-fn
)
224 dup { mal-fn
} new-user
-fn
-env { env }
225 env mal-fn
MalUserFn/body
@ TCO-eval ;;
228 defspecial
fn* { env list
-- val }
229 list
MalList/start
@ cell+ { arg0
}
231 false over MalUserFn/is-macro
? !
232 env over MalUserFn/env !
233 arg0
@ to-list
over MalUserFn/formal
-args
!
234 arg0
cell+ @ over MalUserFn/body
! ;;
236 defspecial
macroexpand ( env list
[_
,form
] -- form
)
237 MalList/start
@ cell+ @ swap
over ( form
env form
)
238 MalList/start
@ @ ( form
env macro
-name
-expr
)
239 eval { macro
-fn } ( form
)
240 dup MalList/start
@ cell+ swap
MalList/count
@ 1- macro
-fn ( argv
argc fn )
241 new-user
-fn-env ( env )
242 macro
-fn MalUserFn/body
@ TCO-eval ;;
244 5555555555 constant
pre-try
246 defspecial
try* { env list
-- val }
247 list
MalList/start
@ cell+ { arg0
}
249 env arg0
@ ['] eval catch ?dup 0= if
252 begin pre-try = until
254 s" forth-errno" MalKeyword. errno MalInt. MalMap/Empty assoc
257 arg0 cell+ @ ( list[catch*,sym,form] )
258 MalList/start @ cell+ { catch0 }
259 env MalEnv. { catch-env }
260 catch0 @ exception-object catch-env env/set
261 catch-env catch0 cell+ @ TCO-eval
264 defspecial . { env coll -- rtn-list }
266 coll to-list dup MalList/count @ swap MalList/start @ { count start }
267 count cells start + start cell+ +do
268 env i @ eval as-native
272 extend mal-eval { env sym -- val }
276 0 0 s" ' not found" sym as-native s" '" ...throw-str
282 : eval-ast { env list -- list }
284 list MalList/start @ { expr-start }
285 list MalList/count @ 0 ?do
286 env expr-start i cells + @ eval ,
291 extend mal-eval { env list -- val }
292 env list MalList/start @ @ eval
293 env list rot eval-invoke ;;
297 extend mal-eval ( env vector -- vector )
298 MalVector/list @ eval-ast
299 MalVector new swap over MalVector/list ! ;;
303 extend mal-eval ( env map -- map )
304 MalMap/list @ eval-ast
305 MalMap new swap over MalMap/list ! ;;
308 defcore eval ( argv argc )
309 drop @ repl-env swap eval ;;
311 : rep ( str-addr str-len -- str-addr str-len )
316 : mk-args-list ( -- )
319 next-arg 2dup 0 0 d<> while
324 create buff 128 allot
325 77777777777 constant stack-leak-detect
329 defcore map ( argv argc -- list )
330 drop dup @ swap cell+ @ to-list { fn list }
332 list MalList/start @ list MalList/count @ cells over + swap +do
334 dup TCO-eval = if drop eval endif
339 defcore readline ( argv argc -- mal-string )
340 drop @ unpack-str type stdout flush-file drop
341 buff 128 stdin read-line throw
342 if buff swap MalString. else drop mal-nil endif ;;
344 s\" (def! *host-language* \"forth\")" rep 2drop
345 s\" (def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))" rep 2drop
346 s\" (defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first
xs) (if (> (count
xs) 1) (nth
xs 1) (throw \"odd number
of forms
to cond
\")) (cons 'cond (rest (rest xs)))))))" rep 2drop
347 s\" (defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) `(let* (or_FIXME ~(first xs)) (if or_FIXME or_FIXME (or ~@(rest xs))))))))" rep 2drop
348 s\" (def! swap! (fn* [a f & args] (reset! a (apply f @a args))))" rep 2drop
351 s\" (println (str \"Mal [\" *host-language* \"]\"))" rep 2drop
355 buff 128 stdin read-line throw
356 while ( num-bytes-read )
357 buff swap ( str-addr str-len )
359 \ execute
['] nop \ uncomment to see stack traces
362 stack-leak-detect <> if ." --stack leak--" cr endif
364 begin stack-leak-detect = until
366 s" forth-errno" MalKeyword. errno MalInt. MalMap/Empty assoc
369 ." Uncaught exception: "
370 exception-object pr-str safe-type cr
375 mk-args-list { args-list }
376 args-list MalList/count @ 0= if
377 s" *ARGV*" MalSymbol. MalList/Empty repl-env env/set
380 args-list MalList/start @ @ { filename }
381 s" *ARGV*" MalSymbol. args-list MalList/rest repl-env env/set
384 here s" load-file" MalSymbol. , filename , here>MalList