wongi-engine 0.1.4 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.hgignore +6 -0
- data/.hgtags +2 -4
- data/.travis.yml +19 -6
- data/README.md +18 -442
- data/examples/ex02.rb +3 -2
- data/examples/graphviz.rb +1 -0
- data/lib/wongi-engine/alpha_memory.rb +11 -6
- data/lib/wongi-engine/beta/assignment_node.rb +0 -15
- data/lib/wongi-engine/beta/beta_memory.rb +7 -31
- data/lib/wongi-engine/beta/beta_node.rb +25 -95
- data/lib/wongi-engine/beta/join_node.rb +14 -46
- data/lib/wongi-engine/beta/ncc_node.rb +8 -34
- data/lib/wongi-engine/beta/ncc_partner.rb +3 -19
- data/lib/wongi-engine/beta/neg_node.rb +7 -16
- data/lib/wongi-engine/beta/optional_node.rb +23 -30
- data/lib/wongi-engine/beta/or_node.rb +0 -51
- data/lib/wongi-engine/beta/production_node.rb +1 -0
- data/lib/wongi-engine/compiler.rb +115 -0
- data/lib/wongi-engine/data_overlay.rb +140 -0
- data/lib/wongi-engine/dsl/action/base.rb +11 -0
- data/lib/wongi-engine/dsl/{actions → action}/error_generator.rb +3 -14
- data/lib/wongi-engine/dsl/action/simple_action.rb +60 -0
- data/lib/wongi-engine/dsl/action/simple_collector.rb +52 -0
- data/lib/wongi-engine/dsl/action/statement_generator.rb +45 -0
- data/lib/wongi-engine/dsl/action/trace_action.rb +49 -0
- data/lib/wongi-engine/dsl/any_rule.rb +4 -21
- data/lib/wongi-engine/dsl/assuming.rb +6 -12
- data/lib/wongi-engine/dsl/builder.rb +44 -0
- data/lib/wongi-engine/dsl/clause/assign.rb +15 -0
- data/lib/wongi-engine/dsl/clause/fact.rb +71 -0
- data/lib/wongi-engine/dsl/clause/gen.rb +17 -0
- data/lib/wongi-engine/dsl/clause/generic.rb +38 -0
- data/lib/wongi-engine/dsl/{dsl_extensions.rb → generated.rb} +5 -5
- data/lib/wongi-engine/dsl/ncc_subrule.rb +15 -0
- data/lib/wongi-engine/dsl/query.rb +10 -11
- data/lib/wongi-engine/dsl/rule.rb +84 -0
- data/lib/wongi-engine/dsl.rb +102 -97
- data/lib/wongi-engine/enumerators.rb +21 -0
- data/lib/wongi-engine/error.rb +13 -2
- data/lib/wongi-engine/filter/filter_test.rb +1 -13
- data/lib/wongi-engine/graph.rb +7 -7
- data/lib/wongi-engine/network.rb +108 -181
- data/lib/wongi-engine/ruleset.rb +6 -6
- data/lib/wongi-engine/template.rb +30 -84
- data/lib/wongi-engine/token.rb +3 -34
- data/lib/wongi-engine/version.rb +1 -1
- data/lib/wongi-engine/wme.rb +9 -60
- data/lib/wongi-engine.rb +3 -0
- data/spec/beta_node_spec.rb +2 -0
- data/spec/generation_spec.rb +1 -1
- data/spec/high_level_spec.rb +29 -11
- data/spec/overlay_spec.rb +22 -0
- data/spec/simple_action_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/wme_spec.rb +22 -22
- data/wongi-engine.gemspec +1 -1
- metadata +37 -17
- data/lib/wongi-engine/dsl/action.rb +0 -12
- data/lib/wongi-engine/dsl/actions/simple_action.rb +0 -62
- data/lib/wongi-engine/dsl/actions/simple_collector.rb +0 -51
- data/lib/wongi-engine/dsl/actions/statement_generator.rb +0 -67
- data/lib/wongi-engine/dsl/actions/trace_action.rb +0 -52
- data/lib/wongi-engine/dsl/dsl_builder.rb +0 -44
- data/lib/wongi-engine/dsl/extension_clause.rb +0 -36
- data/lib/wongi-engine/dsl/generation_clause.rb +0 -15
- data/lib/wongi-engine/dsl/generic_production_rule.rb +0 -82
- data/lib/wongi-engine/dsl/ncc_production_rule.rb +0 -21
- data/lib/wongi-engine/dsl/production_rule.rb +0 -4
- data/lib/wongi-engine/model_context.rb +0 -13
data/lib/wongi-engine/network.rb
CHANGED
@@ -7,6 +7,7 @@ module Wongi::Engine
|
|
7
7
|
attr_reader :alpha_top, :beta_top
|
8
8
|
attr_reader :queries, :results
|
9
9
|
attr_reader :productions
|
10
|
+
attr_reader :overlays
|
10
11
|
|
11
12
|
include NetworkParts::Collectable
|
12
13
|
|
@@ -46,7 +47,7 @@ module Wongi::Engine
|
|
46
47
|
def initialize
|
47
48
|
@timeline = []
|
48
49
|
self.alpha_top = AlphaMemory.new( Template.new( :_, :_, :_ ), self )
|
49
|
-
self.alpha_hash = {
|
50
|
+
self.alpha_hash = { alpha_top.template.hash => alpha_top }
|
50
51
|
self.beta_top = BetaMemory.new(nil)
|
51
52
|
self.beta_top.rete = self
|
52
53
|
self.beta_top.seed
|
@@ -54,7 +55,6 @@ module Wongi::Engine
|
|
54
55
|
self.results = {}
|
55
56
|
@cache = {}
|
56
57
|
@revns = {}
|
57
|
-
@contexts = {}
|
58
58
|
|
59
59
|
@productions = { }
|
60
60
|
|
@@ -67,69 +67,58 @@ module Wongi::Engine
|
|
67
67
|
beta_top.dump
|
68
68
|
end
|
69
69
|
|
70
|
+
def with_overlay(&block)
|
71
|
+
default_overlay.with_child(&block)
|
72
|
+
end
|
73
|
+
|
70
74
|
def alphas
|
71
75
|
alpha_hash.values
|
72
76
|
end
|
73
77
|
|
74
|
-
def import thing
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
78
|
+
# def import thing
|
79
|
+
# case thing
|
80
|
+
# when String, Numeric, TrueClass, FalseClass, NilClass, Wongi::RDF::Node
|
81
|
+
# thing
|
82
|
+
# when Symbol
|
83
|
+
# thing
|
84
|
+
# else
|
85
|
+
# thing
|
86
|
+
# end
|
87
|
+
# end
|
88
|
+
|
89
|
+
def default_overlay
|
90
|
+
@default_overlay ||= DataOverlay.new(self)
|
83
91
|
end
|
84
92
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
if @current_cascade.nil?
|
89
|
-
@current_cascade = @next_cascade
|
90
|
-
@next_cascade = nil
|
91
|
-
process_cascade
|
92
|
-
end
|
93
|
+
# @private
|
94
|
+
def add_overlay(o)
|
95
|
+
overlays << o
|
93
96
|
end
|
94
97
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
if @current_cascade.nil?
|
99
|
-
@current_cascade = @next_cascade
|
100
|
-
@next_cascade = nil
|
101
|
-
process_cascade
|
102
|
-
end
|
98
|
+
# @private
|
99
|
+
def remove_overlay(o)
|
100
|
+
overlays.delete(o) unless o == default_overlay
|
103
101
|
end
|
104
102
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
when :retract
|
113
|
-
real_retract wme, options
|
114
|
-
end
|
115
|
-
end
|
116
|
-
@current_cascade = @next_cascade
|
117
|
-
@next_cascade = nil
|
118
|
-
iterations += 1
|
119
|
-
end
|
103
|
+
# @private
|
104
|
+
def overlays
|
105
|
+
@overlays ||= []
|
106
|
+
end
|
107
|
+
|
108
|
+
def assert(wme)
|
109
|
+
default_overlay.assert(wme)
|
120
110
|
end
|
121
111
|
|
122
|
-
def
|
112
|
+
def retract(wme, options = {})
|
113
|
+
default_overlay.retract(wme, options)
|
114
|
+
end
|
123
115
|
|
116
|
+
# @private
|
117
|
+
def real_assert( wme )
|
124
118
|
unless wme.rete == self
|
125
119
|
wme = wme.import_into self
|
126
120
|
end
|
127
121
|
|
128
|
-
if @current_context
|
129
|
-
@current_context.asserted_wmes << wme
|
130
|
-
wme.context = @current_context
|
131
|
-
end
|
132
|
-
|
133
122
|
if existing = @cache[wme]
|
134
123
|
existing.manual! if wme.manual?
|
135
124
|
return
|
@@ -143,6 +132,28 @@ module Wongi::Engine
|
|
143
132
|
wme
|
144
133
|
end
|
145
134
|
|
135
|
+
# @private
|
136
|
+
def real_retract wme, options
|
137
|
+
real = @cache[wme]
|
138
|
+
|
139
|
+
return if real.nil?
|
140
|
+
if real.generated? # still some generator tokens left
|
141
|
+
if real.manual?
|
142
|
+
real.manual = false
|
143
|
+
else
|
144
|
+
raise Error, "cannot retract automatic facts"
|
145
|
+
end
|
146
|
+
else
|
147
|
+
if options[:automatic] && real.manual? # auto-retracting a fact that has been added manually
|
148
|
+
return
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
@cache.delete(real)
|
153
|
+
|
154
|
+
alphas_for( real ).each { |a| a.deactivate real }
|
155
|
+
end
|
156
|
+
|
146
157
|
def wmes
|
147
158
|
alpha_top.wmes
|
148
159
|
end
|
@@ -173,82 +184,52 @@ module Wongi::Engine
|
|
173
184
|
end
|
174
185
|
|
175
186
|
def rule name = nil, &block
|
176
|
-
r =
|
187
|
+
r = DSL::Rule.new( name || generate_rule_name )
|
177
188
|
r.instance_eval &block
|
178
189
|
self << r
|
179
190
|
end
|
180
191
|
|
181
192
|
def query name, &block
|
182
|
-
q = Query.new name
|
193
|
+
q = DSL::Query.new name
|
183
194
|
q.instance_eval &block
|
184
195
|
self << q
|
185
196
|
end
|
186
197
|
|
187
198
|
def << something
|
188
|
-
|
189
|
-
|
190
|
-
|
199
|
+
if something.respond_to?( :install )
|
200
|
+
something.install( self )
|
201
|
+
else
|
202
|
+
case something
|
203
|
+
when Array
|
191
204
|
assert WME.new( *something )
|
205
|
+
when WME
|
206
|
+
assert something
|
207
|
+
# when Wongi::RDF::Statement
|
208
|
+
# assert WME.new( something.subject, something.predicate, something.object, self )
|
209
|
+
#when Wongi::RDF::Document
|
210
|
+
# something.statements.each do |st|
|
211
|
+
# assert WME.new( st.subject, st.predicate, st.object, self )
|
212
|
+
# end
|
213
|
+
when Network
|
214
|
+
something.wmes.each { |wme| assert( wme ) }
|
192
215
|
else
|
193
|
-
raise "
|
194
|
-
end
|
195
|
-
when ProductionRule
|
196
|
-
derived = something.import_into self
|
197
|
-
production = add_production derived.conditions, derived.actions
|
198
|
-
if something.name
|
199
|
-
productions[ something.name ] = production
|
216
|
+
raise Error, "I don't know how to accept a #{something.class}"
|
200
217
|
end
|
201
|
-
production
|
202
|
-
when Query
|
203
|
-
derived = something.import_into self
|
204
|
-
prepare_query derived.name, derived.conditions, derived.parameters, derived.actions
|
205
|
-
when Ruleset
|
206
|
-
something.install self
|
207
|
-
when WME
|
208
|
-
assert something
|
209
|
-
when Wongi::RDF::Statement
|
210
|
-
assert WME.new( something.subject, something.predicate, something.object, self )
|
211
|
-
#when Wongi::RDF::Document
|
212
|
-
# something.statements.each do |st|
|
213
|
-
# assert WME.new( st.subject, st.predicate, st.object, self )
|
214
|
-
# end
|
215
|
-
when Network
|
216
|
-
something.each do |st|
|
217
|
-
assert st.import_into( self )
|
218
|
-
end
|
219
|
-
else
|
220
|
-
raise "I don't know how to accept a #{something.class}"
|
221
218
|
end
|
222
219
|
end
|
223
220
|
|
224
|
-
def
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
real = @cache[wme]
|
231
|
-
|
232
|
-
return if real.nil?
|
233
|
-
if real.generated? # still some generator tokens left
|
234
|
-
if real.manual?
|
235
|
-
real.manual = false
|
236
|
-
else
|
237
|
-
raise "cannot retract automatic facts"
|
238
|
-
end
|
239
|
-
else
|
240
|
-
if options[:automatic] && real.manual? # auto-retracting a fact that has been added manually
|
241
|
-
return
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
if @current_context
|
246
|
-
@current_context.retracted_wmes << wme
|
221
|
+
def install_rule( rule )
|
222
|
+
derived = rule.import_into self
|
223
|
+
production = build_production beta_top, derived.conditions, [], derived.actions, false
|
224
|
+
if rule.name
|
225
|
+
productions[ rule.name ] = production
|
247
226
|
end
|
227
|
+
production
|
228
|
+
end
|
248
229
|
|
249
|
-
|
250
|
-
|
251
|
-
|
230
|
+
def install_query( query )
|
231
|
+
derived = query.import_into self
|
232
|
+
prepare_query derived.name, derived.conditions, derived.parameters, derived.actions
|
252
233
|
end
|
253
234
|
|
254
235
|
def compile_alpha condition
|
@@ -284,23 +265,16 @@ module Wongi::Engine
|
|
284
265
|
end
|
285
266
|
|
286
267
|
def cache s, p, o
|
287
|
-
compile_alpha Template.new(s, p, o)
|
268
|
+
compile_alpha Template.new(s, p, o)
|
288
269
|
end
|
289
270
|
|
271
|
+
# TODO: pick an alpha with fewer candidates to go through
|
290
272
|
def initial_fill alpha
|
291
|
-
|
292
|
-
|
293
|
-
# puts "more efficient by #{alpha_top.wmes.size - source.wmes.size}" unless source ==
|
294
|
-
# alpha_top
|
295
|
-
source.wmes.each do |wme|
|
296
|
-
alpha.activate wme if wme =~ tpl
|
273
|
+
alpha_top.wmes.each do |wme|
|
274
|
+
alpha.activate wme if wme =~ alpha.template
|
297
275
|
end
|
298
276
|
end
|
299
277
|
|
300
|
-
def add_production conditions, actions = []
|
301
|
-
real_add_production self.beta_top, conditions, [], actions, false
|
302
|
-
end
|
303
|
-
|
304
278
|
def remove_production pnode
|
305
279
|
delete_node_with_ancestors pnode
|
306
280
|
end
|
@@ -308,15 +282,13 @@ module Wongi::Engine
|
|
308
282
|
def prepare_query name, conditions, parameters, actions = []
|
309
283
|
query = self.queries[ name ] = BetaMemory.new( nil )
|
310
284
|
query.rete = self
|
311
|
-
|
312
|
-
|
313
|
-
query.seed transformed
|
314
|
-
self.results[ name ] = real_add_production query, conditions, parameters, actions, true
|
285
|
+
query.seed(Hash[parameters.map{ |param| [param, nil]}])
|
286
|
+
self.results[ name ] = build_production query, conditions, parameters, actions, true
|
315
287
|
end
|
316
288
|
|
317
289
|
def execute name, valuations
|
318
290
|
beta = self.queries[name]
|
319
|
-
raise "Undefined query #{name}; known queries are #{queries.keys}" unless beta
|
291
|
+
raise Error, "Undefined query #{name}; known queries are #{queries.keys}" unless beta
|
320
292
|
beta.subst valuations
|
321
293
|
end
|
322
294
|
|
@@ -324,25 +296,6 @@ module Wongi::Engine
|
|
324
296
|
"<Rete>"
|
325
297
|
end
|
326
298
|
|
327
|
-
def context= name
|
328
|
-
if name && !@contexts.has_key?(name)
|
329
|
-
@current_context = (@contexts[name] ||= ModelContext.new name)
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
# TODO: contexts are probably broken with the new improved handling of manual & generated
|
334
|
-
def retract_context name
|
335
|
-
return unless @contexts.has_key?(name)
|
336
|
-
|
337
|
-
if @current_context && @current_context.name == name
|
338
|
-
@current_context = nil
|
339
|
-
end
|
340
|
-
ctx = @contexts[name]
|
341
|
-
ctx.asserted_wmes.select { |wme| wme.generating_tokens.empty? }.each { |wme| retract(wme, true) }
|
342
|
-
ctx.retracted_wmes.each { |wme| assert(wme) }
|
343
|
-
@contexts.delete name
|
344
|
-
end
|
345
|
-
|
346
299
|
def exists? wme
|
347
300
|
@cache[ wme ]
|
348
301
|
end
|
@@ -350,7 +303,7 @@ module Wongi::Engine
|
|
350
303
|
def each *args
|
351
304
|
return unless block_given?
|
352
305
|
unless args.length == 0 || args.length == 3
|
353
|
-
raise "
|
306
|
+
raise Error, "Network#each expects a pattern or nothing at all"
|
354
307
|
end
|
355
308
|
s, p, o = if args.empty?
|
356
309
|
[:_, :_, :_]
|
@@ -365,7 +318,7 @@ module Wongi::Engine
|
|
365
318
|
end
|
366
319
|
|
367
320
|
def select s, p, o
|
368
|
-
template = Template.new(s, p, o)
|
321
|
+
template = Template.new(s, p, o)
|
369
322
|
matching = alpha_top.wmes.select { |wme| wme =~ template }
|
370
323
|
if block_given?
|
371
324
|
matching.each { |st| yield st.subject, st.predicate, st.object }
|
@@ -374,7 +327,7 @@ module Wongi::Engine
|
|
374
327
|
end
|
375
328
|
|
376
329
|
def find s, p, o
|
377
|
-
template = Template.new(s, p, o)
|
330
|
+
template = Template.new(s, p, o)
|
378
331
|
source = best_alpha(template)
|
379
332
|
# puts "looking for #{template} among #{source.wmes.size} triples of #{source.template}"
|
380
333
|
source.wmes.detect { |wme| wme =~ template }
|
@@ -382,6 +335,7 @@ module Wongi::Engine
|
|
382
335
|
|
383
336
|
protected
|
384
337
|
|
338
|
+
|
385
339
|
def in_snapshot
|
386
340
|
@in_snapshot = true
|
387
341
|
yield
|
@@ -404,7 +358,7 @@ module Wongi::Engine
|
|
404
358
|
lookup(:_, p, :_),
|
405
359
|
lookup(:_, :_, o),
|
406
360
|
lookup(:_, :_, :_),
|
407
|
-
].compact
|
361
|
+
].compact!.tap(&:uniq!)
|
408
362
|
end
|
409
363
|
|
410
364
|
def lookup s, p, o
|
@@ -414,52 +368,25 @@ module Wongi::Engine
|
|
414
368
|
end
|
415
369
|
|
416
370
|
def alpha_activate alpha, wme
|
417
|
-
alpha.activate(wme)
|
418
|
-
end
|
419
|
-
|
420
|
-
def more_generic_alpha template
|
421
|
-
return alpha_top # OPTIMISE => temporary; may use later or not use at all
|
422
|
-
return alpha_top if template.root?
|
423
|
-
more_generic_templates(template).reduce alpha_top do |best, template|
|
424
|
-
alpha = alpha_hash[template.hash]
|
425
|
-
if alpha && alpha.wmes.size < best.wmes.size
|
426
|
-
alpha
|
427
|
-
else
|
428
|
-
best
|
429
|
-
end
|
430
|
-
end
|
431
|
-
end
|
432
|
-
|
433
|
-
def more_generic_templates template
|
434
|
-
set = []
|
435
|
-
set << template.with_subject( :_ ) unless template.subject == :_
|
436
|
-
set << template.with_predicate( :_ ) unless template.predicate == :_
|
437
|
-
set << template.with_object( :_ ) unless template.object == :_
|
438
|
-
set.select { |item| not item.root? }
|
371
|
+
alpha.activate(wme)
|
439
372
|
end
|
440
373
|
|
441
374
|
def best_alpha template
|
442
|
-
|
443
|
-
template =~ alpha.template
|
444
|
-
end
|
445
|
-
result = candidates.inject do |best, alpha|
|
446
|
-
if best.nil?
|
447
|
-
alpha
|
448
|
-
elsif alpha.wmes.to_a.length < best.wmes.to_a.length
|
375
|
+
alpha_hash.inject(nil) do |best, (_, alpha)|
|
376
|
+
if template =~ alpha.template && (best.nil? || alpha.size < best.size)
|
449
377
|
alpha
|
450
378
|
else
|
451
379
|
best
|
452
380
|
end
|
453
381
|
end
|
454
|
-
result
|
455
382
|
end
|
456
383
|
|
457
|
-
def
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
384
|
+
def build_production root, conditions, parameters, actions, alpha_deaf
|
385
|
+
compiler = Compiler.new(self, root, conditions, parameters, alpha_deaf)
|
386
|
+
ProductionNode.new(compiler.compile, actions).tap do |production|
|
387
|
+
production.compilation_context = compiler
|
388
|
+
production.refresh
|
389
|
+
end
|
463
390
|
end
|
464
391
|
|
465
392
|
def delete_node_with_ancestors node
|
data/lib/wongi-engine/ruleset.rb
CHANGED
@@ -5,12 +5,12 @@ module Wongi
|
|
5
5
|
class << self
|
6
6
|
|
7
7
|
def [] name
|
8
|
-
raise "undefined ruleset #{name}" unless rulesets.has_key?( name )
|
8
|
+
raise Error, "undefined ruleset #{name}" unless rulesets.has_key?( name )
|
9
9
|
rulesets[ name ]
|
10
10
|
end
|
11
11
|
|
12
12
|
def register name, ruleset
|
13
|
-
raise "ruleset #{name} already exists" if rulesets.has_key?( name )
|
13
|
+
raise Error, "ruleset #{name} already exists" if rulesets.has_key?( name )
|
14
14
|
rulesets[ name ] = ruleset
|
15
15
|
end
|
16
16
|
|
@@ -36,8 +36,8 @@ module Wongi
|
|
36
36
|
def install rete
|
37
37
|
# puts "Installing ruleset #{name}"
|
38
38
|
@rules.each { |rule| rete << rule }
|
39
|
-
rescue
|
40
|
-
e1 =
|
39
|
+
rescue StandardError => e
|
40
|
+
e1 = Error.new "error installing ruleset '#{name||'<unnamed>'}': #{e}"
|
41
41
|
e1.set_backtrace e.backtrace
|
42
42
|
raise e1
|
43
43
|
end
|
@@ -56,14 +56,14 @@ module Wongi
|
|
56
56
|
# end
|
57
57
|
|
58
58
|
def rule name, &definition
|
59
|
-
r =
|
59
|
+
r = DSL::Rule.new name
|
60
60
|
r.instance_eval &definition
|
61
61
|
@rules << r
|
62
62
|
r
|
63
63
|
end
|
64
64
|
|
65
65
|
def query name, &definition
|
66
|
-
r = Query.new name
|
66
|
+
r = DSL::Query.new name
|
67
67
|
r.instance_eval &definition
|
68
68
|
@rules << r
|
69
69
|
r
|
@@ -1,60 +1,36 @@
|
|
1
1
|
module Wongi::Engine
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
include CoreExt
|
6
|
-
|
7
|
-
attr_reader :unsafe
|
8
|
-
attr_predicate debug: false
|
3
|
+
Template = Struct.new( :subject, :predicate, :object ) do
|
9
4
|
|
10
5
|
def self.variable? thing
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
def initialize s, p, o, options = { }
|
15
|
-
time = options[:time] || 0
|
16
|
-
unsafe = options[:unsafe] || false
|
17
|
-
debug! if options[:debug]
|
18
|
-
raise "Cannot work with continuous time" unless time.integer?
|
19
|
-
raise "Cannot look into the future" if time > 0
|
20
|
-
super( s, p, o, time )
|
21
|
-
@filters = []
|
22
|
-
@unsafe = unsafe
|
6
|
+
return false unless thing.is_a?(Symbol)
|
7
|
+
thing[0] >= 'A' && thing[0] <= 'Z'
|
23
8
|
end
|
24
9
|
|
25
|
-
|
26
|
-
copy = self.class.new r.import( subject ), r.import( predicate ), r.import( object ), time: time, unsafe: unsafe, debug: debug?
|
27
|
-
@filters.each { |f| copy.filters << f }
|
28
|
-
copy
|
29
|
-
end
|
10
|
+
# TODO: reintroduce Network#import when bringing back RDF support
|
30
11
|
|
31
12
|
def root?
|
32
13
|
subject == :_ && predicate == :_ && object == :_
|
33
14
|
end
|
34
15
|
|
35
16
|
def variables
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
17
|
+
[].tap do |a|
|
18
|
+
a << subject if Template.variable?( subject )
|
19
|
+
a << predicate if Template.variable?( predicate )
|
20
|
+
a << object if Template.variable?( object )
|
21
|
+
end
|
41
22
|
end
|
42
23
|
|
43
24
|
def hash
|
44
|
-
@hash ||=
|
25
|
+
@hash ||= [subject.hash, predicate.hash, object.hash].hash
|
45
26
|
end
|
46
27
|
|
47
28
|
def self.hash_for *args
|
48
29
|
args.map( &:hash ).hash
|
49
30
|
end
|
50
31
|
|
51
|
-
def === wme
|
52
|
-
wme =~ self if WME === wme
|
53
|
-
end
|
54
|
-
|
55
32
|
def == other
|
56
|
-
|
57
|
-
subject == other.subject && predicate == other.predicate && object == other.object
|
33
|
+
other.is_a?(Template) && subject == other.subject && predicate == other.predicate && object == other.object
|
58
34
|
end
|
59
35
|
|
60
36
|
def =~ template
|
@@ -64,66 +40,36 @@ module Wongi::Engine
|
|
64
40
|
( template.predicate == :_ || template.predicate == predicate ) &&
|
65
41
|
( template.object == :_ || template.object == object )
|
66
42
|
else
|
67
|
-
raise "
|
43
|
+
raise Error, "templates can only match other templates"
|
68
44
|
end
|
69
45
|
end
|
70
46
|
|
71
|
-
|
72
|
-
def compile context
|
73
|
-
tests, assignment = *JoinNode.compile( self, context.earlier, context.parameters )
|
74
|
-
alpha = context.rete.compile_alpha( self )
|
75
|
-
context.node = context.node.beta_memory.join_node( alpha, tests, assignment, context.alpha_deaf )
|
76
|
-
context.node.context = context
|
77
|
-
context.node.debug = debug?
|
78
|
-
context.earlier << self
|
79
|
-
context
|
80
|
-
end
|
81
|
-
|
82
47
|
def inspect
|
83
|
-
"
|
48
|
+
"<~#{subject.inspect} #{predicate.inspect} #{object.inspect}>"
|
84
49
|
end
|
85
50
|
|
86
51
|
def to_s
|
87
52
|
inspect
|
88
53
|
end
|
89
54
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
context.node.debug = debug?
|
108
|
-
context.earlier << self
|
109
|
-
context
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
class OptionalTemplate < Template
|
114
|
-
|
115
|
-
def compile context
|
116
|
-
tests, assignment = *JoinNode.compile( self, context.earlier, context.parameters )
|
117
|
-
alpha = context.rete.compile_alpha( self )
|
118
|
-
context.node = context.node.beta_memory.optional_node( alpha, tests, assignment, context.alpha_deaf )
|
119
|
-
context.node.context = context
|
120
|
-
context.node.debug = debug?
|
121
|
-
context.earlier << self
|
122
|
-
context
|
55
|
+
def resolve!(token)
|
56
|
+
s = if Template.variable?(subject)
|
57
|
+
token[subject].tap { |x| raise DefinitionError, "unbound variable #{subject} in token #{token}" unless x}
|
58
|
+
else
|
59
|
+
subject
|
60
|
+
end
|
61
|
+
p = if Template.variable?(predicate)
|
62
|
+
token[predicate].tap { |x| raise DefinitionError, "unbound variable #{predicate} in token #{token}" unless x}
|
63
|
+
else
|
64
|
+
predicate
|
65
|
+
end
|
66
|
+
o = if Template.variable?(object)
|
67
|
+
token[object].tap { |x| raise DefinitionError, "unbound variable #{object} in token #{token}" unless x}
|
68
|
+
else
|
69
|
+
object
|
70
|
+
end
|
71
|
+
[s, p, o]
|
123
72
|
end
|
124
73
|
|
125
74
|
end
|
126
|
-
|
127
|
-
|
128
|
-
|
129
75
|
end
|