2 use lib IO
::Path
.new
($?FILE
).dirname
;
12 sub eval_ast
($ast, $env) {
14 when MalSymbol
{ $env.get
($ast.val
) || die X
::MalNotFound
.new
(name
=> $ast.val
) }
15 when MalList
{ MalList
([$ast.map({ eval($_, $env) })]) }
16 when MalVector
{ MalVector
([$ast.map({ eval($_, $env) })]) }
17 when MalHashMap
{ MalHashMap
($ast.kv
.map({ $^a
=> eval($^b
, $env) }).Hash
) }
18 default { $ast // $NIL }
22 sub eval ($ast, $env) {
23 return eval_ast
($ast, $env) if $ast !~~ MalList
;
24 return $ast if !$ast.elems
;
26 my ($a0, $a1, $a2, $a3) = $ast.val
;
29 return $env.set
($a1.val
, eval($a2, $env));
32 my $new_env = MalEnv
.new
($env);
33 for |$a1.val
-> $key, $value {
34 $new_env.set
($key.val
, eval($value, $new_env));
36 return eval($a2, $new_env);
39 my ($func, @args) = eval_ast
($ast, $env).val
;
40 return $func.apply
(|@args);
46 return pr_str
($exp, True
);
49 my $repl_env = MalEnv
.new
;
52 return print(eval(read($str), $repl_env));
56 $repl_env.set
('+', MalCode
({ MalNumber
($^a
.val
+ $^b
.val
) }));
57 $repl_env.set
('-', MalCode
({ MalNumber
($^a
.val
- $^b
.val
) }));
58 $repl_env.set
('*', MalCode
({ MalNumber
($^a
.val
* $^b
.val
) }));
59 $repl_env.set
('/', MalCode
({ MalNumber
(($^a
.val
/ $^b
.val
).Int
) }));
61 while (my $line = prompt
'user> ').defined {
64 when X
::MalException
{ .Str
.say }