mini_kraken 0.2.03 → 0.3.03

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 (136) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +378 -333
  3. data/CHANGELOG.md +48 -0
  4. data/README.md +29 -21
  5. data/lib/mini_kraken/atomic/all_atomic.rb +5 -0
  6. data/lib/mini_kraken/atomic/atomic_term.rb +96 -0
  7. data/lib/mini_kraken/atomic/k_boolean.rb +42 -0
  8. data/lib/mini_kraken/{core → atomic}/k_integer.rb +2 -5
  9. data/lib/mini_kraken/atomic/k_string.rb +17 -0
  10. data/lib/mini_kraken/{core → atomic}/k_symbol.rb +4 -8
  11. data/lib/mini_kraken/composite/all_composite.rb +4 -0
  12. data/lib/mini_kraken/composite/composite_term.rb +27 -0
  13. data/lib/mini_kraken/composite/cons_cell.rb +301 -0
  14. data/lib/mini_kraken/composite/cons_cell_visitor.rb +50 -0
  15. data/lib/mini_kraken/composite/list.rb +32 -0
  16. data/lib/mini_kraken/core/all_core.rb +8 -0
  17. data/lib/mini_kraken/core/any_value.rb +31 -7
  18. data/lib/mini_kraken/core/arity.rb +69 -0
  19. data/lib/mini_kraken/core/association.rb +29 -4
  20. data/lib/mini_kraken/core/association_copy.rb +50 -0
  21. data/lib/mini_kraken/core/base_term.rb +13 -0
  22. data/lib/mini_kraken/core/blackboard.rb +315 -0
  23. data/lib/mini_kraken/core/bookmark.rb +46 -0
  24. data/lib/mini_kraken/core/context.rb +492 -0
  25. data/lib/mini_kraken/core/duck_fiber.rb +21 -19
  26. data/lib/mini_kraken/core/entry.rb +40 -0
  27. data/lib/mini_kraken/core/fail.rb +20 -18
  28. data/lib/mini_kraken/core/fusion.rb +29 -0
  29. data/lib/mini_kraken/core/goal.rb +20 -29
  30. data/lib/mini_kraken/core/log_var.rb +22 -0
  31. data/lib/mini_kraken/core/log_var_ref.rb +108 -0
  32. data/lib/mini_kraken/core/nullary_relation.rb +2 -9
  33. data/lib/mini_kraken/core/parametrized_term.rb +68 -0
  34. data/lib/mini_kraken/core/relation.rb +14 -28
  35. data/lib/mini_kraken/core/scope.rb +67 -0
  36. data/lib/mini_kraken/core/solver_adapter.rb +58 -0
  37. data/lib/mini_kraken/core/specification.rb +48 -0
  38. data/lib/mini_kraken/core/succeed.rb +21 -17
  39. data/lib/mini_kraken/core/symbol_table.rb +137 -0
  40. data/lib/mini_kraken/core/term.rb +15 -4
  41. data/lib/mini_kraken/glue/dsl.rb +44 -88
  42. data/lib/mini_kraken/glue/run_star_expression.rb +28 -30
  43. data/lib/mini_kraken/rela/all_rela.rb +8 -0
  44. data/lib/mini_kraken/rela/binary_relation.rb +30 -0
  45. data/lib/mini_kraken/rela/conde.rb +143 -0
  46. data/lib/mini_kraken/rela/conj2.rb +65 -0
  47. data/lib/mini_kraken/rela/def_relation.rb +93 -0
  48. data/lib/mini_kraken/rela/disj2.rb +70 -0
  49. data/lib/mini_kraken/rela/fresh.rb +98 -0
  50. data/lib/mini_kraken/{core → rela}/goal_relation.rb +7 -9
  51. data/lib/mini_kraken/rela/unify.rb +265 -0
  52. data/lib/mini_kraken/version.rb +1 -1
  53. data/mini_kraken.gemspec +2 -2
  54. data/spec/.rubocop.yml +1 -1
  55. data/spec/atomic/atomic_term_spec.rb +98 -0
  56. data/spec/{core → atomic}/k_boolean_spec.rb +19 -34
  57. data/spec/{core → atomic}/k_symbol_spec.rb +3 -16
  58. data/spec/composite/cons_cell_spec.rb +225 -0
  59. data/spec/{core → composite}/cons_cell_visitor_spec.rb +36 -20
  60. data/spec/composite/list_spec.rb +50 -0
  61. data/spec/core/any_value_spec.rb +52 -0
  62. data/spec/core/arity_spec.rb +92 -0
  63. data/spec/core/association_copy_spec.rb +69 -0
  64. data/spec/core/association_spec.rb +31 -4
  65. data/spec/core/blackboard_spec.rb +287 -0
  66. data/spec/core/bookmark_spec.rb +40 -0
  67. data/spec/core/context_spec.rb +245 -0
  68. data/spec/core/core_spec.rb +40 -0
  69. data/spec/core/duck_fiber_spec.rb +16 -46
  70. data/spec/core/fail_spec.rb +5 -6
  71. data/spec/core/goal_spec.rb +22 -12
  72. data/spec/core/log_var_ref_spec.rb +105 -0
  73. data/spec/core/log_var_spec.rb +64 -0
  74. data/spec/core/nullary_relation_spec.rb +33 -0
  75. data/spec/core/parametrized_tem_spec.rb +39 -0
  76. data/spec/core/relation_spec.rb +33 -0
  77. data/spec/core/scope_spec.rb +73 -0
  78. data/spec/core/solver_adapter_spec.rb +70 -0
  79. data/spec/core/specification_spec.rb +43 -0
  80. data/spec/core/succeed_spec.rb +5 -5
  81. data/spec/core/symbol_table_spec.rb +142 -0
  82. data/spec/glue/dsl_chap1_spec.rb +88 -144
  83. data/spec/glue/dsl_chap2_spec.rb +454 -19
  84. data/spec/glue/run_star_expression_spec.rb +81 -906
  85. data/spec/rela/conde_spec.rb +153 -0
  86. data/spec/rela/conj2_spec.rb +123 -0
  87. data/spec/rela/def_relation_spec.rb +119 -0
  88. data/spec/rela/disj2_spec.rb +117 -0
  89. data/spec/rela/fresh_spec.rb +147 -0
  90. data/spec/rela/unify_spec.rb +369 -0
  91. data/spec/support/factory_atomic.rb +29 -0
  92. data/spec/support/factory_composite.rb +21 -0
  93. data/spec/support/factory_methods.rb +11 -26
  94. metadata +98 -70
  95. data/lib/mini_kraken/core/association_walker.rb +0 -183
  96. data/lib/mini_kraken/core/atomic_term.rb +0 -67
  97. data/lib/mini_kraken/core/base_arg.rb +0 -10
  98. data/lib/mini_kraken/core/binary_relation.rb +0 -63
  99. data/lib/mini_kraken/core/composite_goal.rb +0 -46
  100. data/lib/mini_kraken/core/composite_term.rb +0 -41
  101. data/lib/mini_kraken/core/conde.rb +0 -143
  102. data/lib/mini_kraken/core/conj2.rb +0 -79
  103. data/lib/mini_kraken/core/cons_cell.rb +0 -82
  104. data/lib/mini_kraken/core/cons_cell_visitor.rb +0 -102
  105. data/lib/mini_kraken/core/def_relation.rb +0 -53
  106. data/lib/mini_kraken/core/designation.rb +0 -55
  107. data/lib/mini_kraken/core/disj2.rb +0 -72
  108. data/lib/mini_kraken/core/environment.rb +0 -73
  109. data/lib/mini_kraken/core/equals.rb +0 -193
  110. data/lib/mini_kraken/core/formal_arg.rb +0 -22
  111. data/lib/mini_kraken/core/formal_ref.rb +0 -25
  112. data/lib/mini_kraken/core/freshness.rb +0 -45
  113. data/lib/mini_kraken/core/goal_arg.rb +0 -12
  114. data/lib/mini_kraken/core/goal_template.rb +0 -102
  115. data/lib/mini_kraken/core/k_boolean.rb +0 -35
  116. data/lib/mini_kraken/core/outcome.rb +0 -63
  117. data/lib/mini_kraken/core/variable.rb +0 -41
  118. data/lib/mini_kraken/core/variable_ref.rb +0 -84
  119. data/lib/mini_kraken/core/vocabulary.rb +0 -446
  120. data/lib/mini_kraken/glue/fresh_env.rb +0 -103
  121. data/lib/mini_kraken/glue/fresh_env_factory.rb +0 -83
  122. data/spec/core/association_walker_spec.rb +0 -192
  123. data/spec/core/conde_spec.rb +0 -147
  124. data/spec/core/conj2_spec.rb +0 -114
  125. data/spec/core/cons_cell_spec.rb +0 -107
  126. data/spec/core/def_relation_spec.rb +0 -97
  127. data/spec/core/disj2_spec.rb +0 -99
  128. data/spec/core/environment_spec.rb +0 -142
  129. data/spec/core/equals_spec.rb +0 -317
  130. data/spec/core/goal_template_spec.rb +0 -74
  131. data/spec/core/outcome_spec.rb +0 -56
  132. data/spec/core/variable_ref_spec.rb +0 -30
  133. data/spec/core/variable_spec.rb +0 -35
  134. data/spec/core/vocabulary_spec.rb +0 -219
  135. data/spec/glue/fresh_env_factory_spec.rb +0 -97
  136. data/spec/glue/fresh_env_spec.rb +0 -62
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require_relative '../support/factory_atomic'
5
+
6
+ # Load the class under test
7
+ require_relative '../../lib/mini_kraken/composite/list'
8
+
9
+ module MiniKraken
10
+ module Composite
11
+ describe List do
12
+ include MiniKraken::FactoryAtomic # Use mix-in module
13
+
14
+ let(:pea) { k_symbol(:pea) }
15
+ let(:pod) { k_symbol(:pod) }
16
+ let(:corn) { k_symbol(:corn) }
17
+
18
+ context 'Module as a factory:' do
19
+ subject { List }
20
+
21
+ it 'builds a pair wiht one argument (= one element proper list)' do
22
+ pair = subject.cons(pea)
23
+ expect(pair.car).to eq(pea)
24
+ expect(pair.cdr).to be_nil
25
+ end
26
+
27
+ it 'builds a pair with two explicit arguments' do
28
+ pair = subject.cons(pea, pod)
29
+ expect(pair.car).to eq(pea)
30
+ expect(pair.cdr).to eq(pod)
31
+ end
32
+
33
+ it 'builds a null list from an empty array' do
34
+ l = subject.make_list([])
35
+ expect(l).to be_kind_of(ConsCell)
36
+ expect(l).to be_null
37
+ end
38
+
39
+ it 'builds a proper list from an non-empty array' do
40
+ l = subject.make_list([pea, pod, corn])
41
+
42
+ expect(l.car).to eq(pea)
43
+ expect(l.cdr.car).to eq(pod)
44
+ expect(l.cdr.cdr.car).to eq(corn)
45
+ expect(l.cdr.cdr.cdr).to be_nil
46
+ end
47
+ end # context
48
+ end # describz
49
+ end # module
50
+ end # module
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+
5
+ # Load the class under test
6
+ require_relative '../../lib/mini_kraken/core/any_value'
7
+
8
+
9
+ module MiniKraken
10
+ module Core
11
+ describe AnyValue do
12
+ let(:some_rank) { 2 }
13
+ subject { AnyValue.new(some_rank) }
14
+
15
+ context 'Initialization:' do
16
+ it "should be initialized with a variable's rank" do
17
+ expect { AnyValue.new(0) }.not_to raise_error
18
+ end
19
+
20
+ it 'should know its rank' do
21
+ expect(subject.rank).to eq(some_rank)
22
+ end
23
+ end # context
24
+
25
+ context 'Provided services:' do
26
+ it 'should compare itself to another instance' do
27
+ expect(subject == AnyValue.new(some_rank)).to be_truthy
28
+ expect(subject == AnyValue.new(1)).to be_falsey
29
+ end
30
+
31
+ it 'should compare itself to an integer' do
32
+ expect(subject == some_rank).to be_truthy
33
+ expect(subject == 1).to be_falsey
34
+ end
35
+
36
+ it 'should compare itself to a symbol' do
37
+ expect(subject == :_2).to be_truthy
38
+ expect(subject == :_1).to be_falsey
39
+ end
40
+
41
+ it 'should know its text representation' do
42
+ expect(subject.to_s).to eq('_2')
43
+ end
44
+
45
+ it 'should know that it represents a non-pinned variable' do
46
+ ctx = double('dummy-context')
47
+ expect(subject).not_to be_pinned(ctx)
48
+ end
49
+ end
50
+ end # describe
51
+ end # module
52
+ end # module
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+
5
+ # Load the class under test
6
+ require_relative '../../lib/mini_kraken/core/arity'
7
+
8
+ module MiniKraken
9
+ module Core
10
+ describe Arity do
11
+ subject { Arity.new(0, 1) }
12
+
13
+ context 'Initialization:' do
14
+ it 'should be initialized with two integers' do
15
+ expect { Arity.new(0, 1) }.not_to raise_error
16
+ end
17
+
18
+ it 'should know its lower bound' do
19
+ expect(subject.low).to eq(0)
20
+ end
21
+
22
+ it 'should know its upper bound' do
23
+ expect(subject.high).to eq(1)
24
+ end
25
+ end # context
26
+
27
+ context 'Initialization:' do
28
+ it 'should know whether is is nullary' do
29
+ expect(subject).not_to be_nullary
30
+
31
+ instance = Arity.new(0, '*')
32
+ expect(instance).not_to be_nullary
33
+
34
+ instance = Arity.new(0, 0)
35
+ expect(instance).to be_nullary
36
+ end
37
+
38
+ it 'should know whether is is unary' do
39
+ expect(subject).not_to be_unary
40
+
41
+ instance = Arity.new(1, 2)
42
+ expect(instance).not_to be_unary
43
+
44
+ instance = Arity.new(1, 1)
45
+ expect(instance).to be_unary
46
+ end
47
+
48
+ it 'should know whether is is binary' do
49
+ expect(subject).not_to be_binary
50
+
51
+ instance = Arity.new(1, 2)
52
+ expect(instance).not_to be_binary
53
+
54
+ instance = Arity.new(2, 2)
55
+ expect(instance).to be_binary
56
+ end
57
+
58
+ it 'should know whether is is variadic' do
59
+ expect(subject).not_to be_variadic
60
+
61
+ instance = Arity.new(1, '*')
62
+ expect(instance).to be_variadic
63
+ end
64
+
65
+ it 'should know whether an integer fits the arity range' do
66
+ expect(subject.match?(0)).to be_truthy
67
+ expect(subject.match?(1)).to be_truthy
68
+ expect(subject.match?(2)).to be_falsey
69
+
70
+ instance = Arity.new(2, '*')
71
+ expect(instance.match?(1)).to be_falsey
72
+ expect(instance.match?(2)).to be_truthy
73
+ expect(instance.match?(42)).to be_truthy
74
+ end
75
+
76
+ it 'should know whether is equal to another arity' do
77
+ itself = subject # Renaming as workaround to Rubocop complaint
78
+ expect(subject == itself).to be_truthy
79
+
80
+ same = Arity.new(0, 1)
81
+ expect(subject == same).to be_truthy
82
+
83
+ same_low = Arity.new(0, 2)
84
+ expect(subject == same_low).to be_falsey
85
+
86
+ same_high = Arity.new(1, 1)
87
+ expect(subject == same_high).to be_falsey
88
+ end
89
+ end # context
90
+ end # describe
91
+ end # module
92
+ end # module
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require_relative '../support/factory_atomic'
5
+ require_relative '../../lib/mini_kraken/core/context'
6
+ require_relative '../../lib/mini_kraken/core/log_var'
7
+ require_relative '../../lib/mini_kraken/core/log_var_ref'
8
+
9
+ # Load the class under test
10
+ require_relative '../../lib/mini_kraken/core/association_copy'
11
+
12
+ module MiniKraken
13
+ module Core
14
+ describe AssociationCopy do
15
+ include MiniKraken::FactoryAtomic # Use mix-in module
16
+
17
+ let(:pea) { k_symbol(:pea) }
18
+ let(:q_assoc) { Association.new('q', pea) }
19
+ subject { AssociationCopy.new('q_x', q_assoc) }
20
+
21
+ context 'Initialization:' do
22
+ it 'should be initialized with a name and an association' do
23
+ expect { AssociationCopy.new('q_x', q_assoc) }.not_to raise_error
24
+ end
25
+
26
+ it 'should be initialized with a variable and an association' do
27
+ q_x_var = LogVar.new('q_x')
28
+ expect { AssociationCopy.new(q_x_var, q_assoc) }.not_to raise_error
29
+ end
30
+
31
+ it 'should know the internal variable name' do
32
+ expect(subject.i_name).to eq('q_x')
33
+ end
34
+
35
+ it 'should know the associated value' do
36
+ expect(subject.value).to eq(pea)
37
+ end
38
+ end # context
39
+
40
+ context 'Provided services:' do
41
+ let(:ctx) { Context.new }
42
+
43
+ it 'should tell whether the associated value is pinned' do
44
+ ctx.add_vars(%w[q x q_x])
45
+ expect(subject).to be_pinned(ctx)
46
+
47
+ a = Association.new(ctx.lookup('q'), LogVarRef.new('x'))
48
+ instance = AssociationCopy.new(ctx.lookup('q_x'), a)
49
+ expect(instance).not_to be_pinned(ctx)
50
+ end
51
+
52
+ it 'should tell whether the associated value is floating' do
53
+ ctx.add_vars(%w[q x q_x])
54
+
55
+ expect(subject).not_to be_floating(ctx)
56
+ end
57
+
58
+ it 'should retrieve the dependencies in its value' do
59
+ expect(subject.dependencies(ctx)).to be_empty
60
+
61
+ ctx.add_vars(%w[q x q_x])
62
+ a = Association.new(ctx.lookup('q'), LogVarRef.new('x'))
63
+ instance = AssociationCopy.new(ctx.lookup('q_x'), a)
64
+ expect(instance.dependencies(ctx).size).to eq(1)
65
+ end
66
+ end # context
67
+ end # describe
68
+ end # module
69
+ end # module
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../spec_helper' # Use the RSpec framework
4
- require_relative '../../lib/mini_kraken/core/k_symbol'
5
- require_relative '../../lib/mini_kraken/core/variable'
4
+ require_relative '../support/factory_atomic'
5
+ require_relative '../../lib/mini_kraken/core/context'
6
+ require_relative '../../lib/mini_kraken/core/log_var'
7
+ require_relative '../../lib/mini_kraken/core/log_var_ref'
6
8
 
