File Coverage

blib/lib/Data/Annotation/Expression/Builtin.pm
Criterion Covered Total %
statement 33 225 14.6
branch 3 30 10.0
condition 0 4 0.0
subroutine 8 39 20.5
pod 13 13 100.0
total 57 311 18.3


line stmt bran cond sub pod time code
1             package Data::Annotation::Expression::Builtin;
2 3     3   8586 use v5.24;
  3         14  
3 3     3   20 use utf8;
  3         7  
  3         23  
4 3     3   141 use warnings;
  3         4  
  3         249  
5 3     3   92 use experimental qw< signatures >;
  3         8  
  3         24  
6             { our $VERSION = '0.006' }
7              
8 7     7 1 13 sub factory ($parse_ctx, $name) {
  7         14  
  7         11  
  7         12  
9 0         0 state $immediate_for = {
10              
11             # numeric comparisons
12 0     0   0 '<' => sub ($l, $r) { $l < $r },
  0         0  
  0         0  
  0         0  
13 0     0   0 '<=' => sub ($l, $r) { $l <= $r },
  0         0  
  0         0  
  0         0  
  0         0  
14 0     0   0 '>' => sub ($l, $r) { $l > $r },
  0         0  
  0         0  
  0         0  
  0         0  
15 0     0   0 '>=' => sub ($l, $r) { $l >= $r },
  0         0  
  0         0  
  0         0  
  0         0  
16 0     0   0 '==' => sub ($l, $r) { $l == $r },
  0         0  
  0         0  
  0         0  
  0         0  
17 0     0   0 '!=' => sub ($l, $r) { $l != $r },
  0         0  
  0         0  
  0         0  
  0         0  
18 0     0   0 '<=>' => sub ($l, $r) { $l <=> $r },
  0         0  
  0         0  
  0         0  
  0         0  
19              
20             # string comparisons
21 0     0   0 lt => sub ($l, $r) { $l lt $r },
  0         0  
  0         0  
  0         0  
  0         0  
22 0     0   0 le => sub ($l, $r) { $l le $r },
  0         0  
  0         0  
  0         0  
  0         0  
23 0     0   0 gt => sub ($l, $r) { $l gt $r },
  0         0  
  0         0  
  0         0  
  0         0  
24 0     0   0 ge => sub ($l, $r) { $l ge $r },
  0         0  
  0         0  
  0         0  
  0         0  
25 4     4   17 eq => sub ($l, $r) { $l eq $r },
  4         37  
  4         9  
  4         7  
  4         5  
26 0     0   0 ne => sub ($l, $r) { $l ne $r },
  0         0  
  0         0  
  0         0  
  0         0  
27 0     0   0 cmp => sub ($l, $r) { $l cmp $r },
  0         0  
  0         0  
  0         0  
  0         0  
28              
29             # regular expression match/unmatch
30 2         53 match => \&match,
31             '=~' => \&match,
32             unmatch => \&unmatch,
33             '!~' => \&unmatch,
34              
35             # boolean operators
36 2 100   2   6 and => sub (@os) { for my $o (@os) { return 0 if !$o } ; 1 },
  4         18  
  1         9  
  2         6  
  2         22  
37 0 0   0   0 or => sub (@os) { for my $o (@os) { return 1 if $o } ; 0 },
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
38 0     0   0 not => sub ($o) { return !$o },
  0         0  
  0         0  
  0         0  
39 0   0 0   0 xor => sub ($r, @os) { $r = ($r xor $_) for @os; return $r },
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
40              
41             # set operations
42 0         0 union => \&set_union,
43             U => \&set_union,
44             '⋃' => \&set_union,
45             intersection => \&set_intersection,
46             '⋂' => \&set_intersection,
47             less => \&set_less,
48             symmetric_difference => \&set_symmetric_difference,
49             is_superset_of => \&set_is_superset_of,
50             '⊇' => \&set_is_superset_of,
51             is_subset_of => \&set_is_subset_of,
52             '⊆' => \&set_is_subset_of,
53             is_element_of => \&set_is_element_of,
54             '∈' => \&set_is_element_of,
55             contains => \&set_contains,
56             '∋' => \&set_contains,
57             sets_are_same => \&sets_are_same,
58 0     0   0 set_size => sub ($s) { return scalar($s->@*) },
  0         0  
  0         0  
59 0     0   0 set_is_empty => sub ($s) { return scalar($s->@*) == 0 },
  0         0  
  0         0  
  0         0  
60              
61             # other utilities
62 0     0   0 array => sub ($x) {
  0         0  
  0         0  
63 0 0       0 ref($x) eq 'ARRAY' ? $x : defined($x) ? [ $x ] : [];
    0          
64             },
65 0     0   0 trim => sub ($x) {
  0         0  
  0         0  
66 0 0       0 return $x =~ s{\A\s+|\s+\z}{}rgmxs unless ref($x) eq 'ARRAY';
67 0         0 return [ map { s{\A\s+|\s+\z}{}rgmxs } $x->@* ];
  0         0  
68             },
69              
70 7         131 };
71 7 50       41 return $immediate_for->{$name} if exists($immediate_for->{$name});
72 0         0 return; # nothing found, sorry!
73             }
74              
75 5     5 1 10 sub match ($string, $rx) { scalar($string =~ m{$rx}) }
  5         9  
  5         10  
  5         8  
  5         141  
