File Coverage

blib/lib/Acme/URM.pm
Criterion Covered Total %
statement 90 98 91.8
branch 27 34 79.4
condition 6 8 75.0
subroutine 16 18 88.8
pod 8 8 100.0
total 147 166 88.5


line stmt bran cond sub pod time code
1             package Acme::URM;
2 11     11   89389 use strict;
  11         31  
  11         491  
3 11     11   22132 use Data::Dumper;
  11         160449  
  11         1122  
4              
5             our $VERSION = '0.02';
6              
7 11     11   100 use constant LAST => -1;
  11         34  
  11         891  
8 11     11   61 use constant THIS => -2;
  11         22  
  11         472  
9 11     11   52 use constant MAX_STEPS => -3;
  11         27  
  11         21421  
10              
11             my $DEBUG = 0;
12             sub import {
13 11     11   109 foreach (@_) {
14 11 50       27993 if(/^debug$/) {
15 0         0 $DEBUG = 1;
16             }
17             }
18             }
19              
20             sub new {
21 11     11 1 203 my $class = shift;
22 11         37 my $self = {@_};
23 11         38 $self = bless $self, $class;
24 11         59 $self->_init();
25 11         39 $self
26             }
27              
28             sub _init {
29 11     11   24 my $self = shift;
30 11         91 $self->{registers} = ();
31 11         39 $self->{program} = ();
32 11         59 $self->{instr_num} = 0;
33 11         43 $self->{max_steps} = -1; # infinite
34             }
35              
36             sub program {
37 11     11 1 76 my $self = shift;
38 11 50       53 push @{$self->{program}}, @_ if scalar @_;
  11         86  
39 11         104 [$self->{program}]
40             }
41              
42             sub clear_program {
43 0     0 1 0 my $self = shift;
44 0         0 $self->{program} = ();
45             }
46              
47             sub register {
48 9248     9248 1 10366 my $self = shift;
49 9248   100     22987 my $n = shift || 0;
50 9248         9560 my $i = $n;
51 9248         16134 foreach (@_) {
52 1987         5391 $self->{registers}[$i++] = $_;
53             }
54 9248 100       32651 (defined $self->{registers}[$n]) ? $self->{registers}[$n] : 0
55             }
56              
57             sub clear_registers {
58 74     74 1 174 my $self = shift;
59 74         217 $self->{registers} = [];
60             }
61              
62             sub clear {
63 0     0 1 0 my $self = shift;
64 0         0 $self->clear_program();
65 0         0 $self->clear_registers();
66             }
67              
68             sub run {
69 74     74 1 161 my $self = shift;
70 74         120 $self->{instr_num} = 0;
71 74         100 $self->{steps_num} = 0;
72 74         96 my $run = 1;
73 74         82 do {
74 4592         8933 my $step = $self->_step();
75 4592 100       9757 return $step if MAX_STEPS == $step;
76 4587 100       4564 $run = (scalar(@{$self->{program}}) > $step) ? 1 : 0;
  4587         16256  
77             } while( $run );
78 69         266 _debug( "program executed",
79             "registers: " . Dumper([$self->{registers}]),
80             "",
81             );
82 69         585 $self->register(0)
83             }
84              
85             sub _check_nreg {
86 7405     7405   10310 my $self = shift;
87 7405         9063 my $nreg = shift;
88 7405 50 33     48682 die "invalid register index: '$nreg'\n" if $nreg !~ /^\s*\d+\s*$/ || $nreg < 0;
89             }
90              
91             sub _step {
92 4592     4592   5123 my $self = shift;
93 4592         7987 my $cmd = $self->{program}[ $self->{instr_num} ];
94 4592         15018 _debug( "running instruction $self->{instr_num}: $cmd",
95             "registers: " . Dumper($self->{registers}),
96             "",
97             );
98 4592         32919 my $instr_num_save = $self->{instr_num};
99 4592 100       30336 if( $cmd =~ /^\s*Z\s*\((.*)\)$/i ) {
    100          
    100          
    50          
100 79         154 my $nreg = $1;
101 79         175 $self->_check_nreg( $nreg );
102 79         172 $self->register( $nreg, 0 );
103 79         119 $self->{instr_num}++;
104             } elsif( $cmd =~ /^\s*S\s*\((.*)\)$/i ) {
105 1700         2958 my $nreg = $1;
106 1700         3387 $self->_check_nreg( $nreg );
107 1700         8161 $self->register( $nreg, $self->register($nreg) + 1 );
108 1700         3081 $self->{instr_num}++;
109             } elsif( $cmd =~ /^\s*T\s*\((.*)\)$/i ) {
110 75         455 my ($nreg0,$nreg1) = split /\s*,\s*/, $1;
111 75         195 $self->_check_nreg( $nreg0 );
112 75         154 $self->_check_nreg( $nreg1 );
113 75         170 $self->register( $nreg1, $self->register($nreg0) );
114 75         118 $self->{instr_num}++;
115             } elsif( $cmd =~ /^\s*J\s*\((.*)\)$/i ) {
116 2738         14438 my ($nreg0,$nreg1,$q) = split /\s*,\s*/, $1;
117 2738         6133 $self->_check_nreg( $nreg0 );
118 2738         4802 $self->_check_nreg( $nreg1 );
119 2738 100       5406 if( $self->register($nreg0) == $self->register($nreg1) ) {
120 1791 100       6436 if( $q == LAST ) {
    100          
    50          
121 45         56 $self->{instr_num} = scalar @{$self->{program}};
  45         349  
122             } elsif( $q == THIS ) {
123             # save instruction number
124             } elsif( $q !~ /^\s*\d+\s*$/ ) {
125 0         0 die "invalid instruction index: '$q'\n";
126             } else {
127 814         1712 $self->{instr_num} = $q;
128             }
129             } else {
130 947         1557 $self->{instr_num}++;
131             }
132             } else {
133 0         0 die "invalid instruction: '$cmd'\n";
134             }
135 4592         5967 $self->{steps_num}++;
136 4592 100 100     14556 if( 0 < $self->{max_steps} && $self->{max_steps} < $self->{steps_num} ) {
137 5         15 return MAX_STEPS;
138             }
139 4587         16215 _debug( "after running instruction $instr_num_save: $cmd",
140             "registers: " . Dumper($self->{registers}),
141             "",
142             );
143 4587         36657 $self->{instr_num}
144             }
145              
146             sub max_steps {
147 2     2 1 12 my $self = shift;
148 2         5 my $val = shift;
149 2 50       13 $self->{max_steps} = $val if defined $val;
150 2         6 $self->{max_steps}
151             }
152              
153             sub _debug {
154 9248 50   9248   480530 print join("\n",@_),"\n" if $DEBUG;
155             }
156              
157             1;
158              
159             __END__