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   158 use strict;
  27         62  
  27         655  
4 27     27   137 use warnings;
  27         47  
  27         627  
5              
6 27     27   10155 use App::RecordStream::DomainLanguage::Value;
  27         86  
  27         776  
7 27     27   153 use Scalar::Util ('blessed');
  27         54  
  27         24861  
8              
9             my $registry =
10             {
11             };
12              
13             sub new_node
14             {
15             return
16             {
17 1135     1135 0 4162 'SUBREF' => undef,
18             'EPSILONS' => {},
19             'NORMALS' => {},
20             'REPEATABLE' => undef,
21             };
22             }
23              
24             sub register_ctor
25             {
26 44     44 0 72 my $pkg = shift;
27 44         59 my $token = shift;
28 44         86 my @types = @_;
29              
30 44     17   162 return register_fn(sub { return $pkg->new(@_) }, $token, @types);
  17         96  
31             }
32              
33             sub register_vfn
34             {
35 321     321 0 523 my $tgt = shift;
36 321         430 my $meth = shift;
37 321         408 my $token = shift;
38 321         651 my @types = @_;
39              
40 321     85   1245 return register_fn(sub { return $tgt->$meth(@_) }, $token, @types);
  85         468  
41             }
42              
43             sub register_fn
44             {
45 527     527 0 712 my $subref = shift;
46 527         644 my $token = shift;
47 527         861 my @types = @_;
48              
49 527   66     1932 my $p = ($registry->{$token} ||= new_node());
50              
51 527         1057 for my $type (@types)
52             {
53 779 50       1566 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     1775 $p = ($p->{'NORMALS'}->{$type} ||= new_node());
62             }
63             }
64              
65 527 50       1023 if($p->{'SUBREF'})
66             {
67 0         0 die "Collision in type registry at $token(" . join(", ", @types) . ")";
68             }
69              
70 527         1398 $p->{'SUBREF'} = $subref;
71             }
72              
73             sub get_tokens
74             {
75 389     389 0 5176 return keys(%$registry);
76             }
77              
78             sub evaluate
79             {
80 343     343 0 548 my $token = shift;
81 343         653 my @raw_args = @_;
82              
83 343         464 my @value_args;
84 343         558 for my $arg (@raw_args)
85             {
86 512 100 100     2290 if(blessed($arg) && $arg->isa('App::RecordStream::DomainLanguage::Value'))
87             {
88 160         268 push @value_args, $arg;
89 160         264 next;
90             }
91 352         956 my $value = App::RecordStream::DomainLanguage::Value->new("");
92 352         478 my $done = 0;
93 352 50 66     1274 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     1161 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     1274 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     1240 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       659 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         719 push @value_args, App::RecordStream::DomainLanguage::Value->new_from_scalar($arg);
121             }
122              
123             # now all of @value_args is Value objects
124 343         517 my @results;
125 343   50     1417 evaluate_aux(\@results, ($registry->{$token} || {}), [], @value_args);
126              
127 343         916 my $ret = App::RecordStream::DomainLanguage::Value->new($token . "(" . join(", ", map { $_->get_description() } @value_args) . ")");
  512         1015  
128              
129 343         585 for my $result (@results)
130             {
131 340 100 66     1980 if(blessed($result) && $result->isa('App::RecordStream::DomainLanguage::Value'))
132             {
133 147         312 for my $pair ($result->get_possible_pairs())
134             {
135 294         544 my ($type, $value) = @$pair;
136 294         577 $ret->add_possibility($type, $value);
137             }
138 147         343 next;
139             }
140 193         393 my $done = 0;
141 193 100 66     906 if(blessed($result) && $result->isa('App::RecordStream::DomainLanguage::Valuation'))
142             {
143 4         18 $ret->add_possibility('VALUATION', $result);
144 4         7 $done = 1;
145             }
146 193 100 66     761 if(blessed($result) && $result->isa('App::RecordStream::Aggregator::Aggregation'))
147             {
148 189         499 $ret->add_possibility('AGGREGATOR', $result);
149 189         242 $done = 1;
150             }
151 193 50 33     1160 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     1068 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       371 if($done)
162             {
163 193         360 next;
164             }
165              
166 0         0 $ret->add_possibility('SCALAR', $result);
167             }
168              
169 343         1349 return $ret;
170             }
171              
172             sub evaluate_aux
173             {
174 867     867 0 1070 my $results_ref = shift;
175 867         1059 my $registry_pos = shift;
176 867         1133 my $built_args = shift;
177 867         1309 my @values_left = @_;
178              
179 867         990 for my $type (keys(%{$registry_pos->{'EPSILONS'}}))
  867         1782  
180             {
181 0         0 evaluate_aux($results_ref, $registry_pos->{'EPSILONS'}->{$type}, $built_args, @values_left);
182             }
183              
184 867 100       1515 if(!@values_left)
185             {
186             # this is our stop
187 343         522 my $subref = $registry_pos->{'SUBREF'};
188 343 100       583 if($subref)
189             {
190 340         799 push @$results_ref, $subref->(@$built_args);
191             }
192 343         652 return;
193             }
194              
195 524         675 my $next_value = shift @values_left;
196              
197 524         825 my $repeatable_type = $registry_pos->{'REPEATABLE'};
198 524 50       788 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         669 for my $type (keys(%{$registry_pos->{'NORMALS'}}))
  524         1090  
209             {
210 530         747 my $registry_pos_next = $registry_pos->{'NORMALS'}->{$type};
211 530         976 for my $arg ($next_value->get_possibilities($type))
212             {
213 524         816 push @$built_args, $arg;
214 524         1108 evaluate_aux($results_ref, $registry_pos_next, $built_args, @values_left);
215 524         1114 pop @$built_args;
216             }
217             }
218             }
219              
220             1;