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.04';
4              
5             # ABSTRACT: turns strings and constants into values
6              
7 1     1   48189 use v5.24;
  1         14  
8 1     1   342 use Moo;
  1         8368  
  1         5  
9 1     1   1521 use Function::Parameters;
  1         2885  
  1         4  
10 1     1   823 use Data::Dumper;
  1         5232  
  1         239  
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 9 method get_value($key) {
  2 50       6  
  2         6  
  2         5  
  2         4  
16 2 50       18 die "Missing constant [$key]" unless exists($self->constants->{$key});
17              
18 2         11 return $self->constants->{$key};
19             }
20              
21 2 50   2 1 17 method add_constant($key, $value) {
  2 50       7  
  2         5  
  2         6  
  2         5  
22 2 50 33     19 die "Invalid key [$key]" if ($key =~ /\s/ || $key =~ /^\s*\d/);
23              
24 2 50 33     16 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       8 die "Value undefined for [$key]" unless defined($value);
29 2 50       8 die "Value [$value] for [$key] must be an integer" if ($value =~ /[^\d\-+_]/);
30              
31 2         15 $self->constants->{$key} = $value;
32             }
33              
34 7 50   7 0 3029 method calculate($string) {
  7 50       20  
  7         13  
  7         18  
  7         9  
35 7         42 return $self->_parser->from_string($string);
36             }
37              
38             package
39             App::EvalServerAdvanced::ConstantCalc::Parser;
40              
41 1     1   346 use strict;
  1         2  
  1         21  
42 1     1   4 use warnings;
  1         3  
  1         38  
43              
44             # Ensure we can't accidentally turn to strings, or floats, or anything other than an integer
45 1     1   309 use integer;
  1         12  
  1         5  
46 1     1   30 no warnings 'experimental::bitwise';
  1         2  
  1         38  
47 1     1   5 use feature 'bitwise';
  1         2  
  1         141  
48              
49 1     1   16 use base qw/Parser::MGC/;
  1         4  
  1         370  
50 1     1   15091 use Function::Parameters;
  1         2  
  1         8  
51              
52 1 50 33 1   4 method new($class: %args) {
  1 50       9  
  1         2  
  1         4  
  1         2  
53 1         3 my $consts = delete $args{consts};
54              
55 1         12 my $self = $class->SUPER::new(%args);
56              
57 1         74 $self->{_private}{consts} = $consts;
58              
59 1         32 return $self;
60             }
61              
62 2 50   2   9 method consts() {
  2 50       10  
  2         6  
  2         4  
63 2         10 return $self->{_private}{consts};
64             }
65              
66 20 50   20   44 method parse_upper() {
  20 50       40  
  20         26  
  20         30  
67 20         33 my $val = $self->parse_term();
68              
69             1 while $self->any_of(
70 26     26   390 sub {$self->expect("&"); $val &= $self->parse_term(); 1},
  6         266  
  6         325  
71 20     20   1483 sub {0}
72 20         816 );
73              
74 20         141 return $val;
75             }
76              
77 11 50   11   94 method parse() {
  11 50       22  
  11         19  
  11         13  
78 11         24 my $val = $self->parse_upper();
79              
80             1 while $self->any_of(
81 20     20   316 sub {$self->expect("^"); $val ^= $self->parse_upper(); 1 },
  4         172  
  4         8  
82 16     16   1277 sub {$self->expect("|"); $val |= $self->parse_upper(); 1 },
  5         209  
  5         7  
83 11     11   698 sub {0}
84 11         64 );
85              
86 11         74 return $val;
87             }
88              
89 28 50   28   57 method parse_term() {
  28 50       48  
  28         38  
  28         34  
90             $self->any_of(
91 28     28   386 sub { $self->scope_of( "(", sub { $self->parse }, ")" ) },
  4         211  
92 24     24   2043 sub { $self->expect('~['); my $bitdepth=$self->token_int; $self->expect(']'); my $val = $self->parse_term; (~ ($val & _get_mask($bitdepth))) & _get_mask($bitdepth)},
  2         78  
  2         91  
  2         78  
  2         92  
93 22     22   1587 sub { $self->expect('~'); ~$self->parse_term},
  0         0  
94 22     22   1555 sub { $self->token_constant },
95 20     20   1525 sub { $self->token_int },
96 28         189 );
97             }
98              
99 22 50   22   50 method token_int() {
  22 50       37  
  22         44  
  22         36  
100             0+$self->any_of(
101 22     22   265 sub {_to_int($self->expect(qr/0x[0-9A-F_]+/i));},
102 21     21   1800 sub {_to_int($self->expect(qr/0b[0-7_]+/i));},
103 20     20   1351 sub {_to_int($self->expect(qr/0o?[0-7_]+/i));},
104 19     19   1299 sub {$self->expect(qr/\d+/)}
105 22         127 );
106             }
107              
108 22 50   22   54 method token_constant() {
  22 50       45  
  22         41  
  22         32  
109 22         74 my $const = $self->expect(qr/[a-z_][a-z_0-9]+/i);
110              
111 2         161 $self->consts->get_value($const);
112             }
113              
114 4 50   4   11 fun _get_mask($size) {
  4 50       8  
  4         9  
  4         6  
115 4         11 return 2**($size)-1;
116             }
117              
118              
119 3 50   3   137 fun _to_int($val) {
  3 50       8  
  3         6  
  3         5  
120 3         8 $val =~ s/^0o/0/i;
121 3         9 return oct $val;
122             }
123              
124             1;
125              
126             __END__