15 MalType
READ(string
str)
20 MalType
eval_ast(MalType ast
, Env env
)
22 if (typeid(ast
) == typeid(MalSymbol
))
24 auto sym
= verify_cast
!MalSymbol(ast
);
27 else if (typeid(ast
) == typeid(MalList
))
29 auto lst
= verify_cast
!MalList(ast
);
30 auto el
= array(lst
.elements
.map
!(e
=> EVAL(e
, env
)));
31 return new MalList(el
);
33 else if (typeid(ast
) == typeid(MalVector
))
35 auto lst
= verify_cast
!MalVector(ast
);
36 auto el
= array(lst
.elements
.map
!(e
=> EVAL(e
, env
)));
37 return new MalVector(el
);
39 else if (typeid(ast
) == typeid(MalHashmap
))
41 auto hm
= verify_cast
!MalHashmap(ast
);
42 typeof(hm
.data
) new_data
;
43 foreach (string k
, MalType v
; hm
.data
)
45 new_data
[k
] = EVAL(v
, env
);
47 return new MalHashmap(new_data
);
55 MalType
EVAL(MalType ast
, Env env
)
59 MalList ast_list
= cast(MalList
) ast
;
62 return eval_ast(ast
, env
);
65 auto aste
= ast_list
.elements
;
66 auto a0_sym
= cast(MalSymbol
) aste
[0];
67 auto sym_name
= a0_sym
is null ?
"" : a0_sym
.name
;
71 auto a1
= verify_cast
!MalSymbol(aste
[1]);
72 return env
.set(a1
, EVAL(aste
[2], env
));
75 auto a1
= verify_cast
!MalSequential(aste
[1]);
76 auto let_env
= new Env(env
);
77 foreach (kv
; chunks(a1
.elements
, 2))
79 if (kv
.length
< 2) throw new Exception("let* requires even number of elements");
80 auto var_name
= verify_cast
!MalSymbol(kv
[0]);
81 let_env
.set(var_name
, EVAL(kv
[1], let_env
));
88 auto all_but_last
= new MalList(aste
[1..$-1]);
89 eval_ast(all_but_last
, env
);
94 auto cond
= EVAL(aste
[1], env
);
112 auto args_list
= verify_cast
!MalSequential(aste
[1]);
113 return new MalFunc(args_list
.elements
, aste
[2], env
);
116 auto el
= verify_cast
!MalList(eval_ast(ast
, env
));
117 if (el
.elements
.length
== 0)
119 throw new Exception("Expected a non-empty list");
121 auto first
= el
.elements
[0];
122 auto rest
= el
.elements
[1..$];
123 if (typeid(first
) == typeid(MalFunc
))
125 auto funcobj
= verify_cast
!MalFunc(first
);
126 auto callenv
= new Env(funcobj
.def_env
, funcobj
.arg_names
, rest
);
127 ast
= funcobj
.func_body
;
131 else if (typeid(first
) == typeid(MalBuiltinFunc
))
133 auto builtinfuncobj
= verify_cast
!MalBuiltinFunc(first
);
134 return builtinfuncobj
.fn(rest
);
138 throw new Exception("Expected a function");
144 string
PRINT(MalType ast
)
149 MalType
re(string
str, Env env
)
151 return EVAL(READ(str), env
);
154 string
rep(string
str, Env env
)
156 return PRINT(re(str, env
));
161 auto repl_env
= new Env(null);
162 foreach (string sym_name
, BuiltinStaticFuncType f
; core_ns
)
164 repl_env
.set(new MalSymbol(sym_name
), new MalBuiltinFunc(f
, sym_name
));
167 // core.mal: defined using the language itself
168 re("(def! not (fn* (a) (if a false true)))", repl_env
);
172 string line
= _readline("user> ");
173 if (line
is null) break;
174 if (line
.length
== 0) continue;
177 writeln(rep(line
, repl_env
));
181 writeln("Error: ", e
.msg
);