Perl: add step2_eval.
[jackhill/mal.git] / perl / step2_eval.pl
CommitLineData
a3b0621d
JM
1use strict;
2use warnings;
3use readline qw(readline);
4use feature qw(switch);
5use Data::Dumper;
6
7use reader;
8use printer;
9
10# read
11sub READ {
12 my $str = shift;
13 return reader::read_str($str);
14}
15
16# eval
17sub eval_ast {
18 my($ast, $env) = @_;
19 given (ref $ast) {
20 when (/^Symbol/) {
21 if (exists $env->{$$ast}) {
22 return $env->{$$ast};
23 } else {
24 die "'" . $$ast . "' not found";
25 }
26 }
27 when (/^List/) {
28 my @lst = map {EVAL($_, $env)} @$ast;
29 return List->new(\@lst);
30 }
31 default {
32 return $ast;
33 }
34 }
35}
36
37sub EVAL {
38 my($ast, $env) = @_;
39 #print "EVAL: " . printer::_pr_str($ast) . "\n";
40 if (! ((ref $ast) =~ /^List/)) {
41 return eval_ast($ast, $env);
42 }
43
44 # apply list
45 my $el = eval_ast($ast, $env);
46 my $f = $el->[0];
47 return &{ $f }($el->rest());
48}
49
50# print
51sub PRINT {
52 my $exp = shift;
53 return printer::_pr_str($exp);
54}
55
56# repl
57my $repl_env = {};
58sub REP {
59 my $str = shift;
60 return PRINT(EVAL(READ($str), $repl_env));
61}
62
63$repl_env->{'+'} = sub { Integer->new(${$_[0][0]} + ${$_[0][1]}) };
64$repl_env->{'-'} = sub { Integer->new(${$_[0][0]} - ${$_[0][1]}) };
65$repl_env->{'*'} = sub { Integer->new(${$_[0][0]} * ${$_[0][1]}) };
66$repl_env->{'/'} = sub { Integer->new(${$_[0][0]} / ${$_[0][1]}) };
67
68while (1) {
69 my $line = readline("user> ");
70 if (! defined $line) { last; }
71 eval {
72 use autodie; # always "throw" errors
73 print(REP($line), "\n");
74 1;
75 };
76 if (my $err = $@) {
77 chomp $err;
78 print "Error: $err\n";
79 }
80}