14 return e.is_sequence
&& !e.
emptyp();
17 Val
quasiquote(Val ast
)
19 if(!is_pair(ast
)) return List(({ Symbol("quote"), ast
}));
20 Val ast0
= ast.data
[0];
21 if(ast0.mal_type
== MALTYPE_SYMBOL
&& ast0.value
== "unquote") return ast.data
[1];
22 if(is_pair(ast0
) && ast0.data
[0].mal_type
== MALTYPE_SYMBOL
&& ast0.data
[0].value
== "splice-unquote")
24 return List(({ Symbol("concat"), ast0.data
[1], quasiquote(ast.
rest()) }));
26 return List(({ Symbol("cons"), quasiquote(ast0
), quasiquote(ast.
rest()) }));
29 bool
is_macro_call(Val ast
, Env env
)
31 if(ast.mal_type
== MALTYPE_LIST
&&
33 ast.data
[0].mal_type
== MALTYPE_SYMBOL
&&
34 env.
find(ast.data
[0]))
36 Val v
= env.
get(ast.data
[0]);
37 if(objectp(v
) && v.macro
) return true
;
42 Val
macroexpand(Val ast
, Env env
)
44 while(is_macro_call(ast
, env
))
46 Val macro
= env.
get(ast.data
[0]);
47 ast
= macro(@ast.data
[1..
]);
52 Val
eval_ast(Val ast
, Env env
)
59 return List(map(ast.data
, lambda(Val e
) { return EVAL(e
, env
); }));
61 return Vector(map(ast.data
, lambda(Val e
) { return EVAL(e
, env
); }));
63 array(Val
) elements
= ({ });
64 foreach(ast.data
; Val k
; Val v
)
66 elements
+= ({ k
, EVAL(v
, env
) });
74 Val
EVAL(Val ast
, Env env
)
78 if(ast.mal_type
!= MALTYPE_LIST
) return eval_ast(ast
, env
);
79 ast
= macroexpand(ast
, env
);
80 if(ast.mal_type
!= MALTYPE_LIST
) return eval_ast(ast
, env
);
81 if(ast.
emptyp()) return ast
;
82 if(ast.data
[0].mal_type
== MALTYPE_SYMBOL
) {
83 switch(ast.data
[0].value
)
86 return env.
set(ast.data
[1], EVAL(ast.data
[2], env
));
88 Env let_env
= Env(env
);
89 Val ast1
= ast.data
[1];
90 for(int i
= 0; i
< sizeof(ast1.data
); i
+= 2)
92 let_env.
set(ast1.data
[i
], EVAL(ast1.data
[i
+ 1], let_env
));
100 ast
= quasiquote(ast.data
[1]);
103 Val macro
= EVAL(ast.data
[2], env
).
clone_as_macro();
104 return env.
set(ast.data
[1], macro
);
106 return macroexpand(ast.data
[1], env
);
109 foreach(ast.data
[1..
(sizeof(ast.data
) - 2)], Val element
)
111 result
= EVAL(element
, env
);
116 Val cond
= EVAL(ast.data
[1], env
);
117 if(cond.mal_type
== MALTYPE_FALSE || cond.mal_type
== MALTYPE_NIL
)
119 if(sizeof(ast.data
) > 3)
128 return Fn(ast.data
[2], ast.data
[1], env
,
129 lambda(Val ... a
) { return EVAL(ast.data
[2], Env(env
, ast.data
[1], List(a
))); });
132 Val evaled_ast
= eval_ast(ast
, env
);
133 Val f
= evaled_ast.data
[0];
136 case MALTYPE_BUILTINFN
:
137 return f(@evaled_ast.data
[1..
]);
140 env
= Env(f.env
, f.params
, List(evaled_ast.data
[1..
]));
143 throw("Unknown function type");
148 string PRINT(Val
exp)
150 return pr_str(exp, true
);
153 string rep(string str
, Env env
)
155 return PRINT(EVAL(READ(str
), env
));
158 int main(int argc
, array argv
)
160 Env repl_env
= Env(0);
161 foreach(.Core.
NS(); Val k
; Val v
) repl_env.
set(k
, v
);
162 repl_env.
set(Symbol("eval"), BuiltinFn("eval", lambda(Val a
) { return EVAL(a
, repl_env
); }));
163 repl_env.
set(Symbol("*ARGV*"), List(map(argv
[2..
], String
)));
164 rep("(def! not (fn* (a) (if a false true)))", repl_env
);
165 rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))", repl_env
);
166 rep("(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
);
169 rep("(load-file \"" + argv
[1] + "\")", repl_env
);
174 string line
= readline("user> ");
176 if(strlen(line
) == 0) continue;
177 if(mixed err
= catch { write(({ rep(line
, repl_env
), "\n" })); } )
179 if(arrayp(err
)) err
= err
[0];
180 write(({ "Error: ", err
, "\n" }));