File Coverage

blib/lib/Language/Befunge/Ops.pm
Criterion Covered Total %
statement 435 437 99.5
branch 93 94 98.9
condition 6 6 100.0
subroutine 60 60 100.0
pod 55 55 100.0
total 649 652 99.5


line stmt bran cond sub pod time code
1             #
2             # This file is part of Language-Befunge
3             #
4             # This software is copyright (c) 2003 by Jerome Quelin.
5             #
6             # This is free software; you can redistribute it and/or modify it under
7             # the same terms as the Perl 5 programming language system itself.
8             #
9 67     67   20623 use 5.010;
  67         165  
10 67     67   225 use strict;
  67         70  
  67         1351  
11 67     67   189 use warnings;
  67         63  
  67         2732  
12              
13             package Language::Befunge::Ops;
14             # ABSTRACT: definition of the various operations
15             $Language::Befunge::Ops::VERSION = '5.000';
16              
17 67     67   28021 use File::Spec::Functions qw{ catfile }; # For the 'y' instruction.
  67         38136  
  67         3668  
18 67     67   15205 use Language::Befunge::Debug;
  67         90  
  67         241657  
19              
20              
21             sub num_push_number {
22 650     650 1 498 my ($lbi, $char) = @_;
23              
24             # Fetching char.
25 650         702 my $ip = $lbi->get_curip;
26 650         726 my $num = hex( $char );
27              
28             # Pushing value.
29 650         1063 $ip->spush( $num );
30              
31             # Cosmetics.
32 650         1283 debug( "pushing number '$num'\n" );
33             }
34              
35             sub str_enter_string_mode {
36 37     37 1 46 my ($lbi) = @_;
37              
38             # Cosmetics.
39 37         72 debug( "entering string mode\n" );
40              
41             # Entering string-mode.
42 37         103 $lbi->get_curip->set_string_mode(1);
43             }
44              
45              
46             sub str_fetch_char {
47 29     29 1 30 my ($lbi) = @_;
48 29         22 my $ip = $lbi->get_curip;
49              
50             # Moving pointer...
51 29         56 $lbi->_move_ip_once($lbi->get_curip);
52              
53             # .. then fetch value and push it.
54 29         81 my $ord = $lbi->get_storage->get_value( $ip->get_position );
55 29         61 my $chr = $lbi->get_storage->get_char( $ip->get_position );
56 29         47 $ip->spush( $ord );
57              
58             # Cosmetics.
59 29         64 debug( "pushing value $ord (char='$chr')\n" );
60             }
61              
62              
63             sub str_store_char {
64 2     2 1 6 my ($lbi) = @_;
65 2         5 my $ip = $lbi->get_curip;
66              
67             # Moving pointer.
68 2         9 $lbi->_move_ip_once($lbi->get_curip);
69              
70             # Fetching value.
71 2         6 my $val = $ip->spop;
72              
73             # Storing value.
74 2         9 $lbi->get_storage->set_value( $ip->get_position, $val );
75 2         10 my $chr = $lbi->get_storage->get_char( $ip->get_position );
76              
77             # Cosmetics.
78 2         10 debug( "storing value $val (char='$chr')\n" );
79             }
80              
81             sub math_addition {
82 86     86 1 112 my ($lbi) = @_;
83 86         98 my $ip = $lbi->get_curip;
84              
85             # Fetching values.
86 86         163 my ($v1, $v2) = $ip->spop_mult(2);
87 86         198 debug( "adding: $v1+$v2\n" );
88 86         88 my $res = $v1 + $v2;
89              
90             # Checking over/underflow.
91 86 100       152 $res > 2**31-1 and $lbi->abort( "program overflow while performing addition" );
92 84 100       125 $res < -2**31 and $lbi->abort( "program underflow while performing addition" );
93              
94             # Pushing value.
95 82         198 $ip->spush( $res );
96             }
97              
98              
99             sub math_substraction {
100 42     42 1 85 my ($lbi) = @_;
101 42         57 my $ip = $lbi->get_curip;
102              
103             # Fetching values.
104 42         96 my ($v1, $v2) = $ip->spop_mult(2);
105 42         125 debug( "substracting: $v1-$v2\n" );
106 42         55 my $res = $v1 - $v2;
107              
108             # checking over/underflow.
109 42 100       91 $res > 2**31-1 and $lbi->abort( "program overflow while performing substraction" );
110 40 100       72 $res < -2**31 and $lbi->abort( "program underflow while performing substraction" );
111              
112             # Pushing value.
113 38         72 $ip->spush( $res );
114             }
115              
116              
117             sub math_multiplication {
118 73     73 1 104 my ($lbi) = @_;
119 73         67 my $ip = $lbi->get_curip;
120              
121             # Fetching values.
122 73         121 my ($v1, $v2) = $ip->spop_mult(2);
123 73         166 debug( "multiplicating: $v1*$v2\n" );
124 73         76 my $res = $v1 * $v2;
125              
126             # checking over/underflow.
127 73 100       120 $res > 2**31-1 and $lbi->abort( "program overflow while performing multiplication" );
128 71 100       96 $res < -2**31 and $lbi->abort( "program underflow while performing multiplication" );
129              
130             # Pushing value.
131 69         161 $ip->spush( $res );
132             }
133              
134              
135             sub math_division {
136 7     7 1 7 my ($lbi) = @_;
137 7         11 my $ip = $lbi->get_curip;
138              
139             # Fetching values.
140 7         55 my ($v1, $v2) = $ip->spop_mult(2);
141 7         21 debug( "dividing: $v1/$v2\n" );
142 7 100       18 my $res = $v2 == 0 ? 0 : int($v1 / $v2);
143              
144             # Can't do over/underflow with integer division.
145              
146             # Pushing value.
147 7         16 $ip->spush( $res );
148             }
149              
150              
151             sub math_remainder {
152 5     5 1 9 my ($lbi) = @_;
153 5         7 my $ip = $lbi->get_curip;
154              
155             # Fetching values.
156 5         13 my ($v1, $v2) = $ip->spop_mult(2);
157 5         17 debug( "remainder: $v1%$v2\n" );
158 5 100       11 my $res = $v2 == 0 ? 0 : int($v1 % $v2);
159              
160             # Can't do over/underflow with integer remainder.
161              
162             # Pushing value.
163 5         10 $ip->spush( $res );
164             }
165              
166             sub dir_go_east {
167 106     106 1 107 my ($lbi) = @_;
168 106         192 debug( "going east\n" );
169 106         259 $lbi->get_curip->dir_go_east;
170             }
171              
172              
173             sub dir_go_west {
174 50     50 1 66 my ($lbi) = @_;
175 50         96 debug( "going west\n" );
176 50         123 $lbi->get_curip->dir_go_west;
177             }
178              
179              
180             sub dir_go_north {
181 23     23 1 48 my ($lbi) = @_;
182 23         54 debug( "going north\n" );
183 23         79 $lbi->get_curip->dir_go_north;
184             }
185              
186              
187             sub dir_go_south {
188 68     68 1 82 my ($lbi) = @_;
189 68         115 debug( "going south\n" );
190 68         206 $lbi->get_curip->dir_go_south;
191             }
192              
193              
194             sub dir_go_high {
195 2     2 1 15 my ($lbi) = @_;
196 2         7 debug( "going high\n" );
197 2         12 $lbi->get_curip->dir_go_high;
198             }
199              
200              
201             sub dir_go_low {
202 1     1 1 14 my ($lbi) = @_;
203 1         4 debug( "going low\n" );
204 1         7 $lbi->get_curip->dir_go_low;
205             }
206              
207              
208             sub dir_go_away {
209 2     2 1 14 my ($lbi) = @_;
210 2         7 debug( "going away!\n" );
211 2         10 $lbi->get_curip->dir_go_away;
212             }
213              
214              
215             sub dir_turn_left {
216 5     5 1 18 my ($lbi) = @_;
217 5         14 debug( "turning on the left\n" );
218 5         14 $lbi->get_curip->dir_turn_left;
219             }
220              
221              
222             sub dir_turn_right {
223 5     5 1 17 my ($lbi) = @_;
224 5         11 debug( "turning on the right\n" );
225 5         16 $lbi->get_curip->dir_turn_right;
226             }
227              
228              
229             sub dir_reverse {
230 5     5 1 19 my ($lbi) = @_;
231 5         11 debug( "180 deg!\n" );
232 5         14 $lbi->get_curip->dir_reverse;
233             }
234              
235              
236             sub dir_set_delta {
237 6     6 1 13 my ($lbi) = @_;
238 6         15 my $ip = $lbi->get_curip;
239 6         15 my ($new_d) = $ip->spop_vec;
240 6         17 debug( "setting delta to $new_d\n" );
241 6         20 $ip->set_delta( $new_d );
242             }
243              
244             sub decis_neg {
245 21     21 1 21 my ($lbi) = @_;
246 21         30 my $ip = $lbi->get_curip;
247              
248             # Fetching value.
249 21 100       39 my $val = $ip->spop ? 0 : 1;
250 21         37 $ip->spush( $val );
251              
252 21         51 debug( "logical not: pushing $val\n" );
253             }
254              
255              
256             sub decis_gt {
257 6     6 1 9 my ($lbi) = @_;
258 6         10 my $ip = $lbi->get_curip;
259              
260             # Fetching values.
261 6         14 my ($v1, $v2) = $ip->spop_mult(2);
262 6         21 debug( "comparing $v1 vs $v2\n" );
263 6 100       17 $ip->spush( ($v1 > $v2) ? 1 : 0 );
264             }
265              
266              
267             sub decis_horiz_if {
268 70     70 1 61 my ($lbi) = @_;
269 70         73 my $ip = $lbi->get_curip;
270              
271             # Fetching value.
272 70         122 my $val = $ip->spop;
273 70 100       162 $val ? $ip->dir_go_west : $ip->dir_go_east;
274 70 100       183 debug( "horizontal if: going " . ( $val ? "west\n" : "east\n" ) );
275             }
276              
277              
278             sub decis_vert_if {
279 9     9 1 24 my ($lbi) = @_;
280 9         16 my $ip = $lbi->get_curip;
281              
282             # Fetching value.
283 9         19 my $val = $ip->spop;
284 9 100       29 $val ? $ip->dir_go_north : $ip->dir_go_south;
285 9 100       32 debug( "vertical if: going " . ( $val ? "north\n" : "south\n" ) );
286             }
287              
288              
289             sub decis_z_if {
290 2     2 1 5 my ($lbi) = @_;
291 2         4 my $ip = $lbi->get_curip;
292              
293             # Fetching value.
294 2         4 my $val = $ip->spop;
295 2 100       8 $val ? $ip->dir_go_low : $ip->dir_go_high;
296 2 100       7 debug( "z if: going " . ( $val ? "low\n" : "high\n" ) );
297             }
298              
299              
300             sub decis_cmp {
301 6     6 1 16 my ($lbi) = @_;
302 6         16 my $ip = $lbi->get_curip;
303              
304             # Fetching value.
305 6         17 my ($v1, $v2) = $ip->spop_mult(2);
306 6 100       19 debug( "comparing $v1 with $v2: straight forward!\n"), return if $v1 == $v2;
307              
308 4         5 my $dir;
309 4 100       9 if ( $v1 < $v2 ) {
310 2         9 $ip->dir_turn_left;
311 2         3 $dir = "left";
312             } else {
313 2         9 $ip->dir_turn_right;
314 2         2 $dir = "right";
315             }
316 4         17 debug( "comparing $v1 with $v2: turning: $dir\n" );
317             }
318              
319             sub flow_space {
320 3     3 1 6 my ($lbi) = @_;
321 3         9 my $ip = $lbi->get_curip;
322 3         20 $lbi->_move_ip_till($ip, qr/ /);
323 3         18 $lbi->move_ip($lbi->get_curip);
324              
325 3         14 my $char = $lbi->get_storage->get_char($ip->get_position);
326 3         16 $lbi->_do_instruction($char);
327             }
328              
329              
330             sub flow_no_op {
331 41     41 1 43 my ($lbi) = @_;
332 41         55 debug( "no-op\n" );
333             }
334              
335              
336             sub flow_comments {
337 2     2 1 6 my ($lbi) = @_;
338 2         4 my $ip = $lbi->get_curip;
339              
340 2         7 $lbi->_move_ip_once($ip); # skip comment ';'
341 2         10 $lbi->_move_ip_till( $ip, qr/[^;]/ ); # till just before matching ';'
342 2         6 $lbi->_move_ip_once($ip); # till matching ';'
343 2         4 $lbi->_move_ip_once($ip); # till just after matching ';'
344              
345 2         6 my $char = $lbi->get_storage->get_char($ip->get_position);
346 2         5 $lbi->_do_instruction($char);
347             }
348              
349              
350             sub flow_trampoline {
351 256     256 1 203 my ($lbi) = @_;
352 256         481 $lbi->_move_ip_once($lbi->get_curip);
353 256         498 debug( "trampoline! (skipping next instruction)\n" );
354             }
355              
356              
357             sub flow_jump_to {
358 6     6 1 10 my ($lbi) = @_;
359 6         10 my $ip = $lbi->get_curip;
360 6         14 my $count = $ip->spop;
361 6         17 debug( "skipping $count instructions\n" );
362 6 100       17 $count == 0 and return;
363 4 100       12 $count < 0 and $ip->dir_reverse; # We can move backward.
364 4         20 $lbi->_move_ip_once($lbi->get_curip) for (1..abs($count));
365 4 100       15 $count < 0 and $ip->dir_reverse;
366             }
367              
368              
369             sub flow_repeat {
370 13     13 1 23 my ($lbi) = @_;
371 13         20 my $ip = $lbi->get_curip;
372 13         17 my $pos = $ip->get_position;
373              
374 13         35 my $kcounter = $ip->spop;
375 13         36 debug( "repeating next instruction $kcounter times.\n" );
376              
377             # fetch instruction to repeat
378 13         32 $lbi->move_ip($lbi->get_curip);
379 13         37 my $char = $lbi->get_storage->get_char($ip->get_position);
380              
381 13 100       28 $char eq 'k' and return; # k cannot be itself repeated
382 12 100       21 $kcounter == 0 and return; # nothing to repeat
383 10 100       18 $kcounter < 0 and return; # oops, error
384              
385             # reset position back to where k is, and repeat instruction
386 9         18 $ip->set_position($pos);
387 9         37 $lbi->_do_instruction($char) for (1..$kcounter);
388             }
389              
390              
391             sub flow_kill_thread {
392 19     19 1 30 my ($lbi) = @_;
393 19         30 debug( "end of Instruction Pointer\n" );
394 19         51 $lbi->get_curip->set_end('@');
395             }
396              
397              
398             sub flow_quit {
399 186     186 1 169 my ($lbi) = @_;
400 186         396 debug( "end program\n" );
401 186         271 $lbi->set_newips( [] );
402 186         276 $lbi->set_ips( [] );
403 186         321 $lbi->get_curip->set_end('q');
404 186         402 $lbi->set_retval( $lbi->get_curip->spop );
405             }
406              
407             sub stack_pop {
408 63     63 1 48 my ($lbi) = @_;
409 63         73 debug( "popping a value\n" );
410 63         100 $lbi->get_curip->spop;
411             }
412              
413              
414             sub stack_duplicate {
415 70     70 1 57 my ($lbi) = @_;
416 70         68 my $ip = $lbi->get_curip;
417 70         114 my $value = $ip->spop;
418 70         150 debug( "duplicating value '$value'\n" );
419 70         134 $ip->spush( $value );
420 70         103 $ip->spush( $value );
421             }
422              
423              
424             sub stack_swap {
425 3     3 1 6 my ($lbi) = @_;
426 3         6 my $ ip = $lbi->get_curip;
427 3         9 my ($v1, $v2) = $ip->spop_mult(2);
428 3         12 debug( "swapping $v1 and $v2\n" );
429 3         7 $ip->spush( $v2 );
430 3         7 $ip->spush( $v1 );
431             }
432              
433              
434             sub stack_clear {
435 2     2 1 6 my ($lbi) = @_;
436 2         6 debug( "clearing stack\n" );
437 2         10 $lbi->get_curip->sclear;
438             }
439              
440             sub block_open {
441 19     19 1 25 my ($lbi) = @_;
442 19         31 my $ip = $lbi->get_curip;
443 19         32 debug( "block opening\n" );
444              
445             # Create new TOSS.
446 19         45 $ip->ss_create( $ip->spop );
447              
448             # Store current storage offset on SOSS.
449 19         52 $ip->soss_push( $ip->get_storage->get_all_components );
450              
451             # Set the new Storage Offset.
452 19         104 $lbi->_move_ip_once($lbi->get_curip);
453 19         49 $ip->set_storage( $ip->get_position );
454 19         38 $ip->dir_reverse;
455 19         46 $lbi->_move_ip_once($lbi->get_curip);
456 19         40 $ip->dir_reverse;
457             }
458              
459              
460             sub block_close {
461 12     12 1 19 my ($lbi) = @_;
462 12         23 my $ip = $lbi->get_curip;
463              
464             # No opened block.
465 12 100       30 $ip->ss_count <= 0 and $ip->dir_reverse, debug("no opened block\n"), return;
466              
467 10         27 debug( "block closing\n" );
468              
469             # Restore Storage offset.
470 10         91 $ip->set_storage( $ip->soss_pop_vec );
471              
472             # Remove the TOSS.
473 10         21 $ip->ss_remove( $ip->spop );
474             }
475              
476              
477             sub bloc_transfer {
478 11     11 1 14 my ($lbi) = @_;
479 11         14 my $ip = $lbi->get_curip;
480              
481 11 100       20 $ip->ss_count <= 0 and $ip->dir_reverse, debug("no SOSS available\n"), return;
482              
483             # Transfering values.
484 10         15 debug( "transfering values\n" );
485 10         22 $ip->ss_transfer( $ip->spop );
486             }
487              
488             sub store_get {
489 4     4 1 4 my ($lbi) = @_;
490 4         4 my $ip = $lbi->get_curip;
491              
492             # Fetching coordinates.
493 4         7 my ($v) = $ip->spop_vec;
494 4         9 $v += $ip->get_storage;
495              
496             # Fetching char.
497 4         9 my $val = $lbi->get_storage->get_value( $v );
498 4         7 $ip->spush( $val );
499              
500 4         7 debug( "fetching value at $v: pushing $val\n" );
501             }
502              
503              
504             sub store_put {
505 15     15 1 17 my ($lbi) = @_;
506 15         23 my $ip = $lbi->get_curip;
507              
508             # Fetching coordinates.
509 15         34 my ($v) = $ip->spop_vec;
510 15         39 $v += $ip->get_storage;
511              
512             # Fetching char.
513 15         26 my $val = $ip->spop;
514 15         41 $lbi->get_storage->set_value( $v, $val );
515              
516 15         32 debug( "storing value $val at $v\n" );
517             }
518              
519             sub stdio_out_num {
520 212     212 1 169 my ($lbi) = @_;
521 212         217 my $ip = $lbi->get_curip;
522              
523             # Fetch value and print it.
524 212         366 my $val = $ip->spop;
525 212         452 debug( "numeric output: $val\n");
526 212 100       119141 print( "$val " ) or $ip->dir_reverse;
527             }
528              
529              
530             sub stdio_out_ascii {
531 150     150 1 116 my ($lbi) = @_;
532 150         135 my $ip = $lbi->get_curip;
533              
534             # Fetch value and print it.
535 150         248 my $val = $ip->spop;
536 150         146 my $chr = chr $val;
537 150         303 debug( "ascii output: '$chr' (ord=$val)\n");
538 150 100       2405 print( $chr ) or $ip->dir_reverse;
539             }
540              
541              
542             sub stdio_in_num {
543 12     12 1 6044 my ($lbi) = @_;
544 12         90 my $ip = $lbi->get_curip;
545 12         72 my ($in, $nb) = ('', 0);
546 12         49 my $last = 0;
547 12         146 while(!$last) {
548 59         198 my $char = $lbi->get_input();
549 59 100       113 $in .= $char if defined $char;
550 59         36 my $overflow;
551 59         237 ($nb, $overflow) = $in =~ /(-?\d+)(\D*)$/;
552 59 100 100     380 if((defined($overflow) && length($overflow)) || !defined($char)) {
      100        
553             # either we found a non-digit character: $overflow
554             # or else we reached EOF: !$char
555 12 100       39 return $ip->dir_reverse() unless defined $nb;
556 6 100       52 $nb < -2**31 and $nb = -2**31;
557 6 100       18 $nb > 2**31-1 and $nb = 2**31-1;
558 6         6 $in = $overflow;
559 6         12 $last++;
560             }
561             }
562 6         21 $lbi->set_input( $in );
563 6         81 $ip->spush( $nb );
564 6         85 debug( "numeric input: pushing $nb\n" );
565             }
566              
567              
568             sub stdio_in_ascii {
569 3     3 1 1196 my ($lbi) = @_;
570 3         27 my $ip = $lbi->get_curip;
571 3         36 my $in = $lbi->get_input();
572 3 100       16 return $ip->dir_reverse unless defined $in;
573 2         3 my $ord = ord $in;
574 2         15 $ip->spush( $ord );
575 2         22 debug( "ascii input: pushing $ord\n" );
576             }
577              
578              
579             sub stdio_in_file {
580 3     3 1 6 my ($lbi) = @_;
581 3         8 my $ip = $lbi->get_curip;
582              
583             # Fetch arguments.
584 3         13 my $path = $ip->spop_gnirts;
585 3         12 my $flag = $ip->spop;
586 3         11 my ($vin) = $ip->spop_vec;
587 3         13 $vin += $ip->get_storage;
588              
589             # Read file.
590 3         12 debug( "input file '$path' at $vin\n" );
591 3 100       213 open F, "<", $path or $ip->dir_reverse, return;
592 2         3 my $lines;
593             {
594 2         2 local $/; # slurp mode.
  2         14  
595 2         63 $lines = ;
596             }
597 2         93 close F;
598              
599             # Store the code and the result vector.
600 2 100       25 my ($size) = $flag % 2
601             ? ( $lbi->get_storage->store_binary( $lines, $vin ) )
602             : ( $lbi->get_storage->store( $lines, $vin ) );
603 2         11 $ip->spush_vec( $size, $vin );
604             }
605              
606              
607             sub stdio_out_file {
608 3     3 1 9 my ($lbi) = @_;
609 3         6 my $ip = $lbi->get_curip;
610              
611             # Fetch arguments.
612 3         13 my $path = $ip->spop_gnirts;
613 3         12 my $flag = $ip->spop;
614 3         17 my ($vin) = $ip->spop_vec;
615 3         13 $vin += $ip->get_storage;
616 3         10 my ($size) = $ip->spop_vec;
617 3         14 my $data = $lbi->get_storage->rectangle( $vin, $size );
618              
619             # Cosmetics.
620 3         12 my $vend = $vin + $size;
621 3         8 debug( "output $vin-$vend to '$path'\n" );
622              
623             # Treat the data chunk as text file?
624 3 100       12 if ( $flag & 0x1 ) {
625 1         13 $data =~ s/ +$//mg; # blank lines are now void.
626 1         5 $data =~ s/\n+\z/\n/; # final blank lines are stripped.
627             }
628              
629             # Write file.
630 3 100       523 open F, ">", $path or $ip->dir_reverse, return;
631 2         41 print F $data;
632 2         154 close F;
633             }
634              
635              
636             sub stdio_sys_exec {
637 2     2 1 2 my ($lbi) = @_;
638 2         3 my $ip = $lbi->get_curip;
639              
640             # Fetching command.
641 2         4 my $path = $ip->spop_gnirts;
642 2         6 debug( "spawning external command: $path\n" );
643 2         5378 system( $path );
644 2 100       52 $ip->spush( $? == -1 ? -1 : $? >> 8 );
645             }
646              
647             sub sys_info {
648 30     30 1 28 my ($lbi) = @_;
649 30         34 my $ip = $lbi->get_curip;
650 30         29 my $storage = $lbi->get_storage;
651              
652 30         62 my $val = $ip->spop;
653 30         32 my @infos = ();
654              
655             # 1. flags
656 30         27 push @infos, 0x01 # 't' is implemented.
657             | 0x02 # 'i' is implemented.
658             | 0x04 # 'o' is implemented.
659             | 0x08 # '=' is implemented.
660             | !0x10; # buffered IO (non getch).
661              
662             # 2. number of bytes per cell.
663             # 32 bytes Funge: 4 bytes.
664 30         19 push @infos, 4;
665              
666             # 3. implementation handprint.
667 30         25 my $handprint = 0;
668 30         124 $handprint = $handprint * 256 + ord($_) for split //, $lbi->get_handprint;
669 30         33 push @infos, $handprint;
670              
671             # 4. version number.
672 30         30 my $ver = $Language::Befunge::VERSION;
673 30         122 $ver =~ s/\D//g;
674 30         30 push @infos, $ver;
675              
676             # 5. ID code for Operating Paradigm.
677 30         32 push @infos, 1; # C-language system() call behaviour.
678              
679             # 6. Path separator character.
680 30         79 push @infos, ord( catfile('','') );
681              
682             # 7. Number of dimensions.
683 30         49 push @infos, $ip->get_dims;
684              
685             # 8. Unique IP number.
686 30         31 push @infos, $ip->get_id;
687              
688             # 9. Unique team number for the IP (NetFunge, not implemented).
689 30         25 push @infos, 0;
690              
691             # 10. Position of the curent IP.
692 30         62 my @pos = ( $ip->get_position->get_all_components );
693 30         27 push @infos, \@pos;
694              
695             # 11. Delta of the curent IP.
696 30         51 my @delta = ( $ip->get_delta->get_all_components );
697 30         26 push @infos, \@delta;
698              
699             # 12. Storage offset of the curent IP.
700 30         53 my @stor = ( $ip->get_storage->get_all_components );
701 30         23 push @infos, \@stor;
702              
703             # 13. Top-left point.
704 30         67 my $min = $storage->min;
705             # FIXME: multiple dims?
706 30         54 my @topleft = ( $min->get_component(0), $min->get_component(1) );
707 30         31 push @infos, \@topleft;
708              
709             # 14. Dims of the storage.
710 30         50 my $max = $storage->max;
711             # FIXME: multiple dims?
712 30         42 my @dims = ( $max->get_component(0) - $min->get_component(0),
713             $max->get_component(1) - $min->get_component(1) );
714 30         29 push @infos, \@dims;
715              
716             # 15/16. Current date/time.
717 30         544 my ($s,$m,$h,$dd,$mm,$yy)=localtime;
718 30         64 push @infos, $yy*256*256 + ($mm+1)*256 + $dd;
719 30         30 push @infos, $h*256*256 + $m*256 + $s;
720              
721             # 17. Size of stack stack.
722 30         72 push @infos, $ip->ss_count + 1;
723              
724             # 18. Size of each stack in the stack stack.
725             # note: the number of stack is given by previous value.
726 30         61 my @sizes = reverse $ip->ss_sizes;
727 30         26 push @infos, \@sizes;
728              
729             # 19. $file + params.
730 30         36 my $str = join chr(0), $lbi->get_file, @{$lbi->get_params}, chr(0)x2;
  30         57  
731 30         71 my @cmdline = reverse map { ord } split //, $str;
  250         194  
732 30         45 push @infos, \@cmdline;
733              
734             # 20. %ENV
735             # 00EULAV=EMAN0EULAV=EMAN
736 30         31 $str = "";
737 30         428 $str .= "$_=$ENV{$_}".chr(0) foreach sort keys %ENV;
738 30         39 $str .= chr(0);
739 30         1188 my @env = reverse map { ord } split //, $str;
  16991         10929  
740 30         831 push @infos, \@env;
741              
742 30 100       31 my @cells = map { ref($_) eq 'ARRAY' ? (@$_) : ($_) } reverse @infos;
  600         1510  
743              
744             # Okay, what to do with those cells.
745 30 100       303 if ( $val <= 0 ) {
    100          
746             # Blindly push them onto the stack.
747 3         8 debug( "system info: pushing the whole stuff\n" );
748 3         19 $ip->spush(@cells);
749              
750             } elsif ( $val <= scalar(@cells) ) {
751             # Only push the wanted value.
752 26         72 debug( "system info: pushing the ${val}th value\n" );
753 26         66 $ip->spush( $cells[$#cells-$val+1] );
754              
755             } else {
756             # Pick a given value in the stack and push it.
757 1         3 my $offset = $val - $#cells - 1;
758 1         3 my $value = $ip->svalue($offset);
759 1         4 debug( "system info: picking the ${offset}th value from the stack = $value\n" );
760 1         2 $ip->spush( $value );
761             }
762             }
763              
764             sub spawn_ip {
765 6     6 1 7 my ($lbi) = @_;
766              
767             # Cosmetics.
768 6         11 debug( "spawning new IP\n" );
769              
770             # Cloning and storing new IP.
771 6         14 my $newip = $lbi->get_curip->clone;
772 6         13 $newip->dir_reverse;
773 6         14 $lbi->move_ip($newip);
774 6         5 push @{ $lbi->get_newips }, $newip;
  6         17  
775             }
776              
777             sub lib_load {
778 19     19 1 20 my ($lbi) = @_;
779 19         27 my $ip = $lbi->get_curip;
780              
781             # Fetching fingerprint.
782 19         40 my $count = $ip->spop;
783 19         21 my $fgrprt = 0;
784 19         43 while ( $count-- > 0 ) {
785 70         98 my $val = $ip->spop;
786 70 100       94 $lbi->abort( "Attempt to build a fingerprint with a negative number" )
787             if $val < 0;
788 69         105 $fgrprt = $fgrprt * 256 + $val;
789             }
790              
791             # Transform the fingerprint into a library name.
792 18         17 my $lib = "";
793 18         15 my $finger = $fgrprt;
794 18         30 while ( $finger > 0 ) {
795 69         48 my $c = $finger % 0x100;
796 69         56 $lib .= chr($c);
797 69         109 $finger = int ( $finger / 0x100 );
798             }
799 18         25 $lib = "Language::Befunge::lib::" . reverse $lib;
800              
801             # Checking if library exists.
802 18         1112 eval "require $lib";
803 18 100       58 if ( $@ ) {
804 1         9 debug( sprintf("unknown extension $lib (0x%x): reversing\n", $fgrprt) );
805 1         3 $ip->dir_reverse;
806             } else {
807 17         88 debug( sprintf("extension $lib (0x%x) loaded\n", $fgrprt) );
808 17         52 my $obj = $lib->new;
809 17         46 $ip->load( $obj );
810 17         40 $ip->spush( $fgrprt, 1 );
811             }
812             }
813              
814              
815             sub lib_unload {
816 10     10 1 8 my ($lbi) = @_;
817 10         14 my $ip = $lbi->get_curip;
818              
819             # Fetching fingerprint.
820 10         20 my $count = $ip->spop;
821 10         9 my $fgrprt = 0;
822 10         26 while ( $count-- > 0 ) {
823 16         23 my $val = $ip->spop;
824 16 100       25 $lbi->abort( "Attempt to build a fingerprint with a negative number" )
825             if $val < 0;
826 15         29 $fgrprt = $fgrprt * 256 + $val;
827             }
828              
829             # Transform the fingerprint into a library name.
830 9         8 my $lib = "";
831 9         9 my $finger = $fgrprt;
832 9         18 while ( $finger > 0 ) {
833 35         20 my $c = $finger % 0x100;
834 35         27 $lib .= chr($c);
835 35         51 $finger = int ( $finger / 0x100 );
836             }
837 9         15 $lib = "Language::Befunge::lib::" . reverse $lib;
838              
839             # Checking if library exists.
840 9         445 eval "require $lib";
841 9 100       30 if ( $@ ) {
842 1         6 debug( sprintf("unknown extension $lib (0x%x): reversing\n", $fgrprt) );
843 1         3 $ip->dir_reverse;
844             } else {
845             # Unload the library.
846 8         40 debug( sprintf("unloading library $lib (0x%x)\n", $fgrprt) );
847 8         21 $ip->unload($lib);
848             }
849             }
850              
851              
852             sub lib_run_instruction {
853 13     13 1 15 my ($lbi) = @_;
854 13         21 my $ip = $lbi->get_curip;
855 13         30 my $char = $lbi->get_storage->get_char( $ip->get_position );
856              
857             # Maybe a library semantics.
858 13         20 debug( "library semantics\n" );
859 13         21 my $stack = $ip->get_libs->{$char};
860              
861 13 50       20 if ( scalar @$stack ) {
862 13         15 my $obj = $stack->[-1];
863 13         34 debug( "library semantics processed by ".ref($obj)."\n" );
864 13         35 $obj->$char( $lbi );
865             } else {
866             # Non-overloaded capitals default to reverse.
867 0           debug("no library semantics found: reversing\n");
868 0           $ip->dir_reverse;
869             }
870             }
871              
872              
873             1;
874              
875             __END__