rubylog 0.0.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|