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
@@ -0,0 +1,24 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)+"/../lib"
|
2
|
+
require 'rubylog'
|
3
|
+
|
4
|
+
Rubylog.theory "Try" do
|
5
|
+
subject String
|
6
|
+
|
7
|
+
def primitives.hello
|
8
|
+
puts "Hello"
|
9
|
+
yield
|
10
|
+
end
|
11
|
+
|
12
|
+
def primitives.hello x
|
13
|
+
puts "Hello #{x.rubylog_deep_dereference}!"
|
14
|
+
yield
|
15
|
+
end
|
16
|
+
|
17
|
+
:hello_world.if "World".hello
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
p Try.prove :hello
|
23
|
+
p Try.prove :hello_world
|
24
|
+
p Try.prove{X.is("World").and X.hello}
|
data/examples/theory.rb
CHANGED
@@ -1,20 +1,32 @@
|
|
1
|
+
$:.unshift File.dirname(__FILE__)+"/../lib"
|
1
2
|
require 'rubylog'
|
2
3
|
|
3
|
-
class
|
4
|
-
|
5
|
-
if U.cannot_access_model(M).then :cut.and :fail
|
6
|
-
U.can_access_model(M).if M.is(Conversation).and {|u,m|m.users.include? u}
|
4
|
+
class User
|
5
|
+
attr_accessor :favorite, :possessions
|
7
6
|
|
8
|
-
|
7
|
+
def initialize favorite, possessions
|
8
|
+
@favorite, @possessions = favorite, possessions
|
9
|
+
end
|
10
|
+
end
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
+
Rubylog.theory "LikingTheory" do
|
13
|
+
functor :likes
|
14
|
+
U.likes(D).if {U.favorite == D}
|
15
|
+
end
|
12
16
|
|
17
|
+
Rubylog.theory "HavingTheory" do
|
18
|
+
functor :has
|
19
|
+
U.has(D).if {U.possessions.include? D}
|
13
20
|
end
|
14
21
|
|
15
|
-
|
16
|
-
|
22
|
+
Rubylog.theory "DrinkingTheory" do
|
23
|
+
functor :drinks
|
24
|
+
include LikingTheory, HavingTheory
|
25
|
+
subject User
|
17
26
|
|
27
|
+
U.drinks(D).if U.likes(D).and U.has(D)
|
18
28
|
end
|
19
29
|
|
20
|
-
|
30
|
+
joe = User.new :beer, [:water, :beer]
|
31
|
+
p DrinkingTheory.true? joe.drinks :water # false
|
32
|
+
p DrinkingTheory.true? joe.drinks :beer # true
|
@@ -0,0 +1,15 @@
|
|
1
|
+
theory "Rubylog::FileSystemBuiltins", nil do
|
2
|
+
subject String
|
3
|
+
functor :filename_in, :dirname_in, :file_in, :dir_in
|
4
|
+
|
5
|
+
X.filename_in(D).if Y.file_in(D).and X.is { File.basename Y }
|
6
|
+
X.dirname_in(D).if Y.dir_in(D).and X.is { File.basename Y }
|
7
|
+
X.file_in(D).if Y.in { d = D.rubylog_resolve_function; Dir["#{d}/*", "#{d}/.*"].sort }.and { not ['.','..'].include? File.basename(Y) and not File.directory? Y }.and X.is {File.expand_path Y}
|
8
|
+
X.dir_in(D). if Y.in { d = D.rubylog_resolve_function; Dir["#{d}/*", "#{d}/.*"].sort }.and { not ['.','..'].include? File.basename(Y) and File.directory? Y }.and X.is {File.expand_path Y}
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
Rubylog::DefaultBuiltins.amend do
|
14
|
+
include Rubylog::FileSystemBuiltins
|
15
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
Rubylog.theory "Rubylog::NullaryLogicBuiltins", nil do
|
2
|
+
class << primitives
|
3
|
+
# true
|
4
|
+
def true
|
5
|
+
yield
|
6
|
+
end
|
7
|
+
|
8
|
+
# fail
|
9
|
+
def fail
|
10
|
+
end
|
11
|
+
|
12
|
+
# !
|
13
|
+
def cut!
|
14
|
+
yield
|
15
|
+
throw :cut
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
Rubylog.theory "Rubylog::LogicBuiltinsForCallable", nil do
|
21
|
+
subject ::Rubylog::Callable, ::Rubylog::Structure, Symbol, Proc
|
22
|
+
|
23
|
+
class << primitives
|
24
|
+
# Succeeds if both +a+ and +b+ succeeds.
|
25
|
+
def and a, b
|
26
|
+
a.prove { b.prove { yield } }
|
27
|
+
end
|
28
|
+
|
29
|
+
# Succeeds if either +a+ or +b+ succeeds.
|
30
|
+
def or a, b
|
31
|
+
a.prove { yield }
|
32
|
+
b.prove { yield }
|
33
|
+
end
|
34
|
+
|
35
|
+
# Succeeds if +a+ does not succeed.
|
36
|
+
def false a
|
37
|
+
a.prove { return }
|
38
|
+
yield
|
39
|
+
end
|
40
|
+
|
41
|
+
# ruby iterator predicate allegories
|
42
|
+
|
43
|
+
# For each successful execution of +a+, executes +b+. If any of +b+'s
|
44
|
+
# executions fails, it fails, otherwise it succeeds.
|
45
|
+
def all a,b
|
46
|
+
a.prove {
|
47
|
+
stands = false;
|
48
|
+
b.prove { stands = true; break }
|
49
|
+
return if not stands
|
50
|
+
}
|
51
|
+
yield
|
52
|
+
end
|
53
|
+
|
54
|
+
# Equivalent with +a.all(b).and b.all(a)+
|
55
|
+
def iff a,b
|
56
|
+
all(a,b) { all(b,a) { yield } }
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
def any a,b
|
61
|
+
a.prove { b.prove { yield; return } }
|
62
|
+
end
|
63
|
+
|
64
|
+
def one a,b
|
65
|
+
stands = false
|
66
|
+
a.prove {
|
67
|
+
b.prove {
|
68
|
+
return if stands
|
69
|
+
stands = true
|
70
|
+
}
|
71
|
+
}
|
72
|
+
yield if stands
|
73
|
+
end
|
74
|
+
|
75
|
+
def none a,b
|
76
|
+
a.prove { b.prove { return } }
|
77
|
+
yield
|
78
|
+
end
|
79
|
+
|
80
|
+
def any a
|
81
|
+
a.prove { yield; return }
|
82
|
+
end
|
83
|
+
|
84
|
+
def one a
|
85
|
+
stands = false
|
86
|
+
a.prove {
|
87
|
+
return if stands
|
88
|
+
stands = true
|
89
|
+
}
|
90
|
+
yield if stands
|
91
|
+
end
|
92
|
+
|
93
|
+
alias none false
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
prefix_functor :all, :any, :one, :none, :iff
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
Rubylog.theory "Rubylog::LogicBuiltins", nil do
|
102
|
+
include Rubylog::NullaryLogicBuiltins
|
103
|
+
include Rubylog::LogicBuiltinsForCallable
|
104
|
+
end
|
105
|
+
|
106
|
+
Rubylog::DefaultBuiltins.amend do
|
107
|
+
include Rubylog::LogicBuiltins
|
108
|
+
end
|
109
|
+
|
@@ -0,0 +1,94 @@
|
|
1
|
+
Rubylog.theory "Rubylog::ReflectionBuiltinsForStructure", nil do
|
2
|
+
subject Rubylog::Structure
|
3
|
+
|
4
|
+
class << primitives
|
5
|
+
|
6
|
+
# Succeeds if +c+ is a structure, with functor +fct+ and arguments +args+
|
7
|
+
def structure c, fct, args
|
8
|
+
c = c.rubylog_dereference
|
9
|
+
if c.is_a? Rubylog::Variable
|
10
|
+
fct = fct.rubylog_dereference
|
11
|
+
args = args.rubylog_dereference
|
12
|
+
# We enable variable functors
|
13
|
+
#raise Rubylog::InstantiationError, fct if fct.is_a? Rubylog::Variable
|
14
|
+
raise Rubylog::InstantiationError, args if args.is_a? Rubylog::Variable
|
15
|
+
c.rubylog_unify(Rubylog::Structure.new(fct, *args)) { yield }
|
16
|
+
elsif c.is_a? Rubylog::Structure
|
17
|
+
c.functor.rubylog_unify fct do
|
18
|
+
c.args.rubylog_unify args do
|
19
|
+
yield
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# I don't remember what this is supposed to be.
|
26
|
+
#def predicate l
|
27
|
+
#_functor = Rubylog::Variable.new(:_functor)
|
28
|
+
#_arity = Rubylog::Variable.new(:_arity)
|
29
|
+
#l.rubylog_unify [f, a] do
|
30
|
+
#if f = _functor.value
|
31
|
+
## TODO
|
32
|
+
#else
|
33
|
+
## TODO
|
34
|
+
#end
|
35
|
+
#end
|
36
|
+
#end
|
37
|
+
|
38
|
+
# Succeeds if +head+ unifies with a fact.
|
39
|
+
def fact head
|
40
|
+
head = head.rubylog_dereference
|
41
|
+
raise Rubylog::InstantiationError, head if head.is_a? Rubylog::Variable
|
42
|
+
return yield if head == :true
|
43
|
+
return unless head.respond_to? :functor
|
44
|
+
predicate = Rubylog.current_theory[head.indicator]
|
45
|
+
if predicate.respond_to? :each # if it is a procedure
|
46
|
+
predicate.each do |rule|
|
47
|
+
if rule[1] == :true
|
48
|
+
rule = rule.rubylog_compile_variables
|
49
|
+
rule[0].args.rubylog_unify head.args do
|
50
|
+
yield
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Succeeds if +head+ unifies with a rule's head and +body+ unifies with
|
58
|
+
# this rule's body.
|
59
|
+
def follows_from head, body
|
60
|
+
head = head.rubylog_dereference
|
61
|
+
raise Rubylog::InstantiationError, head if head.is_a? Rubylog::Variable
|
62
|
+
return unless head.respond_to? :functor
|
63
|
+
predicate = Rubylog.current_theory[head.indicator]
|
64
|
+
if predicate.respond_to? :each
|
65
|
+
predicate.each do |rule|
|
66
|
+
unless rule[1]==:true # do not succeed for facts
|
67
|
+
rule = rule.rubylog_compile_variables
|
68
|
+
rule[0].args.rubylog_unify head.args do
|
69
|
+
rule[1].rubylog_unify body do
|
70
|
+
yield
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Succeeds if +a+ unifies with a variable by the name +name+ in the variable binding
|
79
|
+
# context of +name+.
|
80
|
+
# Removed because of the "every built-in prediate is pure logical" principle
|
81
|
+
#def variable a, name
|
82
|
+
#vars = name.rubylog_variables
|
83
|
+
#raise Rubylog::InvalidStateError, "variables not available" if not vars
|
84
|
+
#vars.find
|
85
|
+
#end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
Rubylog.theory "Rubylog::ReflectionBuiltins", nil do
|
89
|
+
include Rubylog::ReflectionBuiltinsForStructure
|
90
|
+
end
|
91
|
+
|
92
|
+
Rubylog::DefaultBuiltins.amend do
|
93
|
+
include Rubylog::ReflectionBuiltins
|
94
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
Rubylog.theory "Rubylog::TermBuiltins", nil do
|
2
|
+
subject ::Rubylog::Term
|
3
|
+
|
4
|
+
class << primitives
|
5
|
+
# = is
|
6
|
+
def is a,b
|
7
|
+
a = a.rubylog_resolve_function
|
8
|
+
b = b.rubylog_resolve_function
|
9
|
+
a.rubylog_unify(b) { yield }
|
10
|
+
end
|
11
|
+
|
12
|
+
def is_not a,b
|
13
|
+
a = a.rubylog_resolve_function
|
14
|
+
b = b.rubylog_resolve_function
|
15
|
+
a.rubylog_unify(b) { return }
|
16
|
+
yield
|
17
|
+
end
|
18
|
+
|
19
|
+
# member
|
20
|
+
def in a,b
|
21
|
+
a = a.rubylog_resolve_function
|
22
|
+
b = b.rubylog_resolve_function.rubylog_dereference
|
23
|
+
if b.instance_of? Rubylog::Variable
|
24
|
+
Rubylog::InternalHelpers.non_empty_list {|l|
|
25
|
+
a.rubylog_unify(l[-1]) {
|
26
|
+
b.rubylog_unify(l) {
|
27
|
+
yield
|
28
|
+
}
|
29
|
+
}
|
30
|
+
}
|
31
|
+
else
|
32
|
+
b.each do |e|
|
33
|
+
a.rubylog_unify(e) { yield }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def not_in a, b
|
39
|
+
self.in(a, b) { return }
|
40
|
+
yield
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
Rubylog::DefaultBuiltins.amend do
|
46
|
+
include Rubylog::TermBuiltins
|
47
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# this class is used as a placeholder for array splats.
|
2
|
+
# [*A] => [ArraySplat.new(A)]
|
3
|
+
class Rubylog::DSL::ArraySplat
|
4
|
+
|
5
|
+
attr_reader :var
|
6
|
+
|
7
|
+
def initialize var = Rubylog::Variable.new
|
8
|
+
@var = var
|
9
|
+
end
|
10
|
+
|
11
|
+
def inspect
|
12
|
+
"*#{var}"
|
13
|
+
end
|
14
|
+
|
15
|
+
# CompositeTerm methods
|
16
|
+
include Rubylog::CompositeTerm
|
17
|
+
|
18
|
+
def rubylog_clone &block
|
19
|
+
block[Rubylog::DSL::ArraySplat.new(@var.rubylog_clone(&block))]
|
20
|
+
end
|
21
|
+
|
22
|
+
def rubylog_deep_dereference
|
23
|
+
Rubylog::DSL::ArraySplat.new(@var.rubylog_deep_dereference)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class Rubylog::DSL::Primitives
|
2
|
+
def initialize theory
|
3
|
+
@theory = theory
|
4
|
+
end
|
5
|
+
|
6
|
+
def singleton_method_added name
|
7
|
+
unless name == :singleton_method_added
|
8
|
+
m = method(name)
|
9
|
+
@theory.functor name unless m.arity.zero?
|
10
|
+
@theory[[name, m.arity]] = m
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def inspect
|
15
|
+
"primitives"
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Rubylog::DSL::Thats < BasicObject
|
2
|
+
def method_missing *msg
|
3
|
+
@messages ||= []
|
4
|
+
@messages << msg
|
5
|
+
self
|
6
|
+
end
|
7
|
+
|
8
|
+
def rubylog_matches_as_guard? other
|
9
|
+
@messages.inject(other) {|o,msg|o.send *msg}
|
10
|
+
end
|
11
|
+
|
12
|
+
def == *msg
|
13
|
+
method_missing :==, *msg
|
14
|
+
end
|
15
|
+
|
16
|
+
debug = true
|
17
|
+
if debug
|
18
|
+
def inspect
|
19
|
+
@messages
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Rubylog::DSL::Variables
|
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
|
8
|
+
|
9
|
+
# find the appropriate variable name
|
10
|
+
var = vars.find{|v|v.name == c}
|
11
|
+
|
12
|
+
# return new variable if not found (probably the user wants to start using a new
|
13
|
+
# one)
|
14
|
+
return Rubylog::Variable.new c unless var
|
15
|
+
|
16
|
+
# dereference it
|
17
|
+
result = var.rubylog_deep_dereference
|
18
|
+
|
19
|
+
# return nil if not bound
|
20
|
+
return nil if result.is_a? Rubylog::Variable
|
21
|
+
|
22
|
+
# return the value
|
23
|
+
result
|
24
|
+
else
|
25
|
+
Rubylog::Variable.new c
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
data/lib/rubylog/dsl.rb
CHANGED
@@ -1,52 +1,70 @@
|
|
1
1
|
module Rubylog::DSL
|
2
|
-
def self.add_first_order_functor *fs
|
3
|
-
add_functors_to FirstOrderFunctors, *fs
|
4
|
-
end
|
5
|
-
|
6
|
-
def self.add_second_order_functor *fs
|
7
|
-
add_functors_to SecondOrderFunctors, *fs
|
8
|
-
end
|
9
|
-
|
10
2
|
def self.add_functors_to class_or_module, *functors
|
11
3
|
functors.each do |f|
|
12
4
|
m = functor_module(f)
|
13
5
|
class_or_module.send :include, m
|
14
6
|
Rubylog::Variable.send :include, m
|
15
|
-
add_global_functor f
|
16
7
|
end
|
17
8
|
end
|
9
|
+
|
18
10
|
|
19
11
|
@functor_modules ||= {}
|
20
12
|
|
13
|
+
def self.normalize_functor fct
|
14
|
+
case s = fct.to_s
|
15
|
+
when /[?!]\z/ then :"#{s[0...-1]}"
|
16
|
+
when /=\z/ then nil
|
17
|
+
else fct
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
21
|
def self.functor_module f
|
22
22
|
@functor_modules[f] ||= Module.new do
|
23
23
|
define_method f do |*args, &block|
|
24
24
|
args << block if block
|
25
|
-
Rubylog::
|
25
|
+
Rubylog::Structure.new f, self, *args
|
26
26
|
end
|
27
27
|
|
28
28
|
f_bang = :"#{f}!"
|
29
29
|
define_method f_bang do |*args, &block|
|
30
30
|
args << block if block
|
31
|
-
Rubylog.
|
31
|
+
Rubylog.current_theory.assert Rubylog::Structure.new(f, self, *args), :true
|
32
32
|
self
|
33
33
|
end
|
34
34
|
|
35
35
|
f_qmark = :"#{f}?"
|
36
36
|
define_method f_qmark do |*args, &block|
|
37
37
|
args << block if block
|
38
|
-
Rubylog.
|
38
|
+
Rubylog.current_theory.true? Rubylog::Structure.new(f, self, *args)
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
|
43
|
+
def self.add_prefix_functors_to class_or_module, *functors
|
44
|
+
functors.each do |f|
|
45
|
+
class_or_module.class_eval do
|
46
|
+
define_method f do |*args, &block|
|
47
|
+
args << block if block
|
48
|
+
Rubylog::Structure.new f, *args
|
49
|
+
end
|
50
|
+
|
51
|
+
f_bang = :"#{f}!"
|
52
|
+
define_method f_bang do |*args, &block|
|
53
|
+
args << block if block
|
54
|
+
# TODO consider self.assert
|
55
|
+
Rubylog.current_theory.assert Rubylog::Structure.new(f, *args), :true
|
56
|
+
self
|
57
|
+
end
|
44
58
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
59
|
+
f_qmark = :"#{f}?"
|
60
|
+
define_method f_qmark do |*args, &block|
|
61
|
+
args << block if block
|
62
|
+
#TODO consider self.true?
|
63
|
+
Rubylog.current_theory.true? Rubylog::Structure.new(f, *args)
|
64
|
+
end
|
65
|
+
end
|
49
66
|
end
|
50
67
|
end
|
68
|
+
|
51
69
|
end
|
52
70
|
|
data/lib/rubylog/errors.rb
CHANGED
@@ -1,8 +1,14 @@
|
|
1
1
|
module Rubylog
|
2
2
|
class RubylogError < StandardError
|
3
3
|
end
|
4
|
+
|
5
|
+
class SyntaxError < RubylogError
|
6
|
+
end
|
7
|
+
|
8
|
+
class DiscontiguousPredicateError < RubylogError
|
9
|
+
end
|
4
10
|
|
5
|
-
class
|
11
|
+
class MultitheoryError < RubylogError
|
6
12
|
end
|
7
13
|
|
8
14
|
class BuiltinPredicateError < RubylogError
|
@@ -14,5 +20,17 @@ module Rubylog
|
|
14
20
|
class InvalidStateError < RubylogError
|
15
21
|
end
|
16
22
|
|
23
|
+
class InstantiationError < RubylogError
|
24
|
+
end
|
25
|
+
|
26
|
+
class TypeError < RubylogError
|
27
|
+
end
|
28
|
+
|
29
|
+
class UnknownVariableError < RubylogError
|
30
|
+
end
|
31
|
+
|
32
|
+
class CheckFailed < StandardError
|
33
|
+
end
|
34
|
+
|
17
35
|
end
|
18
36
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Rubylog::Assertable
|
2
|
+
def if body=nil, &block
|
3
|
+
raise Rubylog::SyntaxError, "No body given", caller unless body || block
|
4
|
+
Rubylog.current_theory.assert self, body || block
|
5
|
+
end
|
6
|
+
|
7
|
+
def if! body=nil, &block
|
8
|
+
raise Rubylog::SyntaxError, "No body given", caller unless body || block
|
9
|
+
Rubylog.current_theory.assert self, Rubylog::Structure.new(:and, :cut!, body || block)
|
10
|
+
end
|
11
|
+
|
12
|
+
def unless body=nil, &block
|
13
|
+
raise Rubylog::SyntaxError, "No body given", caller unless body || block
|
14
|
+
Rubylog.current_theory.assert self, Rubylog::Structure.new(:false, body || block)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Rubylog::Callable
|
2
|
+
# should yield for each possible solution of the term
|
3
|
+
#def prove
|
4
|
+
# raise "abstract method called"
|
5
|
+
#end
|
6
|
+
|
7
|
+
def true?
|
8
|
+
Rubylog.current_theory.true? self
|
9
|
+
end
|
10
|
+
|
11
|
+
def solve
|
12
|
+
if block_given?
|
13
|
+
Rubylog.current_theory.solve(self) {|*a| yield *a}
|
14
|
+
else
|
15
|
+
Rubylog.current_theory.solve(self) {|*a|}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Rubylog::CompositeTerm
|
2
|
+
def rubylog_compile_variables
|
3
|
+
vars = []; vars_by_name = {}
|
4
|
+
rubylog_clone do |subterm|
|
5
|
+
case subterm
|
6
|
+
when Rubylog::Variable
|
7
|
+
var = subterm
|
8
|
+
|
9
|
+
if var.dont_care?
|
10
|
+
var.dup
|
11
|
+
else
|
12
|
+
new_var = vars_by_name[var.name]
|
13
|
+
if new_var
|
14
|
+
new_var.guards = new_var.guards + var.guards
|
15
|
+
new_var
|
16
|
+
else
|
17
|
+
new_var = var.dup
|
18
|
+
vars << new_var
|
19
|
+
vars_by_name[var.name] = new_var
|
20
|
+
new_var
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
when Rubylog::CompositeTerm
|
25
|
+
subterm.instance_variable_set :"@rubylog_variables", vars
|
26
|
+
subterm
|
27
|
+
else
|
28
|
+
subterm
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
#should return a copy with rubylog_deep_dereference called for sub-terms
|
34
|
+
#def rubylog_deep_dereference
|
35
|
+
#self.class.new attr1.rubylog_deep_dereference
|
36
|
+
#end
|
37
|
+
|
38
|
+
attr_reader :rubylog_variables
|
39
|
+
|
40
|
+
|
41
|
+
# This is a general deep-copy generating method
|
42
|
+
# should return a deep copy of the term, atomic terms treated as
|
43
|
+
# leaves, with &block called post-order
|
44
|
+
#def rubylog_clone &block
|
45
|
+
#block.call self.class.new attr1.rubylog_clone &block
|
46
|
+
#end
|
47
|
+
end
|