wongi-engine 0.3.9 → 0.4.0.pre.alpha1

Sign up to get free protection for your applications and to get access to all the features.
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 +16 -15
  8. data/lib/wongi-engine/beta/assignment_node.rb +7 -2
  9. data/lib/wongi-engine/beta/beta_node.rb +27 -23
  10. data/lib/wongi-engine/beta/filter_node.rb +8 -13
  11. data/lib/wongi-engine/beta/join_node.rb +15 -28
  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 +23 -55
  15. data/lib/wongi-engine/beta/optional_node.rb +24 -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