rubylog 1.0.0 → 2.0pre1
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 +3 -12
- data/Gemfile.lock +22 -48
- data/README.rdoc +38 -38
- data/README.rdoc.orig +284 -0
- data/RELEASE_NOTES.rdoc +51 -0
- data/Rakefile +14 -18
- data/TODO.txt +0 -0
- data/VERSION +1 -1
- data/examples/a_plus_b.rb +6 -0
- data/examples/checkmate.rb +88 -0
- data/examples/combination.rb +17 -0
- data/examples/dcg.rb +3 -2
- data/examples/dcg2.rb +2 -2
- data/{logic → examples}/directory_structure_logic.rb +3 -5
- data/examples/dirlist.rb +4 -0
- data/examples/divisors.rb +6 -0
- data/examples/enumerators.rb +3 -3
- data/examples/factorial.rb +2 -3
- data/examples/file_search.rb +14 -0
- data/examples/hanoi.rb +4 -5
- data/examples/hello.rb +6 -4
- data/examples/mice.rb +92 -0
- data/examples/mice2.rb +19 -0
- data/examples/n_queens.rb +32 -0
- data/examples/object_oriented.rb +14 -0
- data/examples/palindrome_detection.rb +18 -0
- data/examples/parsing.rb +6 -4
- data/examples/permutation.rb +12 -0
- data/examples/prefix.rb +13 -0
- data/examples/primality_by_division.rb +22 -0
- data/examples/primitives.rb +10 -8
- data/examples/sieve_of_eratosthenes.rb +14 -0
- data/examples/string_interpolation.rb +4 -0
- data/examples/sudoku.rb +52 -0
- data/examples/tracing.rb +19 -0
- data/lib/rspec/rubylog.rb +29 -0
- data/lib/rubylog/assertable.rb +24 -0
- data/lib/rubylog/builtins/arithmetics.rb +63 -0
- data/lib/rubylog/builtins/assumption.rb +71 -0
- data/lib/rubylog/builtins/ensure.rb +13 -0
- data/lib/rubylog/builtins/file_system.rb +30 -8
- data/lib/rubylog/builtins/logic.rb +69 -38
- data/lib/rubylog/builtins/reflection.rb +35 -50
- data/lib/rubylog/builtins/term.rb +15 -17
- data/lib/rubylog/builtins.rb +11 -0
- data/lib/rubylog/clause.rb +19 -0
- data/lib/rubylog/{interfaces/composite_term.rb → compound_term.rb} +3 -3
- data/lib/rubylog/context.rb +24 -0
- data/lib/rubylog/context_creation.rb +71 -0
- data/lib/rubylog/context_modules/checks.rb +35 -0
- data/lib/rubylog/context_modules/demonstration.rb +16 -0
- data/lib/rubylog/context_modules/predicates.rb +86 -0
- data/lib/rubylog/context_modules/primitives.rb +18 -0
- data/lib/rubylog/context_modules/thats.rb +13 -0
- data/lib/rubylog/default_context.rb +9 -0
- data/lib/rubylog/dsl/array_splat.rb +11 -3
- data/lib/rubylog/dsl/primitives.rb +24 -12
- data/lib/rubylog/dsl/thats.rb +6 -0
- data/lib/rubylog/dsl/variables.rb +56 -21
- data/lib/rubylog/errors.rb +26 -15
- data/lib/rubylog/mixins/array.rb +95 -62
- data/lib/rubylog/mixins/kernel.rb +3 -2
- data/lib/rubylog/mixins/method.rb +0 -1
- data/lib/rubylog/mixins/object.rb +2 -1
- data/lib/rubylog/mixins/proc.rb +9 -12
- data/lib/rubylog/mixins/string.rb +15 -23
- data/lib/rubylog/mixins/symbol.rb +7 -24
- data/lib/rubylog/nullary_predicates.rb +3 -0
- data/lib/rubylog/predicate.rb +53 -0
- data/lib/rubylog/primitive.rb +15 -0
- data/lib/rubylog/procedure.rb +42 -0
- data/lib/rubylog/rule.rb +24 -0
- data/lib/rubylog/structure.rb +19 -38
- data/lib/rubylog/{interfaces/term.rb → term.rb} +2 -7
- data/lib/rubylog/tracing.rb +75 -0
- data/lib/rubylog/variable.rb +31 -12
- data/lib/rubylog.rb +36 -32
- data/rubylog.gemspec +92 -84
- data/spec/inriasuite_spec.rb +906 -9
- data/spec/integration/custom_classes_spec.rb +61 -0
- data/spec/integration/dsl_spec.rb +38 -0
- data/spec/integration/recursion_spec.rb +14 -0
- data/spec/integration/theory_as_module_spec.rb +20 -0
- data/spec/integration/theory_as_module_with_include_spec.rb +14 -0
- data/spec/rspec/rubylog_spec.rb +75 -0
- data/spec/rubylog/assertable_spec.rb +111 -0
- data/spec/rubylog/builtins/arithmetics_spec.rb +94 -0
- data/spec/rubylog/builtins/assumption_spec.rb +70 -0
- data/spec/rubylog/builtins/ensure_spec.rb +8 -0
- data/spec/rubylog/builtins/file_system_spec.rb +40 -0
- data/spec/rubylog/builtins/logic_spec.rb +340 -0
- data/spec/rubylog/builtins/reflection_spec.rb +43 -0
- data/spec/rubylog/builtins/term_spec.rb +85 -0
- data/spec/rubylog/context_modules/demonstration_spec.rb +132 -0
- data/spec/rubylog/context_modules/predicates_spec.rb +57 -0
- data/spec/rubylog/context_modules/thats_spec.rb +94 -0
- data/spec/rubylog/dsl/array_splat_spec.rb +15 -0
- data/spec/rubylog/dsl/primitives_spec.rb +43 -0
- data/spec/rubylog/errors_spec.rb +18 -0
- data/spec/{unification_spec.rb → rubylog/interfaces/term_spec.rb} +8 -9
- data/spec/rubylog/mixins/array_spec.rb +80 -0
- data/spec/rubylog/mixins/composite_term_spec.rb +66 -0
- data/spec/rubylog/mixins/proc_spec.rb +59 -0
- data/spec/rubylog/mixins/string_spec.rb +48 -0
- data/spec/rubylog/mixins/symbol_spec.rb +9 -0
- data/spec/{clause_spec.rb → rubylog/structure_spec.rb} +16 -15
- data/spec/rubylog/term_spec.rb +7 -0
- data/spec/rubylog/tracing_spec.input +27 -0
- data/spec/rubylog/tracing_spec.rb +44 -0
- data/spec/rubylog/variable_spec.rb +279 -0
- data/spec/spec_helper.rb +1 -0
- data/vimrc +11 -0
- metadata +103 -123
- data/README.hu.rb +0 -58
- data/bin/rubylog +0 -18
- data/examples/theory.rb +0 -32
- data/lib/rubylog/builtins/default.rb +0 -10
- data/lib/rubylog/dsl.rb +0 -70
- data/lib/rubylog/interfaces/assertable.rb +0 -16
- data/lib/rubylog/interfaces/callable.rb +0 -18
- data/lib/rubylog/interfaces/predicate.rb +0 -8
- data/lib/rubylog/interfaces/procedure.rb +0 -60
- data/lib/rubylog/mixins/class.rb +0 -11
- data/lib/rubylog/simple_procedure.rb +0 -8
- data/lib/rubylog/theory.rb +0 -422
- data/logic/builtins/file_system_logic.rb +0 -23
- data/logic/builtins/reflection_logic.rb +0 -40
- data/logic/dereference_logic.rb +0 -23
- data/logic/dsl_logic.rb +0 -29
- data/logic/errors_logic.rb +0 -9
- data/logic/guard_logic.rb +0 -115
- data/logic/list_logic.rb +0 -55
- data/logic/map_logic.rb +0 -15
- data/logic/multitheory.rb +0 -23
- data/logic/recursion_logic.rb +0 -12
- data/logic/string_logic.rb +0 -41
- data/logic/thats_logic.rb +0 -51
- data/logic/variable_logic.rb +0 -24
- data/spec/bartak_guide_spec.rb +0 -86
- data/spec/builtins/all_spec.rb +0 -99
- data/spec/builtins/and_spec.rb +0 -22
- data/spec/builtins/array_spec.rb +0 -16
- data/spec/builtins/branch_or_spec.rb +0 -27
- data/spec/builtins/cut_spec.rb +0 -44
- data/spec/builtins/fail_spec.rb +0 -5
- data/spec/builtins/false_spec.rb +0 -5
- data/spec/builtins/in_spec.rb +0 -38
- data/spec/builtins/is_false_spec.rb +0 -12
- data/spec/builtins/is_spec.rb +0 -26
- data/spec/builtins/matches_spec.rb +0 -23
- data/spec/builtins/or_spec.rb +0 -22
- data/spec/builtins/splits_to.rb +0 -18
- data/spec/builtins/then_spec.rb +0 -27
- data/spec/builtins/true_spec.rb +0 -5
- data/spec/compilation_spec.rb +0 -61
- data/spec/custom_classes_spec.rb +0 -43
- data/spec/dereference.rb +0 -10
- data/spec/queries_spec.rb +0 -150
- data/spec/recursion_spec.rb +0 -18
- data/spec/ruby_code_spec.rb +0 -52
- data/spec/rules_spec.rb +0 -97
- data/spec/theory_spec.rb +0 -29
- data/spec/variable_spec.rb +0 -26
@@ -0,0 +1,71 @@
|
|
1
|
+
module Rubylog
|
2
|
+
|
3
|
+
# Creates a new context from a new object or optionally from an existing source
|
4
|
+
# object
|
5
|
+
# @return the new context
|
6
|
+
def self.create_context source_object=Object.new
|
7
|
+
class << source_object
|
8
|
+
include Rubylog::Context
|
9
|
+
end
|
10
|
+
source_object
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
# You can use this to access Rubylog in the command line or in the main object.
|
15
|
+
#
|
16
|
+
# For example,
|
17
|
+
#
|
18
|
+
# require 'rubylog'
|
19
|
+
# extend Rubylog::Context
|
20
|
+
#
|
21
|
+
# solve A.is(5).and { puts A; true }
|
22
|
+
#
|
23
|
+
# You can also use this to convert any object to a context.
|
24
|
+
#
|
25
|
+
# You can extend Rubylog::Context to modules or classes.
|
26
|
+
#
|
27
|
+
# class A
|
28
|
+
# extend Rubylog::Context
|
29
|
+
# predicate ".good"
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# This automatically uses the class as default subject.
|
33
|
+
#
|
34
|
+
# Finally, you can include it to a class.
|
35
|
+
#
|
36
|
+
# class MyContext
|
37
|
+
# include Rubylog::Context
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# myc = MyContext.new
|
41
|
+
# myc.predicate_for A, ".bad"
|
42
|
+
#
|
43
|
+
#
|
44
|
+
module Context
|
45
|
+
|
46
|
+
def self.extended context
|
47
|
+
# We include DSL::Variables in its singleton class
|
48
|
+
class << context
|
49
|
+
include Rubylog::DSL::Variables
|
50
|
+
end
|
51
|
+
|
52
|
+
if context.is_a? Module
|
53
|
+
# if context is a class or module, we also include DSL::Variables directly
|
54
|
+
# in it, so that they can be accessed in class_eval mode or from an
|
55
|
+
# instance method.
|
56
|
+
context.send :include, Rubylog::DSL::Variables
|
57
|
+
|
58
|
+
# Also, we set self as a subject, so that +predicate+ automatically attaches
|
59
|
+
# functors to the class.
|
60
|
+
context.default_subject = context
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.included class_or_module
|
65
|
+
class_or_module.send :include, Rubylog::DSL::Variables
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Rubylog::ContextModules
|
2
|
+
module Checks
|
3
|
+
def check_passed goal
|
4
|
+
end
|
5
|
+
|
6
|
+
def check_failed goal
|
7
|
+
raise Rubylog::CheckFailed.new(goal)
|
8
|
+
end
|
9
|
+
|
10
|
+
def check_raised_exception goal, exception
|
11
|
+
raise exception
|
12
|
+
end
|
13
|
+
|
14
|
+
# Tries to prove goal (or block if goal is not given). If it proves, calles
|
15
|
+
# +check_passed+. If it fails, calls +check_failed+. If it raises an exception, calls +check_raised_exception+.
|
16
|
+
def check goal=nil, &block
|
17
|
+
goal ||= block
|
18
|
+
result = nil
|
19
|
+
begin
|
20
|
+
result = goal.true?
|
21
|
+
rescue
|
22
|
+
check_raised_exception goal, $!
|
23
|
+
else
|
24
|
+
if result
|
25
|
+
check_passed goal, &block
|
26
|
+
else
|
27
|
+
check_failed goal, &block
|
28
|
+
end
|
29
|
+
end
|
30
|
+
result
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Rubylog::ContextModules
|
2
|
+
module Demonstration
|
3
|
+
def solve goal, &block
|
4
|
+
goal ||= block
|
5
|
+
raise ArgumentError, "No goal given", caller if goal.nil?
|
6
|
+
goal.solve &block
|
7
|
+
end
|
8
|
+
|
9
|
+
def true? goal=nil, &block
|
10
|
+
goal ||= block
|
11
|
+
raise ArgumentError, "No goal given", caller if goal.nil?
|
12
|
+
goal.true?
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'rubylog/rule'
|
2
|
+
|
3
|
+
|
4
|
+
module Rubylog
|
5
|
+
module ContextModules
|
6
|
+
module Predicates
|
7
|
+
|
8
|
+
def predicate *indicators
|
9
|
+
each_indicator(indicators) do |indicator|
|
10
|
+
create_procedure(indicator).add_functor_to [default_subject, Variable]
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def predicate_for subjects, *indicators
|
15
|
+
each_indicator(indicators) do |indicator|
|
16
|
+
create_procedure(indicator).add_functor_to [subjects, Variable]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def predicate_for_context *indicators
|
21
|
+
each_indicator(indicators) do |indicator|
|
22
|
+
create_procedure(indicator).add_functor_to ::Rubylog::Context
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_writer :default_subject
|
27
|
+
def default_subject
|
28
|
+
@default_subject || []
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def create_procedure indicator
|
35
|
+
Rubylog::Procedure.new indicator[0], indicator[1]
|
36
|
+
end
|
37
|
+
|
38
|
+
def each_indicator indicators
|
39
|
+
# TODO check if not empty
|
40
|
+
#
|
41
|
+
indicators.
|
42
|
+
flatten.
|
43
|
+
map{|str|str.split(" ")}.
|
44
|
+
flatten.
|
45
|
+
map{|i| unhumanize_indicator(i)}.
|
46
|
+
each {|i| yield i }
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
# Makes human-friendly output from the indicator
|
51
|
+
# For example, .and()
|
52
|
+
def humanize_indicator indicator
|
53
|
+
return indicator if String === indicator
|
54
|
+
functor, arity = indicator
|
55
|
+
if arity > 1
|
56
|
+
".#{functor}(#{ ','*(arity-2) })"
|
57
|
+
elsif arity == 1
|
58
|
+
".#{functor}"
|
59
|
+
elsif arity == 0
|
60
|
+
":#{functor}"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Makes internal representation from predicate indicator
|
65
|
+
#
|
66
|
+
# For example, <tt>.and()</tt> becomes <tt>[:and,2]</tt>
|
67
|
+
def unhumanize_indicator indicator
|
68
|
+
case indicator
|
69
|
+
when Array
|
70
|
+
indicator
|
71
|
+
when /\A:(\w+)\z/
|
72
|
+
[:"#{$1}",0]
|
73
|
+
when /\A\w*\.(\w+)\z/
|
74
|
+
[:"#{$1}",1]
|
75
|
+
when /\A\w*\.(\w+)\(\w*((,\w*)*)\)\z/
|
76
|
+
[:"#{$1}",$2.count(",")+2]
|
77
|
+
else
|
78
|
+
raise ArgumentError, "invalid indicator: #{indicator.inspect}"
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubylog/dsl/primitives'
|
2
|
+
|
3
|
+
module Rubylog::ContextModules
|
4
|
+
module Primitives
|
5
|
+
def primitives
|
6
|
+
Rubylog::DSL::Primitives.new [default_subject, ::Rubylog::Variable]
|
7
|
+
end
|
8
|
+
|
9
|
+
def primitives_for subject
|
10
|
+
Rubylog::DSL::Primitives.new [subject, ::Rubylog::Variable]
|
11
|
+
end
|
12
|
+
|
13
|
+
def primitives_for_context
|
14
|
+
Rubylog::DSL::Primitives.new [::Rubylog::Context]
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -9,11 +9,19 @@ class Rubylog::DSL::ArraySplat
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def inspect
|
12
|
-
"*#{var}"
|
12
|
+
"*#{var.inspect}"
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
def eql? other
|
16
|
+
self.class == other.class && @var.eql?(other.var)
|
17
|
+
end
|
18
|
+
|
19
|
+
def == other
|
20
|
+
self.class == other.class && @var == other.var
|
21
|
+
end
|
22
|
+
|
23
|
+
# CompoundTerm methods
|
24
|
+
include Rubylog::CompoundTerm
|
17
25
|
|
18
26
|
def rubylog_clone &block
|
19
27
|
block[Rubylog::DSL::ArraySplat.new(@var.rubylog_clone(&block))]
|
@@ -1,17 +1,29 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
module Rubylog
|
2
|
+
class DSL::Primitives
|
3
|
+
def initialize subject
|
4
|
+
@subject = subject
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
def singleton_method_added name
|
9
|
+
unless name == :singleton_method_added
|
10
|
+
m = method(name)
|
5
11
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
12
|
+
predicate = Rubylog::Primitive.new(name, m)
|
13
|
+
|
14
|
+
# nullary predicate
|
15
|
+
if m.arity.zero?
|
16
|
+
Rubylog::NullaryPredicates[name] = predicate
|
17
|
+
else
|
18
|
+
predicate.add_functor_to(@subject)
|
19
|
+
end
|
20
|
+
end
|
11
21
|
end
|
12
|
-
end
|
13
22
|
|
14
|
-
|
15
|
-
|
23
|
+
def inspect
|
24
|
+
if @subject
|
25
|
+
"primitives_for(#{@subject.inspect})"
|
26
|
+
end
|
27
|
+
end
|
16
28
|
end
|
17
29
|
end
|
data/lib/rubylog/dsl/thats.rb
CHANGED
@@ -1,30 +1,65 @@
|
|
1
|
-
|
2
|
-
def self.included mod
|
3
|
-
def mod.const_missing c
|
4
|
-
# different semantics in native blocks than otherwise
|
5
|
-
# @see Proc#call_with_rubylog_variables
|
6
|
-
if vars = Thread.current[:rubylog_current_variables]
|
7
|
-
# in native blocks
|
1
|
+
require 'rubylog/variable'
|
8
2
|
|
9
|
-
|
10
|
-
|
3
|
+
module Rubylog::DSL
|
4
|
+
# When included to a module, defines const_missing. This method creates a new
|
5
|
+
# variable automatically, but if a variable with that name
|
6
|
+
# exists in the current dynamic context, returns its deeply dereferenced
|
7
|
+
# value.
|
8
|
+
#
|
9
|
+
# For example,
|
10
|
+
#
|
11
|
+
# A # => A
|
12
|
+
#
|
13
|
+
# In blocks, variables are substituted with the deeply dereferenced value:
|
14
|
+
#
|
15
|
+
# A.is(5).map{A} # => [5]
|
16
|
+
# B.is(5).and(A.is([2,B])).map{A} # => [[2,5]]
|
17
|
+
#
|
18
|
+
# When variables do not have a value, it is not substituted.
|
19
|
+
#
|
20
|
+
# A.is(B).map{A} # => [B]
|
21
|
+
# B.is(C).and(A.is([2,B])).map{A} # => [[2,C]]
|
22
|
+
# A.is([B]).map{A} # => [[B]]
|
23
|
+
#
|
24
|
+
# @see Proc#call_with_rubylog_variables
|
25
|
+
module Variables
|
26
|
+
def self.included mod
|
11
27
|
|
12
|
-
|
13
|
-
|
14
|
-
|
28
|
+
def mod.const_missing c
|
29
|
+
if vars = Thread.current[:rubylog_current_variables]
|
30
|
+
# in native blocks
|
15
31
|
|
16
|
-
|
17
|
-
|
32
|
+
# find the appropriate variable name
|
33
|
+
var = vars.find{|v|v.name == c}
|
18
34
|
|
19
|
-
|
20
|
-
|
35
|
+
# return new variable if not found (most probably the user wants to start using a new
|
36
|
+
# one)
|
37
|
+
return Rubylog::Variable.new c unless var
|
21
38
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
39
|
+
# dereference it
|
40
|
+
result = var.rubylog_deep_dereference
|
41
|
+
|
42
|
+
# return the value
|
43
|
+
result
|
44
|
+
else
|
45
|
+
Rubylog::Variable.new c
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Call the given block with variables substituted with their
|
50
|
+
def self.with_vars vars
|
51
|
+
begin
|
52
|
+
old_vars = Thread.current[:rubylog_current_variables]
|
53
|
+
if old_vars
|
54
|
+
Thread.current[:rubylog_current_variables] = vars + old_vars
|
55
|
+
else
|
56
|
+
Thread.current[:rubylog_current_variables] = vars
|
57
|
+
end
|
58
|
+
yield
|
59
|
+
ensure
|
60
|
+
Thread.current[:rubylog_current_variables] = old_vars
|
61
|
+
end
|
26
62
|
end
|
27
63
|
end
|
28
64
|
end
|
29
65
|
end
|
30
|
-
|
data/lib/rubylog/errors.rb
CHANGED
@@ -1,35 +1,46 @@
|
|
1
1
|
module Rubylog
|
2
|
+
|
2
3
|
class RubylogError < StandardError
|
3
|
-
|
4
|
-
|
5
|
-
class SyntaxError < RubylogError
|
6
|
-
end
|
4
|
+
def initialize *args
|
5
|
+
super
|
7
6
|
|
8
|
-
|
9
|
-
|
7
|
+
remove_internal_lines
|
8
|
+
end
|
10
9
|
|
11
|
-
|
10
|
+
def remove_internal_lines
|
11
|
+
internal_dir = File.dirname(__FILE__) or return
|
12
|
+
return unless backtrace
|
13
|
+
index = backtrace.index{|l| not l.start_with?(internal_dir) } or return
|
14
|
+
set_backtrace backtrace[index..-1]
|
15
|
+
end
|
12
16
|
end
|
13
|
-
|
14
|
-
class
|
17
|
+
|
18
|
+
class SyntaxError < RubylogError
|
15
19
|
end
|
16
20
|
|
17
21
|
class ExistenceError < RubylogError
|
22
|
+
def initialize clause
|
23
|
+
super "Predicate #{clause.inspect} does not exist"
|
24
|
+
end
|
18
25
|
end
|
19
26
|
|
20
27
|
class InvalidStateError < RubylogError
|
21
28
|
end
|
22
29
|
|
23
30
|
class InstantiationError < RubylogError
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
31
|
+
def initialize functor, args=nil
|
32
|
+
if args
|
33
|
+
super "Instantiation error in #{args[0].inspect}.#{functor}(#{args[1..-1].map{|a|a.rubylog_deep_dereference.inspect}.join(", ")})"
|
34
|
+
else
|
35
|
+
super "Instantiation error in #{functor.inspect}"
|
36
|
+
end
|
37
|
+
end
|
30
38
|
end
|
31
39
|
|
32
40
|
class CheckFailed < StandardError
|
41
|
+
def initialize goal
|
42
|
+
super "Check failed #{goal.inspect}"
|
43
|
+
end
|
33
44
|
end
|
34
45
|
|
35
46
|
end
|
data/lib/rubylog/mixins/array.rb
CHANGED
@@ -1,100 +1,131 @@
|
|
1
|
-
|
2
|
-
# for the future
|
3
|
-
def self.unify_arrays a, a_start, a_end, b, b_start, b_end
|
4
|
-
case
|
5
|
-
when (a_start > a_end and b_start > b_end)
|
6
|
-
yield
|
7
|
-
when (a_start > a_end or b_start > b_end)
|
8
|
-
return
|
9
|
-
when (a[a_start].is_a? Rubylog::DSL::ArraySplat and b[b_start].is_a? Rubylog::DSL::ArraySplat)
|
10
|
-
raise "not implemented"
|
11
|
-
when (a[a_start].is_a? Rubylog::DSL::ArraySplat)
|
12
|
-
# A=[]
|
13
|
-
a[a_start].var.rubylog_unify [] do
|
14
|
-
unify_arrays(a, a_start+1, a_end, b, b_start, b_end) { yield }
|
15
|
-
end
|
16
|
-
|
17
|
-
# A=[_X, *_Y]
|
18
|
-
new_arr = [Rubylog::Variable.new, Rubylog::DSL::ArraySplat.new(Rubylog::Variable.new)]
|
19
|
-
a[a_start].var.rubylog_unify new_arr do
|
20
|
-
unify_arrays(a[a_start].var, a_start+1, a_end, b, b_start, b_end) { yield }
|
21
|
-
end
|
22
|
-
when (b[b_start].is_a? Rubylog::DSL::ArraySplat)
|
23
|
-
raise "not implemented"
|
24
|
-
else
|
25
|
-
a[a_start].rubylog_unify b[b_start] do
|
26
|
-
unify_arrays(a, a_start+1, a_end, b, b_start+1, b_end) { yield }
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
1
|
+
require 'rubylog/dsl/array_splat'
|
31
2
|
|
32
3
|
class Array
|
33
4
|
|
34
5
|
# Term methods
|
35
6
|
def rubylog_unify other
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
7
|
+
case
|
8
|
+
|
9
|
+
when ! other.is_a?(Array)
|
10
|
+
# [...] = 1
|
11
|
+
return super{yield}
|
12
|
+
|
13
|
+
when empty?
|
14
|
+
case
|
15
|
+
when other.empty?
|
16
|
+
# if [] = []
|
17
|
+
# then true
|
40
18
|
yield
|
41
|
-
|
42
|
-
|
19
|
+
when other[0].is_a?(Rubylog::DSL::ArraySplat)
|
20
|
+
# if [] = [*A,...]
|
21
|
+
# then [] = A, []=[...]
|
22
|
+
[].rubylog_unify other[0].var do
|
43
23
|
self.rubylog_unify other[1..-1] do
|
44
24
|
yield
|
45
25
|
end
|
46
26
|
end
|
47
27
|
else
|
48
|
-
#
|
28
|
+
# fail
|
49
29
|
end
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
30
|
+
|
31
|
+
when self[0].is_a?(Rubylog::DSL::ArraySplat)
|
32
|
+
# if [*A,...] = [...]
|
33
|
+
case
|
34
|
+
when other.empty?
|
35
|
+
# [*A,...] = []
|
36
|
+
self[0].var.rubylog_unify [] do
|
37
|
+
self[1..-1].rubylog_unify [] do
|
38
|
+
yield
|
39
|
+
end
|
40
|
+
end
|
41
|
+
when other[0].is_a?(Rubylog::DSL::ArraySplat )
|
42
|
+
# [*A,...] = [*B,...]
|
43
|
+
case
|
44
|
+
when self.length == 1 && other.length == 1
|
45
|
+
# if [*A] = [*B]
|
46
|
+
# then A=B
|
54
47
|
self[0].var.rubylog_unify other[0].var do
|
55
48
|
yield
|
56
49
|
end
|
57
|
-
|
50
|
+
when self.length == 1
|
51
|
+
# if [*A] = [*B,...]
|
52
|
+
# then A=[...]
|
53
|
+
self[0].var.rubylog_unify other do
|
54
|
+
yield
|
55
|
+
end
|
56
|
+
# TODO: we can also optimize ends of arrays.
|
57
|
+
else
|
58
|
+
# this may lead to infinite loop if variables are unbound
|
59
|
+
# TODO: Maybe an InstantiationError may be better.
|
60
|
+
# if [*A,...] = [*B,...]
|
61
|
+
# then eiter A=[], [...]=[*B,...]
|
62
|
+
self[0].var.rubylog_unify [] do
|
63
|
+
self[1..-1].rubylog_unify other do
|
64
|
+
yield
|
65
|
+
end
|
66
|
+
end
|
67
|
+
# or A=[H,*T], [H,*T,...]=[*B,...]
|
68
|
+
part = [Rubylog::Variable.new, Rubylog::DSL::ArraySplat.new]
|
69
|
+
self[0].var.rubylog_unify part do
|
70
|
+
(part + self[1..-1]).rubylog_unify other do
|
71
|
+
yield
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
58
75
|
end
|
59
76
|
|
77
|
+
else
|
78
|
+
# if [*A,...] = [X,...]
|
79
|
+
# then eiter A=[], [...]=[X,...]
|
60
80
|
self[0].var.rubylog_unify [] do
|
61
81
|
self[1..-1].rubylog_unify other do
|
62
82
|
yield
|
63
83
|
end
|
64
84
|
end
|
85
|
+
# or A=[H,*T], [H,*T,...]=[X,...]
|
65
86
|
part = [Rubylog::Variable.new, Rubylog::DSL::ArraySplat.new]
|
66
87
|
self[0].var.rubylog_unify part do
|
67
88
|
(part + self[1..-1]).rubylog_unify other do
|
68
89
|
yield
|
69
90
|
end
|
70
91
|
end
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
92
|
+
end
|
93
|
+
|
94
|
+
else
|
95
|
+
# if [H,...]
|
96
|
+
case
|
97
|
+
when other.empty?
|
98
|
+
# [H,...] = []
|
99
|
+
# fail
|
100
|
+
when other[0].is_a?(Rubylog::DSL::ArraySplat)
|
101
|
+
# [H,...] = [*A,...]
|
102
|
+
# either []=A, [H,...]=[...]
|
103
|
+
[].rubylog_unify other[0].var do
|
104
|
+
self.rubylog_unify other[1..-1] do
|
105
|
+
yield
|
77
106
|
end
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
107
|
+
end
|
108
|
+
# or A=[X,*R], [H,...]=[X,*R,...]
|
109
|
+
part = [Rubylog::Variable.new, Rubylog::DSL::ArraySplat.new]
|
110
|
+
other[0].var.rubylog_unify part do
|
111
|
+
self.rubylog_unify(part + other[1..-1]) do
|
112
|
+
yield
|
83
113
|
end
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
114
|
+
end
|
115
|
+
else
|
116
|
+
# if [H,...]=[X,...]
|
117
|
+
# then H=X, [...]=[...]
|
118
|
+
self[0].rubylog_unify other[0] do
|
119
|
+
self[1..-1].rubylog_unify other[1..-1] do
|
120
|
+
yield
|
90
121
|
end
|
91
122
|
end
|
92
123
|
end
|
93
124
|
end
|
94
125
|
end
|
95
126
|
|
96
|
-
#
|
97
|
-
include Rubylog::
|
127
|
+
# CompoundTerm methods
|
128
|
+
include Rubylog::CompoundTerm
|
98
129
|
def rubylog_clone &block
|
99
130
|
block[map{|t|t.rubylog_clone &block}]
|
100
131
|
end
|
@@ -104,9 +135,11 @@ class Array
|
|
104
135
|
case t
|
105
136
|
when Rubylog::DSL::ArraySplat
|
106
137
|
v = t.var.rubylog_dereference
|
107
|
-
if v.is_a?
|
138
|
+
if v.is_a?(Array)
|
139
|
+
# if it could be resolved
|
108
140
|
v.rubylog_deep_dereference
|
109
141
|
else
|
142
|
+
# if it is still a variable
|
110
143
|
[t]
|
111
144
|
end
|
112
145
|
else
|