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   161 use strict;
  27         57  
  27         726  
4 27     27   143 use warnings;
  27         57  
  27         732  
5              
6 27     27   7624 use App::RecordStream::DomainLanguage::Value;
  27         99  
  27         796  
7 27     27   258 use Scalar::Util ('blessed');
  27         65  
  27         25926  
8              
9             my $registry =
10             {
11             };
12              
13             sub new_node
14             {
15             return
16             {
17 1135     1135 0 4835 'SUBREF' => undef,
18             'EPSILONS' => {},
19             'NORMALS' => {},
20             'REPEATABLE' => undef,
21             };
22             }
23              
24             sub register_ctor
25             {
26 44     44 0 79 my $pkg = shift;
27 44         70 my $token = shift;
28 44         93 my @types = @_;
29              
30 44     17   193 return register_fn(sub { return $pkg->new(@_) }, $token, @types);
  17         109  
31             }
32              
33             sub register_vfn
34             {
35 321     321 0 613 my $tgt = shift;
36 321         516 my $meth = shift;
37 321         502 my $token = shift;
38 321         757 my @types = @_;
39              
40 321     85   1528 return register_fn(sub { return $tgt->$meth(@_) }, $token, @types);
  85         657  
41             }
42              
43             sub register_fn
44             {
45 527     527 0 910 my $subref = shift;
46 527         792 my $token = shift;
47 527         1028 my @types = @_;
48              
49 527   66     1840 my $p = ($registry->{$token} ||= new_node());
50              
51 527         1081 for my $type (@types)
52             {
53 779 50       1760 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     2303 $p = ($p->{'NORMALS'}->{$type} ||= new_node());
62             }
63             }
64              
65 527 50       1225 if($p->{'SUBREF'})
66             {
67 0         0 die "Collision in type registry at $token(" . join(", ", @types) . ")";
68             }
69              
70 527         1524 $p->{'SUBREF'} = $subref;
71             }
72              
73             sub get_tokens
74             {
75 389     389 0 6927 return keys(%$registry);
76             }
77              
78             sub evaluate
79             {
80 343     343 0 670 my $token = shift;
81 343         771 my @raw_args = @_;
82              
83 343         550 my @value_args;
84 343         728 for my $arg (@raw_args)
85             {
86 512 100 100     3125 if(blessed($arg) && $arg->isa('App::RecordStream::DomainLanguage::Value'))
87             {
88 160         345 push @value_args, $arg;
89 160         311 next;
90             }
91 352         1872 my $value = App::RecordStream::DomainLanguage::Value->new("");
92 352         627 my $done = 0;
93 352 50 66     1573 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     1551 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     1690 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     1633 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       782 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         1138 push @value_args, App::RecordStream::DomainLanguage::Value->new_from_scalar($arg);
121             }
122              
123             # now all of @value_args is Value objects
124 343         668 my @results;
125 343   50     1785 evaluate_aux(\@results, ($registry->{$token} || {}), [], @value_args);
126              
127 343         1375 my $ret = App::RecordStream::DomainLanguage::Value->new($token . "(" . join(", ", map { $_->get_description() } @value_args) . ")");
  512         1629  
128              
129 343         1180 for my $result (@results)
130             {
131 340 100 66     2734 if(blessed($result) && $result->isa('App::RecordStream::DomainLanguage::Value'))
132             {
133 147         470 for my $pair ($result->get_possible_pairs())
134             {
135 294         627 my ($type, $value) = @$pair;
136 294         642 $ret->add_possibility($type, $value);
137             }
138 147         497 next;
139             }
140 193         499 my $done = 0;
141 193 100 66     1392 if(blessed($result) && $result->isa('App::RecordStream::DomainLanguage::Valuation'))
142             {
143 4         226 $ret->add_possibility('VALUATION', $result);
144 4         9 $done = 1;
145             }
146 193 100 66     1284 if(blessed($result) && $result->isa('App::RecordStream::Aggregator::Aggregation'))
147             {
148 189         684 $ret->add_possibility('AGGREGATOR', $result);
149 189         462 $done = 1;
150             }
151 193 50 33     1703 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     1513 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       584 if($done)
162             {
163 193         463 next;
164             }
165              
166 0         0 $ret->add_possibility('SCALAR', $result);
167             }
168              
169 343         1683 return $ret;
170             }
171              
172             sub evaluate_aux
173             {
174 867     867 0 1370 my $results_ref = shift;
175 867         1231 my $registry_pos = shift;
176 867         1242 my $built_args = shift;
177 867         2049 my @values_left = @_;
178              
179 867         1214 for my $type (keys(%{$registry_pos->{'EPSILONS'}}))
  867         2237  
180             {
181 0         0 evaluate_aux($results_ref, $registry_pos->{'EPSILONS'}->{$type}, $built_args, @values_left);
182             }
183              
184 867 100       1930 if(!@values_left)
185             {
186             # this is our stop
187 343         963 my $subref = $registry_pos->{'SUBREF'};
188 343 100       744 if($subref)
189             {
190 340         1102 push @$results_ref, $subref->(@$built_args);
191             }
192 343         742 return;
193             }
194              
195 524         983 my $next_value = shift @values_left;
196              
197 524         1161 my $repeatable_type = $registry_pos->{'REPEATABLE'};
198 524 50       1081 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         997 for my $type (keys(%{$registry_pos->{'NORMALS'}}))
  524         1402  
209             {
210 530         937 my $registry_pos_next = $registry_pos->{'NORMALS'}->{$type};
211 530         1394 for my $arg ($next_value->get_possibilities($type))
212             {
213 524         1187 push @$built_args, $arg;
214 524         1416 evaluate_aux($results_ref, $registry_pos_next, $built_args, @values_left);
215 524         1293 pop @$built_args;
216             }
217             }
218             }
219              
220             1;