Merge pull request #219 from hinrik/perl6_eval_tests
[jackhill/mal.git] / perl6 / step3_env.pl
1 use v6;
2 use lib IO::Path.new($?FILE).dirname;
3 use reader;
4 use printer;
5 use types;
6 use env;
7
8 sub read ($str) {
9 return read_str($str);
10 }
11
12 sub eval_ast ($ast, $env) {
13 given $ast {
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 }
19 }
20 }
21
22 sub eval ($ast, $env) {
23 return eval_ast($ast, $env) if $ast !~~ MalList;
24 return $ast if !$ast.elems;
25
26 my ($a0, $a1, $a2, $a3) = $ast.val;
27 given $a0.val {
28 when 'def!' {
29 return $env.set($a1.val, eval($a2, $env));
30 }
31 when 'let*' {
32 my $new_env = MalEnv.new($env);
33 for |$a1.val -> $key, $value {
34 $new_env.set($key.val, eval($value, $new_env));
35 }
36 return eval($a2, $new_env);
37 }
38 default {
39 my ($func, @args) = eval_ast($ast, $env).val;
40 return $func.apply(|@args);
41 }
42 }
43 }
44
45 sub print ($exp) {
46 return pr_str($exp, True);
47 }
48
49 my $repl_env = MalEnv.new;
50
51 sub rep ($str) {
52 return print(eval(read($str), $repl_env));
53 }
54
55 sub MAIN {
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) }));
60
61 while (my $line = prompt 'user> ').defined {
62 say rep($line);
63 CATCH {
64 when X::MalException { .Str.say }
65 }
66 }
67 }