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
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
}
43 env expr
-start
i cells
+ @ eval
49 extend eval
-invoke
{ env list
this -- list
}
50 env list
eval-rest
( argv
argc )
52 extend invoke ( argv
argc this -- val )
53 MalNativeFn/xt
@ execute
;;
57 extend eval-invoke ( env list
this -- list
)
58 SpecialOp/xt
@ execute
;;
61 : install
-special
( symbol
xt )
62 SpecialOp. repl-env env
/set
;
65 parse
-allot
-name
MalSymbol.
70 : is-pair? ( obj -- bool )
73 defspecial quote ( env list -- form )
74 nip MalList/start @ cell+ @ ;;
76 s" concat" MalSymbol. constant concat-sym
77 s" cons" MalSymbol. constant cons-sym
80 : quasiquote0 { ast -- form }
82 here quote-sym , ast , here>MalList
84 ast to-list MalList/start @ { ast-start }
85 ast-start @ { ast[0] }
86 ast[0] unquote-sym m= if
90 ast[0] to-list MalList/start @ { ast[0]-start }
91 ast[0]-start @ splice-unquote-sym m= if
94 ast[0]-start cell+ @ ,
95 ast to-list MalList/rest quasiquote ,
104 ast to-list MalList/rest quasiquote ,
109 ' quasiquote0
is quasiquote
111 defspecial
quasiquote ( env list
)
112 MalList/start
@ cell+ @ ( ast
)
113 quasiquote TCO-eval ;;
115 defspecial
def! { env list
-- val }
116 list
MalList/start
@ cell+ { arg0
}
118 env arg0
cell+ @ eval dup { val } ( key
val )
121 defspecial
let* { old
-env list
-- val }
122 old
-env
MalEnv. { env
}
123 list
MalList/start
@ cell+ dup { arg0
}
125 dup MalList/start
@ { bindings
-start
} ( list
)
126 MalList/count
@ 0 +do
127 bindings
-start
i cells
+ dup @ swap
cell+ @ ( sym expr
)
131 env arg0
cell+ @ TCO-eval
132 \
TODO: dec refcount
of env
135 defspecial
do { env list
-- val }
136 list
MalList/start
@ { start
}
137 list
MalList/count
@ dup 1- { last
} 1 ?do
138 env start
i cells
+ @
146 defspecial
if { env list
-- val }
147 list
MalList/start
@ cell+ { arg0
}
148 env arg0
@ eval ( test
-val )
156 list
MalList/count
@ 3 > if
157 env arg0
cell+ cell+ @ TCO-eval
163 env arg0
cell+ @ TCO-eval
166 s
" &" MalSymbol. constant
&-sym
168 : new-user
-fn
-env
{ argv
argc mal
-fn
-- env
}
169 mal
-fn
MalUserFn/formal
-args
@ { f
-args
-list
}
170 mal
-fn
MalUserFn/env
@ MalEnv. { env
}
172 f
-args
-list
MalList/start
@ { f
-args
}
173 f
-args
-list
MalList/count
@ ?dup 0= if else
174 \ pass
empty list
for last
arg, unless
overridden below
175 1- cells
f-args
+ @ MalList new env env
/set
182 c cells
allocate throw
{ start
}
183 argv
i cells
+ start
c cells
cmove
184 f-args
i 1+ cells
+ @ ( more
-args
-symbol
)
185 start
c MalList. env env
/set
194 extend eval-invoke { call
-env list
mal-fn
-- list
}
195 call
-env list
eval-rest
198 extend invoke ( argv
argc mal-fn
)
199 dup { mal-fn
} new-user
-fn
-env
{ env
}
200 env
mal-fn
MalUserFn/body
@ TCO-eval ;;
203 defspecial
fn* { env list
-- val }
204 list
MalList/start
@ cell+ { arg0
}
206 env over
MalUserFn/env
!
207 arg0
@ to-list
over MalUserFn/formal
-args
!
208 arg0
cell+ @ over MalUserFn/body
! ;;
211 extend mal-eval { env sym
-- val }
215 0 0 s
" ' not found" sym pr
-str s
" '" ...throw
-str
221 : eval-ast
{ env list
-- list
}
223 list
MalList/start
@ { expr
-start
}
224 list
MalList/count
@ 0 ?do
225 env expr
-start
i cells
+ @ eval ,
230 extend mal-eval { env list
-- val }
231 list
MalList/count
@ 0= if
234 env list
MalList/start
@ @ eval
235 env list
rot eval-invoke
240 extend mal-eval ( env vector
-- vector
)
241 MalVector/list
@ eval-ast
242 MalVector new swap
over MalVector/list
! ;;
246 extend mal-eval ( env map
-- map
)
247 MalMap/list
@ eval-ast
248 MalMap new swap
over MalMap/list
! ;;
251 defcore
eval ( argv
argc )
252 drop @ repl-env swap
eval ;;
254 : rep
( str
-addr str
-len
-- str
-addr str
-len
)
259 : mk
-args
-list
( -- )
262 next
-arg 2dup 0 0 d
<> while
267 create
buff 128 allot
268 77777777777 constant
stack-leak
-detect
272 defcore
swap! { argv
argc -- val }
273 \ argv
is (atom
fn args
...)
276 argc 1- { call
-argc }
277 call
-argc cells
allocate throw
{ call
-argv
}
278 atom
Atom/val call-argv
1 cells
cmove
279 argv
cell+ cell+ call-argv
cell+ call-argc 1- cells
cmove
280 call-argv
call-argc fn invoke
281 dup TCO-eval = if drop eval endif { new-val }
282 new-val atom Atom/val !
285 s
\" (def! not (fn* (x
) (if x
false true)))" rep 2drop
286 s\" (def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))" rep
2drop
292 buff 128 stdin read
-line
throw
293 while ( num
-bytes
-read
)
295 buff swap ( str
-addr str
-len
)
297 \ execute ['] nop \ uncomment
to see
stack traces
300 stack-leak
-detect
<> if ." --stack leak--" cr endif
302 begin stack-leak
-detect
= until
304 s
" forth-errno" MalKeyword. errno
MalInt. MalMap/Empty assoc
307 ." Uncaught exception: "
308 exception-object
pr-str
safe-type cr
314 mk
-args
-list
{ args
-list
}
315 args
-list
MalList/count
@ 0= if
316 s
" *ARGV*" MalSymbol. MalList/Empty repl-env env
/set
319 args
-list
MalList/start
@ @ { filename
}
320 s
" *ARGV*" MalSymbol. args
-list
MalList/rest
repl-env env
/set
323 here
s" load-file" MalSymbol. , filename
, here
>MalList