File Coverage

blib/lib/Language/Nouse.pm
Criterion Covered Total %
statement 170 200 85.0
branch 50 72 69.4
condition n/a
subroutine 20 25 80.0
pod 10 13 76.9
total 250 310 80.6


line stmt bran cond sub pod time code
1             package Language::Nouse;
2              
3 3     3   56970 use strict;
  3         8  
  3         109  
4 3     3   16 use warnings;
  3         5  
  3         7110  
5              
6             our $VERSION = '0.04';
7              
8             sub new {
9 3     3 1 36 my $class = shift;
10 3         9 my $self = bless {}, $class;
11              
12 3         7 my $options = shift;
13 3         17 $self->clear();
14              
15 3         10 $self->{sub_get} = \&NOUSE_DEFAULT_get;
16 3         9 $self->{sub_put} = \&NOUSE_DEFAULT_put;
17              
18 3         11 return $self;
19             }
20              
21             sub clear {
22 8     8 1 1078 my ($self) = @_;
23 8         193 $self->{ring} = [];
24 8         22 $self->{stack} = [];
25 8         23 $self->{ring_pointer} = 0;
26             }
27              
28             sub set_get {
29 0     0 1 0 my ($self, $new) = @_;
30 0         0 $self->{sub_get} = $new;
31             }
32              
33             sub set_put {
34 1     1 1 19 my ($self, $new) = @_;
35 1         5 $self->{sub_put} = $new;
36             }
37              
38             sub NOUSE_DEFAULT_get {
39 0     0 0 0 return getc;
40             }
41              
42             sub NOUSE_DEFAULT_put {
43 0     0 0 0 print $_[0];
44             }
45              
46             sub load_linenoise {
47 4     4 1 15 my ($self, $input) = @_;
48              
49 4         13 $self->_reset_ring();
50              
51 4         16 my $op = qr/[#:<>+?^]/;
52 4         12 my $mul = qr/[0-9a-z_]/;
53              
54 4         8 my $not_op = qr/[^#:<>+?^]/;
55 4         12 my $not_mul = qr/[^0-9a-z_]/;
56              
57 4         143 while ($input =~ m/$not_op*($op)$not_mul*($mul)/g){
58              
59 43         73 my $this_op = $1;
60 43         79 my $this_mul = $2;
61              
62 43         54 $this_op =~ y/#:<>+?^/0123456/;
63              
64 43 100       121 $this_mul = 10 + (ord($this_mul) - ord('a')) if ($this_mul =~ m/[a-z]/);
65 43 50       92 $this_mul = 36 if ($this_mul eq '_');
66              
67 43         79 my $op_code = ($this_mul * 7) + $this_op;
68              
69 43         51 push @{$self->{ring}}, $op_code;
  43         305  
70             }
71              
72             }
73              
74             sub load_assembly {
75 4     4 1 822 my ($self, $input) = @_;
76              
77 4         13 $self->_reset_ring();
78              
79 4         19 $input =~ s/#(.*?)(\r|\n|$)/$2/g;
80              
81 4         28 my @tokens = split /[,\n\r]/, $input;
82              
83 4         12 for my $token(@tokens){
84 16         72 $token =~ s/\s*(.*?)\s*/$1/;
85              
86 16 100       91 if ($token =~ m/(cut|paste|read|write|add|test|swap) (\d+)/i){
    50          
87              
88 15         25 my $op = $1;
89 15         25 my $mul = $2;
90              
91 15 50       91 if ($op eq 'cut'){$op = 0;}
  0 50       0  
  0 100       0  
    100          
    100          
    100          
    50          
92 3         6 elsif ($op eq 'paste'){$op = 1;}
93 3         6 elsif ($op eq 'read'){$op = 2;}
94 3         5 elsif ($op eq 'write'){$op = 3;}
95 3         13 elsif ($op eq 'add'){$op = 4;}
96 3         6 elsif ($op eq 'test'){$op = 5;}
97             elsif ($op eq 'swap'){$op = 6;}
98              
99 15         17 push @{$self->{ring}}, ($mul * 7) + $op;
  15         58  
100              
101             }elsif ($token =~ m/(\d+)/){
102              
103 0         0 push @{$self->{ring}}, $1+0;
  0         0  
104              
105             }
106             }
107             }
108              
109             sub get_linenoise {
110 36     36 1 98 my ($self) = @_;
111              
112 36         75 $self->_reset_ring();
113              
114 36         57 my $buffer = '';
115 36         44 for my $raw(@{$self->{ring}}){
  36         78  
116 943         1278 my $op = $raw % 7;
117 943         1253 my $mul = int($raw / 7);
118              
119 943         1144 $op =~ y/0123456/#:<>+?^/;
120              
121 943 50       2315 if ($mul == 36){
    100          
122 0         0 $mul = '_';
123             }elsif ($mul > 9){
124 656         916 $mul = chr(ord('a') + ($mul - 10));
125             }
126              
127 943         1566 $buffer .= $op.$mul;
128             }
129 36         171 return $buffer;
130             }
131              
132             sub get_assembly {
133 5     5 1 34 my ($self, $per_line) = @_;
134              
135 5         14 $self->_reset_ring();
136              
137 5 50       14 $per_line = 4 unless defined $per_line;
138              
139 5         7 my @ops;
140              
141 5         7 for my $raw(@{$self->{ring}}){
  5         13  
142 25         99 my $op = $raw % 7;
143 25         38 my $mul = int($raw / 7);
144              
145 25 50       117 if ($op == 0){
    50          
    100          
    100          
    100          
    100          
    50          
146 0         0 $op = 'cut';
147             }elsif ($op == 1){
148 0         0 $op = 'paste';
149             }elsif ($op == 2){
150 5         8 $op = 'read';
151             }elsif ($op == 3){
152 5         6 $op = 'write';
153             }elsif ($op == 4){
154 5         20 $op = 'add';
155             }elsif ($op == 5){
156 5         8 $op = 'test';
157             }elsif ($op == 6){
158 5         8 $op = 'swap';
159             }
160              
161 25         62 push @ops, "$op $mul";
162             }
163              
164 5         18 my $buffer = '';
165 5         13 while (@ops){
166 10         40 $buffer .= join(', ', splice @ops, 0, $per_line)."\n";
167             }
168              
169 5         26 return $buffer;
170             }
171              
172             sub run {
173 0     0 1 0 my ($self) = @_;
174              
175 0         0 while(scalar(@{$self->{ring}})){
  0         0  
176 0         0 $self->step();
177             }
178             }
179              
180             sub step {
181 30     30 1 11944 my ($self) = @_;
182              
183 30         66 my ($op, $mul, $raw) = $self->_get_op();
184              
185 30         39 my $skip = scalar(@{$self->{stack}}) * $mul;
  30         62  
186 30         36 $skip++;
187              
188 30 100       73 if ($op == 0){
189             # cut
190 3         10 $self->_skip($skip);
191 3         9 $self->_push($self->_get_oprand());
192 3         11 $self->_remove_op();
193 3         6 $skip--;
194             }
195              
196 30 100       98 if ($op == 1){
197             # paste
198 1         4 $self->_skip($skip);
199 1 50       1 if (scalar(@{$self->{stack}})){
  1         4  
200 1         3 $self->_insert_op($self->_pop());
201             }else{
202 0         0 $self->_insert_op($self->_get_oprand());
203             }
204             }
205              
206 30 50       69 if ($op == 2){
207             # read
208 0         0 my $in = &{$self->{sub_get}}();
  0         0  
209 0 0       0 if (defined $in){
210 0         0 $self->_push(ord($in) % 256);
211             }
212             }
213              
214 30 100       55 if ($op == 3){
215             # write
216 14 50       22 if (scalar(@{$self->{stack}})){
  14         36  
217 14         32 &{$self->{sub_put}}(chr($self->_peek()));
  14         51  
218             }
219             }
220              
221 30 100       90 if ($op == 4){
222             # add
223 11 50       14 if (scalar(@{$self->{stack}})){
  11         30  
224 11         24 $self->_skip($skip);
225 11         21 my $oprand = $self->_get_oprand();
226 11         23 $oprand += $self->_pop();
227 11         30 $self->_push($oprand % 256);
228             }
229             }
230              
231 30 50       61 if ($op == 5){
232             # test
233 0 0       0 if (scalar(@{$self->{stack}})){
  0         0  
234 0         0 $self->_skip($skip);
235 0         0 my $oprand = $self->_get_oprand();
236 0 0       0 if ($oprand == $self->_peek()){
237 0         0 $self->_pop();
238             }
239             }
240             }
241              
242 30 100       55 if ($op == 6){
243             # swap
244 1         4 $self->_swap();
245             }
246              
247 30         62 $self->_skip($skip);
248             }
249              
250             sub _skip {
251 45     45   59 my ($self, $by) = @_;
252             # skip the ring pointer along by $by places
253 45         75 $self->{ring_pointer} += $by;
254              
255 45         49 my $s = scalar(@{$self->{ring}});
  45         77  
256 45 100       97 if ($s == 0){
257 1         2 $self->{ring_pointer} = 0;
258 1         3 return;
259             }
260              
261 44         122 $self->{ring_pointer} = $self->{ring_pointer} % $s;
262             }
263              
264             sub _get_op {
265 30     30   40 my ($self) = @_;
266              
267 30         58 my $raw = $self->_get_oprand();
268 30         56 my $op = $raw % 7;
269 30         58 my $mul = int($raw / 7);
270              
271 30         71 return ($op, $mul, $raw);
272             }
273              
274             sub _get_oprand {
275 44     44   53 my ($self) = @_;
276 44 50       50 die "ARGH: The ring is empty and you're asking for an oprand!" if !scalar(@{$self->{ring}});
  44         132  
277 44         114 return $self->{ring}->[$self->{ring_pointer}];
278             }
279              
280             sub _push {
281 28     28   39 my ($self, $value) = @_;
282 28         32 push @{$self->{stack}}, $value;
  28         68  
283             }
284              
285             sub _pop {
286 26     26   621 my ($self) = @_;
287 26         28 return pop @{$self->{stack}};
  26         63  
288             }
289              
290             sub _peek {
291 14     14   19 my ($self) = @_;
292 14         31 my $data = $self->_pop();
293 14         31 $self->_push($data);
294 14         31 return $data;
295             }
296              
297             sub _remove_op {
298 3     3   5 my ($self) = @_;
299 3         6 splice @{$self->{ring}}, $self->{ring_pointer}, 1;
  3         10  
300             }
301              
302             sub _insert_op {
303 1     1   2 my ($self, $value) = @_;
304 1         2 splice @{$self->{ring}}, $self->{ring_pointer}, 0, ($value);
  1         4  
305             }
306              
307             sub _reset_ring {
308 49     49   68 my ($self) = @_;
309              
310 49         76 my $p = $self->{ring_pointer};
311 49         54 my $l = scalar(@{$self->{ring}});
  49         85  
312              
313 49         67 my @new_ring = splice(@{$self->{ring}}, $p, $l-$p);
  49         3839  
314 49         119 push @new_ring, splice(@{$self->{ring}}, 0, $p);
  49         159  
315              
316 49         102 $self->{ring} = \@new_ring;
317 49         124 $self->{ring_pointer} = 0;
318             }
319              
320             sub _swap {
321 1     1   4 my ($self) = @_;
322              
323 1         2 my @new_ring = @{$self->{stack}};
  1         4  
324              
325 1         3 my $p = $self->{ring_pointer};
326 1         2 my $l = scalar(@{$self->{ring}});
  1         3  
327              
328 1         2 my @new_stack = splice(@{$self->{ring}}, $p, $l-$p);
  1         11  
329 1         4 push @new_stack, splice(@{$self->{ring}}, 0, $p);
  1         3  
330              
331 1         3 $self->{stack} = \@new_stack;
332 1         2 $self->{ring} = \@new_ring;
333 1         4 $self->{ring_pointer} = 0;
334             }
335              
336              
337             sub debug {
338 0     0 0   my ($self) = @_;
339              
340 0           print "RING: ".join(',',@{$self->{ring}})." STACK:".join(',',@{$self->{stack}})."\n";
  0            
  0            
341             }
342              
343             1;
344              
345             __END__