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
)
57 MalList ast_list
= cast(MalList
) ast
;
60 return eval_ast(ast
, env
);
63 auto aste
= ast_list
.elements
;
64 auto a0_sym
= cast(MalSymbol
) aste
[0];
65 auto sym_name
= a0_sym
is null ?
"" : a0_sym
.name
;
69 auto a1
= verify_cast
!MalSymbol(aste
[1]);
70 return env
.set(a1
, EVAL(aste
[2], env
));
73 auto a1
= verify_cast
!MalSequential(aste
[1]);
74 auto let_env
= new Env(env
);
75 foreach (kv
; chunks(a1
.elements
, 2))
77 if (kv
.length
< 2) throw new Exception("let* requires even number of elements");
78 auto var_name
= verify_cast
!MalSymbol(kv
[0]);
79 let_env
.set(var_name
, EVAL(kv
[1], let_env
));
81 return EVAL(aste
[2], let_env
);
84 auto rest
= new MalList(aste
[1..$]);
85 auto el
= verify_cast
!MalList(eval_ast(rest
, env
));
86 return el
.elements
[$-1];
89 auto cond
= EVAL(aste
[1], env
);
91 return EVAL(aste
[2], env
);
94 return EVAL(aste
[3], env
);
99 auto args_list
= verify_cast
!MalSequential(aste
[1]);
100 return new MalFunc(args_list
.elements
, aste
[2], env
);
103 auto el
= verify_cast
!MalList(eval_ast(ast
, env
));
104 if (el
.elements
.length
== 0)
106 throw new Exception("Expected a non-empty list");
108 auto first
= el
.elements
[0];
109 auto rest
= el
.elements
[1..$];
110 if (typeid(first
) == typeid(MalFunc
))
112 auto funcobj
= verify_cast
!MalFunc(first
);
113 auto callenv
= new Env(funcobj
.def_env
, funcobj
.arg_names
, rest
);
114 return EVAL(funcobj
.func_body
, callenv
);
116 else if (typeid(first
) == typeid(MalBuiltinFunc
))
118 auto builtinfuncobj
= verify_cast
!MalBuiltinFunc(first
);
119 return builtinfuncobj
.fn(rest
);
123 throw new Exception("Expected a function");
128 string
PRINT(MalType ast
)
133 MalType
re(string
str, Env env
)
135 return EVAL(READ(str), env
);
138 string
rep(string
str, Env env
)
140 return PRINT(re(str, env
));
145 auto repl_env
= new Env(null);
146 foreach (string sym_name
, BuiltinStaticFuncType f
; core_ns
)
148 repl_env
.set(new MalSymbol(sym_name
), new MalBuiltinFunc(f
, sym_name
));
151 // core.mal: defined using the language itself
152 re("(def! not (fn* (a) (if a false true)))", repl_env
);
156 string line
= _readline("user> ");
157 if (line
is null) break;
158 if (line
.length
== 0) continue;
161 writeln(rep(line
, repl_env
));
165 writeln("Error: ", e
.msg
);