File Coverage

blib/lib/App/EvalServerAdvanced/ConstantCalc.pm
Criterion Covered Total %
statement 135 137 98.5
branch 29 58 50.0
condition 3 9 33.3
subroutine 37 37 100.0
pod 2 3 66.6
total 206 244 84.4


line stmt bran cond sub pod time code
1             package App::EvalServerAdvanced::ConstantCalc;
2              
3             our $VERSION = '0.05';
4              
5             # ABSTRACT: turns strings and constants into values
6              
7 1     1   44745 use v5.24;
  1         10  
8 1     1   307 use Moo;
  1         7598  
  1         4  
9 1     1   1332 use Function::Parameters;
  1         2678  
  1         4  
10 1     1   676 use Data::Dumper;
  1         5056  
  1         176  
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 5 method get_value($key) {
  2 50       4  
  2         7  
  2         4  
  2         3  
16 2 50       8 die "Missing constant [$key]" unless exists($self->constants->{$key});
17              
18 2         6 return $self->constants->{$key};
19             }
20              
21 2 50   2 1 11 method add_constant($key, $value) {
  2 50       5  
  2         3  
  2         5  
  2         4  
22 2 50 33     19 die "Invalid key [$key]" if ($key =~ /\s/ || $key =~ /^\s*\d/);
23              
24 2 50 33     15 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 2 50       5 die "Value undefined for [$key]" unless defined($value);
29 2 50       10 die "Value [$value] for [$key] must be an integer" if ($value =~ /[^xob\d\-+_]/i);
30              
31 2         7 $self->constants->{$key} = App::EvalServerAdvanced::ConstantCalc::Parser::_to_int($value);
32             }
33              
34 7 50   7 0 2959 method calculate($string) {
  7 50       17  
  7         11  
  7         14  
  7         8  
35 7         27 return $self->_parser->from_string($string);
36             }
37              
38             package
39             App::EvalServerAdvanced::ConstantCalc::Parser;
40              
41 1     1   355 use strict;
  1         3  
  1         17  
42 1     1   5 use warnings;
  1         1  
  1         23  
43              
44             # Ensure we can't accidentally turn to strings, or floats, or anything other than an integer
45 1     1   288 use integer;
  1         11  
  1         4  
46 1     1   28 no warnings 'experimental::bitwise';
  1         2  
  1         29  
47 1     1   5 use feature 'bitwise';
  1         2  
  1         110  
48              
49 1     1   6 use base qw/Parser::MGC/;
  1         2  
  1         366  
50 1     1   13765 use Function::Parameters;
  1         2  
  1         6  
51              
52 1 50 33 1   5 method new($class: %args) {
  1 50       7  
  1         3  
  1         3  
  1         2  
53 1         2 my $consts = delete $args{consts};
54              
55 1         11 my $self = $class->SUPER::new(%args);
56              
57 1         59 $self->{_private}{consts} = $consts;
58              
59 1         20 return $self;
60             }
61              
62 2 50   2   6 method consts() {
  2 50       5  
  2         4  
  2         3  
63 2         6 return $self->{_private}{consts};
64             }
65              
66 20 50   20   39 method parse_upper() {
  20 50       36  
  20         25  
  20         22  
67 20         42 my $val = $self->parse_term();
68              
69             1 while $self->any_of(
70 26     26   355 sub {$self->expect("&"); $val &= $self->parse_term(); 1},
  6         305  
  6         320  
71 20     20   1413 sub {0}
72 20         782 );
73              
74 20         153 return $val;
75             }
76              
77 11 50   11   87 method parse() {
  11 50       28  
  11         15  
  11         14  
78 11         23 my $val = $self->parse_upper();
79              
80             1 while $self->any_of(
81 20     20   290 sub {$self->expect("^"); $val ^= $self->parse_upper(); 1 },
  4         158  
  4         8  
82 16     16   1088 sub {$self->expect("|"); $val |= $self->parse_upper(); 1 },
  5         190  
  5         9  
83 11     11   728 sub {0}
84 11         53 );
85              
86 11         80 return $val;
87             }
88              
89 28 50   28   54 method parse_term() {
  28 50       50  
  28         37  
  28         35  
90             $self->any_of(
91 28     28   391 sub { $self->scope_of( "(", sub { $self->parse }, ")" ) },
  4         212  
92 24     24   2017 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         135  
  2         137  
  2         93  
93 22     22   1566 sub { $self->expect('~'); ~$self->parse_term},
  0         0  
94 22     22   1531 sub { $self->token_constant },
95 20     20   1548 sub { $self->token_int },
96 28         192 );
97             }
98              
99 22 50   22   53 method token_int() {
  22 50       41  
  22         32  
  22         27  
100             0+$self->any_of(
101 22     22   285 sub {_to_int($self->expect(qr/0x[0-9A-F_]+/i));},
102 21     21   1483 sub {_to_int($self->expect(qr/0b[0-7_]+/i));},
103 20     20   1344 sub {_to_int($self->expect(qr/0o?[0-7_]+/i));},
104 19     19   1329 sub {$self->expect(qr/\d+/)}
105 22         118 );
106             }
107              
108 22 50   22   49 method token_constant() {
  22 50       42  
  22         39  
  22         25  
109 22         67 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   9 fun _get_mask($size) {
  4 50       8  
  4         8  
  4         5  
115 4         11 return 2**($size)-1;
116             }
117              
118              
119 5 50   5   140 fun _to_int($val) {
  5 50       12  
  5         13  
  5         8  
120 5         13 $val =~ s/^0o/0/i;
121 5         23 return oct $val;
122             }
123              
124             1;
125              
126             __END__