wongi-engine 0.3.9 → 0.4.0.pre.alpha2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +2 -2
  3. data/.gitignore +2 -0
  4. data/README.md +12 -12
  5. data/lib/wongi-engine/alpha_index.rb +58 -0
  6. data/lib/wongi-engine/alpha_memory.rb +2 -24
  7. data/lib/wongi-engine/beta/aggregate_node.rb +17 -15
  8. data/lib/wongi-engine/beta/assignment_node.rb +7 -2
  9. data/lib/wongi-engine/beta/beta_node.rb +36 -23
  10. data/lib/wongi-engine/beta/filter_node.rb +8 -13
  11. data/lib/wongi-engine/beta/join_node.rb +17 -29
  12. data/lib/wongi-engine/beta/ncc_node.rb +14 -26
  13. data/lib/wongi-engine/beta/ncc_partner.rb +18 -18
  14. data/lib/wongi-engine/beta/neg_node.rb +25 -55
  15. data/lib/wongi-engine/beta/optional_node.rb +26 -48
  16. data/lib/wongi-engine/beta/or_node.rb +24 -1
  17. data/lib/wongi-engine/beta/production_node.rb +9 -3
  18. data/lib/wongi-engine/beta/root_node.rb +47 -0
  19. data/lib/wongi-engine/beta.rb +1 -1
  20. data/lib/wongi-engine/compiler.rb +6 -34
  21. data/lib/wongi-engine/dsl/action/{base.rb → base_action.rb} +5 -1
  22. data/lib/wongi-engine/dsl/action/error_generator.rb +1 -1
  23. data/lib/wongi-engine/dsl/action/simple_action.rb +1 -1
  24. data/lib/wongi-engine/dsl/action/simple_collector.rb +1 -1
  25. data/lib/wongi-engine/dsl/action/statement_generator.rb +21 -22
  26. data/lib/wongi-engine/dsl/action/trace_action.rb +1 -1
  27. data/lib/wongi-engine/dsl/clause/fact.rb +2 -6
  28. data/lib/wongi-engine/dsl.rb +1 -25
  29. data/lib/wongi-engine/graph.rb +1 -1
  30. data/lib/wongi-engine/network/debug.rb +2 -10
  31. data/lib/wongi-engine/network.rb +44 -105
  32. data/lib/wongi-engine/overlay.rb +589 -0
  33. data/lib/wongi-engine/template.rb +22 -2
  34. data/lib/wongi-engine/token.rb +10 -26
  35. data/lib/wongi-engine/token_assignment.rb +15 -0
  36. data/lib/wongi-engine/version.rb +1 -1
  37. data/lib/wongi-engine/wme.rb +10 -39
  38. data/lib/wongi-engine.rb +3 -1
  39. data/spec/alpha_index_spec.rb +78 -0
  40. data/spec/bug_specs/issue_4_spec.rb +11 -11
  41. data/spec/high_level_spec.rb +8 -101
  42. data/spec/network_spec.rb +8 -6
  43. data/spec/overlay_spec.rb +161 -3
  44. data/spec/rule_specs/any_rule_spec.rb +39 -0
  45. data/spec/rule_specs/assign_spec.rb +1 -1
  46. data/spec/rule_specs/maybe_rule_spec.rb +58 -1
  47. data/spec/rule_specs/ncc_spec.rb +78 -19
  48. data/spec/rule_specs/negative_rule_spec.rb +12 -14
  49. data/spec/spec_helper.rb +4 -0
  50. data/spec/wme_spec.rb +0 -32
  51. metadata +11 -9
  52. data/lib/wongi-engine/beta/beta_memory.rb +0 -60
  53. data/lib/wongi-engine/data_overlay.rb +0 -149
  54. data/spec/rule_specs/or_rule_spec.rb +0 -40
