mini_kraken 0.2.04 → 0.3.00
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +16 -16
- data/lib/mini_kraken/atomic/all_atomic.rb +1 -0
- data/lib/mini_kraken/atomic/atomic_term.rb +32 -17
- data/lib/mini_kraken/atomic/k_integer.rb +0 -4
- data/lib/mini_kraken/atomic/k_string.rb +17 -0
- data/lib/mini_kraken/atomic/k_symbol.rb +0 -6
- data/lib/mini_kraken/composite/all_composite.rb +4 -0
- data/lib/mini_kraken/composite/composite_term.rb +2 -18
- data/lib/mini_kraken/composite/cons_cell.rb +178 -11
- data/lib/mini_kraken/composite/cons_cell_visitor.rb +12 -64
- 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 +624 -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 +4 -30
- data/lib/mini_kraken/core/log_var_ref.rb +72 -48
- 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 +35 -69
- 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 +146 -0
- data/lib/mini_kraken/rela/conj2.rb +65 -0
- data/lib/mini_kraken/rela/def_relation.rb +64 -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 +6 -8
- data/lib/mini_kraken/rela/unify.rb +258 -0
- data/lib/mini_kraken/version.rb +1 -1
- data/spec/atomic/atomic_term_spec.rb +23 -20
- data/spec/atomic/k_symbol_spec.rb +0 -5
- data/spec/composite/cons_cell_spec.rb +116 -0
- data/spec/composite/cons_cell_visitor_spec.rb +16 -3
- data/spec/composite/list_spec.rb +50 -0
- data/spec/core/any_value_spec.rb +52 -0
- data/spec/core/arity_spec.rb +91 -0
- data/spec/core/association_copy_spec.rb +69 -0
- data/spec/core/association_spec.rb +25 -0
- data/spec/core/blackboard_spec.rb +287 -0
- data/spec/core/bookmark_spec.rb +40 -0
- data/spec/core/context_spec.rb +221 -0
- data/spec/core/core_spec.rb +40 -0
- data/spec/core/duck_fiber_spec.rb +22 -46
- data/spec/core/fail_spec.rb +5 -6
- data/spec/core/goal_spec.rb +20 -11
- data/spec/core/log_var_ref_spec.rb +80 -5
- data/spec/core/log_var_spec.rb +35 -6
- 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 +88 -99
- data/spec/glue/dsl_chap2_spec.rb +59 -41
- data/spec/glue/run_star_expression_spec.rb +69 -896
- data/spec/{core → rela}/conde_spec.rb +50 -46
- 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 +7 -0
- data/spec/support/factory_composite.rb +21 -0
- metadata +71 -48
- data/lib/mini_kraken/core/association_walker.rb +0 -183
- 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/conde.rb +0 -143
- data/lib/mini_kraken/core/conj2.rb +0 -79
- data/lib/mini_kraken/core/def_relation.rb +0 -53
- 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 -191
- 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 -102
- data/lib/mini_kraken/core/outcome.rb +0 -63
- data/lib/mini_kraken/core/tap.rb +0 -46
- data/lib/mini_kraken/core/vocabulary.rb +0 -446
- data/lib/mini_kraken/glue/fresh_env.rb +0 -108
- data/lib/mini_kraken/glue/fresh_env_factory.rb +0 -83
- data/spec/core/association_walker_spec.rb +0 -194
- data/spec/core/conj2_spec.rb +0 -116
- data/spec/core/def_relation_spec.rb +0 -99
- data/spec/core/disj2_spec.rb +0 -100
- data/spec/core/environment_spec.rb +0 -144
- data/spec/core/equals_spec.rb +0 -319
- data/spec/core/goal_template_spec.rb +0 -74
- data/spec/core/outcome_spec.rb +0 -56
- data/spec/core/vocabulary_spec.rb +0 -220
- data/spec/glue/fresh_env_factory_spec.rb +0 -99
- data/spec/glue/fresh_env_spec.rb +0 -62
@@ -1,63 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'vocabulary'
|
4
|
-
|
5
|
-
unless MiniKraken::Core.constants(false).include? :Outcome
|
6
|
-
module MiniKraken
|
7
|
-
module Core
|
8
|
-
class Outcome
|
9
|
-
include Vocabulary # Use mix-in module
|
10
|
-
|
11
|
-
# @return [Symbol] One of: :"#s" (success), :"#u" (failure)
|
12
|
-
attr_reader :resultant
|
13
|
-
|
14
|
-
def initialize(aResult, aParent = nil)
|
15
|
-
init_vocabulary(aParent)
|
16
|
-
@resultant = aResult
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.failure(aParent = nil)
|
20
|
-
new(:"#u", aParent)
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.success(aParent = nil)
|
24
|
-
new(:"#s", aParent)
|
25
|
-
end
|
26
|
-
|
27
|
-
def failure?
|
28
|
-
resultant != :"#s"
|
29
|
-
end
|
30
|
-
|
31
|
-
def success?
|
32
|
-
resultant == :"#s"
|
33
|
-
end
|
34
|
-
|
35
|
-
def ==(other)
|
36
|
-
are_equal = false
|
37
|
-
|
38
|
-
if resultant == other.resultant && parent == other.parent &&
|
39
|
-
associations == other.associations
|
40
|
-
are_equal = true
|
41
|
-
end
|
42
|
-
|
43
|
-
are_equal
|
44
|
-
end
|
45
|
-
|
46
|
-
# Remove associations of variables of this environment, if
|
47
|
-
# persistence flag is set to false.
|
48
|
-
def prune!
|
49
|
-
parent.prune(self)
|
50
|
-
end
|
51
|
-
|
52
|
-
protected
|
53
|
-
|
54
|
-
def introspect
|
55
|
-
", @resultant=#{resultant}"
|
56
|
-
end
|
57
|
-
end # class
|
58
|
-
|
59
|
-
Failure = Outcome.new(:"#u")
|
60
|
-
BasicSuccess = Outcome.new(:"#s")
|
61
|
-
end # module
|
62
|
-
end # module
|
63
|
-
end # defined
|
data/lib/mini_kraken/core/tap.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'singleton'
|
4
|
-
require_relative 'duck_fiber'
|
5
|
-
require_relative 'goal'
|
6
|
-
require_relative 'goal_relation'
|
7
|
-
require_relative 'outcome'
|
8
|
-
|
9
|
-
module MiniKraken
|
10
|
-
module Core
|
11
|
-
class Tap < GoalRelation
|
12
|
-
include Singleton
|
13
|
-
|
14
|
-
def initialize
|
15
|
-
super('tap', nil)
|
16
|
-
end
|
17
|
-
|
18
|
-
def arity
|
19
|
-
1
|
20
|
-
end
|
21
|
-
|
22
|
-
# @param actuals [Array<Term>] A two-elements array
|
23
|
-
# @param anEnv [Vocabulary] A vocabulary object
|
24
|
-
# @return [Fiber<Outcome>] A Fiber that yields Outcomes objects
|
25
|
-
def solver_for(actuals, anEnv)
|
26
|
-
args = *validated_args(actuals)
|
27
|
-
DuckFiber.new(:custom) do
|
28
|
-
outcome = tap(args.first, anEnv)
|
29
|
-
# outcome.prune!
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def tap(aGoal, anEnv)
|
34
|
-
require 'debug'
|
35
|
-
f1 = aGoal.attain(anEnv)
|
36
|
-
outcome1 = f1.resume
|
37
|
-
# key = outcome1.associations.keys.first
|
38
|
-
# outcome1.associations['x'] = outcome1.associations[key]
|
39
|
-
# outcome1.associations.delete(key)
|
40
|
-
outcome1
|
41
|
-
end
|
42
|
-
end # class
|
43
|
-
|
44
|
-
Tap.instance.freeze
|
45
|
-
end # module
|
46
|
-
end # module
|
@@ -1,446 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'set'
|
4
|
-
require_relative 'association'
|
5
|
-
require_relative 'association_walker'
|
6
|
-
|
7
|
-
module MiniKraken
|
8
|
-
module Core
|
9
|
-
module Vocabulary
|
10
|
-
# @return [Environment] Parent environment to this one.
|
11
|
-
attr_accessor :parent
|
12
|
-
|
13
|
-
# @return [Hash] Pairs of the kind {String => Array[Association]}
|
14
|
-
attr_reader :associations
|
15
|
-
|
16
|
-
# @return [Hash] Pairs of the kind {String => Integer}
|
17
|
-
attr_reader :rankings
|
18
|
-
|
19
|
-
# @param aParent [Environment, NilClass] Parent environment to this one.
|
20
|
-
def init_vocabulary(aParent = nil)
|
21
|
-
@parent = validated_parent(aParent)
|
22
|
-
@associations = {}
|
23
|
-
@rankings = {} unless aParent
|
24
|
-
end
|
25
|
-
|
26
|
-
# Return a Enumerator object that can iterate over this vocabulary and
|
27
|
-
# all its direct and indirect parent(s).
|
28
|
-
# @return [Enumerator<Vocabulary, NilClass>]
|
29
|
-
def ancestor_walker
|
30
|
-
unless @ancestors # Not yet in cache?...
|
31
|
-
@ancestors = []
|
32
|
-
relative = self
|
33
|
-
while relative
|
34
|
-
@ancestors << relative
|
35
|
-
relative = relative.parent
|
36
|
-
end
|
37
|
-
@ancestors << nil # nil marks end of iteration...
|
38
|
-
end
|
39
|
-
|
40
|
-
@ancestors.to_enum
|
41
|
-
end
|
42
|
-
|
43
|
-
def clear_rankings
|
44
|
-
walker = ancestor_walker
|
45
|
-
orphan = nil
|
46
|
-
loop do
|
47
|
-
orphan_temp = walker.next
|
48
|
-
break unless orphan_temp
|
49
|
-
|
50
|
-
orphan = orphan_temp
|
51
|
-
end
|
52
|
-
|
53
|
-
orphan.rankings&.clear
|
54
|
-
end
|
55
|
-
|
56
|
-
# @param aName [String]
|
57
|
-
# @param alternate_names [Array<String>]
|
58
|
-
def get_rank(aName, alternate_names = [])
|
59
|
-
walker = ancestor_walker
|
60
|
-
orphan = nil
|
61
|
-
loop do
|
62
|
-
orphan_temp = walker.next
|
63
|
-
break unless orphan_temp
|
64
|
-
|
65
|
-
orphan = orphan_temp
|
66
|
-
end
|
67
|
-
|
68
|
-
raise StandardError unless orphan
|
69
|
-
|
70
|
-
rank = nil
|
71
|
-
if orphan.rankings.include?(aName)
|
72
|
-
rank = orphan.rankings[aName]
|
73
|
-
else
|
74
|
-
other = alternate_names.find do |a_name|
|
75
|
-
rank = orphan.rankings.include?(a_name)
|
76
|
-
end
|
77
|
-
if other
|
78
|
-
rank = get_rank(other)
|
79
|
-
else
|
80
|
-
rank = orphan.rankings.keys.size
|
81
|
-
orphan.rankings[aName] = rank
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
rank
|
86
|
-
end
|
87
|
-
|
88
|
-
# Record an association between a variable with given user-defined name
|
89
|
-
# and a term.
|
90
|
-
# @param aName [String, Variable] A user-defined variable name
|
91
|
-
# @param aTerm [Term] A term to associate with the variable
|
92
|
-
def add_assoc(aName, aTerm)
|
93
|
-
name = aName.respond_to?(:name) ? aName.name : aName
|
94
|
-
|
95
|
-
var = name2var(name)
|
96
|
-
unless var
|
97
|
-
err_msg = "Unknown variable '#{name}'."
|
98
|
-
raise StandardError, err_msg
|
99
|
-
end
|
100
|
-
siblings = detect_fuse(var, aTerm)
|
101
|
-
if siblings.empty?
|
102
|
-
anAssociation = Association.new(var.i_name, aTerm)
|
103
|
-
do_add_assocs([anAssociation]).first
|
104
|
-
else
|
105
|
-
fuse_vars(siblings << var)
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
# Handler for the event: an outcome has been produced.
|
110
|
-
# Can be overridden in other to propagate associations from child
|
111
|
-
# @param _descendent [Outcome]
|
112
|
-
def propagate(_descendent)
|
113
|
-
# Do nothing...
|
114
|
-
end
|
115
|
-
|
116
|
-
# Remove all the associations of this vocabulary
|
117
|
-
def clear
|
118
|
-
associations.clear
|
119
|
-
end
|
120
|
-
|
121
|
-
# @param aVarName [String] A user-defined variable name
|
122
|
-
# @param other [Vocabulary]
|
123
|
-
def move_assocs(aVarName, other)
|
124
|
-
i_name = to_internal(aVarName)
|
125
|
-
assocs = other.associations[i_name]
|
126
|
-
if assocs
|
127
|
-
do_add_assocs(assocs)
|
128
|
-
other.associations.delete(i_name)
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
# Merge the associations from another vocabulary-like object.
|
133
|
-
# @param another [Vocabulary]
|
134
|
-
def merge(another)
|
135
|
-
another.associations.each_value { |assocs| do_add_assocs(assocs) }
|
136
|
-
end
|
137
|
-
|
138
|
-
# Check that the provided variable must be fused with the argument.
|
139
|
-
# @return [Array<Variable>]
|
140
|
-
def detect_fuse(aVariable, aTerm)
|
141
|
-
return [] unless aTerm.kind_of?(LogVarRef)
|
142
|
-
|
143
|
-
assocs = self[aTerm.var_name]
|
144
|
-
# Simplified implementation: cope with binary cycles only...
|
145
|
-
# TODO: Extend to n-ary (n > 2) cycles
|
146
|
-
assoc_refs = assocs.select { |a| a.value.kind_of?(LogVarRef) }
|
147
|
-
return [] if assoc_refs.empty? # No relevant association...
|
148
|
-
|
149
|
-
visitees = Set.new
|
150
|
-
to_fuse = []
|
151
|
-
to_visit = assoc_refs
|
152
|
-
loop do
|
153
|
-
assc = to_visit.shift
|
154
|
-
next if visitees.include?(assc)
|
155
|
-
|
156
|
-
visitees.add(assc)
|
157
|
-
ref = assc.value
|
158
|
-
if ref.var_name == aVariable.name
|
159
|
-
to_fuse << assc.i_name unless assc.i_name == aVariable.i_name
|
160
|
-
end
|
161
|
-
other_assocs = self[ref.var_name]
|
162
|
-
other_assoc_refs = other_assocs.select { |a| a.value.kind_of?(LogVarRef) }
|
163
|
-
other_assoc_refs.each do |a|
|
164
|
-
to_visit << a unless visitess.include?(a)
|
165
|
-
end
|
166
|
-
|
167
|
-
|
168
|
-
break if to_visit.empty?
|
169
|
-
end
|
170
|
-
|
171
|
-
to_fuse.map { |i_name| i_name2var(i_name) }
|
172
|
-
end
|
173
|
-
|
174
|
-
# Fuse the given variables:
|
175
|
-
# Collect all their associations
|
176
|
-
# Put them under a new internal name
|
177
|
-
# Remove all entries from old internal names
|
178
|
-
# For all fused variables, change internal names
|
179
|
-
# @param theVars [Array<Variable>]
|
180
|
-
def fuse_vars(theVars)
|
181
|
-
new_i_name = Object.new.object_id.to_s
|
182
|
-
fused_vars = theVars.dup
|
183
|
-
fused_vars.each do |a_var|
|
184
|
-
old_i_name = a_var.i_name
|
185
|
-
old_names = fused_vars.map(&:name)
|
186
|
-
walker = ancestor_walker
|
187
|
-
|
188
|
-
loop do
|
189
|
-
voc = walker.next
|
190
|
-
break unless voc
|
191
|
-
|
192
|
-
if voc.associations.include?(old_i_name)
|
193
|
-
assocs = voc.associations[old_i_name]
|
194
|
-
keep_assocs = assocs.reject do |assc|
|
195
|
-
assc.value.kind_of?(LogVarRef) && old_names.include?(assc.value.var_name)
|
196
|
-
end
|
197
|
-
unless keep_assocs.empty?
|
198
|
-
keep_assocs.each { |assc| assc.i_name = new_i_name }
|
199
|
-
if voc.associations.include?(new_i_name)
|
200
|
-
voc.associations[new_i_name].concat(keep_assocs)
|
201
|
-
else
|
202
|
-
voc.associations[new_i_name] = keep_assocs
|
203
|
-
end
|
204
|
-
end
|
205
|
-
voc.associations.delete(old_i_name)
|
206
|
-
end
|
207
|
-
next unless voc.respond_to?(:vars) && voc.vars.include?(a_var.name)
|
208
|
-
|
209
|
-
user_names = voc.ivars[old_i_name]
|
210
|
-
unseen = user_names.reject { |nm| old_names.include?(nm) }
|
211
|
-
unseen.each do |usr_name|
|
212
|
-
new_var = name2var(usr_name)
|
213
|
-
fused_vars << new_var
|
214
|
-
end
|
215
|
-
unless voc.ivars.include?(new_i_name)
|
216
|
-
voc.ivars[new_i_name] = user_names
|
217
|
-
else
|
218
|
-
voc.ivars[new_i_name].merge(user_names)
|
219
|
-
end
|
220
|
-
voc.ivars.delete(old_i_name)
|
221
|
-
break
|
222
|
-
end
|
223
|
-
a_var.i_name = new_i_name
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
# @param var [Variable, LogVarRef] the variable to check.
|
228
|
-
# @return [Boolean]
|
229
|
-
def fresh?(var)
|
230
|
-
ground_term = ground_value(var)
|
231
|
-
ground_term.nil? ? true : false
|
232
|
-
end
|
233
|
-
|
234
|
-
# @param var [Variable, LogVarRef] variable for which the value to retrieve
|
235
|
-
# @return [Term, NilClass]
|
236
|
-
def ground_value(var)
|
237
|
-
name = var.respond_to?(:var_name) ? var.var_name : var.name
|
238
|
-
|
239
|
-
walker = AssociationWalker.new
|
240
|
-
walker.find_ground(name, self)
|
241
|
-
end
|
242
|
-
|
243
|
-
# @param val [CompositeTerm] the composite term to check.
|
244
|
-
# @return [Boolean]
|
245
|
-
def fresh_value?(val)
|
246
|
-
walker = AssociationWalker.new
|
247
|
-
ground_term = walker.walk_value(val, self)
|
248
|
-
ground_term.nil? ? true : false
|
249
|
-
end
|
250
|
-
|
251
|
-
# A composite term is fresh when all its members are nil or all non-nil members
|
252
|
-
# are all fresh
|
253
|
-
# A composite term is bound when it is not fresh and not ground
|
254
|
-
# A composite term is a ground term when all its non-nil members are ground.
|
255
|
-
# @param aComposite [CompositeTerm]
|
256
|
-
# @return [Freshness]
|
257
|
-
def freshness_composite(aComposite)
|
258
|
-
walker = AssociationWalker.new
|
259
|
-
walker.freshness_composite(aComposite)
|
260
|
-
end
|
261
|
-
|
262
|
-
# Determine whether the reference points to a fresh, bound or ground term.
|
263
|
-
# @param aVariableRef [LogVarRef]
|
264
|
-
# @return [Freshness]
|
265
|
-
def freshness_ref(aVariableRef)
|
266
|
-
walker = AssociationWalker.new
|
267
|
-
walker.determine_freshness(aVariableRef, self)
|
268
|
-
end
|
269
|
-
|
270
|
-
# @param aVariableRef [LogVarRef]
|
271
|
-
# @return [Term, NilClass]
|
272
|
-
def quote_ref(aVariableRef)
|
273
|
-
walker = AssociationWalker.new
|
274
|
-
walker.quote_term(aVariableRef, self)
|
275
|
-
end
|
276
|
-
|
277
|
-
# Return the variable with given user-defined variable name.
|
278
|
-
# @param aName [String] User-defined variable name
|
279
|
-
def name2var(aName)
|
280
|
-
var = nil
|
281
|
-
walker = ancestor_walker
|
282
|
-
|
283
|
-
loop do
|
284
|
-
voc = walker.next
|
285
|
-
if voc
|
286
|
-
next unless voc.respond_to?(:vars) && voc.vars.include?(aName)
|
287
|
-
|
288
|
-
var = voc.vars[aName]
|
289
|
-
end
|
290
|
-
|
291
|
-
break
|
292
|
-
end
|
293
|
-
|
294
|
-
var
|
295
|
-
end
|
296
|
-
|
297
|
-
# Return the variable with given internal variable name.
|
298
|
-
# @param i_name [String] internal variable name
|
299
|
-
# @return [Variable]
|
300
|
-
def i_name2var(i_name)
|
301
|
-
var = nil
|
302
|
-
voc = nil
|
303
|
-
walker = ancestor_walker
|
304
|
-
|
305
|
-
loop do
|
306
|
-
voc = walker.next
|
307
|
-
if voc
|
308
|
-
next unless voc.respond_to?(:ivars) && voc.ivars.include?(i_name)
|
309
|
-
|
310
|
-
var_name = voc.ivars[i_name].first # TODO: what if multiple vars?
|
311
|
-
var = voc.vars[var_name]
|
312
|
-
end
|
313
|
-
|
314
|
-
break
|
315
|
-
end
|
316
|
-
|
317
|
-
raise StandardError, 'Nil variable object' if var.nil?
|
318
|
-
|
319
|
-
var
|
320
|
-
end
|
321
|
-
|
322
|
-
# Return the internal name to corresponding to a given user-defined
|
323
|
-
# variable name.
|
324
|
-
# @param aName [String] User-defined variable name
|
325
|
-
def to_internal(aName)
|
326
|
-
var = name2var(aName)
|
327
|
-
var ? var.i_name : nil
|
328
|
-
end
|
329
|
-
|
330
|
-
# Return the internal names fused with given user-defined
|
331
|
-
# variable name.
|
332
|
-
# @param aName [String] User-defined variable name
|
333
|
-
def names_fused(aName)
|
334
|
-
# require 'debug'
|
335
|
-
var = name2var(aName)
|
336
|
-
return [] unless var&.fused?
|
337
|
-
|
338
|
-
i_name = var.i_name
|
339
|
-
names = []
|
340
|
-
walker = ancestor_walker
|
341
|
-
|
342
|
-
loop do
|
343
|
-
voc = walker.next
|
344
|
-
break unless voc
|
345
|
-
next unless voc.respond_to?(:ivars)
|
346
|
-
|
347
|
-
if voc.ivars.include?(i_name)
|
348
|
-
fused = voc.ivars[i_name]
|
349
|
-
names.concat(fused.to_a)
|
350
|
-
end
|
351
|
-
end
|
352
|
-
|
353
|
-
names.uniq!
|
354
|
-
names.reject { |nm| nm == aName }
|
355
|
-
end
|
356
|
-
|
357
|
-
# Retrieve all the associations for a given variable
|
358
|
-
# @param aVariable [Variable]
|
359
|
-
# @return [Array<Association>]
|
360
|
-
def assocs4var(aVariable)
|
361
|
-
i_name = aVariable.i_name
|
362
|
-
assocs = []
|
363
|
-
walker = ancestor_walker
|
364
|
-
|
365
|
-
loop do
|
366
|
-
voc = walker.next
|
367
|
-
break unless voc
|
368
|
-
next unless voc.associations.include?(i_name)
|
369
|
-
|
370
|
-
assocs.concat(voc.associations[i_name])
|
371
|
-
end
|
372
|
-
|
373
|
-
assocs
|
374
|
-
end
|
375
|
-
|
376
|
-
# @param aName [String] User-defined variable name
|
377
|
-
# @return [Array<Association>]
|
378
|
-
def [](aName)
|
379
|
-
iname = to_internal(aName)
|
380
|
-
return [] unless iname
|
381
|
-
|
382
|
-
assoc_arr = associations[iname]
|
383
|
-
assoc_arr = [] if assoc_arr.nil?
|
384
|
-
|
385
|
-
# TODO: Optimize
|
386
|
-
assoc_arr.concat(parent[aName]) if parent
|
387
|
-
assoc_arr
|
388
|
-
end
|
389
|
-
|
390
|
-
# Check that a variable with given name is defined in this vocabulary
|
391
|
-
# or one of its ancestor.
|
392
|
-
# @param aVarName [String] A user-defined variable name.
|
393
|
-
# @return [Boolean]
|
394
|
-
def include?(aVarName)
|
395
|
-
name2var(aVarName) ? true : false
|
396
|
-
end
|
397
|
-
|
398
|
-
def prune(anOutcome)
|
399
|
-
anOutcome # Don't touch outcome
|
400
|
-
end
|
401
|
-
|
402
|
-
def inspect
|
403
|
-
result = +"#<#{self.class.name}:#{object_id.to_s(16)} @parent="
|
404
|
-
if parent
|
405
|
-
result << "#<#{parent.class.name}:#{parent.object_id.to_s(16)}>"
|
406
|
-
else
|
407
|
-
result << 'nil'
|
408
|
-
end
|
409
|
-
result << introspect
|
410
|
-
result << '>'
|
411
|
-
result
|
412
|
-
end
|
413
|
-
|
414
|
-
protected
|
415
|
-
|
416
|
-
def validated_parent(aParent)
|
417
|
-
if aParent
|
418
|
-
unless aParent.kind_of?(Vocabulary)
|
419
|
-
raise StandardError, "Invalid parent type #{aParent.class}"
|
420
|
-
end
|
421
|
-
end
|
422
|
-
|
423
|
-
aParent
|
424
|
-
end
|
425
|
-
|
426
|
-
# @param theAssociations [Array<Association>]
|
427
|
-
def do_add_assocs(theAssociations)
|
428
|
-
theAssociations.each do |assc|
|
429
|
-
i_name = assc.i_name
|
430
|
-
found_assocs = associations[i_name]
|
431
|
-
if found_assocs
|
432
|
-
found_assocs << assc
|
433
|
-
else
|
434
|
-
associations[i_name] = [assc]
|
435
|
-
end
|
436
|
-
|
437
|
-
assc
|
438
|
-
end
|
439
|
-
end
|
440
|
-
|
441
|
-
def introspect
|
442
|
-
''
|
443
|
-
end
|
444
|
-
end # class
|
445
|
-
end # module
|
446
|
-
end # module
|