File Coverage

blib/lib/Language/MinCaml/Evaluator.pm
Criterion Covered Total %
statement 22 94 23.4
branch 8 60 13.3
condition 0 12 0.0
subroutine 5 8 62.5
pod 0 4 0.0
total 35 178 19.6


line stmt bran cond sub pod time code
1             package Language::MinCaml::Evaluator;
2 1     1   7 use strict;
  1         2  
  1         48  
3 1     1   6 use Carp;
  1         2  
  1         78  
4 1     1   6 use Language::MinCaml::Node;
  1         3  
  1         12  
5              
6             sub new {
7 3     3 0 24 my $class = shift;
8 3         14 return bless {}, $class;
9             }
10              
11             sub error {
12 0     0 0 0 croak "evaluation error!";
13             }
14              
15             sub compare {
16 18     18 0 34 my($self, $left, $right) = @_;
17              
18 18 100       82 if (ref($left) eq 'ARRAY') {
    100          
19 5 100       15 if (@$left == @$right) {
20 3         5 for my $index (0..$#{$left}) {
  3         11  
21 9         26 my $result = $self->compare($left->[$index], $right->[$index]);
22 9 100       30 return $result if $result != 0;
23             }
24 1         7 return 0;
25             }
26             else {
27 2         9 return @$left <=> @$right;
28             }
29             }
30             elsif (defined $left) {
31 12         33 return $left <=> $right;
32             }
33             else {
34 1         15 return 0;
35             }
36             }
37              
38             sub evaluate {
39 0     0 0   my($self, $node, %env) = @_;
40 0           my $kind = $node->kind;
41              
42 0 0 0       if ($kind eq 'Unit') {
    0 0        
    0 0        
    0 0        
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
43 0           return;
44             }
45             elsif ($kind eq 'Bool') {
46 0 0         return $node->children->[0] eq 'true' ? 1 : 0;
47             }
48             elsif ($kind eq 'Int' || $kind eq 'Float') {
49 0           return $node->children->[0] + 0;
50             }
51             elsif ($kind eq 'Not') {
52 0 0         return $self->evaluate($node->children->[0], %env) ? 0 : 1;
53             }
54             elsif ($kind eq 'Neg' || $kind eq 'FNeg') {
55 0           return -1 * $self->evaluate($node->children->[0], %env);
56             }
57             elsif ($kind eq 'Add' || $kind eq 'FAdd') {
58 0           return $self->evaluate($node->children->[0], %env) + $self->evaluate($node->children->[1], %env);
59             }
60             elsif ($kind eq 'Sub' || $kind eq 'FSub') {
61 0           return $self->evaluate($node->children->[0], %env) - $self->evaluate($node->children->[1], %env);
62             }
63             elsif ($kind eq 'FMul') {
64 0           return $self->evaluate($node->children->[0], %env) * $self->evaluate($node->children->[1], %env);
65             }
66             elsif ($kind eq 'FDiv') {
67 0           return $self->evaluate($node->children->[0], %env) / $self->evaluate($node->children->[1], %env);
68             }
69             elsif ($kind eq 'Eq') {
70 0           my $left = $self->evaluate($node->children->[0], %env);
71 0           my $right = $self->evaluate($node->children->[1], %env);
72              
73 0 0         if ($self->compare($left, $right) == 0) {
74 0           return 1;
75             }
76             else {
77 0           return 0;
78             }
79             }
80             elsif ($kind eq 'LE') {
81 0           my $left = $self->evaluate($node->children->[0], %env);
82 0           my $right = $self->evaluate($node->children->[1], %env);
83              
84 0 0         if ($self->compare($left, $right) <= 0) {
85 0           return 1;
86             }
87             else {
88 0           return 0;
89             }
90             }
91             elsif ($kind eq 'If') {
92 0 0         if ($self->evaluate($node->children->[0], %env)) {
93 0           return $self->evaluate($node->children->[1], %env);
94             }
95             else {
96 0           return $self->evaluate($node->children->[2], %env);
97             }
98             }
99             elsif ($kind eq 'Let') {
100 0           $env{$node->children->[0]->[0]} = $self->evaluate($node->children->[1], %env);
101              
102 0           return $self->evaluate($node->children->[2], %env);
103             }
104             elsif ($kind eq 'Var') {
105 0           return $env{$node->children->[0]};
106             }
107             elsif ($kind eq 'LetRec') {
108 0           my $body = $node->children->[0]->{body};
109 0           my @arg_names = ();
110              
111 0           for my $arg (@{$node->children->[0]->{args}}) {
  0            
112 0           push(@arg_names, $arg->[0]);
113             }
114              
115             $env{$node->children->[0]->{ident}->[0]} = sub {
116 0     0     my(@arg_values) = @_;
117 0           for my $index (0..$#arg_values) {
118 0           $env{$arg_names[$index]} = $arg_values[$index];
119             }
120 0           return $self->evaluate($body, %env);
121 0           };
122              
123 0           return $self->evaluate($node->children->[1], %env);
124             }
125             elsif ($kind eq 'App') {
126 0           my $func = $self->evaluate($node->children->[0], %env);
127 0           my $args = $node->children->[1];
128 0           my @evaluated_args = ();
129              
130 0           for my $arg (@$args) {
131 0           push(@evaluated_args, $self->evaluate($arg, %env));
132             }
133              
134 0           return $func->(@evaluated_args);
135             }
136             elsif ($kind eq 'Tuple') {
137 0           my $elems = $node->children->[0];
138 0           my @evaluated_elems = ();
139              
140 0           for my $elem (@$elems) {
141 0           push(@evaluated_elems, $self->evaluate($elem, %env));
142             }
143              
144 0           return \@evaluated_elems;
145             }
146             elsif ($kind eq 'LetTuple') {
147 0           my $elem_idents = $node->children->[0];
148 0           my $elem_values = $self->evaluate($node->children->[1], %env);
149              
150 0           for my $index (0..$#{$elem_idents}) {
  0            
151 0           $env{$elem_idents->[$index]} = $elem_values->[$index];
152             }
153              
154 0           return $self->evaluate($node->children->[2], %env);
155             }
156             elsif ($kind eq 'Array') {
157 0           my $number = $self->evaluate($node->children->[0], %env);
158 0           my $value = $self->evaluate($node->children->[1], %env);
159 0           my @array = ();
160              
161 0           for (1..$number) {
162 0           push(@array, $value);
163             }
164              
165 0           return \@array;
166             }
167             elsif ($kind eq 'Get') {
168 0           my $array = $self->evaluate($node->children->[0], %env);
169 0           my $index = $self->evaluate($node->children->[1], %env);
170              
171 0           return $array->[$index];
172             }
173             elsif ($kind eq 'Put') {
174 0           my $array = $self->evaluate($node->children->[0], %env);
175 0           my $index = $self->evaluate($node->children->[1], %env);
176 0           my $value = $self->evaluate($node->children->[2], %env);
177              
178 0           $array->[$index] = $value;
179              
180 0           return;
181             }
182             else {
183 0           croak "This must not happen.";
184             }
185             }
186              
187             1;