7
9
  # Load the class under test
8
10
  require_relative '../../lib/mini_kraken/core/association'
@@ -10,7 +12,9 @@ require_relative '../../lib/mini_kraken/core/association'
10
12
  module MiniKraken
11
13
  module Core
12
14
  describe Association do
13
- let(:pea) { KSymbol.new(:pea) }
15
+ include MiniKraken::FactoryAtomic # Use mix-in module
16
+
17
+ let(:pea) { k_symbol(:pea) }
14
18
  subject { Association.new('q', pea) }
15
19
 
16
20
  context 'Initialization:' do
@@ -19,7 +23,7 @@ module MiniKraken
19
23
  end
20
24
 
21
25
  it 'should be initialized with a variable and a value' do
22
- expect { Association.new(Variable.new('p'), pea) }.not_to raise_error
26
+ expect { Association.new(LogVar.new('p'), pea) }.not_to raise_error
23
27
  end
24
28
 
25
29
  it 'should know the variable name' do
@@ -32,6 +36,29 @@ module MiniKraken
32
36
  end # context
33
37
 
34
38
  context 'Provided services:' do
39
+ let(:ctx) { Context.new }
40
+
41
+ it 'should tell whether the associated value is pinned' do
42
+ ctx.add_vars(%w[q x])
43
+
44
+ expect(subject).to be_pinned(ctx)
45
+ instance = Association.new(ctx.lookup('q'), LogVarRef.new('x'))
46
+ expect(instance).not_to be_pinned(ctx)
47
+ end
48
+
49
+ it 'should tell whether the associated value is floating' do
50
+ ctx.add_vars(%w[q x])
51
+
52
+ expect(subject).not_to be_floating(ctx)
53
+ end
54
+
55
+ it 'should retrieve the dependencies in its value' do
56
+ expect(subject.dependencies(ctx)).to be_empty
57
+
58
+ ctx.add_vars(%w[q x])
59
+ instance = Association.new(ctx.lookup('q'), LogVarRef.new('x'))
60
+ expect(instance.dependencies(ctx).size).to eq(1)
61
+ end
35
62
  end # context
