rubylog 0.0.1 → 1.0.0
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.
- data/Gemfile +1 -1
- data/README.hu.rb +58 -0
- data/README.rdoc +248 -89
- data/Rakefile +6 -1
- data/VERSION +1 -1
- data/bin/rubylog +18 -0
- data/examples/dcg.rb +35 -0
- data/examples/dcg2.rb +42 -0
- data/examples/enumerators.rb +30 -0
- data/examples/factorial.rb +9 -8
- data/examples/hanoi.rb +24 -0
- data/examples/hello.rb +11 -5
- data/examples/parsing.rb +27 -0
- data/examples/primitives.rb +24 -0
- data/examples/theory.rb +22 -10
- data/lib/rubylog/builtins/default.rb +10 -0
- data/lib/rubylog/builtins/file_system.rb +15 -0
- data/lib/rubylog/builtins/logic.rb +109 -0
- data/lib/rubylog/builtins/reflection.rb +94 -0
- data/lib/rubylog/builtins/term.rb +47 -0
- data/lib/rubylog/dsl/array_splat.rb +25 -0
- data/lib/rubylog/dsl/primitives.rb +17 -0
- data/lib/rubylog/dsl/thats.rb +22 -0
- data/lib/rubylog/dsl/variables.rb +30 -0
- data/lib/rubylog/dsl.rb +35 -17
- data/lib/rubylog/errors.rb +19 -1
- data/lib/rubylog/interfaces/assertable.rb +16 -0
- data/lib/rubylog/interfaces/callable.rb +18 -0
- data/lib/rubylog/interfaces/composite_term.rb +47 -0
- data/lib/rubylog/interfaces/predicate.rb +8 -0
- data/lib/rubylog/interfaces/procedure.rb +60 -0
- data/lib/rubylog/interfaces/term.rb +41 -0
- data/lib/rubylog/mixins/array.rb +118 -0
- data/lib/{class.rb → rubylog/mixins/class.rb} +2 -2
- data/lib/rubylog/mixins/hash.rb +8 -0
- data/lib/rubylog/mixins/kernel.rb +5 -0
- data/lib/rubylog/mixins/method.rb +3 -0
- data/lib/rubylog/mixins/object.rb +8 -0
- data/lib/rubylog/mixins/proc.rb +37 -0
- data/lib/rubylog/mixins/string.rb +104 -0
- data/lib/rubylog/mixins/symbol.rb +44 -0
- data/lib/rubylog/simple_procedure.rb +8 -0
- data/lib/rubylog/{clause.rb → structure.rb} +32 -31
- data/lib/rubylog/theory.rb +368 -79
- data/lib/rubylog/variable.rb +102 -23
- data/lib/rubylog.rb +33 -25
- data/logic/builtins/file_system_logic.rb +23 -0
- data/logic/builtins/reflection_logic.rb +40 -0
- data/logic/dereference_logic.rb +23 -0
- data/logic/directory_structure_logic.rb +19 -0
- data/logic/dsl_logic.rb +29 -0
- data/logic/errors_logic.rb +9 -0
- data/logic/guard_logic.rb +115 -0
- data/logic/list_logic.rb +55 -0
- data/logic/map_logic.rb +15 -0
- data/logic/multitheory.rb +23 -0
- data/logic/recursion_logic.rb +12 -0
- data/logic/string_logic.rb +41 -0
- data/logic/thats_logic.rb +51 -0
- data/logic/variable_logic.rb +24 -0
- data/rubylog.gemspec +85 -46
- data/spec/bartak_guide_spec.rb +57 -62
- data/spec/builtins/all_spec.rb +99 -0
- data/spec/builtins/and_spec.rb +22 -0
- data/spec/builtins/array_spec.rb +16 -0
- data/spec/builtins/branch_or_spec.rb +27 -0
- data/spec/builtins/cut_spec.rb +44 -0
- data/spec/builtins/fail_spec.rb +5 -0
- data/spec/builtins/false_spec.rb +5 -0
- data/spec/builtins/in_spec.rb +38 -0
- data/spec/builtins/is_false_spec.rb +12 -0
- data/spec/builtins/is_spec.rb +26 -0
- data/spec/builtins/matches_spec.rb +23 -0
- data/spec/builtins/or_spec.rb +22 -0
- data/spec/{rubylog/builtins → builtins}/splits_to.rb +0 -0
- data/spec/builtins/then_spec.rb +27 -0
- data/spec/builtins/true_spec.rb +5 -0
- data/spec/clause_spec.rb +82 -0
- data/spec/compilation_spec.rb +61 -0
- data/spec/custom_classes_spec.rb +43 -0
- data/spec/dereference.rb +10 -0
- data/spec/{inriasuite.rb → inriasuite_spec.rb} +2 -9
- data/spec/queries_spec.rb +150 -0
- data/spec/recursion_spec.rb +4 -4
- data/spec/ruby_code_spec.rb +52 -0
- data/spec/rules_spec.rb +97 -0
- data/spec/spec_helper.rb +6 -2
- data/spec/theory_spec.rb +28 -0
- data/spec/unification_spec.rb +84 -0
- data/spec/variable_spec.rb +26 -0
- metadata +153 -180
- data/examples/4queens.rb +0 -10
- data/examples/calculation.rb +0 -12
- data/examples/concepts.rb +0 -46
- data/examples/fp.rb +0 -56
- data/examples/historia_de_espana.rb +0 -31
- data/examples/idea.rb +0 -143
- data/examples/lists.rb +0 -5
- data/examples/mechanika.rb +0 -409
- data/examples/parse.rb +0 -15
- data/lib/array.rb +0 -24
- data/lib/method.rb +0 -4
- data/lib/object.rb +0 -5
- data/lib/proc.rb +0 -4
- data/lib/rubylog/builtins.rb +0 -193
- data/lib/rubylog/callable.rb +0 -20
- data/lib/rubylog/composite_term.rb +0 -38
- data/lib/rubylog/dsl/constants.rb +0 -15
- data/lib/rubylog/dsl/first_order_functors.rb +0 -9
- data/lib/rubylog/dsl/global_functors.rb +0 -3
- data/lib/rubylog/dsl/second_order_functors.rb +0 -8
- data/lib/rubylog/internal_helpers.rb +0 -16
- data/lib/rubylog/predicate.rb +0 -34
- data/lib/rubylog/proc_method_additions.rb +0 -69
- data/lib/rubylog/term.rb +0 -20
- data/lib/rubylog/unifiable.rb +0 -19
- data/lib/symbol.rb +0 -35
- data/script/inriasuite2spec +0 -0
- data/script/inriasuite2spec.pl +0 -22
- data/spec/rubylog/clause_spec.rb +0 -81
- data/spec/rubylog/variable_spec.rb +0 -25
- data/spec/rubylog_spec.rb +0 -914
data/lib/rubylog/theory.rb
CHANGED
@@ -1,133 +1,422 @@
|
|
1
1
|
module Rubylog
|
2
|
-
|
2
|
+
|
3
|
+
# @return [Rubylog::Theory] the current theory
|
4
|
+
def self.current_theory
|
5
|
+
Thread.current[:rubylog_current_theory]
|
6
|
+
end
|
7
|
+
|
8
|
+
# Create a new Rubylog theory or modify an existing one.
|
9
|
+
#
|
10
|
+
# You can create theories with the theory method, which is available from
|
11
|
+
# anywhere:
|
12
|
+
# theory "MyTheory" do
|
13
|
+
# # ...
|
14
|
+
# end
|
15
|
+
def self.theory full_name=nil, *args, &block
|
16
|
+
case full_name
|
17
|
+
when nil
|
18
|
+
theory = Rubylog::Theory.new
|
19
|
+
when Rubylog::Theory
|
20
|
+
theory=full_name
|
21
|
+
else
|
22
|
+
names = full_name.to_s.split("::")
|
23
|
+
parent_names, name = names[0...-1], names[-1]
|
24
|
+
parent = parent_names.inject(block.binding.eval("Module.nesting[0]") || Object) {|a,b| a.const_get b}
|
25
|
+
|
26
|
+
if not parent.const_defined?(name)
|
27
|
+
theory = Rubylog::Theory.new *args
|
28
|
+
parent.const_set name, theory
|
29
|
+
else
|
30
|
+
theory = parent.const_get name
|
31
|
+
raise TypeError, "#{name} is not a theory" unless theory.is_a? Rubylog::Theory
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
theory.amend &block
|
36
|
+
theory
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
# The Theory class represents a collection of rules.
|
42
|
+
class Rubylog::Theory
|
43
|
+
|
44
|
+
|
45
|
+
include Rubylog::DSL::Variables
|
46
|
+
|
47
|
+
# Call the given block with variables automatically resolved
|
48
|
+
def self.with_vars vars
|
49
|
+
begin
|
50
|
+
old_vars = Thread.current[:rubylog_current_variables]
|
51
|
+
Thread.current[:rubylog_current_variables] = vars
|
52
|
+
yield
|
53
|
+
ensure
|
54
|
+
Thread.current[:rubylog_current_variables] = old_vars
|
55
|
+
end
|
3
56
|
end
|
4
57
|
|
5
|
-
|
6
|
-
|
58
|
+
attr_reader :public_interface, :included_theories, :prefix_functor_modules
|
59
|
+
|
60
|
+
def initialize base=Rubylog::DefaultBuiltins, &block
|
61
|
+
clear
|
62
|
+
include base if base
|
63
|
+
|
64
|
+
if block
|
65
|
+
with_context &block
|
66
|
+
end
|
7
67
|
end
|
8
68
|
|
9
|
-
|
10
|
-
|
69
|
+
def [] indicator
|
70
|
+
@database[indicator]
|
71
|
+
end
|
72
|
+
|
73
|
+
def []= indicator, predicate
|
74
|
+
@database[indicator] = predicate
|
75
|
+
end
|
11
76
|
|
12
|
-
|
13
|
-
|
77
|
+
def keys
|
78
|
+
@database.keys
|
79
|
+
end
|
80
|
+
|
81
|
+
def each_pair
|
82
|
+
if block_given?
|
83
|
+
@database.each_pair {|*a| yield *a }
|
84
|
+
else
|
85
|
+
@database.each_pair
|
14
86
|
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Clear all data in the theory and bring it to its initial state.
|
90
|
+
def clear
|
91
|
+
@database = {}
|
92
|
+
@primitives = Rubylog::DSL::Primitives.new self
|
93
|
+
@variable_bindings = []
|
94
|
+
@public_interface = Module.new
|
95
|
+
@subjects = []
|
96
|
+
@trace = false
|
97
|
+
@implicit = false
|
98
|
+
@check_discontiguous = true
|
99
|
+
@included_theories = []
|
100
|
+
@check_number = 0
|
101
|
+
@prefix_functor_modules = []
|
102
|
+
end
|
103
|
+
|
104
|
+
def primitives
|
105
|
+
@primitives
|
106
|
+
end
|
107
|
+
private :primitives
|
108
|
+
|
109
|
+
def with_context &block
|
110
|
+
begin
|
111
|
+
# save current theory
|
112
|
+
old_theory = Thread.current[:rubylog_current_theory]
|
113
|
+
Thread.current[:rubylog_current_theory] = self
|
114
|
+
|
115
|
+
# start implicit mode
|
116
|
+
if @implicit
|
117
|
+
start_implicit
|
118
|
+
end
|
15
119
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
120
|
+
# call the block
|
121
|
+
return instance_exec &block
|
122
|
+
ensure
|
123
|
+
# restore current theory
|
124
|
+
Thread.current[:rubylog_current_theory] = old_theory
|
125
|
+
|
126
|
+
# stop implicit mode
|
127
|
+
if @implicit_started
|
128
|
+
stop_implicit
|
129
|
+
end
|
23
130
|
end
|
131
|
+
end
|
132
|
+
|
133
|
+
alias amend with_context
|
134
|
+
alias eval with_context
|
24
135
|
|
25
|
-
|
26
|
-
|
136
|
+
|
137
|
+
# directives
|
138
|
+
#
|
139
|
+
def predicate *indicators
|
140
|
+
indicators.each do |indicator|
|
141
|
+
check_indicator indicator
|
142
|
+
create_procedure indicator
|
27
143
|
end
|
144
|
+
end
|
28
145
|
|
29
|
-
|
30
|
-
|
146
|
+
def discontiguous *indicators
|
147
|
+
indicators.each do |indicator|
|
148
|
+
check_indicator indicator
|
149
|
+
create_procedure(indicator).discontiguous!
|
31
150
|
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def check_discontiguous value = true
|
154
|
+
@check_discontiguous = value
|
155
|
+
end
|
156
|
+
|
157
|
+
def check_discontiguous?
|
158
|
+
@check_discontiguous
|
159
|
+
end
|
32
160
|
|
161
|
+
def multitheory *indicators
|
162
|
+
indicators.each do |indicator|
|
163
|
+
check_indicator indicator
|
164
|
+
create_procedure(indicator).multitheory!
|
165
|
+
end
|
166
|
+
end
|
33
167
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
168
|
+
def functor *functors
|
169
|
+
functors.each do |fct|
|
170
|
+
Rubylog::DSL.add_functors_to @public_interface, fct
|
171
|
+
@subjects.each do |s|
|
172
|
+
Rubylog::DSL.add_functors_to s, fct
|
39
173
|
end
|
40
174
|
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def prefix_functor *functors
|
178
|
+
functors.each do |fct|
|
179
|
+
m = Module.new
|
180
|
+
Rubylog::DSL.add_prefix_functors_to m, fct
|
181
|
+
@prefix_functor_modules << m
|
182
|
+
extend m
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def functor_for target, *functors
|
187
|
+
functors.each do |fct|
|
188
|
+
Rubylog::DSL.add_functors_to target, fct
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def private *indicators
|
193
|
+
end
|
194
|
+
|
195
|
+
def subject *subjects
|
196
|
+
subjects.each do |s|
|
197
|
+
s.send :include, @public_interface
|
198
|
+
@subjects << s
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def include *theories
|
203
|
+
theories.each do |theory|
|
204
|
+
|
205
|
+
@included_theories << theory
|
41
206
|
|
42
|
-
|
43
|
-
|
44
|
-
|
207
|
+
# include all public_interface predicates
|
208
|
+
@public_interface.send :include, theory.public_interface
|
209
|
+
theory.each_pair do |indicator, predicate|
|
210
|
+
if keys.include? indicator and self[indicator].respond_to? :multitheory? and self[indicator].multitheory?
|
211
|
+
raise TypeError, "You can only use a procedure as a multitheory predicate (#{indicator})" unless predicate.respond_to? :each
|
212
|
+
predicate.each do |rule|
|
213
|
+
@database[indicator].assertz rule
|
214
|
+
end
|
215
|
+
else
|
216
|
+
@database[indicator] = predicate
|
217
|
+
end
|
45
218
|
end
|
219
|
+
|
220
|
+
# include prefix_functors
|
221
|
+
theory.prefix_functor_modules.each do |m|
|
222
|
+
@prefix_functor_modules << m
|
223
|
+
extend m
|
224
|
+
end
|
225
|
+
|
46
226
|
end
|
227
|
+
end
|
228
|
+
|
229
|
+
|
230
|
+
def explain c
|
231
|
+
require "rubylog/because"
|
232
|
+
include Rubylog::Because unless included_theories.include? Rubylog::Because
|
233
|
+
expl = Rubylog::Variable.new :_expl
|
234
|
+
c.because(expl).solve do
|
235
|
+
return c.because(expl.value)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def check_passed goal
|
240
|
+
print "#{n = check_number} :)\t"
|
241
|
+
end
|
47
242
|
|
48
|
-
|
49
|
-
|
243
|
+
def check_failed goal
|
244
|
+
puts "#{check_number} :/\t"
|
245
|
+
puts "Check failed: #{goal.inspect}"
|
246
|
+
puts caller[1]
|
247
|
+
#raise Rubylog::CheckFailed, goal.inspect, caller[1..-1]
|
248
|
+
end
|
50
249
|
|
250
|
+
def check_raised_exception goal, exception
|
251
|
+
puts "#{check_number} :(\t"
|
252
|
+
puts "Check raised exception: #{exception}"
|
253
|
+
puts exception.backtrace
|
254
|
+
end
|
51
255
|
|
52
|
-
|
256
|
+
# returns the line number of the most recen +check+ call
|
257
|
+
def check_number
|
258
|
+
i = caller.index{|l| l.end_with? "in `check'" }
|
259
|
+
caller[i+1] =~ /:(\d+):/
|
260
|
+
$1
|
261
|
+
end
|
262
|
+
private :check_number
|
53
263
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
264
|
+
# Tries to prove goal (or block if goal is not given). If it proves, calles
|
265
|
+
# +check_passed+. If it fails, calls +check_failed+. If it raises an exception, calls +check_raised_exception+.
|
266
|
+
def check goal=nil, &block
|
267
|
+
goal ||= block
|
268
|
+
result = nil
|
269
|
+
begin
|
270
|
+
result = true?(goal)
|
271
|
+
rescue
|
272
|
+
check_raised_exception goal, $!
|
273
|
+
else
|
274
|
+
if result
|
275
|
+
check_passed goal, &block
|
59
276
|
else
|
60
|
-
|
277
|
+
check_failed goal, &block
|
61
278
|
end
|
62
|
-
predicate << Clause.new(:-, head, body)
|
63
|
-
@last_predicate = predicate
|
64
279
|
end
|
280
|
+
result
|
281
|
+
end
|
282
|
+
|
283
|
+
# Starts (if +val+ is not given or true) or stops (if +val+ is false) implicit mode.
|
284
|
+
#
|
285
|
+
# In implicit mode you can start using infix functors without declaring them.
|
286
|
+
def implicit val=true
|
287
|
+
@implicit = val
|
288
|
+
|
289
|
+
if val
|
290
|
+
if Thread.current[:rubylog_current_theory] == self
|
291
|
+
start_implicit
|
292
|
+
end
|
293
|
+
else
|
294
|
+
if @implicit_started
|
295
|
+
stop_implicit
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def thats
|
301
|
+
Rubylog::DSL::Thats.new
|
302
|
+
end
|
303
|
+
|
304
|
+
|
305
|
+
# predicates
|
306
|
+
|
307
|
+
def assert head, body=:true
|
308
|
+
indicator = head.indicator
|
309
|
+
predicate = @database[indicator]
|
310
|
+
if predicate
|
311
|
+
check_assertable predicate, head, body
|
312
|
+
else
|
313
|
+
predicate = create_procedure indicator
|
314
|
+
end
|
315
|
+
predicate.assertz Rubylog::Structure.new(:-, head, body)
|
316
|
+
@last_predicate = predicate
|
317
|
+
end
|
65
318
|
|
66
319
|
|
67
|
-
|
320
|
+
def solve goal, &block
|
321
|
+
with_context do
|
68
322
|
goal = goal.rubylog_compile_variables
|
69
|
-
goal.prove {
|
323
|
+
goal.prove { block.call_with_rubylog_variables(goal.rubylog_variables) }
|
70
324
|
end
|
325
|
+
end
|
71
326
|
|
72
|
-
|
327
|
+
def true? goal=nil, &block
|
328
|
+
if goal.nil?
|
329
|
+
raise ArgumentError, "No goal given" if block.nil?
|
330
|
+
goal = with_context &block
|
331
|
+
end
|
332
|
+
with_context do
|
73
333
|
goal = goal.rubylog_compile_variables
|
74
334
|
goal.prove { return true }
|
75
|
-
false
|
76
335
|
end
|
336
|
+
false
|
337
|
+
end
|
77
338
|
|
78
|
-
|
79
|
-
#
|
80
|
-
#
|
81
|
-
def trace?
|
82
|
-
@trace
|
83
|
-
end
|
339
|
+
alias prove true?
|
84
340
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
341
|
+
# debugging
|
342
|
+
#
|
343
|
+
#
|
344
|
+
def trace val=true, &block
|
345
|
+
@trace=block || val
|
346
|
+
@trace_levels = 0
|
347
|
+
end
|
89
348
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
349
|
+
def print_trace level, *args
|
350
|
+
return unless @trace
|
351
|
+
if @trace.respond_to? :call
|
352
|
+
@trace.call @trace_levels, *args if not args.empty?
|
353
|
+
else
|
354
|
+
puts " "*@trace_levels + args.map{|a|a.rubylog_deep_dereference.to_s}.join(" ") if not args.empty?
|
94
355
|
end
|
356
|
+
@trace_levels += level
|
357
|
+
end
|
358
|
+
|
359
|
+
protected
|
95
360
|
|
96
|
-
protected
|
97
361
|
|
362
|
+
def check_assertable predicate, head, body
|
363
|
+
raise Rubylog::NonAssertableError, head.indicator.inspect, caller[2..-1] unless predicate.respond_to? :assertz
|
364
|
+
raise Rubylog::DiscontiguousPredicateError, head.indicator.inspect, caller[2..-1] if check_discontiguous? and not predicate.empty? and predicate != @last_predicate and not predicate.discontiguous?
|
365
|
+
end
|
366
|
+
|
367
|
+
def create_procedure indicator
|
368
|
+
functor indicator[0]
|
369
|
+
@database[indicator] = Rubylog::SimpleProcedure.new
|
370
|
+
end
|
98
371
|
|
99
|
-
|
100
|
-
|
101
|
-
|
372
|
+
def start_implicit
|
373
|
+
[@public_interface, Rubylog::Variable].each do |m|
|
374
|
+
m.send :define_method, :method_missing do |m, *args|
|
375
|
+
fct = Rubylog::DSL.normalize_functor(m)
|
376
|
+
return super if fct.nil?
|
377
|
+
raise NameError, "'#{fct}' method already exists" if respond_to? fct
|
378
|
+
Rubylog.current_theory.functor fct
|
379
|
+
self.class.send :include, Rubylog::DSL.functor_module(fct)
|
380
|
+
send m, *args
|
381
|
+
end
|
102
382
|
end
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
383
|
+
@implicit_started = true
|
384
|
+
end
|
385
|
+
|
386
|
+
def stop_implicit
|
387
|
+
[@public_interface, Rubylog::Variable].each do |m|
|
388
|
+
m.send :remove_method, :method_missing
|
107
389
|
end
|
108
|
-
|
390
|
+
@implicit_started = false
|
391
|
+
end
|
392
|
+
|
109
393
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
#else
|
115
|
-
#end
|
116
|
-
#end
|
117
|
-
#def protected *args
|
118
|
-
#if args.empty?
|
119
|
-
#@scope = :protected
|
120
|
-
#else
|
121
|
-
#end
|
122
|
-
#end
|
394
|
+
#def private *args
|
395
|
+
#if args.empty?
|
396
|
+
#@scope = :private
|
397
|
+
#else
|
123
398
|
#end
|
399
|
+
#end
|
400
|
+
#def protected *args
|
401
|
+
#if args.empty?
|
402
|
+
#@scope = :protected
|
403
|
+
#else
|
404
|
+
#end
|
405
|
+
#end
|
406
|
+
|
407
|
+
private
|
124
408
|
|
125
|
-
|
409
|
+
def check_indicator indicator
|
410
|
+
raise ArgumentError, "#{indicator.inspect} should be a predicate indicator", caller[2..-1] unless indicator.is_a? Array and
|
411
|
+
indicator.length == 2 and
|
412
|
+
indicator[0].is_a? Symbol and
|
413
|
+
indicator[1].is_a? Integer
|
126
414
|
end
|
127
|
-
end
|
128
415
|
|
129
416
|
|
130
417
|
|
418
|
+
end
|
419
|
+
|
131
420
|
|
132
421
|
|
133
422
|
|
data/lib/rubylog/variable.rb
CHANGED
@@ -4,23 +4,25 @@ module Rubylog
|
|
4
4
|
# data structure
|
5
5
|
|
6
6
|
attr_reader :name
|
7
|
-
def initialize name
|
8
|
-
@name = name
|
9
|
-
@
|
10
|
-
@dont_care = !!(name.to_s =~ /^(?:ANY|_)/)
|
7
|
+
def initialize name = :"_#{object_id}"
|
8
|
+
@name = name
|
9
|
+
@bound = false
|
10
|
+
@dont_care = !!(name.to_s =~ /^(?:ANY|_)/i)
|
11
|
+
@guards = []
|
11
12
|
end
|
12
13
|
|
13
|
-
def
|
14
|
-
@
|
14
|
+
def bound?
|
15
|
+
@bound
|
15
16
|
end
|
16
17
|
|
17
18
|
def inspect
|
18
|
-
@
|
19
|
+
if @guards.empty?
|
20
|
+
@name.to_s
|
21
|
+
else
|
22
|
+
"#{@name}#{@guards}"
|
23
|
+
end
|
19
24
|
end
|
20
25
|
|
21
|
-
def to_s
|
22
|
-
@name.to_s
|
23
|
-
end
|
24
26
|
|
25
27
|
def == other
|
26
28
|
Variable === other and @name == other.name
|
@@ -49,24 +51,43 @@ module Rubylog
|
|
49
51
|
[self]
|
50
52
|
end
|
51
53
|
|
52
|
-
#
|
53
|
-
include Unifiable
|
54
|
-
|
54
|
+
# unify two variables
|
55
55
|
def rubylog_unify other
|
56
|
-
if
|
56
|
+
# check if we are bound
|
57
|
+
if @bound
|
58
|
+
# if we are bound
|
59
|
+
# proceed to our dereferenced value
|
57
60
|
rubylog_dereference.rubylog_unify(other) do yield end
|
58
61
|
else
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
62
|
+
# if we are unbound
|
63
|
+
|
64
|
+
# dereference the other
|
65
|
+
other = other.rubylog_dereference
|
66
|
+
|
67
|
+
# if the other is a variable
|
68
|
+
if other.is_a? Rubylog::Variable
|
69
|
+
# we union our guards with the other's
|
70
|
+
other.append_guards guards do
|
71
|
+
bind_to other do
|
72
|
+
yield
|
73
|
+
end
|
74
|
+
end
|
75
|
+
else
|
76
|
+
# if the other is a value
|
77
|
+
# bind to it and
|
78
|
+
bind_to other do
|
79
|
+
# check our guards
|
80
|
+
if guards.all? {|g|g.rubylog_matches_as_guard? other}
|
81
|
+
yield
|
82
|
+
end
|
83
|
+
end
|
64
84
|
end
|
65
85
|
end
|
66
86
|
end
|
67
87
|
|
88
|
+
|
68
89
|
def rubylog_dereference
|
69
|
-
if @
|
90
|
+
if @bound
|
70
91
|
@value.rubylog_dereference
|
71
92
|
else
|
72
93
|
self
|
@@ -74,7 +95,7 @@ module Rubylog
|
|
74
95
|
end
|
75
96
|
|
76
97
|
def rubylog_deep_dereference
|
77
|
-
if @
|
98
|
+
if @bound
|
78
99
|
@value.rubylog_deep_dereference
|
79
100
|
else
|
80
101
|
self
|
@@ -85,12 +106,70 @@ module Rubylog
|
|
85
106
|
include Callable
|
86
107
|
|
87
108
|
def prove
|
88
|
-
# XXX not tested
|
89
109
|
v = value
|
90
|
-
raise InstantiationError if v.nil?
|
110
|
+
raise InstantiationError, self if v.nil?
|
91
111
|
v.prove{yield}
|
92
112
|
end
|
93
113
|
|
114
|
+
|
115
|
+
# Array splats
|
116
|
+
def to_a
|
117
|
+
[Rubylog::DSL::ArraySplat.new(self)]
|
118
|
+
end
|
119
|
+
alias to_ary to_a
|
120
|
+
|
121
|
+
# String variables
|
122
|
+
def to_s
|
123
|
+
if @guards.empty?
|
124
|
+
"#{String::RUBYLOG_VAR_START}#{@name}[]#{String::RUBYLOG_VAR_END}"
|
125
|
+
else
|
126
|
+
String::RubylogStringVariableGuards << @guards
|
127
|
+
guard_index = String::RubylogStringVariableGuards.length-1
|
128
|
+
"#{String::RUBYLOG_VAR_START}#{@name}[#{guard_index}]#{String::RUBYLOG_VAR_END}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# guards
|
133
|
+
def [] *guards
|
134
|
+
@guards += guards
|
135
|
+
self
|
136
|
+
end
|
137
|
+
|
138
|
+
attr_reader :guards
|
139
|
+
attr_writer :guards
|
140
|
+
|
141
|
+
|
142
|
+
protected
|
143
|
+
|
144
|
+
# yields with self bound to the given value
|
145
|
+
def bind_to other
|
146
|
+
begin
|
147
|
+
@bound = true; @value = other
|
148
|
+
Rubylog.current_theory.print_trace 1, "#{inspect}=#{@value.inspect}"
|
149
|
+
|
150
|
+
yield
|
151
|
+
|
152
|
+
ensure
|
153
|
+
@bound = false
|
154
|
+
Rubylog.current_theory.print_trace -1
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# yields with self.guards = self.guards + other_guards, then restores guards
|
159
|
+
def append_guards other_guards
|
160
|
+
original_guards = @guards
|
161
|
+
|
162
|
+
@guards = @guards + other_guards
|
163
|
+
|
164
|
+
begin
|
165
|
+
yield
|
166
|
+
ensure
|
167
|
+
@guards = original_guards
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
|
172
|
+
|
94
173
|
end
|
95
174
|
|
96
175
|
|