@@ -0,0 +1,589 @@
1
+ module Wongi::Engine
2
+ class Overlay
3
+ class JoinResults
4
+ attr_reader :by_wme, :by_token, :hidden
5
+ private :by_wme, :by_token
6
+ private :hidden
7
+ def initialize
8
+ @by_wme = Hash.new { |h, k| h[k] = {} }
9
+ @by_token = Hash.new { |h, k| h[k] = {} }
10
+ @hidden = {}
11
+ end
12
+
13
+ def for(wme: nil, token: nil)
14
+ if wme
15
+ by_wme.key?(wme.object_id) ? by_wme[wme.object_id].keys : []
16
+ elsif token
17
+ by_token.key?(token.object_id) ? by_token[token.object_id].keys : []
18
+ else
19
+ []
20
+ end
21
+ end
22
+
23
+ def has?(jr)
24
+ by_wme.key?(jr.wme.object_id) && by_wme[jr.wme.object_id].key?(jr)
25
+ end
26
+
27
+ def hidden?(jr)
28
+ hidden.key?(jr)
29
+ end
30
+
31
+ def add(jr)
32
+ if hidden.key?(jr)
33
+ hidden.delete(jr)
34
+ else
35
+ by_wme[jr.wme.object_id][jr] = true
36
+ by_token[jr.token.object_id][jr] = true
37
+ end
38
+ end
39
+
40
+ def remove(jr)
41
+ unless has?(jr)
42
+ hide(jr)
43
+ return
44
+ end
45
+
46
+ if by_wme.key?(jr.wme.object_id)
47
+ by_wme[jr.wme.object_id].delete(jr)
48
+ if by_wme[jr.wme.object_id].empty?
49
+ by_wme.delete(jr.wme.object_id)
50
+ end
51
+ end
52
+
53
+ if by_token.key?(jr.token.object_id)
54
+ by_token[jr.token.object_id].delete(jr)
55
+ if by_token[jr.token.object_id].empty?
56
+ by_token.delete(jr.token.object_id)
57
+ end
58
+ end
59
+ end
60
+
61
+ def hide(jr)
62
+ hidden[jr] = true
63
+ end
64
+
65
+ def remove_token(token)
66
+ return unless by_token.key?(token.object_id)
67
+
68
+ by_token[token.object_id].keys.each do |jr|
69
+ remove(jr)
70
+ end
71
+ end
72
+
73
+ def remove_wme(wme)
74
+ return unless by_wme.key?(wme.object_id)
75
+
76
+ by_wme[wme.object_id].keys do |jr|
77
+ remove(jr)
78
+ end
79
+ end
80
+ end
81
+
82
+ attr_reader :rete, :parent, :wmes, :tokens, :indexes, :queue, :hidden_parent_wmes, :hidden_parent_tokens, :wme_generators, :hidden_parent_wme_generators, :wme_manual, :hidden_parent_wme_manual, :neg_join_results, :opt_join_results, :ncc_tokens, :ncc_tokens_owner, :hidden_ncc_tokens
83
+ private :wmes, :tokens
84
+ private :indexes
85
+ private :queue
86
+ private :hidden_parent_wmes
87
+ private :hidden_parent_tokens
88
+ private :wme_generators
89
+ private :hidden_parent_wme_generators
90
+ private :wme_manual
91
+ private :hidden_parent_wme_manual
92
+ private :neg_join_results
93
+ private :opt_join_results
94
+ private :ncc_tokens
95
+ private :ncc_tokens_owner
96
+ private :hidden_ncc_tokens
97
+
98
+ def initialize(rete, parent = nil)
99
+ @rete = rete
100
+ @parent = parent
101
+
102
+ @wmes = []
103
+ @indexes = [
104
+ AlphaIndex.new(%i[subject]),
105
+ AlphaIndex.new(%i[predicate]),
106
+ AlphaIndex.new(%i[object]),
107
+ AlphaIndex.new(%i[subject predicate]),
108
+ AlphaIndex.new(%i[subject object]),
109
+ AlphaIndex.new(%i[predicate object]),
110
+ ]
111
+ @hidden_parent_wmes = {}
112
+
113
+ @tokens = Hash.new { |h, k| h[k] = [] }
114
+ @hidden_parent_tokens = {}
115
+
116
+ @wme_generators = Hash.new { |h, k| h[k] = [] }
117
+ @hidden_parent_wme_generators = {}
118
+
119
+ @wme_manual = {}
120
+ @hidden_parent_wme_manual = {}
121
+
122
+ @neg_join_results = JoinResults.new
123
+ @opt_join_results = JoinResults.new
124
+
125
+ @ncc_tokens = Hash.new { |h, k| h[k] = [] }
126
+ @ncc_tokens_owner = {}
127
+ @hidden_ncc_tokens = Hash.new { |h, k| h[k] = {} }
128
+
129
+ @queue = []
130
+ end
131
+
132
+ def new_child
133
+ Overlay.new(rete, self)
134
+ end
135
+
136
+ def ancestor?(other)
137
+ return false if parent.nil?
138
+ return true if parent == other
139
+
140
+ parent.ancestor?(other)
141
+ end
142
+
143
+ def dispose!
144
+ return if default?
145
+
146
+ tokens.each do |_node, tokens|
147
+ tokens.each(&:dispose!)
148
+ end
149
+ end
150
+
151
+ def <<(thing)
152
+ case thing
153
+ when Array
154
+ assert(WME.new(*thing))
155
+ when WME
156
+ assert(thing)
157
+ else
158
+ raise Error, "overlays can only accept data"
159
+ end
160
+ end
161
+
162
+ def assert(wme, generator: nil)
163
+ operation = [:assert, wme, { generator: generator }]
164
+ queue.push(operation)
165
+
166
+ run_queue if queue.length == 1
167
+ end
168
+
169
+ def retract(wme, options = {})
170
+ if wme.is_a?(Array)
171
+ wme = WME.new(*wme)
172
+ end
173
+
174
+ operation = [:retract, wme, options]
175
+ queue.push(operation)
176
+
177
+ run_queue if queue.length == 1
178
+ end
179
+
180
+ def run_queue
181
+ until queue.empty?
182
+ operation, wme, options = queue.shift
183
+ case operation
184
+ when :assert
185
+ wme = find_ignoring_hidden(wme) || wme
186
+ add_wme(wme, **options)
187
+ rete.real_assert(wme)
188
+ when :retract
189
+ wme = find_ignoring_hidden(wme)
190
+ return if wme.nil? # it's perhaps better to return quietly, because complicated cascades may delete a WME while we're going through the queue
191
+
192
+ remove_wme(wme, **options)
193
+ rete.real_retract(wme)
194
+ end
195
+ end
196
+ end
197
+
198
+ def default?
199
+ self == rete.default_overlay
200
+ end
201
+
202
+ # TODO: this is inconsistent.
203
+ # A WME retracted in-flight will be visible in active enumerators
204
+ # but a token will not.
205
+ # But this is how it works.
206
+
207
+ # def wmes(template)
208
+ # DuplicatingEnumerator.new(index(template))
209
+ # end
210
+
211
+ # def tokens(beta)
212
+ # DeleteSafeEnumerator.new(raw_tokens(beta))
213
+ # end
214
+
215
+ def find(wme)
216
+ if wme.is_a?(Array)
217
+ wme = WME.new(*wme)
218
+ end
219
+ find_wme(wme)
220
+ end
221
+
222
+ def select(*args)
223
+ case args.length
224
+ when 1
225
+ case args.first
226
+ when Template
227
+ select_by_template(args.first)
228
+ else
229
+ raise ArgumentError
230
+ end
231
+ when 3
232
+ select_by_template(Template.new(*args))
233
+ else
234
+ raise ArgumentError
235
+ end
236
+ end
237
+
238
+ def manual?(wme)
239
+ wme_manual.key?(wme.object_id) ||
240
+ if parent
241
+ parent.manual?(wme) && !hidden_parent_wme_manual.key?(wme.object_id)
242
+ end
243
+ end
244
+
245
+ def generated?(wme)
246
+ generators(wme).any?
247
+ end
248
+
249
+ def generated_by?(wme, gen)
250
+ own_generated_by?(wme, gen) ||
251
+ if parent
252
+ parent.generated_by?(wme, gen) && !hidden_parent_wme_generators.key?(gen)
253
+ else
254
+ false
255
+ end
256
+ end
257
+
258
+ private def own_generated_by?(wme, gen)
259
+ wme_generators.key?(wme.object_id) && wme_generators[wme.object_id].include?(gen)
260
+ end
261
+
262
+ def generators(wme)
263
+ own_generators = wme_generators.key?(wme.object_id) ? wme_generators[wme.object_id] : []
264
+ parent_generators =
265
+ if parent
266
+ parent.generators(wme).reject { |g| hidden_parent_wme_generators.key?(g) }
267
+ else
268
+ []
269
+ end
270
+ own_generators + parent_generators
271
+ end
272
+
273
+ private def own_manual?(wme)
274
+ wme_manual.key?(wme.object_id)
275
+ end
276
+
277
+ private def own_generated?(wme)
278
+ wme_generators.key?(wme.object_id) && wme_generators[wme.object_id].any?
279
+ end
280
+
281
+ private def find_wme(wme)
282
+ find_own_wme(wme) || find_parents_wme(wme)
283
+ end
284
+
285
+ private def find_own_wme(wme)
286
+ collections = indexes.map { |index|
287
+ index.collection_for_wme(wme)
288
+ }
289
+ smallest = collections.min_by(&:size)
290
+ smallest.find { _1 == wme }
291
+ end
292
+
293
+ private def find_parents_wme(wme)
294
+ return unless parent
295
+
296
+ parent_wme = parent.find(wme)
297
+ parent_wme unless hidden_wme?(parent_wme)
298
+ end
299
+
300
+ def find_ignoring_hidden(wme)
301
+ find_own_wme(wme) ||
302
+ if parent
303
+ parent.find_ignoring_hidden(wme)
304
+ end
305
+ end
306
+
307
+ private def select_by_template(template)
308
+ select_parents_template(template) + select_own_template(template)
309
+ end
310
+
311
+ private def select_own_template(template)
312
+ if template.concrete?
313
+ wme = find_own_wme(WME.from_concrete_template(template))
314
+ wme ? [wme] : []
315
+ elsif template.root?
316
+ wmes
317
+ else
318
+ indexes.map { |index|
319
+ index.collections_for_template(template)
320
+ }.compact.first
321
+ end
322
+ end
323
+
324
+ private def select_parents_template(template)
325
+ if parent
326
+ parent.select(template).reject { hidden_wme?(_1) }
327
+ else
328
+ []
329
+ end
330
+ end
331
+
332
+ private def add_wme(wme, generator:)
333
+ # p add_wme: { wme:, generator: !!generator }
334
+
335
+ # if we previously hid this locally, unhide it
336
+ hidden_parent_wmes.delete(wme.object_id)
337
+ if generator
338
+ hidden_parent_wme_generators.delete(generator)
339
+ else
340
+ hidden_parent_wme_manual.delete(wme.object_id)
341
+ end
342
+
343
+ if find_own_wme(wme)
344
+ if generator
345
+ wme_generators[wme.object_id] << generator unless own_generated_by?(wme, generator)
346
+ else
347
+ wme_manual[wme.object_id] = true
348
+ end
349
+ elsif find_parents_wme(wme)
350
+ if generator
351
+ wme_generators[wme.object_id] << generator unless generated_by?(wme, generator)
352
+ else
353
+ wme_manual[wme.object_id] = true unless manual?(wme)
354
+ end
355
+ else
356
+ wmes << wme
357
+ indexes.each { _1.add(wme) }
358
+ if generator
359
+ wme_generators[wme.object_id] << generator
360
+ else
361
+ wme_manual[wme.object_id] = true
362
+ end
363
+ end
364
+ end
365
+
366
+ private def remove_wme(wme, generator: nil)
367
+ # p remove_wme: { wme:, generator: !!generator }
368
+
369
+ if find_own_wme(wme)
370
+ if generator
371
+ if own_generated_by?(wme, generator)
372
+ wme_generators[wme.object_id].delete(generator)
373
+ wme_generators.delete(wme.object_id) if wme_generators[wme.object_id].empty?
374
+ end
375
+ elsif own_manual?(wme)
376
+ wme_manual.delete(wme.object_id)
377
+ end
378
+
379
+ if !own_generated?(wme) && !own_manual?(wme)
380
+ wmes.delete(wme)
381
+ indexes.each { _1.remove(wme) }
382
+ end
383
+
384
+ neg_join_results.remove_wme(wme)
385
+ opt_join_results.remove_wme(wme)
386
+ end
387
+
388
+ # did we also have an unshadowed parent version?
389
+ return unless find_parents_wme(wme)
390
+
391
+ # must be parents' then
392
+
393
+ if generator
394
+ # first, delete local
395
+ if own_generated_by?(wme, generator)
396
+ wme_generators[wme.object_id].delete(generator)
397
+ wme_generators.delete(wme.object_id) if wme_generators[wme.object_id].empty?
398
+ end
399
+ # if we're still generated, hide parents'
400
+ if generated_by?(wme, generator)
401
+ hidden_parent_wme_generators[generator] = true
402
+ end
403
+ else
404
+ if own_manual?(wme)
405
+ wme_manual.delete(wme.object_id)
406
+ end
407
+ if manual?(wme)
408
+ hidden_parent_wme_manual[wme.object_id] = true
409
+ end
410
+ end
411
+
412
+ if !manual?(wme) && !generated?(wme)
413
+ hidden_parent_wmes[wme.object_id] = true
414
+ end
415
+ end
416
+
417
+ def add_token(token)
418
+ # p add_token: {token:}
419
+ # TODO: is this really likely to happen? we don't normally restore deleted tokens but rather create new ones in the activation
420
+ if hidden_token?(token)
421
+ hidden_parent_tokens.delete(token.object_id)
422
+ return
423
+ end
424
+
425
+ tokens[token.node.object_id].push(token) # unless tokens.include?(token) # TODO: pretty unlikely to somehow trigger a repeated evaluation for the same token?..
426
+ end
427
+
428
+ def remove_token(token)
429
+ # p remove_token: {token:}
430
+ if own_node_tokens(token.node).find { _1.equal?(token) }.nil?
431
+ if parents_node_tokens(token.node).find { _1.equal?(token) }
432
+ hidden_parent_tokens[token.object_id] = true
433
+
434
+ # do not hide JRs from the WME side: it will be done in the alpha deactivation and the JRs have to stay visible until then
435
+ parent_neg_join_results_for(token: token).each { neg_join_results.hide(_1) }
436
+ parent_opt_join_results_for(token: token).each { opt_join_results.hide(_1) }
437
+
438
+ parent_ncc_tokens_for(token).each do |ncc|
439
+ hidden_ncc_tokens[token][ncc] = true
440
+ end
441
+ end
442
+ return
443
+ end
444
+
445
+ remove_own_token(token)
446
+ end
447
+
448
+ def remove_own_token(token)
449
+ # p remove_own_token: {token:}
450
+ tokens[token.node.object_id].delete(token)
451
+ neg_join_results.remove_token(token)
452
+ opt_join_results.remove_token(token)
453
+
454
+ # if this is an NCC partner token
455
+ if (owner = ncc_tokens_owner[token])
456
+ if ncc_tokens.key?(owner)
457
+ ncc_tokens[owner].delete(token)
458
+ end
459
+ if hidden_ncc_tokens.key?(owner)
460
+ hidden_ncc_tokens[owner].delete(token)
461
+ end
462
+ end
463
+
464
+ # if this is an NCC owner token
465
+ own_ncc_tokens_for(token).each do |ncc|
466
+ ncc_tokens_owner.delete(ncc)
467
+ end
468
+ ncc_tokens.delete(token)
469
+ hidden_ncc_tokens.delete(token)
470
+
471
+ # we know we are the owner, and nobody wants it anymore, so this is the safe place to do it
472
+ token.dispose!
473
+ end
474
+
475
+ def node_tokens(beta)
476
+ parents = parents_node_tokens(beta)
477
+ own = own_node_tokens(beta)
478
+ parents + own
479
+ end
480
+
481
+ private def own_node_tokens(beta)
482
+ tokens[beta.object_id]
483
+ end
484
+
485
+ private def parents_node_tokens(beta)
486
+ if parent
487
+ parent.node_tokens(beta).reject { hidden_parent_tokens.key?(_1.object_id) }
488
+ else
489
+ []
490
+ end
491
+ end
492
+
493
+ def add_neg_join_result(njr)
494
+ neg_join_results.add(njr)
495
+ end
496
+
497
+ def remove_neg_join_result(njr)
498
+ neg_join_results.remove(njr)
499
+ end
500
+
501
+ def neg_join_results_for(wme: nil, token: nil)
502
+ if wme
503
+ neg_join_results.for(wme: wme) + parent_neg_join_results_for(wme: wme)
504
+ elsif token
505
+ neg_join_results.for(token: token) + parent_neg_join_results_for(token: token)
506
+ else
507
+ []
508
+ end
509
+ end
510
+
511
+ def add_opt_join_result(ojr)
512
+ opt_join_results.add(ojr)
513
+ end
514
+
515
+ def remove_opt_join_result(ojr)
516
+ # p remove_opt_join_result: {ojr:}
517
+ opt_join_results.remove(ojr)
518
+ end
519
+
520
+ def opt_join_results_for(wme: nil, token: nil)
521
+ if wme
522
+ opt_join_results.for(wme: wme) + parent_opt_join_results_for(wme: wme)
523
+ elsif token
524
+ opt_join_results.for(token: token) + parent_opt_join_results_for(token: token)
525
+ else
526
+ []
527
+ end
528
+ end
529
+
530
+ private def parent_opt_join_results_for(wme: nil, token: nil)
531
+ if parent
532
+ parent.opt_join_results_for(wme: wme, token: token).reject { opt_join_results.hidden?(_1) }
533
+ else
534
+ []
535
+ end
536
+ end
537
+
538
+ private def parent_neg_join_results_for(wme: nil, token: nil)
539
+ if parent
540
+ parent.neg_join_results_for(wme: wme, token: token).reject { neg_join_results.hidden?(_1) }
541
+ else
542
+ []
543
+ end
544
+ end
545
+
546
+ def add_ncc_token(owner, ncc)
547
+ if hidden_ncc_tokens.key?(owner) && hidden_ncc_tokens[token].include?(ncc)
548
+ hidden_ncc_tokens[owner].delete(ncc)
549
+ if hidden_ncc_tokens[owner].empty?
550
+ hidden_ncc_tokens.delete(owner)
551
+ end
552
+ return
553
+ end
554
+
555
+ ncc_tokens[owner] << ncc
556
+ ncc_tokens_owner[ncc] = owner
557
+ end
558
+
559
+ def ncc_owner(ncc)
560
+ ncc_tokens_owner[ncc]
561
+ end
562
+
563
+ def ncc_tokens_for(token)
564
+ own_ncc_tokens_for(token) + parent_ncc_tokens_for(token)
565
+ end
566
+
567
+ private def own_ncc_tokens_for(token)
568
+ ncc_tokens.key?(token) ? ncc_tokens[token] : []
569
+ end
570
+
571
+ private def parent_ncc_tokens_for(token)
572
+ if parent
573
+ parent.ncc_tokens_for(token).reject { |parent_token|
574
+ hidden_ncc_tokens.key?(token) && hidden_ncc_tokens[token].key?(parent_token)
575
+ }
576
+ else
577
+ []
578
+ end
579
+ end
580
+
581
+ private def hidden_wme?(wme)
582
+ hidden_parent_wmes.key?(wme.object_id)
583
+ end
584
+
585
+ private def hidden_token?(token)
586
+ hidden_parent_tokens.key?(token.object_id)
587
+ end
588
+ end
589
+ end
@@ -1,9 +1,21 @@
1
1
  module Wongi::Engine
