File Coverage

blib/lib/App/RecordStream/DomainLanguage/Registry.pm
Criterion Covered Total %
statement 92 116 79.3
branch 23 34 67.6
condition 24 41 58.5
subroutine 13 13 100.0
pod 0 7 0.0
total 152 211 72.0


line stmt bran cond sub pod time code
1             package App::RecordStream::DomainLanguage::Registry;
2              
3 27     27   165 use strict;
  27         54  
  27         655  
4 27     27   121 use warnings;
  27         55  
  27         629  
5              
6 27     27   9144 use App::RecordStream::DomainLanguage::Value;
  27         82  
  27         682  
7 27     27   213 use Scalar::Util ('blessed');
  27         57  
  27         22218  
8              
9             my $registry =
10             {
11             };
12              
13             sub new_node
14             {
15             return
16             {
17 1135     1135 0 4902 'SUBREF' => undef,
18             'EPSILONS' => {},
19             'NORMALS' => {},
20             'REPEATABLE' => undef,
21             };
22             }
23              
24             sub register_ctor
25             {
26 44     44 0 90 my $pkg = shift;
27 44         73 my $token = shift;
28 44         103 my @types = @_;
29              
30 44     17   199 return register_fn(sub { return $pkg->new(@_) }, $token, @types);
  17         104  
31             }
32              
33             sub register_vfn
34             {
35 321     321 0 639 my $tgt = shift;
36 321         620 my $meth = shift;
37 321         521 my $token = shift;
38 321         871 my @types = @_;
39              
40 321     85   1544 return register_fn(sub { return $tgt->$meth(@_) }, $token, @types);
  85         579  
41             }
42              
43             sub register_fn
44             {
45 527     527 0 1209 my $subref = shift;
46 527         857 my $token = shift;
47 527         1150 my @types = @_;
48              
49 527   66     1903 my $p = ($registry->{$token} ||= new_node());
50              
51 527         1090 for my $type (@types)
52             {
53 779 50       1831 if($type =~ /^(.*)\*$/)
54             {
55 0         0 my $raw_type = $1;
56 0   0     0 $p = ($p->{'EPSILONS'}->{$raw_type} ||= new_node());
57 0         0 $p->{'REPEATABLE'} = $raw_type;
58             }
59             else
60             {
61 779   66     2542 $p = ($p->{'NORMALS'}->{$type} ||= new_node());
62             }
63             }
64              
65 527 50       1371 if($p->{'SUBREF'})
66             {
67 0         0 die "Collision in type registry at $token(" . join(", ", @types) . ")";
68             }
69              
70 527         1603 $p->{'SUBREF'} = $subref;
71             }
72              
73             sub get_tokens
74             {
75 389     389 0 5370 return keys(%$registry);
76             }
77              
78             sub evaluate
79             {
80 343     343 0 658 my $token = shift;
81 343         829 my @raw_args = @_;
82              
83 343         594 my @value_args;
84 343         712 for my $arg (@raw_args)
85             {
86 512 100 100     3128 if(blessed($arg) && $arg->isa('App::RecordStream::DomainLanguage::Value'))
87             {
88 160         311 push @value_args, $arg;
89 160         333 next;
90             }
91 352         1308 my $value = App::RecordStream::DomainLanguage::Value->new("");
92 352         584 my $done = 0;
93 352 50 66     1720 if(blessed($arg) && $arg->isa('App::RecordStream::DomainLanguage::Valuation'))
94             {
95 0         0 $value->add_possibility('VALUATION', $arg);
96 0         0 $done = 1;
97             }
98 352 50 66     1570 if(blessed($arg) && $arg->isa('App::RecordStream::Aggregator::Aggregation'))
99             {
100 0         0 $value->add_possibility('AGGREGATOR', $arg);
101 0         0 $done = 1;
102             }
103 352 50 66     1771 if(blessed($arg) && $arg->isa('App::RecordStream::Deaggregator::Base'))
104             {
105 0         0 $value->add_possibility('DEAGGREGATOR', $arg);
106 0         0 $done = 1;
107             }
108 352 50 66     1696 if(blessed($arg) && $arg->isa('App::RecordStream::Clumper::Base'))
109             {
110 0         0 $value->add_possibility('CLUMPER', $arg);
111 0         0 $done = 1;
112             }
113 352 50       917 if($done)
114             {
115 0         0 push @value_args, $value;
116 0         0 next;
117             }
118              
119             # uh, no clue, must be a scalar
120 352         1021 push @value_args, App::RecordStream::DomainLanguage::Value->new_from_scalar($arg);
121             }
122              
123             # now all of @value_args is Value objects
124 343         658 my @results;
125 343   50     1627 evaluate_aux(\@results, ($registry->{$token} || {}), [], @value_args);
126              
127 343         1129 my $ret = App::RecordStream::DomainLanguage::Value->new($token . "(" . join(", ", map { $_->get_description() } @value_args) . ")");
  512         1392  
128              
129 343         782 for my $result (@results)
130             {
131 340 100 66     2673 if(blessed($result) && $result->isa('App::RecordStream::DomainLanguage::Value'))
132             {
133 147         460 for my $pair ($result->get_possible_pairs())
134             {
135 294         704 my ($type, $value) = @$pair;
136 294         741 $ret->add_possibility($type, $value);
137             }
138 147         407 next;
139             }
140 193         414 my $done = 0;
141 193 100 66     1287 if(blessed($result) && $result->isa('App::RecordStream::DomainLanguage::Valuation'))
142             {
143 4         152 $ret->add_possibility('VALUATION', $result);
144 4         8 $done = 1;
145             }
146 193 100 66     1109 if(blessed($result) && $result->isa('App::RecordStream::Aggregator::Aggregation'))
147             {
148 189         684 $ret->add_possibility('AGGREGATOR', $result);
149 189         353 $done = 1;
150             }
151 193 50 33     1501 if(blessed($result) && $result->isa('App::RecordStream::Deaggregator::Base'))
152             {
153 0         0 $ret->add_possibility('DEAGGREGATOR', $result);
154 0         0 $done = 1;
155             }
156 193 50 33     1456 if(blessed($result) && $result->isa('App::RecordStream::Clumper::Base'))
157             {
158 0         0 $ret->add_possibility('CLUMPER', $result);
159 0         0 $done = 1;
160             }
161 193 50       490 if($done)
162             {
163 193         444 next;
164             }
165              
166 0         0 $ret->add_possibility('SCALAR', $result);
167             }
168              
169 343         1667 return $ret;
170             }
171              
172             sub evaluate_aux
173             {
174 867     867 0 1365 my $results_ref = shift;
175 867         1348 my $registry_pos = shift;
176 867         1334 my $built_args = shift;
177 867         1758 my @values_left = @_;
178              
179 867         1330 for my $type (keys(%{$registry_pos->{'EPSILONS'}}))
  867         2227  
180             {
181 0         0 evaluate_aux($results_ref, $registry_pos->{'EPSILONS'}->{$type}, $built_args, @values_left);
182             }
183              
184 867 100       2161 if(!@values_left)
185             {
186             # this is our stop
187 343         632 my $subref = $registry_pos->{'SUBREF'};
188 343 100       794 if($subref)
189             {
190 340         1017 push @$results_ref, $subref->(@$built_args);
191             }
192 343         789 return;
193             }
194              
195 524         913 my $next_value = shift @values_left;
196              
197 524         960 my $repeatable_type = $registry_pos->{'REPEATABLE'};
198 524 50       1148 if($repeatable_type)
199             {
200 0         0 for my $arg ($next_value->get_possibilities($repeatable_type))
201             {
202 0         0 push @$built_args, $arg;
203 0         0 evaluate_aux($results_ref, $registry_pos, $built_args, @values_left);
204 0         0 pop @$built_args;
205             }
206             }
207              
208 524         848 for my $type (keys(%{$registry_pos->{'NORMALS'}}))
  524         1270  
209             {
210 530         938 my $registry_pos_next = $registry_pos->{'NORMALS'}->{$type};
211 530         1482 for my $arg ($next_value->get_possibilities($type))
212             {
213 524         1097 push @$built_args, $arg;
214 524         1438 evaluate_aux($results_ref, $registry_pos_next, $built_args, @values_left);
215 524         1408 pop @$built_args;
216             }
217             }
218             }
219              
220             1;