36
63
  end # describe
37
64
  end # module
@@ -0,0 +1,287 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spec_helper' # Use the RSpec framework
4
+ require_relative '../support/factory_atomic'
5
+ require_relative '../../lib/mini_kraken/core/log_var_ref'
6
+ require_relative '../../lib/mini_kraken/core/scope'
7
+ require_relative '../../lib/mini_kraken/composite/cons_cell'
8
+
9
+ # Load the class under test
10
+ require_relative '../../lib/mini_kraken/core/blackboard'
11
+
12
+ module MiniKraken
13
+ module Core
14
+ describe Blackboard do
15
+ include MiniKraken::FactoryAtomic # Use mix-in module
16
+ subject { Blackboard.new }
17
+
18
+ context 'Initialization:' do
19
+ it 'should be initialized without argument' do
20
+ expect { Blackboard.new }.not_to raise_error
21
+ end
22
+
23
+ it "shouldn't have internal name entry at initialization" do
24
+ expect(subject.i_name2moves).to be_empty
25
+ end
26
+
27
+ it 'should have an empty association queue at initialization' do
28
+ expect(subject.move_queue).to be_empty
29
+ end
30
+
31
+ it 'should be empty at initialization' do
32
+ expect(subject).to be_empty
33
+ end
34
+
35
+ it 'should be ready to assign a serial number' do
36
+ expect(subject.next_serial_num).to be_zero
37
+ end
38
+
39
+ it 'should have its resultant attribute un-initialized' do
40
+ expect(subject.resultant).to be_nil
41
+ end
42
+ end # context
43
+
44
+ context 'Provided services:' do
45
+ let(:a_ser_num) { 42 }
46
+ let(:pea) { k_symbol(:pea) }
47
+ let(:pod) { k_symbol(:pod) }
48
+ let(:x_assoc) { Core::Association.new('x', pea) }
49
+ let(:y_assoc) { Core::Association.new('y', pod) }
50
+ let(:z_assoc) { Core::Association.new('z', pea) }
51
+
52
+ def var_ref(aName)
53
+ LogVarRef.new(aName)
54
+ end
55
+
56
+ def cons(car, cdr = nil)
57
+ Composite::ConsCell.new(car, cdr)
58
+ end
59
+
60
+ it 'should allow the enqueuing of one association' do
61
+ expect { subject.enqueue_association(x_assoc) }.not_to raise_error
62
+ expect(subject.i_name2moves).not_to be_empty
63
+ expect(subject.move_queue).not_to be_empty
64
+ expect(subject.i_name2moves['x']).to be_kind_of(Array)
65
+ expect(subject.i_name2moves['x'].first).to eq(0)
66
+ expect(subject.last_move).to eq(x_assoc)
67
+ end
68
+
69
+ it 'should allow the enqueuing of multiple associations' do
70
+ expect(subject.enqueue_association(x_assoc)).to eq(x_assoc)
71
+ expect { subject.enqueue_association(y_assoc) }.not_to raise_error
72
+ expect(subject.i_name2moves.size).to eq(2)
73
+ expect(subject.move_queue.size).to eq(2)
74
+ expect(subject.i_name2moves['y']).to be_kind_of(Array)
75
+ expect(subject.i_name2moves['y'].first).to eq(1)
76
+ expect(subject.last_move).to eq(y_assoc)
77
+ end
78
+
79
+ it 'should allow the enqueuing of multiple associations for same i_name' do
80
+ subject.enqueue_association(x_assoc)
81
+
82
+ x_assoc_b = Core::Association.new('x', double('something'))
83
+ expect { subject.enqueue_association(x_assoc_b) }.not_to raise_error
84
+ expect(subject.i_name2moves.size).to eq(1)
85
+ expect(subject.move_queue.size).to eq(2)
86
+ expect(subject.i_name2moves['x']).to be_kind_of(Array)
87
+ expect(subject.i_name2moves['x'].size).to eq(2)
88
+ expect(subject.i_name2moves['x'].last).to eq(1)
89
+ expect(subject.move_queue.pop).to eq(x_assoc_b)
90
+ end
91
+
92
+ it 'should allow the removal of the association at TOS position' do
93
+ subject.enqueue_association(x_assoc)
94
+ x_assoc_b = Core::Association.new('x', double('something'))
95
+ subject.enqueue_association(x_assoc_b)
96
+ expect(subject.move_queue.size).to eq(2)
97
+ expect(subject.i_name2moves.size).to eq(1)
98
+
99
+ expect { subject.send(:dequeue_item) }.not_to raise_error
100
+ expect(subject.move_queue.size).to eq(1)
101
+ expect(subject.i_name2moves.size).to eq(1)
102
+
103
+ subject.send(:dequeue_item)
104
+ expect(subject.move_queue).to be_empty
105
+ expect(subject.i_name2moves).to be_empty
106
+ end
107
+
108
+ it 'should allow the enqueuing of a backtrack bookmark' do
109
+ subject.enqueue_association(x_assoc)
110
+
111
+ expect { subject.place_bt_point }.not_to raise_error
112
+ expect(subject.i_name2moves.size).to eq(1)
113
+ expect(subject.move_queue.size).to eq(2)
114
+ expect(subject.i_name2moves['x']).to be_kind_of(Array)
115
+ expect(subject.i_name2moves['x'].size).to eq(1)
116
+ expect(subject.last_move).to be_kind_of(Bookmark)
117
+ end
118
+
119
+ it 'should allow the enqueuing of a scope bookmark' do
120
+ subject.enqueue_association(x_assoc)
121
+
122
+ expect { subject.enter_scope }.not_to raise_error
123
+ expect(subject.i_name2moves.size).to eq(1)
124
+ expect(subject.move_queue.size).to eq(2)
125
+ expect(subject.i_name2moves['x']).to be_kind_of(Array)
126
+ expect(subject.i_name2moves['x'].size).to eq(1)
127
+ expect(subject.last_move).to be_kind_of(Bookmark)
128
+ end
129
+
130
+ it 'should allow the fusion of two unbound variables' do
131
+ q_var = LogVar.new('q')
132
+ x_var = LogVar.new('x')
133
+ q_x_var = LogVar.new('q_x')
134
+ fusion = Fusion.new(q_x_var.i_name, [q_var.i_name, x_var.i_name])
135
+ pre_size = subject.move_queue.size
136
+ subject.enqueue_fusion(fusion)
137
+
138
+ expect(subject.move_queue.size).to eq(pre_size + 1)
139
+ expect(subject.i_name2moves).to be_include(q_x_var.i_name)
140
+ expect(subject.vars2cv[q_var.i_name]).to eq(q_x_var.i_name)
141
+ expect(subject.vars2cv[x_var.i_name]).to eq(q_x_var.i_name)
142
+ end
143
+
144
+ it 'should allow the fusion of one unbound and one floating variable' do
145
+ q_var = LogVar.new('q')
146
+ x_var = LogVar.new('x')
147
+ assoc_x = Association.new('x', cons(LogVarRef.new('y'), pea))
148
+ subject.enqueue_association(assoc_x)
149
+ q_x_var = LogVar.new('q_x')
150
+ fusion = Fusion.new(q_x_var.i_name, [q_var.i_name, x_var.i_name])
151
+ pre_size = subject.move_queue.size
152
+
153
+ subject.enqueue_fusion(fusion)
154
+ expect(subject.move_queue.size).to eq(pre_size + 2)
155
+ expect(subject.i_name2moves).to be_include(q_x_var.i_name)
156
+ indices = subject.i_name2moves[q_x_var.i_name]
157
+ expect(indices.size).to eq(2) # 2 = 1 Fusion + 1 AssocCopy
158
+ new_assoc = subject.move_queue[indices.last]
159
+ expect(new_assoc.value).to eq(assoc_x.value)
160
+ end
161
+
162
+ it 'should allow the fusion of two floating variables' do
163
+ q_var = LogVar.new('q')
164
+ x_var = LogVar.new('x')
165
+ assoc_q = Association.new('x', cons(pod, var_ref('z')))
166
+ subject.enqueue_association(assoc_q)
167
+ assoc_x = Association.new('x', cons(var_ref('y'), pea))
168
+ subject.enqueue_association(assoc_x)
169
+ q_x_var = LogVar.new('q_x')
170
+ fusion = Fusion.new(q_x_var.i_name, [q_var.i_name, x_var.i_name])
171
+ pre_size = subject.move_queue.size
172
+
173
+ subject.enqueue_fusion(fusion)
174
+ expect(subject.move_queue.size).to eq(pre_size + 3)
175
+ expect(subject.i_name2moves).to be_include(q_x_var.i_name)
176
+ indices = subject.i_name2moves[q_x_var.i_name]
177
+ expect(indices.size).to eq(3)
178
+ new_move1 = subject.move_queue[indices[0]]
179
+ expect(new_move1).to be_kind_of(Core::Fusion)
180
+ new_move2 = subject.move_queue[indices[1]]
181
+ expect(new_move2.value).to eq(assoc_q.value)
182
+ new_move3 = subject.move_queue[indices[2]]
183
+ expect(new_move3.value).to eq(assoc_x.value)
184
+ end
185
+
186
+ it 'should allow the removal of a fusion object at TOS position' do
187
+ q_var = LogVar.new('q')
188
+ x_var = LogVar.new('x')
189
+ q_x_var = LogVar.new('q_x')
190
+ fusion = Fusion.new(q_x_var.i_name, [q_var.i_name, x_var.i_name])
191
+ pre_size = subject.move_queue.size
192
+ subject.enqueue_fusion(fusion)
193
+
194
+ expect(subject.move_queue.size).to eq(pre_size + 1)
195
+ expect(subject.i_name2moves).to be_include(q_x_var.i_name)
196
+ expect(subject.vars2cv[q_var.i_name]).to eq(q_x_var.i_name)
197
+ expect(subject.vars2cv[x_var.i_name]).to eq(q_x_var.i_name)
198
+
199
+ expect { subject.send(:dequeue_item) }.not_to raise_error
200
+ expect(subject.move_queue.size).to eq(pre_size)
201
+ expect(subject.i_name2moves).not_to be_include(q_x_var.i_name)
202
+ expect(subject.vars2cv[q_var.i_name]).to be_nil
203
+ expect(subject.vars2cv[x_var.i_name]).to be_nil
204
+ end
205
+
206
+ it 'should retrieve association for a given i_name (0 fusion)' do
207
+ subject.enqueue_association(x_assoc)
208
+ subject.enqueue_association(y_assoc)
209
+
210
+ x_assoc_b = Core::Association.new('x', double('something'))
211
+ subject.enqueue_association(x_assoc_b)
212
+ expect(subject.associations_for('z')).to be_empty
213
+ expect(subject.associations_for('y').size).to eq(1)
214
+ expect(subject.associations_for('x').size).to eq(2)
215
+ expect(subject.associations_for('x').last).to eq(x_assoc_b)
216
+ end
217
+
218
+ it 'should retrieve association for a given i_name (1 fusion)' do
219
+ subject.enqueue_association(x_assoc)
220
+ expect(subject.associations_for('x').size).to eq(1)
221
+ expect(subject.associations_for('z').size).to eq(0)
222
+ expect(subject.associations_for('z', true).size).to eq(0)
223
+
224
+ x_z_var = LogVar.new('x_z')
225
+ fusion = Fusion.new(x_z_var.i_name, %w[x z])
226
+ subject.enqueue_fusion(fusion)
227
+ expect(subject.associations_for('z', true).size).to eq(1)
228
+ x_z_assoc = Core::Association.new(x_z_var.i_name, var_ref('y'))
229
+ subject.enqueue_association(x_z_assoc)
230
+ expect(subject.associations_for('z', false).size).to eq(0)
231
+ expect(subject.associations_for('z', true).size).to eq(2)
232
+ expect(subject.associations_for('x', false).size).to eq(1)
233
+ expect(subject.associations_for('x', true).size).to eq(2)
234
+ end
235
+
236
+ it 'should accept the succeeded notification' do
237
+ subject.enqueue_association(x_assoc)
238
+ subject.enqueue_association(y_assoc)
239
+ subject.succeeded!
240
+ expect(subject).to be_success
241
+ expect(subject.move_queue.size).to eq(2)
242
+ end
243
+
244
+ it 'should accept the failed notification in absence of bookmarks' do
245
+ subject.enqueue_association(x_assoc)
246
+ subject.enqueue_association(y_assoc)
247
+ subject.failed!
248
+ expect(subject).to be_failure
249
+ expect(subject.move_queue).to be_empty
250
+ expect(subject.i_name2moves).to be_empty
251
+ end
252
+
253
+ it 'should accept the failed notification with backtrack' do
254
+ x_assoc2 = Core::Association.new('x', pea)
255
+
256
+ subject.enqueue_association(x_assoc)
257
+ subject.enqueue_association(y_assoc)
258
+ subject.place_bt_point
259
+ subject.enqueue_association(z_assoc)
260
+ subject.enqueue_association(x_assoc2)
261
+ expect(subject.i_name2moves['x'].size).to eq(2)
262
+
263
+ subject.failed!
264
+ expect(subject.resultant).to eq(:"#u")
265
+ expect(subject.last_move).to be_kind_of(Core::Bookmark)
266
+ expect(subject.i_name2moves.include?('z')).to be_falsey
267
+ expect(subject.i_name2moves['x'].size).to eq(1)
268
+ end
269
+
270
+ it 'should accept the failed notification on a bookmark' do
271
+ subject.enqueue_association(x_assoc)
272
+ subject.enqueue_association(y_assoc)
273
+ subject.place_bt_point # Backtrack point bookmark added...
274
+
275
+ subject.enqueue_association(z_assoc)
276
+ subject.enter_scope # Scope bookmark
277
+
278
+ expect(subject.move_queue.size).to eq(5)
279
+
280
+ subject.failed!
281
+ expect(subject.resultant).to eq(:"#u")
282
+ expect(subject.move_queue.size).to eq(3) # 3 = 2 assocs + 1 bookmark
283
+ end
284
+ end # context
285
+ end # describe
286
+ end # module
287
+ end # module