2
2
  Template = Struct.new(:subject, :predicate, :object) do
3
3
  def self.variable?(thing)
4
- return false unless thing.is_a?(Symbol)
4
+ thing.is_a?(Symbol) && thing[0] >= 'A' && thing[0] <= 'Z'
5
+ end
6
+
7
+ def self.placeholder?(thing)
8
+ thing.is_a?(Symbol) && thing.start_with?('_')
9
+ end
10
+
11
+ def self.concrete?(thing)
12
+ !variable?(thing) && !placeholder?(thing)
13
+ end
5
14
 
6
- thing[0] >= 'A' && thing[0] <= 'Z'
15
+ def self.match?(wme_element, template_element)
16
+ return true if variable?(template_element) || placeholder?(template_element)
17
+
18
+ wme_element == template_element
7
19
  end
8
20
 
9
21
  # TODO: reintroduce Network#import when bringing back RDF support
@@ -12,6 +24,10 @@ module Wongi::Engine
12
24
  subject == :_ && predicate == :_ && object == :_
13
25
  end
14
26
 
27
+ def concrete?
28
+ Template.concrete?(subject) && Template.concrete?(predicate) && Template.concrete?(object)
29
+ end
30
+
15
31
  def variables
16
32
  [].tap do |a|
17
33
  a << subject if Template.variable?(subject)
