15 MalType
READ(string
str)
20 MalType
eval_ast(MalType ast
, Env env
)
22 if (auto sym
= cast(MalSymbol
)ast
)
26 else if (auto lst
= cast(MalList
)ast
)
28 auto el
= array(lst
.elements
.map
!(e
=> EVAL(e
, env
)));
29 return new MalList(el
);
31 else if (auto lst
= cast(MalVector
)ast
)
33 auto el
= array(lst
.elements
.map
!(e
=> EVAL(e
, env
)));
34 return new MalVector(el
);
36 else if (auto hm
= cast(MalHashmap
)ast
)
38 typeof(hm
.data
) new_data
;
39 foreach (string k
, MalType v
; hm
.data
)
41 new_data
[k
] = EVAL(v
, env
);
43 return new MalHashmap(new_data
);
51 MalType
EVAL(MalType ast
, Env env
)
53 MalList ast_list
= cast(MalList
) ast
;
56 return eval_ast(ast
, env
);
59 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 (auto funcobj
= cast(MalFunc
)first
)
112 auto callenv
= new Env(funcobj
.def_env
, funcobj
.arg_names
, rest
);
113 return EVAL(funcobj
.func_body
, callenv
);
115 else if (auto builtinfuncobj
= cast(MalBuiltinFunc
)first
)
117 return builtinfuncobj
.fn(rest
);
121 throw new Exception("Expected a function");
126 string
PRINT(MalType ast
)
131 MalType
re(string
str, Env env
)
133 return EVAL(READ(str), env
);
136 string
rep(string
str, Env env
)
138 return PRINT(re(str, env
));
143 auto repl_env
= new Env(null);
144 foreach (string sym_name
, BuiltinStaticFuncType f
; core_ns
)
146 repl_env
.set(new MalSymbol(sym_name
), new MalBuiltinFunc(f
, sym_name
));
149 // core.mal: defined using the language itself
150 re("(def! not (fn* (a) (if a false true)))", repl_env
);
154 string line
= _readline("user> ");
155 if (line
is null) break;
156 if (line
.length
== 0) continue;
159 writeln(rep(line
, repl_env
));
163 writeln("Error: ", e
.msg
);