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 MalNativeFn/xt
@ { xt
}
51 eval
-rest
( argv
argc )
52 xt
execute ( return
-val ) ;;
56 extend eval
-invoke
( env list
this -- list
)
57 SpecialOp/xt
@ execute ;;
60 : install
-special
( symbol
xt )
61 SpecialOp. repl-env env
/set
;
64 parse
-allot
-name
MalSymbol.
69 : is-pair? ( obj -- bool )
72 defspecial quote ( env list -- form )
73 nip MalList/start @ cell+ @ ;;
75 s" concat" MalSymbol. constant concat-sym
76 s" cons" MalSymbol. constant cons-sym
79 : quasiquote0 { ast -- form }
81 here quote-sym , ast , here>MalList
83 ast to-list MalList/start @ { ast-start }
84 ast-start @ { ast[0] }
85 ast[0] unquote-sym m= if
89 ast[0] to-list MalList/start @ { ast[0]-start }
90 ast[0]-start @ splice-unquote-sym m= if
93 ast[0]-start cell+ @ ,
94 ast to-list MalList/rest quasiquote ,
103 ast to-list MalList/rest quasiquote ,
108 ' quasiquote0
is quasiquote
110 defspecial
quasiquote ( env list
)
111 MalList/start
@ cell+ @ ( ast
)
112 quasiquote TCO-eval
;;
114 defspecial
def! { env list
-- val }
115 list
MalList/start
@ cell+ { arg0
}
117 env arg0
cell+ @ eval
dup { val } ( key
val )
120 defspecial
defmacro! { env list
-- val }
121 list
MalList/start
@ cell+ { arg0
}
123 env arg0
cell+ @ eval
{ val }
124 true val MalUserFn/is-macro
? !
128 defspecial
let* { old
-env list
-- val }
129 old
-env MalEnv. { env }
130 list
MalList/start
@ cell+ dup { arg0
}
132 dup MalList/start
@ { bindings
-start
} ( list
)
133 MalList/count
@ 0 +do
134 bindings
-start
i cells
+ dup @ swap
cell+ @ ( sym expr
)
138 env arg0
cell+ @ TCO-eval
139 \
TODO: dec refcount
of env
142 defspecial
do { env list
-- val }
143 list
MalList/start
@ { start
}
144 list
MalList/count
@ dup 1- { last
} 1 ?do
145 env start
i cells
+ @
153 defspecial
if { env list
-- val }
154 list
MalList/start
@ cell+ { arg0
}
155 env arg0
@ eval
( test
-val )
163 list
MalList/count
@ 3 > if
164 env arg0
cell+ cell+ @ TCO-eval
170 env arg0
cell+ @ TCO-eval
173 s
" &" MalSymbol. constant
&-sym
175 : new-user
-fn
-env { argv
argc mal
-fn
-- env }
176 mal
-fn
MalUserFn/formal
-args
@ { f
-args
-list
}
177 mal
-fn
MalUserFn/env @ MalEnv. { env }
179 f
-args
-list
MalList/start
@ { f
-args
}
180 f
-args
-list
MalList/count
@ ?dup 0= if else
181 \ pass
nil for last
arg, unless
overridden below
182 1- cells
f-args
+ @ mal
-nil env env/set
188 f-args
i 1+ cells
+ @ ( more
-args
-symbol
)
189 MalList new ( sym more
-args
)
190 argc i - dup { c
} over
MalList/count
!
191 c cells
allocate throw
dup { start
} over
MalList/start
!
192 argv
i cells
+ start
c cells
cmove
202 extend eval
-invoke
{ call
-env list
mal-fn
-- list
}
203 mal-fn
MalUserFn/is-macro
? @ if
204 list
MalList/start
@ cell+ list
MalList/count
@ 1-
206 call
-env list
eval-rest
208 mal-fn
new-user
-fn
-env { env }
210 mal-fn
MalUserFn/is-macro
? @ if
211 env mal-fn
MalUserFn/body
@ eval
214 env mal-fn
MalUserFn/body
@ TCO-eval
218 defspecial
fn* { env list
-- val }
219 list
MalList/start
@ cell+ { arg0
}
221 env over
MalUserFn/env !
222 arg0
@ to-list
over MalUserFn/formal
-args
!
223 arg0
cell+ @ over MalUserFn/body
! ;;
225 defspecial
macroexpand ( env list
[_
,form
] -- form
)
226 MalList/start
@ cell+ @ swap
over ( form
env form
)
227 MalList/start
@ @ ( form
env macro
-name
-expr
)
228 eval { macro
-fn } ( form
)
229 dup MalList/start
@ cell+ swap
MalList/count
@ 1- macro
-fn ( argv
argc fn )
230 new-user
-fn-env ( env )
231 macro
-fn MalUserFn/body
@ TCO-eval ;;
234 extend mal-eval { env sym
-- val }
238 ." Symbol '" sym pr
-str
safe-type ." ' not found." cr
245 : eval-ast
{ env list
-- list
}
247 list
MalList/start
@ { expr
-start
}
248 list
MalList/count
@ 0 ?do
249 env expr
-start
i cells
+ @ eval ,
254 extend mal-eval { env list
-- val }
255 env list
MalList/start
@ @ eval
256 env list
rot eval-invoke
;;
260 extend mal-eval ( env vector
-- vector
)
261 MalVector/list
@ eval-ast
262 MalVector new swap
over MalVector/list
! ;;
266 extend mal-eval ( env map
-- map
)
267 MalMap/list
@ eval-ast
268 MalMap new swap
over MalMap/list
! ;;
271 defcore
eval ( argv
argc )
272 drop @ repl-env swap
eval ;;
274 : rep
( str
-addr str
-len
-- str
-addr str
-len
)
279 : mk
-args
-list
( -- )
282 next
-arg 2dup 0 0 d
<> while
287 create
buff 128 allot
288 77777777777 constant
stack-leak
-detect
290 s
\" (def! load
-file
(fn* (f) (eval (read
-string (str
\"(do \" (slurp
f) \")\")))))" rep 2drop
291 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
292 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
298 buff 128 stdin read-line throw
299 while ( num-bytes-read )
300 buff swap ( str-addr str-len )
303 catch ?dup 0= if safe-type else ." Caught error " . endif
305 stack-leak-detect <> if ." --stack leak
--" cr endif
309 mk-args-list { args-list }
310 args-list MalList/count @ 0= if
311 s" *ARGV*" MalSymbol. MalList/Empty repl-env env/set
314 args-list MalList/start @ @ { filename }
315 s" *ARGV*" MalSymbol. args-list MalList/rest repl-env env/set
318 here s" load
-file
" MalSymbol. , filename , here>MalList