line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
|
2
|
3
|
|
|
3
|
|
84272
|
use v5.10; |
|
3
|
|
|
|
|
11
|
|
3
|
3
|
|
|
3
|
|
13
|
use strict; |
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
49
|
|
4
|
3
|
|
|
3
|
|
11
|
use warnings; |
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
108
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package Context::Singleton::Frame; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $VERSION = v1.0.5; |
9
|
|
|
|
|
|
|
|
10
|
3
|
|
|
3
|
|
13
|
use List::Util; |
|
3
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
200
|
|
11
|
3
|
|
|
3
|
|
16
|
use Scalar::Util; |
|
3
|
|
|
|
|
4
|
|
|
3
|
|
|
|
|
88
|
|
12
|
|
|
|
|
|
|
|
13
|
3
|
|
|
3
|
|
977
|
use Context::Singleton::Frame::DB; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
84
|
|
14
|
3
|
|
|
3
|
|
1015
|
use Context::Singleton::Exception::Invalid; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
73
|
|
15
|
3
|
|
|
3
|
|
1021
|
use Context::Singleton::Exception::Deduced; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
71
|
|
16
|
3
|
|
|
3
|
|
949
|
use Context::Singleton::Exception::Nondeducible; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
68
|
|
17
|
3
|
|
|
3
|
|
964
|
use Context::Singleton::Frame::Promise; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
88
|
|
18
|
3
|
|
|
3
|
|
1011
|
use Context::Singleton::Frame::Promise::Builder; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
70
|
|
19
|
3
|
|
|
3
|
|
982
|
use Context::Singleton::Frame::Promise::Rule; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
154
|
|
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
use overload ( |
22
|
96
|
|
|
96
|
|
726
|
'""' => sub { ref ($_[0]) . '[' . $_[0]->{depth} . ']' }, |
23
|
3
|
|
|
|
|
23
|
fallback => 1, |
24
|
3
|
|
|
3
|
|
17
|
); |
|
3
|
|
|
|
|
18
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub new { |
27
|
66
|
|
|
66
|
0
|
58856
|
my ($class, %proclaim) = @_; |
28
|
66
|
|
|
|
|
160
|
my $self = { |
29
|
|
|
|
|
|
|
promises => {}, |
30
|
|
|
|
|
|
|
depth => 0, |
31
|
|
|
|
|
|
|
db => $class->default_db_instance, |
32
|
|
|
|
|
|
|
}; |
33
|
|
|
|
|
|
|
|
34
|
66
|
100
|
|
|
|
162
|
if (ref $class) { |
35
|
22
|
|
|
|
|
40
|
$self->{root} = $class->{root}; |
36
|
22
|
|
|
|
|
35
|
$self->{parent} = $class; |
37
|
22
|
|
|
|
|
35
|
$self->{db} = $class->{db}; |
38
|
22
|
|
|
|
|
33
|
$self->{depth} = $class->{depth} + 1; |
39
|
|
|
|
|
|
|
|
40
|
22
|
|
|
|
|
38
|
$class = ref $class; |
41
|
|
|
|
|
|
|
} |
42
|
|
|
|
|
|
|
|
43
|
66
|
100
|
|
|
|
133
|
unless ($self->{root}) { |
44
|
44
|
|
|
|
|
64
|
$self->{root} = $self; |
45
|
44
|
|
|
|
|
123
|
Scalar::Util::weaken $self->{root}; |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
66
|
|
|
|
|
116
|
$self = bless $self, $class; |
49
|
|
|
|
|
|
|
|
50
|
66
|
|
|
|
|
172
|
$self->proclaim (%proclaim); |
51
|
|
|
|
|
|
|
|
52
|
66
|
|
|
|
|
147
|
return $self; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
sub depth { |
56
|
205
|
|
|
205
|
0
|
499
|
$_[0]->{depth}; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub parent { |
60
|
122
|
|
|
122
|
0
|
251
|
$_[0]->{parent}; |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
sub default_db_class { |
64
|
100
|
|
|
100
|
0
|
370
|
'Context::Singleton::Frame::DB'; |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub default_db_instance { |
68
|
66
|
|
|
66
|
0
|
146
|
$_[0]->default_db_class->instance; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
sub db { |
72
|
401
|
|
|
401
|
0
|
1070
|
$_[0]->{db}; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub debug { |
76
|
0
|
|
|
0
|
0
|
0
|
my ($self, @message) = @_; |
77
|
|
|
|
|
|
|
|
78
|
0
|
|
|
|
|
0
|
my $sub = (caller(1))[3]; |
79
|
0
|
|
|
|
|
0
|
$sub =~ s/^.*://; |
80
|
|
|
|
|
|
|
|
81
|
3
|
|
|
3
|
|
983
|
use feature 'say'; |
|
3
|
|
|
|
|
8
|
|
|
3
|
|
|
|
|
3208
|
|
82
|
0
|
|
|
|
|
0
|
say "# [${\ $self->depth}] $sub ${\ join ' ', @message }"; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
sub _build_builder_promise_for { |
86
|
44
|
|
|
44
|
|
65
|
my ($self, $builder) = @_; |
87
|
|
|
|
|
|
|
|
88
|
44
|
|
|
|
|
79
|
my $promise = $self->_class_builder_promise->new ( |
89
|
|
|
|
|
|
|
depth => $self->depth, |
90
|
|
|
|
|
|
|
builder => $builder, |
91
|
|
|
|
|
|
|
); |
92
|
|
|
|
|
|
|
|
93
|
44
|
|
|
|
|
132
|
my %optional = $builder->default; |
94
|
44
|
|
|
|
|
91
|
my %required = map +($_ => 1), $builder->required; |
95
|
44
|
|
|
|
|
75
|
delete @required{ keys %optional }; |
96
|
|
|
|
|
|
|
|
97
|
44
|
|
|
|
|
116
|
$promise->add_dependencies ( |
98
|
|
|
|
|
|
|
map $self->_search_promise_for ($_), keys %required |
99
|
|
|
|
|
|
|
); |
100
|
|
|
|
|
|
|
|
101
|
44
|
100
|
|
|
|
149
|
$promise->set_deducible (0) unless keys %required; |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
$promise->listen ($self->_search_promise_for ($_)) |
104
|
44
|
|
|
|
|
79
|
for keys %optional; |
105
|
|
|
|
|
|
|
|
106
|
44
|
|
|
|
|
102
|
$promise; |
107
|
|
|
|
|
|
|
} |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
sub _build_rule_promise_for { |
110
|
88
|
|
|
88
|
|
144
|
my ($self, $rule) = @_; |
111
|
|
|
|
|
|
|
|
112
|
88
|
|
33
|
|
|
174
|
$self->{promises}{$rule} // do { |
113
|
88
|
|
|
|
|
158
|
my $promise = $self->{promises}{$rule} = $self->_class_rule_promise->new ( |
114
|
|
|
|
|
|
|
depth => $self->depth, |
115
|
|
|
|
|
|
|
rule => $rule, |
116
|
|
|
|
|
|
|
); |
117
|
|
|
|
|
|
|
|
118
|
88
|
100
|
|
|
|
168
|
$promise->add_dependencies ($self->parent->_search_promise_for ($rule)) |
119
|
|
|
|
|
|
|
if $self->parent; |
120
|
|
|
|
|
|
|
|
121
|
88
|
|
|
|
|
163
|
for my $builder ($self->db->find_builder_for ($rule)) { |
122
|
44
|
|
|
|
|
97
|
$promise->add_dependencies ( |
123
|
|
|
|
|
|
|
$self->_build_builder_promise_for ($builder) |
124
|
|
|
|
|
|
|
); |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
|
127
|
88
|
|
|
|
|
256
|
$promise; |
128
|
|
|
|
|
|
|
}; |
129
|
|
|
|
|
|
|
} |
130
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
sub _class_builder_promise { |
132
|
44
|
|
|
44
|
|
84
|
'Context::Singleton::Frame::Promise::Builder'; |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
sub _class_rule_promise { |
136
|
88
|
|
|
88
|
|
154
|
'Context::Singleton::Frame::Promise::Rule'; |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
sub _deduce_rule { |
140
|
41
|
|
|
41
|
|
62
|
my ($self, $rule) = @_; |
141
|
|
|
|
|
|
|
|
142
|
41
|
|
|
|
|
59
|
my $promise = $self->_search_promise_for( $rule ); |
143
|
41
|
100
|
|
|
|
77
|
return $promise->value if $promise->is_deduced; |
144
|
|
|
|
|
|
|
|
145
|
26
|
|
|
|
|
55
|
my $builder_promise = $promise->deducible_builder; |
146
|
26
|
50
|
|
|
|
51
|
return $builder_promise->value if $builder_promise->is_deduced; |
147
|
|
|
|
|
|
|
|
148
|
26
|
|
|
|
|
70
|
my $builder = $builder_promise->builder; |
149
|
26
|
|
|
|
|
52
|
my %deduced = $builder->default; |
150
|
|
|
|
|
|
|
|
151
|
26
|
|
|
|
|
51
|
for my $dependency ($builder->required) { |
152
|
|
|
|
|
|
|
# dependencies with default values may not be deducible |
153
|
|
|
|
|
|
|
# relying on promises to detect deducible values |
154
|
22
|
100
|
|
|
|
44
|
next unless $self->is_deducible( $dependency ); |
155
|
|
|
|
|
|
|
|
156
|
19
|
|
|
|
|
44
|
$deduced{$dependency} = $self->deduce ($dependency); |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
26
|
|
|
|
|
71
|
$builder->build (\%deduced); |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
sub _execute_triggers { |
163
|
30
|
|
|
30
|
|
45
|
my ($self, $rule, $value) = @_; |
164
|
|
|
|
|
|
|
|
165
|
30
|
|
|
|
|
52
|
$_->($value) for $self->db->find_trigger_for ($rule); |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
sub _find_promise_for { |
169
|
266
|
|
|
266
|
|
359
|
my ($self, $rule) = @_; |
170
|
|
|
|
|
|
|
|
171
|
266
|
|
|
|
|
732
|
$self->{promises}{$rule}; |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub _frame_by_depth { |
175
|
44
|
|
|
44
|
|
353
|
my ($self, $depth) = @_; |
176
|
|
|
|
|
|
|
|
177
|
44
|
100
|
|
|
|
96
|
return if $depth < 0; |
178
|
|
|
|
|
|
|
|
179
|
43
|
|
|
|
|
69
|
my $distance = $self->depth - $depth; |
180
|
43
|
100
|
|
|
|
78
|
return if $distance < 0; |
181
|
|
|
|
|
|
|
|
182
|
42
|
|
|
|
|
54
|
my $found = $self; |
183
|
|
|
|
|
|
|
|
184
|
42
|
|
|
|
|
85
|
$found = $found->parent |
185
|
|
|
|
|
|
|
while $distance-- > 0; |
186
|
|
|
|
|
|
|
|
187
|
42
|
|
|
|
|
95
|
$found; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
sub _root_frame { |
191
|
2
|
|
|
2
|
|
199
|
$_[0]->{root}; |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub _search_promise_for { |
195
|
181
|
|
|
181
|
|
252
|
my ($self, $rule) = @_; |
196
|
|
|
|
|
|
|
|
197
|
181
|
|
66
|
|
|
273
|
$self->_find_promise_for ($rule) |
198
|
|
|
|
|
|
|
// $self->_build_rule_promise_for ($rule) |
199
|
|
|
|
|
|
|
; |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
sub _set_promise_value { |
203
|
30
|
|
|
30
|
|
54
|
my ($self, $promise, $value) = @_; |
204
|
|
|
|
|
|
|
|
205
|
30
|
|
|
|
|
48
|
$promise->set_value ($value, $self->depth); |
206
|
30
|
|
|
|
|
60
|
$self->_execute_triggers ($promise->rule, $value); |
207
|
|
|
|
|
|
|
|
208
|
30
|
|
|
|
|
83
|
$value; |
209
|
|
|
|
|
|
|
} |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub _throw_deduced { |
212
|
3
|
|
|
3
|
|
7
|
my ($self, $rule) = @_; |
213
|
|
|
|
|
|
|
|
214
|
3
|
|
|
|
|
16
|
throw Context::Singleton::Exception::Deduced ($rule); |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
sub _throw_nondeducible { |
218
|
3
|
|
|
3
|
|
8
|
my ($self, $rule) = @_; |
219
|
|
|
|
|
|
|
|
220
|
3
|
|
|
|
|
34
|
throw Context::Singleton::Exception::Nondeducible ($rule); |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub contrive { |
224
|
243
|
|
|
243
|
0
|
1554
|
my ($self, $rule, @how) = @_; |
225
|
|
|
|
|
|
|
|
226
|
243
|
|
|
|
|
389
|
$self->db->contrive ($rule, @how); |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
sub load_rules { |
230
|
6
|
|
|
6
|
0
|
13
|
shift->db->load_rules (@_); |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub trigger { |
234
|
0
|
|
|
0
|
0
|
0
|
shift->db->trigger (@_); |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
sub deduce { |
238
|
43
|
|
|
43
|
0
|
1539
|
my ($self, $rule, @proclaim) = @_; |
239
|
|
|
|
|
|
|
|
240
|
43
|
50
|
|
|
|
88
|
$self = $self->new (@proclaim) if @proclaim; |
241
|
|
|
|
|
|
|
|
242
|
43
|
100
|
|
|
|
88
|
$self->_throw_nondeducible ($rule) |
243
|
|
|
|
|
|
|
unless $self->try_deduce ($rule); |
244
|
|
|
|
|
|
|
|
245
|
40
|
|
|
|
|
70
|
$self->_find_promise_for ($rule)->value; |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
sub is_deduced { |
249
|
12
|
|
|
12
|
0
|
2805
|
my ($self, $rule) = @_; |
250
|
|
|
|
|
|
|
|
251
|
12
|
100
|
|
|
|
27
|
return unless my $promise = $self->_find_promise_for ($rule); |
252
|
7
|
|
|
|
|
18
|
return $promise->is_deduced; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub is_deducible { |
256
|
29
|
|
|
29
|
0
|
930
|
my ($self, $rule) = @_; |
257
|
|
|
|
|
|
|
|
258
|
29
|
50
|
|
|
|
57
|
return unless my $promise = $self->_search_promise_for ($rule); |
259
|
29
|
|
|
|
|
56
|
return $promise->is_deducible; |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
sub proclaim { |
263
|
82
|
|
|
82
|
0
|
1352
|
my ($self, @proclaim) = @_; |
264
|
|
|
|
|
|
|
|
265
|
82
|
100
|
|
|
|
179
|
return unless @proclaim; |
266
|
|
|
|
|
|
|
|
267
|
31
|
|
|
|
|
41
|
my $retval; |
268
|
31
|
|
|
|
|
61
|
while (@proclaim) { |
269
|
33
|
|
|
|
|
48
|
my $key = shift @proclaim; |
270
|
33
|
|
|
|
|
48
|
my $value = shift @proclaim; |
271
|
|
|
|
|
|
|
|
272
|
33
|
|
66
|
|
|
61
|
my $promise = $self->_find_promise_for ($key) |
273
|
|
|
|
|
|
|
// $self->_build_rule_promise_for ($key) |
274
|
|
|
|
|
|
|
; |
275
|
|
|
|
|
|
|
|
276
|
33
|
100
|
|
|
|
77
|
$self->_throw_deduced ($key) |
277
|
|
|
|
|
|
|
if $promise->is_deduced; |
278
|
|
|
|
|
|
|
|
279
|
30
|
|
|
|
|
95
|
$retval = $self->_set_promise_value ($promise, $value); |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
|
282
|
28
|
|
|
|
|
46
|
$retval; |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
sub try_deduce { |
286
|
48
|
|
|
48
|
0
|
85
|
my ($self, $rule) = @_; |
287
|
|
|
|
|
|
|
|
288
|
48
|
|
|
|
|
79
|
my $promise = $self->_search_promise_for ($rule); |
289
|
48
|
100
|
|
|
|
91
|
return unless $promise->is_deducible; |
290
|
|
|
|
|
|
|
|
291
|
41
|
|
|
|
|
68
|
my $value = $self |
292
|
|
|
|
|
|
|
->_frame_by_depth ($promise->deduced_in_depth) |
293
|
|
|
|
|
|
|
->_deduce_rule ($promise->rule) |
294
|
|
|
|
|
|
|
; |
295
|
|
|
|
|
|
|
|
296
|
41
|
|
|
|
|
162
|
$promise->set_value ($value, $promise->deduced_in_depth); |
297
|
|
|
|
|
|
|
|
298
|
41
|
|
|
|
|
75
|
1; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
1; |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
__END__ |