File Coverage

blib/lib/App/EvalServerAdvanced/ConstantCalc.pm
Criterion Covered Total %
statement 137 139 98.5
branch 31 60 51.6
condition 3 9 33.3
subroutine 37 37 100.0
pod 2 3 66.6
total 210 248 84.6


line stmt bran cond sub pod time code
1             package App::EvalServerAdvanced::ConstantCalc;
2              
3             our $VERSION = '0.06';
4              
5             # ABSTRACT: turns strings and constants into values
6              
7 1     1   47006 use v5.24;
  1         11  
8 1     1   306 use Moo;
  1         7975  
  1         4  
9 1     1   1362 use Function::Parameters;
  1         2879  
  1         4  
10 1     1   753 use Data::Dumper;
  1         5303  
  1         201  
11              
12             has constants => (is => 'ro', default => sub {+{}});
13             has _parser => (is => 'ro', default => sub {App::EvalServerAdvanced::ConstantCalc::Parser->new(consts => $_[0])});
14              
15 2 50   2 1 6 method get_value($key) {
  2 50       5  
  2         3  
  2         4  
  2         2  
16 2 50       11 die "Missing constant [$key]" unless exists($self->constants->{$key});
17              
18 2         6 return $self->constants->{$key};
19             }
20              
21 3 50   3 1 13 method add_constant($key, $value) {
  3 50       7  
  3         6  
  3         7  
  3         3  
22 3 50 33     20 die "Invalid key [$key]" if ($key =~ /\s/ || $key =~ /^\s*\d/);
23              
24 3 50 33     13 if (exists($self->constants->{$key}) && defined(my $eval = $self->constants->{$key})) {
25 0         0 die "Cannot redefine a constant [$key]. Existing value [$eval] new value [$value]"
26             }
27              
28 3 50       7 die "Value undefined for [$key]" unless defined($value);
29 3 50       8 die "Value [$value] for [$key] must be an integer" if ($value =~ /[^xob\d\-+_]/i);
30              
31 3         7 $self->constants->{$key} = App::EvalServerAdvanced::ConstantCalc::Parser::_to_int($value);
32             }
33              
34 7 50   7 0 2880 method calculate($string) {
  7 50       19  
  7         11  
  7         15  
  7         11  
35 7         36 return $self->_parser->from_string($string);
36             }
37              
38             package
39             App::EvalServerAdvanced::ConstantCalc::Parser;
40              
41 1     1   434 use strict;
  1         2  
  1         23  
42 1     1   4 use warnings;
  1         2  
  1         35  
43              
44             # Ensure we can't accidentally turn to strings, or floats, or anything other than an integer
45 1     1   320 use integer;
  1         13  
  1         4  
46 1     1   29 no warnings 'experimental::bitwise';
  1         2  
  1         39  
47 1     1   4 use feature 'bitwise';
  1         2  
  1         139  
48              
49 1     1   264 use parent qw/Parser::MGC/;
  1         267  
  1         5  
50 1     1   14820 use Function::Parameters;
  1         2  
  1         8  
51              
52 1 50 33 1   7 method new($class: %args) {
  1 50       11  
  1         3  
  1         4  
  1         1  
53 1         3 my $consts = delete $args{consts};
54              
55 1         10 my $self = $class->SUPER::new(%args);
56              
57 1         59 $self->{_private}{consts} = $consts;
58              
59 1         22 return $self;
60             }
61              
62 2 50   2   7 method consts() {
  2 50       4  
  2         4  
  2         2  
63 2         6 return $self->{_private}{consts};
64             }
65              
66 20 50   20   41 method parse_upper() {
  20 50       39  
  20         31  
  20         22  
67 20         40 my $val = $self->parse_term();
68              
69             1 while $self->any_of(
70 26     26   360 sub {$self->expect("&"); $val &= $self->parse_term(); 1},
  6         230  
  6         299  
71 20     20   1369 sub {0}
72 20         758 );
73              
74 20         133 return $val;
75             }
76              
77 11 50   11   110 method parse() {
  11 50       23  
  11         17  
  11         17  
78 11         24 my $val = $self->parse_upper();
79              
80             1 while $self->any_of(
81 20     20   294 sub {$self->expect("^"); $val ^= $self->parse_upper(); 1 },
  4         205  
  4         7  
82 16     16   1037 sub {$self->expect("|"); $val |= $self->parse_upper(); 1 },
  5         193  
  5         8  
83 11     11   711 sub {0}
84 11         54 );
85              
86 11         73 return $val;
87             }
88              
89 28 50   28   55 method parse_term() {
  28 50       48  
  28         34  
  28         42  
90             $self->any_of(
91 28     28   374 sub { $self->scope_of( "(", sub { $self->parse }, ")" ) },
  4         216  
92 24     24   2005 sub { $self->expect('~['); my $bitdepth=$self->token_int; $self->expect(']'); my $val = $self->parse_term; (~ ($val & _get_mask($bitdepth))) & _get_mask($bitdepth)},
  2         77  
  2         90  
  2         103  
  2         91  
93 22     22   1491 sub { $self->expect('~'); ~$self->parse_term},
  0         0  
94 22     22   1579 sub { $self->token_constant },
95 20     20   1508 sub { $self->token_int },
96 28         175 );
97             }
98              
99 22 50   22   47 method token_int() {
  22 50       41  
  22         31  
  22         28  
100             0+$self->any_of(
101 22     22   298 sub {_to_int($self->expect(qr/0x[0-9A-F_]+/i));},
102 21     21   1450 sub {_to_int($self->expect(qr/0b[0-7_]+/i));},
103 20     20   1328 sub {_to_int($self->expect(qr/0o?[0-7_]+/i));},
104 19     19   1291 sub {$self->expect(qr/\d+/)}
105 22         116 );
106             }
107              
108 22 50   22   50 method token_constant() {
  22 50       43  
  22         29  
  22         27  
109 22         64 my $const = $self->expect(qr/[a-z_][a-z_0-9]+/i);
110              
111 2         103 $self->consts->get_value($const);
112             }
113              
114 4 50   4   10 fun _get_mask($size) {
  4 50       8  
  4         7  
  4         5  
115 4         11 return 2**($size)-1;
116             }
117              
118              
119 6 50   6   168 fun _to_int($val) {
  6 50       12  
  6         12  
  6         8  
120 6         16 $val =~ s/^0o/0/i;
121              
122 6 100       18 if ($val =~ /^0/) {
123 4         15 return oct $val;
124             } else {
125 2         12 return 0+$val;
126             }
127             }
128              
129             1;
130              
131             __END__