@@ -24,6 +40,10 @@ module Wongi::Engine
24
40
  @hash ||= [subject.hash, predicate.hash, object.hash].hash
25
41
  end
26
42
 
43
+ def eql?(other)
44
+ subject.eql?(other.subject) && predicate.eql?(other.predicate) && object.eql?(other.object)
45
+ end
46
+
27
47
  def self.hash_for(*args)
28
48
  args.map(&:hash).hash
29
49
  end
@@ -1,27 +1,15 @@
1
1
  module Wongi::Engine
2
2
  class Token
3
- include CoreExt
3
+ attr_reader :children, :wme, :node, :generated_wmes
4
+ attr_accessor :parent
4
5
 
5
- attr_reader :children, :wme, :node, :overlay, :neg_join_results, :opt_join_results, :ncc_results, :generated_wmes
6
- attr_accessor :owner, :parent
7
-
8
- attr_predicate :optional
9
- attr_predicate :deleted
10
-
11
- def initialize(node, token, wme, assignments)
6
+ def initialize(node, token, wme, assignments = {})
12
7
  @node = node
13
8
  @parent = token
14
9
  @wme = wme
15
10
  @assignments = assignments
16
- @overlay = if wme
17
- wme.overlay.highest(token.overlay)
18
- else
19
- token ? token.overlay : node.rete.default_overlay
20
- end
21
11
  @children = []