76              
77 0     0 1   sub unmatch ($string, $rx) { scalar($string !~ m{$rx}) }
  0            
  0            
  0            
  0            
78              
79 0     0 1   sub sets_are_same ($lhs, $rhs) {
  0            
  0            
  0            
80 0           my %in_lhs = map { $_ => 1 } $lhs->@*;
  0            
81 0           my %seen_in_rhs;
82 0           for my $item ($rhs->@*) {
83 0 0         next if $seen_in_rhs{$item}++;
84 0 0         return 0 unless exists($in_lhs{$item});
85 0           delete($in_lhs{$item});
86             }
87 0           return scalar(keys(%in_lhs)) == 0;
88             }
89              
90 0     0 1   sub set_contains ($set, $target) {
  0            
  0            
  0            
91 0 0         for my $item ($set->@*) { return 1 if $item eq $target }
  0            
92 0           return 0;
93             }
94              
95 0     0 1   sub set_intersection (@lists) {
  0            
  0            
96 0 0         return [] unless @lists;
97              
98 0           my $first = shift(@lists);
99 0 0         return [ $first->@* ] unless @lists;
100              
101 0           my $whole;
102 0           $whole->{$_} = 1 for $first->@*;
103 0           for my $list (@lists) {
104 0 0         return [] unless scalar(keys($whole->%*));
105 0           ($whole, my $previous) = ({}, $whole);
106 0           for my $item ($list->@*) {
107 0 0         $whole->{$item} = 1 if $previous->{$item}
108             }
109             }
110 0           return set_sorted_result($whole);
111             }
112              
113 0     0 1   sub set_is_element_of ($elem, $set) { return set_contains($set, $elem) }
  0            
  0            
  0            
  0            
114              
115 0     0 1   sub set_is_subset_of ($lh, $rh) { return set_is_superset_of($rh, $lh) }
  0            
  0            
  0            
  0            
116              
117 0     0 1   sub set_is_superset_of ($lhs, $rhs) {
  0            
  0            
  0            
118 0           my %in_lhs = map { $_ => 1 } $lhs->@*;
  0            
119 0           for my $item ($rhs->@*) {
120 0 0         return 0 unless exists($in_lhs{$item});
121             }
122 0           return 1;
123             }
124              
125 0     0 1   sub set_less ($lhs, $rhs) {
  0            
  0            
  0            
126 0           my %in_rhs = map { $_ => 1 } $rhs->@*;
  0            
127 0           my %result = map { $_ => 1 } grep { ! $in_rhs{$_} } $lhs->@*;
  0            
  0            
128 0           return set_sorted_result(\%result);
129             }
130              
131 0     0 1   sub set_sorted_result ($href) { [ sort { $a cmp $b } keys($href->%*) ] }
  0            
  0            
  0            
  0            
132              
133 0     0 1   sub set_symmetric_difference ($lhs, $rhs) {
  0            
  0            
  0            
134 0           my %result = map { $_ => 1 } $lhs->@*;
  0            
135 0           my %in_rhs = map { $_ => 1 } $rhs->@*;
  0            
136 0           for my $item (keys(%in_rhs)) {
137 0 0         if (exists($result{$item})) { delete($result{$item}) }
  0            
138 0           else { $result{$item} = 1 } # add it
139             }
140 0           return set_sorted_result(\%result);
141             }
142              
143 0     0 1   sub set_union (@lists) {
  0            
  0            
144 0           my %whole;
145 0           for my $list (@lists) { $whole{$_} = 1 for $list->@* }
  0            
146 0           return set_sorted_result(\%whole);
147             }
148              
149             1;