File Coverage

blib/lib/Pegex/Forth/Runtime.pm
Criterion Covered Total %
statement 29 31 93.5
branch 6 8 75.0
condition n/a
subroutine 9 10 90.0
pod 0 7 0.0
total 44 56 78.5


line stmt bran cond sub pod time code
1             package Pegex::Forth::Runtime;
2 4     4   21 use Pegex::Base;
  4         7  
  4         25  
3 4     4   15441 use POSIX;
  4         39180  
  4         32  
4              
5             has stack => [];
6             has return_stack => [];
7              
8             sub call {
9 44     44 0 319 my $self = shift;
10 44         117 for my $word (@_) {
11 47 100       218 my $function = $self->dict->{lc $word}
12             or $self->error("Undefined word: '$word'");
13 46         561 $function->($self);
14             }
15             }
16              
17             sub size {
18 0     0 0 0 scalar(@{$_[0]->{stack}});
  0         0  
19             }
20              
21             sub push {
22 114     114 0 881 my ($self, @items) = @_;
23 114         236 push @{$self->stack}, @items;
  114         365  
24             }
25              
26             sub pop {
27 39     39 0 77 my ($self, $count) = (@_);
28 39         77 my $stack = $self->{stack};
29 39 100       119 $self->underflow unless $count <= @$stack;
30 38         333 return splice(@$stack, 0 - $count, $count);
31             }
32              
33             sub peek {
34 3     3 0 6 my $self = shift;
35 3         6 my $stack = $self->{stack};
36 3         6 map {
37 3         5 my $i = $_ + 1;
38 3 50       8 $self->underflow unless $i <= @$stack;
39 3         7 my $a = $stack->[0 - $i];
40 3 50       28 return $a unless wantarray;
41             } @_;
42             }
43              
44             sub underflow {
45 1     1 0 4 $_[0]->error("Stack underflow");
46             }
47              
48             sub error {
49 3     3 0 222 die "$_[1]\n";
50             }
51              
52             has dict => {
53              
54             '.' => sub {
55             my $num = $_[0]->pop(1);
56             print "$num\n";
57             },
58              
59             '.s' => sub {
60             my $stack = $_[0]->stack;
61             my $size = @$stack;
62             print "<$size>" . join('', map " $_", @$stack) . "\n";
63             },
64              
65             '+' => sub {
66             my ($a, $b) = $_[0]->pop(2);
67             $_[0]->push($a + $b);
68             },
69              
70             '-' => sub {
71             my ($a, $b) = $_[0]->pop(2);
72             $_[0]->push($a - $b);
73             },
74              
75             '*' => sub {
76             my ($a, $b) = $_[0]->pop(2);
77             $_[0]->push($a * $b);
78             },
79              
80             '/' => sub {
81             my ($a, $b) = $_[0]->pop(2);
82             $_[0]->error("Division by zero") if $b == 0;
83             $_[0]->push(floor($a / $b));
84             },
85              
86             '/2' => sub {
87             my ($a) = $_[0]->pop(1);
88             $_[0]->push(floor($a / 2));
89             },
90              
91             'mod' => sub {
92             my ($a, $b) = $_[0]->pop(2);
93             $_[0]->error("Division by zero") if $b == 0;
94             $_[0]->push($a % $b);
95             },
96              
97             '/mod' => sub {
98             $_[0]->call(qw(2dup mod -rot /));
99             },
100              
101             'clearstack' => sub {
102             $_[0]->{stack} = [];
103             },
104              
105             '0sp' => sub {
106             $_[0]->call('clearstack');
107             },
108              
109             'dup' => sub {
110             my ($a) = $_[0]->pop(1);
111             $_[0]->push($a, $a);
112             },
113              
114             'swap' => sub {
115             $_[0]->push(reverse $_[0]->pop(2));
116             },
117              
118             'over' => sub {
119             my ($a, $b) = $_[0]->pop(2);
120             $_[0]->push($a, $b, $a);
121             },
122              
123             'drop' => sub {
124             $_[0]->pop(1);
125             },
126              
127             'rot' => sub {
128             my ($a, $b, $c) = $_[0]->pop(3);
129             $_[0]->push($b, $c, $a);
130             },
131              
132             'pick' => sub {
133             $_[0]->push(scalar $_[0]->peek($_[0]->pop(1)));
134             },
135              
136             '?dup' => sub {
137             $_[0]->call('dup') if ($_[0]->peek(0) != 0);
138             },
139              
140             '-rot' => sub {
141             my ($a, $b, $c) = $_[0]->pop(3);
142             $_[0]->push($c, $a, $b);
143             },
144              
145             '2swap' => sub {
146             my ($a, $b, $c, $d) = $_[0]->pop(4);
147             $_[0]->push($c, $d, $a, $b);
148             },
149              
150             '2over' => sub {
151             my ($a, $b, $c, $d) = $_[0]->pop(4);
152             $_[0]->push($a, $b, $c, $d, $a, $b);
153             },
154              
155             '2dup' => sub {
156             my ($a, $b) = $_[0]->pop(2);
157             $_[0]->push($a, $b, $a, $b);
158             },
159              
160             'nip' => sub {
161             my ($a, $b) = $_[0]->pop(2);
162             $_[0]->push($b);
163             },
164              
165             'tuck' => sub {
166             my ($a, $b) = $_[0]->pop(2);
167             $_[0]->push($b, $a, $b);
168             },
169              
170             'abs' => sub {
171             $_[0]->push(abs $_[0]->pop(1));
172             },
173              
174             'negate' => sub {
175             $_[0]->push(0 - $_[0]->pop(1));
176             },
177              
178             'lshift' => sub {
179             my ($a, $b) = $_[0]->pop(2);
180             $_[0]->push($a << $b);
181             },
182              
183             'rshift' => sub {
184             my ($a, $b) = $_[0]->pop(2);
185             $_[0]->push($a >> $b);
186             },
187              
188             'arshift' => sub {
189 4     4   28343 use integer;
  4         45  
  4         30  
190             my ($a, $b) = $_[0]->pop(2);
191             $_[0]->push($a >> $b);
192             },
193              
194             'min' => sub {
195             my ($a, $b) = $_[0]->pop(2);
196             $_[0]->push($a < $b ? $a : $b);
197             },
198              
199             'max' => sub {
200             my ($a, $b) = $_[0]->pop(2);
201             $_[0]->push($a > $b ? $a : $b);
202             },
203              
204             'emit' => sub {
205             print chr $_[0]->pop(1);
206             },
207              
208             words => sub {
209             print join(' ', sort keys %{$_[0]{dict}}) . "\n";
210             },
211              
212             };
213              
214             1