22
12
  @deleted = false
23
- @neg_join_results = []
24
- @opt_join_results = []
25
13
  @ncc_results = []
26
14
  @generated_wmes = []
27
15
  token.children << self if token
@@ -49,8 +37,6 @@ module Wongi::Engine
49
37
 
50
38
  def [](var)
51
39
  a = assignments[var]
52
- return unless a
53
-
54
40
  a.respond_to?(:call) ? a.call(self) : a
55
41
  end
56
42
 
@@ -64,8 +50,8 @@ module Wongi::Engine
64
50
  end
65
51
 
66
52
  def to_s
67
- str = "TOKEN [ #{object_id} parent=#{parent ? parent.object_id : 'nil'} "
68
- all_assignments.each_pair { |key, value| str << "#{key} => #{value} " }
53
+ str = "TOKEN [ #{object_id} ancestors=#{ancestors.map(&:object_id).map(&:to_s).join('.')} "
54
+ all_assignments.each_pair { |key, value| str << "#{key}=#{value.is_a?(TokenAssignment) ? "#{value.call} (#{value})" : value} " }
69
55
  str << "]"
70
56
  str
71
57
  end
@@ -74,15 +60,13 @@ module Wongi::Engine
74
60
  to_s
75
61
  end
76
62
 
77
- def destroy
78
- deleted!
79
- end
63
+ # def destroy
64
+ # deleted!
65
+ # end
80
66
 
81
67
  def dispose!
82
- parent.children.delete(self) if parent
83
- neg_join_results.dup.each(&:unlink)
84
- opt_join_results.dup.each(&:unlink)
85
- @parent = nil
68
+ # parent.children.delete(self) if parent
69
+ # @parent = nil
86
70
  @wme = nil
87
71
  end
88
72
 
@@ -0,0 +1,15 @@
1
+ module Wongi::Engine
2
+ TokenAssignment = Struct.new(:wme, :field) do
3
+ def call(_token = nil)
4
+ wme.send field
5
+ end
6
+
7
+ def inspect
8
+ "#{field} of #{wme}"
9
+ end
10
+
11
+ def to_s
12
+ inspect
13
+ end
14
+ end
15
+ end