mini_kraken 0.2.02 → 0.3.02
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +378 -333
- data/CHANGELOG.md +52 -0
- data/README.md +19 -19
- data/lib/mini_kraken.rb +0 -1
- data/lib/mini_kraken/atomic/all_atomic.rb +5 -0
- data/lib/mini_kraken/atomic/atomic_term.rb +96 -0
- data/lib/mini_kraken/atomic/k_boolean.rb +42 -0
- data/lib/mini_kraken/{core → atomic}/k_integer.rb +2 -5
- data/lib/mini_kraken/atomic/k_string.rb +17 -0
- data/lib/mini_kraken/{core → atomic}/k_symbol.rb +4 -8
- data/lib/mini_kraken/composite/all_composite.rb +4 -0
- data/lib/mini_kraken/composite/composite_term.rb +27 -0
- data/lib/mini_kraken/composite/cons_cell.rb +299 -0
- data/lib/mini_kraken/composite/cons_cell_visitor.rb +50 -0
- data/lib/mini_kraken/composite/list.rb +32 -0
- data/lib/mini_kraken/core/all_core.rb +8 -0
- data/lib/mini_kraken/core/any_value.rb +31 -7
- data/lib/mini_kraken/core/arity.rb +69 -0
- data/lib/mini_kraken/core/association.rb +29 -4
- data/lib/mini_kraken/core/association_copy.rb +50 -0
- data/lib/mini_kraken/core/base_term.rb +13 -0
- data/lib/mini_kraken/core/blackboard.rb +315 -0
- data/lib/mini_kraken/core/bookmark.rb +46 -0
- data/lib/mini_kraken/core/context.rb +492 -0
- data/lib/mini_kraken/core/duck_fiber.rb +21 -19
- data/lib/mini_kraken/core/entry.rb +40 -0
- data/lib/mini_kraken/core/fail.rb +20 -18
- data/lib/mini_kraken/core/fusion.rb +29 -0
- data/lib/mini_kraken/core/goal.rb +20 -29
- data/lib/mini_kraken/core/log_var.rb +22 -0
- data/lib/mini_kraken/core/log_var_ref.rb +108 -0
- data/lib/mini_kraken/core/nullary_relation.rb +2 -9
- data/lib/mini_kraken/core/parametrized_term.rb +61 -0
- data/lib/mini_kraken/core/relation.rb +14 -28
- data/lib/mini_kraken/core/scope.rb +67 -0
- data/lib/mini_kraken/core/solver_adapter.rb +58 -0
- data/lib/mini_kraken/core/specification.rb +48 -0
- data/lib/mini_kraken/core/succeed.rb +21 -17
- data/lib/mini_kraken/core/symbol_table.rb +137 -0
- data/lib/mini_kraken/core/term.rb +15 -4
- data/lib/mini_kraken/glue/dsl.rb +45 -81
- data/lib/mini_kraken/glue/run_star_expression.rb +28 -30
- data/lib/mini_kraken/rela/all_rela.rb +8 -0
- data/lib/mini_kraken/rela/binary_relation.rb +30 -0
- data/lib/mini_kraken/rela/conde.rb +143 -0
- data/lib/mini_kraken/rela/conj2.rb +65 -0
- data/lib/mini_kraken/rela/def_relation.rb +93 -0
- data/lib/mini_kraken/rela/disj2.rb +70 -0
- data/lib/mini_kraken/rela/fresh.rb +98 -0
- data/lib/mini_kraken/{core → rela}/goal_relation.rb +7 -9
- data/lib/mini_kraken/rela/unify.rb +258 -0
- data/lib/mini_kraken/version.rb +1 -1
- data/mini_kraken.gemspec +2 -2
- data/spec/.rubocop.yml +1 -1
- data/spec/atomic/atomic_term_spec.rb +98 -0
- data/spec/{core → atomic}/k_boolean_spec.rb +19 -34
- data/spec/{core → atomic}/k_symbol_spec.rb +3 -16
- data/spec/composite/cons_cell_spec.rb +225 -0
- data/spec/composite/cons_cell_visitor_spec.rb +158 -0
- data/spec/composite/list_spec.rb +50 -0
- data/spec/core/any_value_spec.rb +52 -0
- data/spec/core/arity_spec.rb +92 -0
- data/spec/core/association_copy_spec.rb +69 -0
- data/spec/core/association_spec.rb +31 -4
- data/spec/core/blackboard_spec.rb +287 -0
- data/spec/core/bookmark_spec.rb +40 -0
- data/spec/core/context_spec.rb +245 -0
- data/spec/core/core_spec.rb +40 -0
- data/spec/core/duck_fiber_spec.rb +16 -46
- data/spec/core/fail_spec.rb +5 -6
- data/spec/core/goal_spec.rb +24 -14
- data/spec/core/log_var_ref_spec.rb +105 -0
- data/spec/core/log_var_spec.rb +64 -0
- data/spec/core/nullary_relation_spec.rb +33 -0
- data/spec/core/parametrized_tem_spec.rb +39 -0
- data/spec/core/relation_spec.rb +33 -0
- data/spec/core/scope_spec.rb +73 -0
- data/spec/core/solver_adapter_spec.rb +70 -0
- data/spec/core/specification_spec.rb +43 -0
- data/spec/core/succeed_spec.rb +5 -5
- data/spec/core/symbol_table_spec.rb +142 -0
- data/spec/glue/dsl_chap1_spec.rb +96 -144
- data/spec/glue/dsl_chap2_spec.rb +350 -0
- data/spec/glue/run_star_expression_spec.rb +82 -906
- data/spec/rela/conde_spec.rb +153 -0
- data/spec/rela/conj2_spec.rb +123 -0
- data/spec/rela/def_relation_spec.rb +119 -0
- data/spec/rela/disj2_spec.rb +117 -0
- data/spec/rela/fresh_spec.rb +147 -0
- data/spec/rela/unify_spec.rb +369 -0
- data/spec/support/factory_atomic.rb +29 -0
- data/spec/support/factory_composite.rb +21 -0
- data/spec/support/factory_methods.rb +11 -26
- metadata +100 -64
- data/lib/mini_kraken/core/association_walker.rb +0 -183
- data/lib/mini_kraken/core/atomic_term.rb +0 -67
- data/lib/mini_kraken/core/base_arg.rb +0 -10
- data/lib/mini_kraken/core/binary_relation.rb +0 -63
- data/lib/mini_kraken/core/composite_goal.rb +0 -46
- data/lib/mini_kraken/core/composite_term.rb +0 -41
- data/lib/mini_kraken/core/conde.rb +0 -143
- data/lib/mini_kraken/core/conj2.rb +0 -79
- data/lib/mini_kraken/core/cons_cell.rb +0 -82
- data/lib/mini_kraken/core/def_relation.rb +0 -50
- data/lib/mini_kraken/core/designation.rb +0 -55
- data/lib/mini_kraken/core/disj2.rb +0 -72
- data/lib/mini_kraken/core/environment.rb +0 -73
- data/lib/mini_kraken/core/equals.rb +0 -156
- data/lib/mini_kraken/core/formal_arg.rb +0 -22
- data/lib/mini_kraken/core/formal_ref.rb +0 -25
- data/lib/mini_kraken/core/freshness.rb +0 -45
- data/lib/mini_kraken/core/goal_arg.rb +0 -12
- data/lib/mini_kraken/core/goal_template.rb +0 -62
- data/lib/mini_kraken/core/k_boolean.rb +0 -35
- data/lib/mini_kraken/core/outcome.rb +0 -53
- data/lib/mini_kraken/core/variable.rb +0 -41
- data/lib/mini_kraken/core/variable_ref.rb +0 -78
- data/lib/mini_kraken/core/vocabulary.rb +0 -442
- data/lib/mini_kraken/glue/fresh_env.rb +0 -75
- data/spec/core/association_walker_spec.rb +0 -192
- data/spec/core/conde_spec.rb +0 -147
- data/spec/core/conj2_spec.rb +0 -114
- data/spec/core/cons_cell_spec.rb +0 -107
- data/spec/core/def_relation_spec.rb +0 -96
- data/spec/core/disj2_spec.rb +0 -99
- data/spec/core/environment_spec.rb +0 -142
- data/spec/core/equals_spec.rb +0 -304
- data/spec/core/goal_template_spec.rb +0 -74
- data/spec/core/outcome_spec.rb +0 -48
- data/spec/core/variable_ref_spec.rb +0 -27
- data/spec/core/variable_spec.rb +0 -35
- data/spec/core/vocabulary_spec.rb +0 -219
- data/spec/glue/fresh_env_spec.rb +0 -62
@@ -4,10 +4,10 @@ require_relative '../spec_helper' # Use the RSpec framework
|
|
4
4
|
require 'ostruct'
|
5
5
|
|
6
6
|
# Load the class under test
|
7
|
-
require_relative '../../lib/mini_kraken/
|
7
|
+
require_relative '../../lib/mini_kraken/atomic/k_boolean'
|
8
8
|
|
9
9
|
module MiniKraken
|
10
|
-
module
|
10
|
+
module Atomic
|
11
11
|
describe KBoolean do
|
12
12
|
subject { KBoolean.new('#t') }
|
13
13
|
|
@@ -28,12 +28,23 @@ module MiniKraken
|
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'should know its value' do
|
31
|
-
|
32
|
-
|
31
|
+
other = KBoolean.new(true)
|
32
|
+
expect(other.value).to eq(true)
|
33
|
+
|
34
|
+
other = KBoolean.new('#t')
|
35
|
+
expect(other.value).to eq(true)
|
36
|
+
|
37
|
+
other = KBoolean.new(:"#t")
|
38
|
+
expect(other.value).to eq(true)
|
39
|
+
|
40
|
+
other = KBoolean.new(false)
|
41
|
+
expect(other.value).to eq(false)
|
42
|
+
|
43
|
+
other = KBoolean.new('#f')
|
44
|
+
expect(other.value).to eq(false)
|
33
45
|
|
34
|
-
|
35
|
-
|
36
|
-
expect(subject.ground?(env)).to be_truthy
|
46
|
+
other = KBoolean.new(:"#f")
|
47
|
+
expect(other.value).to eq(false)
|
37
48
|
end
|
38
49
|
end # context
|
39
50
|
|
@@ -43,27 +54,13 @@ module MiniKraken
|
|
43
54
|
other = KBoolean.new(true)
|
44
55
|
expect(subject).to be_eql(other)
|
45
56
|
|
46
|
-
other = KBoolean.new(:"#t")
|
47
|
-
expect(subject).to be_eql(other)
|
48
|
-
|
49
|
-
other = KBoolean.new('#t')
|
50
|
-
expect(subject).to be_eql(other)
|
51
|
-
|
52
57
|
# Same type, other value
|
53
58
|
another = KBoolean.new(false)
|
54
59
|
expect(subject).not_to be_eql(another)
|
55
60
|
|
56
|
-
# Same type, other value
|
57
|
-
another = KBoolean.new(:"#f")
|
58
|
-
expect(subject).not_to be_eql(another)
|
59
|
-
|
60
61
|
# Same type, other value
|
61
62
|
another = KBoolean.new('#f')
|
62
63
|
expect(subject).not_to be_eql(another)
|
63
|
-
|
64
|
-
# Different type, same value
|
65
|
-
yet_another = OpenStruct.new(value: true)
|
66
|
-
expect(subject).not_to be_eql(yet_another)
|
67
64
|
end
|
68
65
|
|
69
66
|
it 'should know whether it has same value than other object' do
|
@@ -71,27 +68,15 @@ module MiniKraken
|
|
71
68
|
other = KBoolean.new(true)
|
72
69
|
expect(subject == other).to be_truthy
|
73
70
|
|
74
|
-
other = KBoolean.new(:"#t")
|
75
|
-
expect(subject == other).to be_truthy
|
76
|
-
|
77
|
-
other = KBoolean.new('#t')
|
78
|
-
expect(subject == other).to be_truthy
|
79
|
-
|
80
71
|
# Same type, other value
|
81
72
|
another = KBoolean.new(false)
|
82
73
|
expect(subject == another).to be_falsy
|
83
74
|
|
84
|
-
another = KBoolean.new(:"#f")
|
85
|
-
expect(subject == another).to be_falsy
|
86
|
-
|
87
|
-
another = KBoolean.new('#f')
|
88
|
-
expect(subject == another).to be_falsy
|
89
|
-
|
90
75
|
# Same duck type, same value
|
91
76
|
yet_another = OpenStruct.new(value: true)
|
92
77
|
expect(subject == yet_another).to be_truthy
|
93
78
|
|
94
|
-
#
|
79
|
+
# Same duck type, different value
|
95
80
|
still_another = OpenStruct.new(value: false)
|
96
81
|
expect(subject == still_another).to be_falsy
|
97
82
|
|
@@ -4,10 +4,10 @@ require_relative '../spec_helper' # Use the RSpec framework
|
|
4
4
|
require 'ostruct'
|
5
5
|
|
6
6
|
# Load the class under test
|
7
|
-
require_relative '../../lib/mini_kraken/
|
7
|
+
require_relative '../../lib/mini_kraken/atomic/k_symbol'
|
8
8
|
|
9
9
|
module MiniKraken
|
10
|
-
module
|
10
|
+
module Atomic
|
11
11
|
describe KSymbol do
|
12
12
|
let(:a_value) { :pea }
|
13
13
|
subject { KSymbol.new(a_value) }
|
@@ -20,11 +20,6 @@ module MiniKraken
|
|
20
20
|
it 'should know its value' do
|
21
21
|
expect(subject.value).to eq(a_value)
|
22
22
|
end
|
23
|
-
|
24
|
-
it 'should know that it is a ground term' do
|
25
|
-
env = double('mock-env')
|
26
|
-
expect(subject.ground?(env)).to be_truthy
|
27
|
-
end
|
28
23
|
end # context
|
29
24
|
|
30
25
|
context 'Provided services:' do
|
@@ -37,7 +32,7 @@ module MiniKraken
|
|
37
32
|
another = KSymbol.new(:pod)
|
38
33
|
expect(subject).not_to be_eql(another)
|
39
34
|
|
40
|
-
# Different type, same value
|
35
|
+
# Different duck type, same value
|
41
36
|
yet_another = OpenStruct.new(value: :pea)
|
42
37
|
expect(subject).not_to be_eql(yet_another)
|
43
38
|
end
|
@@ -51,14 +46,6 @@ module MiniKraken
|
|
51
46
|
another = KSymbol.new(:pod)
|
52
47
|
expect(subject == another).to be_falsy
|
53
48
|
|
54
|
-
# Same duck type, same value
|
55
|
-
yet_another = OpenStruct.new(value: :pea)
|
56
|
-
expect(subject == yet_another).to be_truthy
|
57
|
-
|
58
|
-
# Different duck type, different value
|
59
|
-
still_another = OpenStruct.new(value: :pod)
|
60
|
-
expect(subject == still_another).to be_falsy
|
61
|
-
|
62
49
|
# Default Ruby representation, same value
|
63
50
|
expect(subject == :pea).to be_truthy
|
64
51
|
|
@@ -0,0 +1,225 @@
|
|
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/composite/cons_cell'
|
11
|
+
|
12
|
+
module MiniKraken
|
13
|
+
module Composite
|
14
|
+
describe ConsCell do
|
15
|
+
include MiniKraken::FactoryAtomic # Use mix-in module
|
16
|
+
|
17
|
+
let(:pea) { k_symbol(:pea) }
|
18
|
+
let(:pod) { k_symbol(:pod) }
|
19
|
+
let(:corn) { k_symbol(:corn) }
|
20
|
+
let(:ctx) { Core::Context.new }
|
21
|
+
subject { ConsCell.new(pea, pod) }
|
22
|
+
|
23
|
+
context 'Initialization:' do
|
24
|
+
it 'could be initialized with one argument' do
|
25
|
+
expect { ConsCell.new(pea) }.not_to raise_error
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'could be initialized with a second optional argument' do
|
29
|
+
expect { ConsCell.new(pea, pod) }.not_to raise_error
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'could be initialized as null list' do
|
33
|
+
expect { ConsCell.null }.not_to raise_error
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should know its car child' do
|
37
|
+
expect(subject.car).to eq(pea)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should know its cdr child' do
|
41
|
+
expect(subject.cdr).to eq(pod)
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
it 'should know its children' do
|
46
|
+
expect(subject.children).to eq([pea, pod])
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should know if it is empty (null)' do
|
50
|
+
expect(subject).not_to be_null
|
51
|
+
expect(ConsCell.new(nil, nil)).to be_null
|
52
|
+
expect(ConsCell.null).to be_null
|
53
|
+
expect(NullList).to be_null
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'simplifies cdr if its referencing a null list' do
|
57
|
+
instance = ConsCell.new(pea, NullList)
|
58
|
+
expect(instance.car).to eq(pea)
|
59
|
+
expect(instance.cdr).to be_nil
|
60
|
+
end
|
61
|
+
end # context
|
62
|
+
|
63
|
+
context 'Provided services:' do
|
64
|
+
it 'should compare to itself' do
|
65
|
+
expect(subject.eql?(subject)).to be_truthy
|
66
|
+
synonym = subject
|
67
|
+
expect(subject == synonym).to be_truthy
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'should compare to another instance' do
|
71
|
+
same = ConsCell.new(pea, pod)
|
72
|
+
expect(subject.eql?(same)).to be_truthy
|
73
|
+
|
74
|
+
different = ConsCell.new(pod, pea)
|
75
|
+
expect(subject.eql?(different)).to be_falsey
|
76
|
+
|
77
|
+
different = ConsCell.new(pea)
|
78
|
+
expect(subject.eql?(different)).to be_falsey
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should set_car! another cons cell' do
|
82
|
+
instance = ConsCell.new(pea)
|
83
|
+
head = ConsCell.new(pod)
|
84
|
+
instance.set_car!(head)
|
85
|
+
expect(instance.car).to eq(head)
|
86
|
+
expect(instance.cdr).to be_nil
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should set_cdr! another cons cell' do
|
90
|
+
instance = ConsCell.new(pea)
|
91
|
+
trail = ConsCell.new(pod)
|
92
|
+
instance.set_cdr!(trail)
|
93
|
+
expect(instance.car).to eq(pea)
|
94
|
+
expect(instance.cdr).to eq(trail)
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should set a member to some term' do
|
98
|
+
instance = ConsCell.null
|
99
|
+
head = ConsCell.new(pea)
|
100
|
+
trail = ConsCell.new(pod)
|
101
|
+
instance.set!(:car, head)
|
102
|
+
instance.set!(:cdr, trail)
|
103
|
+
expect(instance.car).to eq(head)
|
104
|
+
expect(instance.cdr).to eq(trail)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should know whether it is pinned or not' do
|
108
|
+
# Case: all pair members are atomic items
|
109
|
+
expect(subject).to be_pinned(ctx)
|
110
|
+
|
111
|
+
# Case: cdr is nil
|
112
|
+
instance = ConsCell.new(pea)
|
113
|
+
expect(instance).to be_pinned(ctx)
|
114
|
+
|
115
|
+
# Case: embedded composite
|
116
|
+
nested = ConsCell.new(ConsCell.new(pod, pea), ConsCell.new(pea))
|
117
|
+
expect(nested).to be_pinned(ctx)
|
118
|
+
|
119
|
+
ctx.add_vars('q')
|
120
|
+
nested.set_cdr!(Core::LogVarRef.new('q'))
|
121
|
+
expect(nested).not_to be_pinned(ctx)
|
122
|
+
expect(nested).to be_floating(ctx)
|
123
|
+
|
124
|
+
ctx.associate('q', ConsCell.new(pea))
|
125
|
+
expect(nested).to be_pinned(ctx)
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should provide a list representation of itself' do
|
129
|
+
# Case of null list
|
130
|
+
expect(NullList.to_s).to eq '()'
|
131
|
+
|
132
|
+
# Case of one element proper list
|
133
|
+
cell = ConsCell.new(pea)
|
134
|
+
expect(cell.to_s).to eq '(:pea)'
|
135
|
+
|
136
|
+
# Case of two elements proper list
|
137
|
+
cell = ConsCell.new(pea, ConsCell.new(pod))
|
138
|
+
expect(cell.to_s).to eq '(:pea :pod)'
|
139
|
+
|
140
|
+
# Case of two elements improper list
|
141
|
+
expect(subject.to_s).to eq '(:pea . :pod)'
|
142
|
+
|
143
|
+
# Case of one element plus null list
|
144
|
+
cell = ConsCell.new(pea)
|
145
|
+
cell.set_cdr!(ConsCell.null)
|
146
|
+
expect(cell.to_s).to eq '(:pea)'
|
147
|
+
|
148
|
+
# Case of three elements proper list
|
149
|
+
cell = ConsCell.new(pea, ConsCell.new(pod, ConsCell.new(corn)))
|
150
|
+
expect(cell.to_s).to eq '(:pea :pod :corn)'
|
151
|
+
|
152
|
+
# Case of three elements improper list
|
153
|
+
cell = ConsCell.new(pea, ConsCell.new(pod, corn))
|
154
|
+
expect(cell.to_s).to eq '(:pea :pod . :corn)'
|
155
|
+
|
156
|
+
# Case of a nested list
|
157
|
+
cell = ConsCell.new(ConsCell.new(pea), ConsCell.new(pod))
|
158
|
+
expect(cell.to_s).to eq '((:pea) :pod)'
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'should know its dependencies' do
|
162
|
+
# Case: no var ref...
|
163
|
+
lst = ConsCell.new(ConsCell.new(pod, pea), ConsCell.new(pea))
|
164
|
+
expect(lst.dependencies(ctx)).to be_empty
|
165
|
+
|
166
|
+
# Case: multiple var refs
|
167
|
+
ctx.add_vars(%w[q x])
|
168
|
+
q_ref = Core::LogVarRef.new('q')
|
169
|
+
x_ref = Core::LogVarRef.new('x')
|
170
|
+
list2 = ConsCell.new(ConsCell.new(q_ref, pea), ConsCell.new(x_ref))
|
171
|
+
expect(list2.dependencies(ctx).size).to eq(2)
|
172
|
+
q_var = ctx.lookup('q')
|
173
|
+
x_var = ctx.lookup('x')
|
174
|
+
predicted = Set.new([q_var.i_name, x_var.i_name])
|
175
|
+
expect(list2.dependencies(ctx)).to eq(predicted)
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'should, as list with atomic terms, provide an expanded copy' do
|
179
|
+
# Case of a list of atomic terms
|
180
|
+
lst = ConsCell.new(ConsCell.new(ConsCell.new(pea), pod))
|
181
|
+
representation = lst.to_s
|
182
|
+
|
183
|
+
copy = lst.expand(ctx, {})
|
184
|
+
expect(copy.to_s).to eq(representation)
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'should, as list with variable refs, provide an expanded copy' do
|
188
|
+
# Case of a list of variable refs
|
189
|
+
ctx.add_vars(['x'])
|
190
|
+
x_ref = Core::LogVarRef.new('x')
|
191
|
+
x_var = ctx.lookup('x')
|
192
|
+
ctx.associate('x', Core::AnyValue.new(0))
|
193
|
+
lst = ConsCell.new(x_ref, ConsCell.new(x_ref))
|
194
|
+
substitutions = {}
|
195
|
+
substitutions[x_var.i_name] = Core::AnyValue.new(0)
|
196
|
+
|
197
|
+
copy = lst.expand(ctx, substitutions)
|
198
|
+
expect(copy.to_s).to eq('(_0 _0)')
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'should provide a duplicate with variable replaced by their value' do
|
202
|
+
q_ref = Core::LogVarRef.new('q')
|
203
|
+
x_ref = Core::LogVarRef.new('x')
|
204
|
+
y_ref = Core::LogVarRef.new('y')
|
205
|
+
substitutions = {
|
206
|
+
'q' => ConsCell.new(pea, ConsCell.new(x_ref, y_ref)),
|
207
|
+
'x' => pod,
|
208
|
+
'y' => corn
|
209
|
+
}
|
210
|
+
|
211
|
+
# Basic case: variable ref points to an atomic value
|
212
|
+
expr = ConsCell.new(pea, x_ref)
|
213
|
+
duplicate = expr.dup_cond(substitutions)
|
214
|
+
expect(duplicate.to_s).to eq('(:pea . :pod)')
|
215
|
+
|
216
|
+
expr = ConsCell.new(pod, ConsCell.new(q_ref, y_ref))
|
217
|
+
duplicate = expr.dup_cond(substitutions)
|
218
|
+
expect(duplicate.car).to eq(pod)
|
219
|
+
expect(duplicate.cdr.car.to_s).to eq('(:pea :pod . :corn)')
|
220
|
+
expect(duplicate.to_s).to eq('(:pod (:pea :pod . :corn) . :corn)')
|
221
|
+
end
|
222
|
+
end # context
|
223
|
+
end # describe
|
224
|
+
end # module
|
225
|
+
end # module
|
@@ -0,0 +1,158 @@
|
|
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
|
+
|
7
|
+
# Load the class under test
|
8
|
+
require_relative '../../lib/mini_kraken/composite/cons_cell_visitor'
|
9
|
+
|
10
|
+
module MiniKraken
|
11
|
+
module Composite
|
12
|
+
describe ConsCellVisitor do
|
13
|
+
include MiniKraken::FactoryAtomic # Use mix-in module
|
14
|
+
|
15
|
+
let(:pea) { k_symbol(:pea) }
|
16
|
+
let(:pod) { k_symbol(:pod) }
|
17
|
+
let(:corn) { k_symbol(:corn) }
|
18
|
+
let(:ref_q) { LogVarRef.new('q') }
|
19
|
+
let(:l_pea) { ConsCell.new(pea) }
|
20
|
+
let(:l_pea_pod) { ConsCell.new(pea, ConsCell.new(pod)) }
|
21
|
+
let(:l_pea_pod_corn) { ConsCell.new(pea, ConsCell.new(pod, ConsCell.new(corn))) }
|
22
|
+
subject { ConsCellVisitor }
|
23
|
+
|
24
|
+
context 'Provided services:' do
|
25
|
+
it 'acts as a factory of Fiber objects' do
|
26
|
+
expect(subject.df_visitor(l_pea)).to be_kind_of(Fiber)
|
27
|
+
end
|
28
|
+
end # context
|
29
|
+
|
30
|
+
context 'proper list visiting:' do
|
31
|
+
it 'can visit a null list' do
|
32
|
+
null_list = ConsCell.null
|
33
|
+
visitor = subject.df_visitor(null_list)
|
34
|
+
expect(visitor.resume).to eq([:car, null_list])
|
35
|
+
expect(visitor.resume).to eq([:car, nil])
|
36
|
+
expect(visitor.resume).to eq([:cdr, nil])
|
37
|
+
expect(visitor.resume).to eq([:stop, nil])
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'can visit a single element proper list' do
|
41
|
+
visitor = subject.df_visitor(l_pea)
|
42
|
+
expect(visitor.resume).to eq([:car, l_pea])
|
43
|
+
expect(visitor.resume).to eq([:car, pea])
|
44
|
+
expect(visitor.resume).to eq([:cdr, nil])
|
45
|
+
expect(visitor.resume).to eq([:stop, nil])
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'can visit a two elements proper list' do
|
49
|
+
visitor = subject.df_visitor(l_pea_pod)
|
50
|
+
expect(visitor.resume).to eq([:car, l_pea_pod])
|
51
|
+
expect(visitor.resume).to eq([:car, pea])
|
52
|
+
expect(visitor.resume).to eq([:cdr, l_pea_pod.cdr])
|
53
|
+
expect(visitor.resume).to eq([:car, pod])
|
54
|
+
expect(visitor.resume).to eq([:cdr, nil])
|
55
|
+
expect(visitor.resume).to eq([:stop, nil])
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'can visit a three elements proper list' do
|
59
|
+
visitor = subject.df_visitor(l_pea_pod_corn)
|
60
|
+
expect(visitor.resume).to eq([:car, l_pea_pod_corn])
|
61
|
+
expect(visitor.resume).to eq([:car, pea])
|
62
|
+
expect(visitor.resume).to eq([:cdr, l_pea_pod_corn.cdr])
|
63
|
+
expect(visitor.resume).to eq([:car, pod])
|
64
|
+
expect(visitor.resume).to eq([:cdr, l_pea_pod_corn.cdr.cdr])
|
65
|
+
expect(visitor.resume).to eq([:car, corn])
|
66
|
+
expect(visitor.resume).to eq([:cdr, nil])
|
67
|
+
expect(visitor.resume).to eq([:stop, nil])
|
68
|
+
end
|
69
|
+
end # context
|
70
|
+
|
71
|
+
context 'improper list visiting:' do
|
72
|
+
it 'can visit a single element improper list' do
|
73
|
+
l_improper = ConsCell.new(nil, pea)
|
74
|
+
visitor = subject.df_visitor(l_improper)
|
75
|
+
expect(visitor.resume).to eq([:car, l_improper])
|
76
|
+
expect(visitor.resume).to eq([:car, nil])
|
77
|
+
expect(visitor.resume).to eq([:cdr, pea])
|
78
|
+
expect(visitor.resume).to eq([:stop, nil])
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'can visit a two elements improper list' do
|
82
|
+
l_improper = ConsCell.new(pea, pod)
|
83
|
+
visitor = subject.df_visitor(l_improper)
|
84
|
+
expect(visitor.resume).to eq([:car, l_improper])
|
85
|
+
expect(visitor.resume).to eq([:car, pea])
|
86
|
+
expect(visitor.resume).to eq([:cdr, pod])
|
87
|
+
expect(visitor.resume).to eq([:stop, nil])
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'can visit a three elements improper list' do
|
91
|
+
l_improper = ConsCell.new(pea, ConsCell.new(pod, corn))
|
92
|
+
expect(l_improper.to_s).to eq('(:pea :pod . :corn)')
|
93
|
+
visitor = subject.df_visitor(l_improper)
|
94
|
+
expect(visitor.resume).to eq([:car, l_improper])
|
95
|
+
expect(visitor.resume).to eq([:car, pea])
|
96
|
+
expect(visitor.resume).to eq([:cdr, l_improper.cdr])
|
97
|
+
expect(visitor.resume).to eq([:car, pod])
|
98
|
+
expect(visitor.resume).to eq([:cdr, corn])
|
99
|
+
expect(visitor.resume).to eq([:stop, nil])
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'smurch' do
|
103
|
+
composite = ConsCell.new(ConsCell.new(ConsCell.new(pea)), pod)
|
104
|
+
visitor = subject.df_visitor(composite)
|
105
|
+
expect(visitor.resume).to eq([:car, composite])
|
106
|
+
expect(visitor.resume).to eq([:car, composite.car])
|
107
|
+
expect(visitor.resume).to eq([:car, composite.car.car])
|
108
|
+
expect(visitor.resume).to eq([:car, pea])
|
109
|
+
expect(visitor.resume).to eq([:cdr, nil])
|
110
|
+
expect(visitor.resume).to eq([:cdr, nil])
|
111
|
+
expect(visitor.resume).to eq([:cdr, pod])
|
112
|
+
end
|
113
|
+
end # context
|
114
|
+
|
115
|
+
context 'Skip visit of children of a ConsCell:' do
|
116
|
+
it 'can skip the visit of null list children' do
|
117
|
+
null_list = ConsCell.new(nil)
|
118
|
+
visitor = subject.df_visitor(null_list)
|
119
|
+
|
120
|
+
# Tell to skip children by passing a true value to resume
|
121
|
+
expect(visitor.resume(true)).to eq([:car, null_list])
|
122
|
+
expect(visitor.resume).to eq([:stop, nil])
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'can skip the visit of some children' do
|
126
|
+
tree = ConsCell.new(pea, ConsCell.new(l_pea_pod, ConsCell.new(corn)))
|
127
|
+
expect(tree.to_s).to eq('(:pea (:pea :pod) :corn)')
|
128
|
+
visitor = subject.df_visitor(tree)
|
129
|
+
expect(visitor.resume).to eq([:car, tree])
|
130
|
+
expect(visitor.resume).to eq([:car, pea])
|
131
|
+
expect(visitor.resume).to eq([:cdr, tree.cdr])
|
132
|
+
expect(visitor.resume).to eq([:car, l_pea_pod])
|
133
|
+
|
134
|
+
# Tell to skip children by passing a true value to resume
|
135
|
+
expect(visitor.resume(true)).to eq([:cdr, tree.cdr.cdr])
|
136
|
+
expect(visitor.resume).to eq([:car, corn])
|
137
|
+
expect(visitor.resume).to eq([:cdr, nil])
|
138
|
+
expect(visitor.resume).to eq([:stop, nil])
|
139
|
+
end
|
140
|
+
end # context
|
141
|
+
|
142
|
+
context 'Circular structures visiting:' do
|
143
|
+
it 'should cope with a circular graph' do
|
144
|
+
second_cell = ConsCell.new(pea)
|
145
|
+
first_cell = ConsCell.new(pea, second_cell)
|
146
|
+
second_cell.set_car!(first_cell)
|
147
|
+
|
148
|
+
visitor = subject.df_visitor(first_cell)
|
149
|
+
expect(visitor.resume).to eq([:car, first_cell])
|
150
|
+
expect(visitor.resume).to eq([:car, pea])
|
151
|
+
expect(visitor.resume).to eq([:cdr, second_cell])
|
152
|
+
expect(visitor.resume).to eq([:cdr, nil]) # Skip car (was already visited)
|
153
|
+
expect(visitor.resume).to eq([:stop, nil])
|
154
|
+
end
|
155
|
+
end # context
|
156
|
+
end # describe
|
157
|
+
end # module
|
158
|
+
end # module
|