1 set_path
, get_env
("YORICK_MAL_PATH") + ":" + get_path
()
15 return
((type
== MalList
) ||
(type
== MalVector
)) && count(ast) > 0
20 if
(!is_pair
(ast
)) return MalList
(val
=&[&MalSymbol(val="quote"), &ast])
23 if
(structof
(ast1
) == MalSymbol
&& ast1.val == "unquote") return *lst(2)
25 ast11
= *((*ast1.val
)(1))
26 if
(structof
(ast11
) == MalSymbol
&& ast11.val == "splice-unquote") {
27 return MalList
(val
=&[&MalSymbol(val="concat"), (*ast1.val)(2), &quasiquote(rest(ast))])
30 return MalList
(val
=&[&MalSymbol(val="cons"), &quasiquote(ast1), &quasiquote(rest(ast))])
33 func is_macro_call
(ast
, env
)
35 if
(structof
(ast
) != MalList
) return
0
36 if
(count
(ast
) == 0) return
0
38 if
(structof
(a1
) != MalSymbol
) return
0
40 found_env
= env_find
(env
, var_name
)
41 if
(is_void
(found_env
)) return
0
42 obj
= env_get
(env
, var_name
)
46 func macroexpand
(ast
, env
)
48 while
(is_macro_call
(ast
, env
)) {
49 macro_name
= (*ast.val
)(1)->val
50 macro_obj
= env_get
(env
, macro_name
)
51 macro_args
= *rest
(ast
).val
52 fn_env
= env_new
(macro_obj.env
, binds
=*macro_obj.binds
, exprs
=macro_args
)
53 ast
= EVAL
(*macro_obj.ast
, fn_env
)
58 func eval_ast
(ast
, env
)
61 if
(type
== MalSymbol
) {
62 return env_get
(env
, ast.val
)
63 } else if
(type
== MalList
) {
65 if
(numberof
(seq
) == 0) return ast
66 res
= array
(pointer
, numberof
(seq
))
67 for
(i
= 1; i
<= numberof
(seq
); ++i
) {
68 e
= EVAL
(*seq
(i
), env
)
69 if
(structof
(e
) == MalError
) return e
72 return MalList
(val
=&res)
73 } else if
(type
== MalVector
) {
75 if
(numberof
(seq
) == 0) return ast
76 res
= array
(pointer
, numberof
(seq
))
77 for
(i
= 1; i
<= numberof
(seq
); ++i
) {
78 e
= EVAL
(*seq
(i
), env
)
79 if
(structof
(e
) == MalError
) return e
82 return MalVector
(val
=&res)
83 } else if
(type
== MalHashmap
) {
85 if
(numberof
(*h.keys
) == 0) return ast
87 for
(i
= 1; i
<= numberof
(*h.keys
); ++i
) {
88 new_key
= EVAL
(hashmap_key_to_obj
((*h.keys
)(i
)), env
)
89 if
(structof
(new_key
) == MalError
) return new_key
90 new_val
= EVAL
(*((*h.vals
)(i
)), env
)
91 if
(structof
(new_val
) == MalError
) return new_val
92 hash_set
, res
, hashmap_obj_to_key
(new_key
), new_val
94 return MalHashmap
(val
=&res)
101 if
(structof
(ast
) == MalError
) return ast
102 if
(structof
(ast
) != MalList
) return eval_ast
(ast
, env
)
103 ast
= macroexpand
(ast
, env
)
104 if
(structof
(ast
) != MalList
) return eval_ast
(ast
, env
)
106 if
(numberof
(lst
) == 0) return ast
109 new_value
= EVAL
(*lst
(3), env
)
110 if
(structof
(new_value
) == MalError
) return new_value
111 return env_set
(env
, lst
(2)->val
, new_value
)
112 } else if
(a1
== "let*") {
113 let_env
= env_new
(&env)
114 args_lst
= *(lst
(2)->val
)
115 for
(i
= 1; i
<= numberof
(args_lst
); i
+= 2) {
116 var_name
= args_lst
(i
)->val
117 var_value
= EVAL
(*args_lst
(i
+ 1), let_env
)
118 if
(structof
(var_value
) == MalError
) return var_value
119 env_set
, let_env
, var_name
, var_value
124 } else if
(a1
== "quote") {
126 } else if
(a1
== "quasiquote") {
127 ast
= quasiquote
(*lst
(2)) // TCO
128 } else if
(a1
== "defmacro!") {
129 new_value
= EVAL
(*lst
(3), env
)
130 if
(structof
(new_value
) == MalError
) return new_value
132 return env_set
(env
, lst
(2)->val
, new_value
)
133 } else if
(a1
== "macroexpand") {
134 return macroexpand
(*lst
(2), env
)
135 } else if
(a1
== "try*") {
136 ret
= EVAL
(*lst
(2), env
)
137 if
(structof
(ret
) == MalError
&& numberof(lst) > 2) {
140 exc
= MalString
(val
=ret.message
)
142 catch_lst
= *(lst
(3)->val
)
143 catch_env
= env_new
(&env)
144 env_set
, catch_env
, catch_lst
(2)->val
, exc
145 return EVAL
(*catch_lst
(3), catch_env
)
149 } else if
(a1
== "do") {
150 for
(i
= 2; i
< numberof
(lst
); ++i
) {
151 ret
= EVAL
(*lst
(i
), env
)
152 if
(structof
(ret
) == MalError
) return ret
154 ast
= *lst
(numberof
(lst
))
156 } else if
(a1
== "if") {
157 cond_val
= EVAL
(*lst
(2), env
)
158 if
(structof
(cond_val
) == MalError
) return cond_val
159 if
((structof
(cond_val
) == MalNil
) ||
(structof
(cond_val
) == MalFalse
)) {
160 if
(numberof
(lst
) > 3) {
169 } else if
(a1
== "fn*") {
170 return MalFunction
(env
=&env, binds=lst(2)->val, ast=lst(3), macro=0)
172 el
= eval_ast
(ast
, env
)
173 if
(structof
(el
) == MalError
) return el
175 if
(structof
(*seq
(1)) == MalNativeFunction
) {
176 args
= (numberof
(seq
) > 1) ? seq
(2:) : []
177 return call_core_fn
(seq
(1)->val
, args
)
178 } else if
(structof
(*seq
(1)) == MalFunction
) {
180 exprs
= numberof
(seq
) > 1 ? seq
(2:) : []
181 fn_env
= env_new
(fn.env
, binds
=*fn.binds
, exprs
=exprs
)
186 return MalError
(message
="Unknown function type")
194 if
(structof
(exp
) == MalError
) return exp
195 return pr_str
(exp
, 1)
200 return EVAL
(READ(str
), env
)
205 return PRINT
(EVAL
(READ(str
), env
))
208 func get_command_line
(void
)
209 // Force quiet mode
(-q
) to prevent Yorick from printing its banner
212 return numberof
(argv
) > 1 ? grow
([argv
(1), "-q"], argv
(2:)) : [argv
(1), "-q"]
215 func prepare_argv_list
(args
)
217 if
(numberof
(args
) <= 1) return MalList
(val
=&[])
218 str_lst
= array
(pointer
, numberof
(args
) - 1)
219 for
(i
= 2; i
<= numberof
(args
); ++i
) {
220 str_lst
(i
- 1) = &MalString(val=args(i))
222 return MalList
(val
=&str_lst)
230 repl_env
= env_new
(pointer
(0))
232 // core.i
: defined using Yorick
233 core_symbols
= h_keys
(core_ns
)
234 for
(i
= 1; i
<= numberof
(core_symbols
); ++i
) {
235 env_set
, repl_env
, core_symbols
(i
), MalNativeFunction
(val
=core_symbols
(i
))
237 command_line_args
= process_argv
()
238 env_set
, repl_env
, "*ARGV*", prepare_argv_list
(command_line_args
)
240 // core.mal
: defined using the language itself
241 RE
, "(def! *host-language* \"yorick\
")", repl_env
242 RE
, "(def! not (fn* (a) (if a false true)))", repl_env
243 RE
, "(def! load-file (fn* (f) (eval (read-string (str \"(do \
" (slurp f) \")\
")))))", repl_env
244 RE
, "(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)))))))", repl_env
246 if
(numberof
(command_line_args
) > 0) {
247 RE
, "(load-file \"" + command_line_args(1) + "\
")", repl_env
251 RE
, "(println (str \"Mal
[\
" *host-language* \"]\
"))", repl_env
252 stdin_file
= open
("/dev/stdin", "r")
254 write
, format
="%s", "user> "
255 line
= rdline
(stdin_file
, prompt
="")
257 if
(strlen
(line
) > 0) {
258 result
= REP
(line
, repl_env
)
259 if
(structof
(result
) == MalError
) {
262 write
, format
="Error: %s\n", result.message
264 write
, format
="Error: %s\n", pr_str
(exc
, 1)
267 else write
, format
="%s\n", result