mini_kraken 0.2.02 → 0.3.02
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +378 -333
- data/CHANGELOG.md +52 -0
- data/README.md +19 -19
- data/lib/mini_kraken.rb +0 -1
- data/lib/mini_kraken/atomic/all_atomic.rb +5 -0
- data/lib/mini_kraken/atomic/atomic_term.rb +96 -0
- data/lib/mini_kraken/atomic/k_boolean.rb +42 -0
- data/lib/mini_kraken/{core → atomic}/k_integer.rb +2 -5
- data/lib/mini_kraken/atomic/k_string.rb +17 -0
- data/lib/mini_kraken/{core → atomic}/k_symbol.rb +4 -8
- data/lib/mini_kraken/composite/all_composite.rb +4 -0
- data/lib/mini_kraken/composite/composite_term.rb +27 -0
- data/lib/mini_kraken/composite/cons_cell.rb +299 -0
- data/lib/mini_kraken/composite/cons_cell_visitor.rb +50 -0
- data/lib/mini_kraken/composite/list.rb +32 -0
- data/lib/mini_kraken/core/all_core.rb +8 -0
- data/lib/mini_kraken/core/any_value.rb +31 -7
- data/lib/mini_kraken/core/arity.rb +69 -0
- data/lib/mini_kraken/core/association.rb +29 -4
- data/lib/mini_kraken/core/association_copy.rb +50 -0
- data/lib/mini_kraken/core/base_term.rb +13 -0
- data/lib/mini_kraken/core/blackboard.rb +315 -0
- data/lib/mini_kraken/core/bookmark.rb +46 -0
- data/lib/mini_kraken/core/context.rb +492 -0
- data/lib/mini_kraken/core/duck_fiber.rb +21 -19
- data/lib/mini_kraken/core/entry.rb +40 -0
- data/lib/mini_kraken/core/fail.rb +20 -18
- data/lib/mini_kraken/core/fusion.rb +29 -0
- data/lib/mini_kraken/core/goal.rb +20 -29
- data/lib/mini_kraken/core/log_var.rb +22 -0
- data/lib/mini_kraken/core/log_var_ref.rb +108 -0
- data/lib/mini_kraken/core/nullary_relation.rb +2 -9
- data/lib/mini_kraken/core/parametrized_term.rb +61 -0
- data/lib/mini_kraken/core/relation.rb +14 -28
- data/lib/mini_kraken/core/scope.rb +67 -0
- data/lib/mini_kraken/core/solver_adapter.rb +58 -0
- data/lib/mini_kraken/core/specification.rb +48 -0
- data/lib/mini_kraken/core/succeed.rb +21 -17
- data/lib/mini_kraken/core/symbol_table.rb +137 -0
- data/lib/mini_kraken/core/term.rb +15 -4
- data/lib/mini_kraken/glue/dsl.rb +45 -81
- data/lib/mini_kraken/glue/run_star_expression.rb +28 -30
- data/lib/mini_kraken/rela/all_rela.rb +8 -0
- data/lib/mini_kraken/rela/binary_relation.rb +30 -0
- data/lib/mini_kraken/rela/conde.rb +143 -0
- data/lib/mini_kraken/rela/conj2.rb +65 -0
- data/lib/mini_kraken/rela/def_relation.rb +93 -0
- data/lib/mini_kraken/rela/disj2.rb +70 -0
- data/lib/mini_kraken/rela/fresh.rb +98 -0
- data/lib/mini_kraken/{core → rela}/goal_relation.rb +7 -9
- data/lib/mini_kraken/rela/unify.rb +258 -0
- data/lib/mini_kraken/version.rb +1 -1
- data/mini_kraken.gemspec +2 -2
- data/spec/.rubocop.yml +1 -1
- data/spec/atomic/atomic_term_spec.rb +98 -0
- data/spec/{core → atomic}/k_boolean_spec.rb +19 -34
- data/spec/{core → atomic}/k_symbol_spec.rb +3 -16
- data/spec/composite/cons_cell_spec.rb +225 -0
- data/spec/composite/cons_cell_visitor_spec.rb +158 -0
- data/spec/composite/list_spec.rb +50 -0
- data/spec/core/any_value_spec.rb +52 -0
- data/spec/core/arity_spec.rb +92 -0
- data/spec/core/association_copy_spec.rb +69 -0
- data/spec/core/association_spec.rb +31 -4
- data/spec/core/blackboard_spec.rb +287 -0
- data/spec/core/bookmark_spec.rb +40 -0
- data/spec/core/context_spec.rb +245 -0
- data/spec/core/core_spec.rb +40 -0
- data/spec/core/duck_fiber_spec.rb +16 -46
- data/spec/core/fail_spec.rb +5 -6
- data/spec/core/goal_spec.rb +24 -14
- data/spec/core/log_var_ref_spec.rb +105 -0
- data/spec/core/log_var_spec.rb +64 -0
- data/spec/core/nullary_relation_spec.rb +33 -0
- data/spec/core/parametrized_tem_spec.rb +39 -0
- data/spec/core/relation_spec.rb +33 -0
- data/spec/core/scope_spec.rb +73 -0
- data/spec/core/solver_adapter_spec.rb +70 -0
- data/spec/core/specification_spec.rb +43 -0
- data/spec/core/succeed_spec.rb +5 -5
- data/spec/core/symbol_table_spec.rb +142 -0
- data/spec/glue/dsl_chap1_spec.rb +96 -144
- data/spec/glue/dsl_chap2_spec.rb +350 -0
- data/spec/glue/run_star_expression_spec.rb +82 -906
- data/spec/rela/conde_spec.rb +153 -0
- data/spec/rela/conj2_spec.rb +123 -0
- data/spec/rela/def_relation_spec.rb +119 -0
- data/spec/rela/disj2_spec.rb +117 -0
- data/spec/rela/fresh_spec.rb +147 -0
- data/spec/rela/unify_spec.rb +369 -0
- data/spec/support/factory_atomic.rb +29 -0
- data/spec/support/factory_composite.rb +21 -0
- data/spec/support/factory_methods.rb +11 -26
- metadata +100 -64
- data/lib/mini_kraken/core/association_walker.rb +0 -183
- data/lib/mini_kraken/core/atomic_term.rb +0 -67
- data/lib/mini_kraken/core/base_arg.rb +0 -10
- data/lib/mini_kraken/core/binary_relation.rb +0 -63
- data/lib/mini_kraken/core/composite_goal.rb +0 -46
- data/lib/mini_kraken/core/composite_term.rb +0 -41
- data/lib/mini_kraken/core/conde.rb +0 -143
- data/lib/mini_kraken/core/conj2.rb +0 -79
- data/lib/mini_kraken/core/cons_cell.rb +0 -82
- data/lib/mini_kraken/core/def_relation.rb +0 -50
- data/lib/mini_kraken/core/designation.rb +0 -55
- data/lib/mini_kraken/core/disj2.rb +0 -72
- data/lib/mini_kraken/core/environment.rb +0 -73
- data/lib/mini_kraken/core/equals.rb +0 -156
- data/lib/mini_kraken/core/formal_arg.rb +0 -22
- data/lib/mini_kraken/core/formal_ref.rb +0 -25
- data/lib/mini_kraken/core/freshness.rb +0 -45
- data/lib/mini_kraken/core/goal_arg.rb +0 -12
- data/lib/mini_kraken/core/goal_template.rb +0 -62
- data/lib/mini_kraken/core/k_boolean.rb +0 -35
- data/lib/mini_kraken/core/outcome.rb +0 -53
- data/lib/mini_kraken/core/variable.rb +0 -41
- data/lib/mini_kraken/core/variable_ref.rb +0 -78
- data/lib/mini_kraken/core/vocabulary.rb +0 -442
- data/lib/mini_kraken/glue/fresh_env.rb +0 -75
- data/spec/core/association_walker_spec.rb +0 -192
- data/spec/core/conde_spec.rb +0 -147
- data/spec/core/conj2_spec.rb +0 -114
- data/spec/core/cons_cell_spec.rb +0 -107
- data/spec/core/def_relation_spec.rb +0 -96
- data/spec/core/disj2_spec.rb +0 -99
- data/spec/core/environment_spec.rb +0 -142
- data/spec/core/equals_spec.rb +0 -304
- data/spec/core/goal_template_spec.rb +0 -74
- data/spec/core/outcome_spec.rb +0 -48
- data/spec/core/variable_ref_spec.rb +0 -27
- data/spec/core/variable_spec.rb +0 -35
- data/spec/core/vocabulary_spec.rb +0 -219
- data/spec/glue/fresh_env_spec.rb +0 -62
@@ -1,37 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'specification'
|
4
|
+
require_relative 'context'
|
5
|
+
|
3
6
|
module MiniKraken
|
4
7
|
module Core
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
# @param
|
13
|
-
# @param
|
14
|
-
|
15
|
-
|
16
|
-
@alt_name = alternateName
|
17
|
-
end
|
18
|
-
|
19
|
-
# A relation is polyadic when it accepts an arbitrary number of arguments.
|
20
|
-
# Most built-in relation takes a fixed number of arguments (= arity).
|
21
|
-
# @return [Boolean]
|
22
|
-
def polyadic?
|
23
|
-
false
|
24
|
-
end
|
25
|
-
|
26
|
-
# Number of arguments for the relation.
|
27
|
-
# @return [Integer]
|
28
|
-
def arity
|
8
|
+
# Formally, a n-relation over R, where R represents the cartesian product
|
9
|
+
# (A1 x A2 x ... An) is a subset of R.
|
10
|
+
# In other words, a n-relation is a subset of all tuples represented by R.
|
11
|
+
# In MiniKraken, a n-relation is an object that indicates whether a given
|
12
|
+
# tuple -of length n- is valid (or non valid).
|
13
|
+
class Relation < Specification
|
14
|
+
# Abstract method to override in subclass(es).
|
15
|
+
# @param actuals [Array<Term>] Argument count must
|
16
|
+
# @param ctx [Core::Context] Runtime context
|
17
|
+
# @return [#resume] A Fiber-like object that yields Context.
|
18
|
+
def solver_for(actuals, ctx)
|
29
19
|
raise NotImplementedError
|
30
20
|
end
|
31
|
-
|
32
|
-
def inspect
|
33
|
-
alt_name || name
|
34
|
-
end
|
35
21
|
end # class
|
36
22
|
end # module
|
37
23
|
end # module
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'log_var'
|
4
|
+
|
5
|
+
module MiniKraken
|
6
|
+
module Core
|
7
|
+
# A scope is a name space that corresponds either to a specific
|
8
|
+
# delimited region in MiniKraken source code or to an activation record
|
9
|
+
# of a relation or a relation definition.
|
10
|
+
# It contains a map of names to the objects they name (e.g. logical var)
|
11
|
+
class Scope
|
12
|
+
# The parent (enclosing) scope.
|
13
|
+
# @return [Scope, NilClass]
|
14
|
+
attr_accessor :parent
|
15
|
+
|
16
|
+
# Mapping from user-defined name to related definition
|
17
|
+
# (say, a logical variable object)
|
18
|
+
# @return [Hash{String => LogVar}] Pairs of the kind
|
19
|
+
attr_reader :defns
|
20
|
+
|
21
|
+
# Construct a scope instance.
|
22
|
+
# TODO: extend with defrel and procedure
|
23
|
+
# @param aParent [Scope, NilClass] Parent scope to this one.
|
24
|
+
def initialize(aParent = nil)
|
25
|
+
@parent = aParent
|
26
|
+
@defns = {}
|
27
|
+
end
|
28
|
+
|
29
|
+
# Add a new logical variable to the scope.
|
30
|
+
# @param anEntry [LogVar]
|
31
|
+
# @return [LogVar] the variable
|
32
|
+
def insert(anEntry)
|
33
|
+
e = validated_entry(anEntry)
|
34
|
+
e.suffix = default_suffix if e.kind_of?(LogVar)
|
35
|
+
defns[e.name] = e
|
36
|
+
|
37
|
+
e
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns a string with a human-readable representation of the object.
|
41
|
+
# @return [String]
|
42
|
+
def inspect
|
43
|
+
+"#<#{self.class}:#{object_id.to_s(16)}>"
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def validated_entry(anEntry)
|
49
|
+
name = anEntry.name
|
50
|
+
unless name.kind_of?(String) && !name.empty?
|
51
|
+
err_msg = 'Invalid variable name argument.'
|
52
|
+
raise StandardError, err_msg
|
53
|
+
end
|
54
|
+
if defns.include?(name)
|
55
|
+
err_msg = "Variable with name '#{name}' already exists."
|
56
|
+
raise StandardError, err_msg
|
57
|
+
end
|
58
|
+
|
59
|
+
anEntry
|
60
|
+
end
|
61
|
+
|
62
|
+
def default_suffix
|
63
|
+
@default_suffix ||= "_#{object_id.to_s(16)}"
|
64
|
+
end
|
65
|
+
end # class
|
66
|
+
end # module
|
67
|
+
end # module
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MiniKraken
|
4
|
+
module Core
|
5
|
+
# A wrapper around a "solver" object.
|
6
|
+
# A solver in MiniKraken is Fiber or an object that quacks like
|
7
|
+
# a Fiber in that its has a 'resume' method.
|
8
|
+
# To be a solver, the adaptee object must yield a Context or nil.
|
9
|
+
# A SolverAdapter implements a customized resume method that
|
10
|
+
# acts as an "execute around" method for the adaptee's ´resume´ method.
|
11
|
+
class SolverAdapter
|
12
|
+
# @return [#resume] A Fiber-like object as adaptee
|
13
|
+
attr_reader :adaptee
|
14
|
+
|
15
|
+
# ->(adapter, aContext) do
|
16
|
+
# aContext.push_bookmark(adapter.adaptee)
|
17
|
+
# result = adapter.adaptee.resume
|
18
|
+
# aContext.pop_bookmark
|
19
|
+
# result
|
20
|
+
# end
|
21
|
+
# @return [Proc] lambda to execute when resume is called
|
22
|
+
attr_reader :around_resume
|
23
|
+
|
24
|
+
# Constructor.
|
25
|
+
# @param fib [#resume] A Fiber-like object
|
26
|
+
def initialize(fib, &blk)
|
27
|
+
@adaptee = validated_adaptee(fib)
|
28
|
+
@around_resume = blk if block_given?
|
29
|
+
end
|
30
|
+
|
31
|
+
# Update the bookmarks and resume the Fiber
|
32
|
+
# @param aContext [Core::Context]
|
33
|
+
# @return [Core::Context, NilClass]
|
34
|
+
def resume(aContext)
|
35
|
+
ctx = validated_ctx(aContext)
|
36
|
+
if around_resume
|
37
|
+
around_resume.call(self, ctx)
|
38
|
+
else
|
39
|
+
adaptee.resume
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def validated_adaptee(fib)
|
46
|
+
raise StandardError, 'No resume method' unless fib.respond_to?(:resume)
|
47
|
+
|
48
|
+
fib
|
49
|
+
end
|
50
|
+
|
51
|
+
def validated_ctx(aContext)
|
52
|
+
raise StandardError unless aContext.kind_of?(Context)
|
53
|
+
|
54
|
+
aContext
|
55
|
+
end
|
56
|
+
end # class
|
57
|
+
end # module
|
58
|
+
end # module
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'arity'
|
4
|
+
|
5
|
+
module MiniKraken
|
6
|
+
module Core
|
7
|
+
class Specification
|
8
|
+
# @return [String] Name of the specification object.
|
9
|
+
attr_reader :name
|
10
|
+
|
11
|
+
# @return [Arity] arity = allowed number of arguments
|
12
|
+
attr_reader :arity
|
13
|
+
|
14
|
+
# @param aName [String] Name of the relation.
|
15
|
+
# @param anArity [Arity, Integer] Arity of the relation.
|
16
|
+
def initialize(aName, anArity)
|
17
|
+
@name = aName
|
18
|
+
@arity = anArity.is_a?(Integer) ? Arity.new(anArity, anArity) : anArity
|
19
|
+
end
|
20
|
+
|
21
|
+
# A relation is variadic when it accepts an arbitrary number of arguments.
|
22
|
+
# Most built-in relation takes a fixed number of arguments (= arity).
|
23
|
+
# @return [Boolean]
|
24
|
+
def variadic?
|
25
|
+
arity.variadic?
|
26
|
+
end
|
27
|
+
|
28
|
+
def inspect
|
29
|
+
name + "[#{arity.low}]"
|
30
|
+
end
|
31
|
+
|
32
|
+
# Control that the number of actual arguments matches
|
33
|
+
# the relation's arity.
|
34
|
+
# Raise an exception if the check fails
|
35
|
+
# @param actuals [Array<Term>] Actuals from a goal.
|
36
|
+
# @return [Array<Term>] Input array if compatible with arity.
|
37
|
+
def check_arity(actuals)
|
38
|
+
unless arity.match?(actuals.size)
|
39
|
+
msg1 = "Count of arguments (#{actuals.size})"
|
40
|
+
msg2 = " is out of allowed range (#{arity.low}, #{arity.high})."
|
41
|
+
raise StandardError, msg1 + msg2
|
42
|
+
end
|
43
|
+
|
44
|
+
actuals
|
45
|
+
end
|
46
|
+
end # class
|
47
|
+
end # module
|
48
|
+
end # module
|
@@ -4,23 +4,27 @@ require 'singleton'
|
|
4
4
|
require_relative 'duck_fiber'
|
5
5
|
require_relative 'nullary_relation'
|
6
6
|
|
7
|
-
|
8
|
-
module
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
include Singleton
|
7
|
+
module MiniKraken
|
8
|
+
module Core
|
9
|
+
# A nullary relation that always returns success outcomes.
|
10
|
+
class Succeed < NullaryRelation
|
11
|
+
include Singleton
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
# Constructor. Initialize the relation's name & freeze it...
|
14
|
+
def initialize
|
15
|
+
super('succeed')
|
16
|
+
end
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
# Returns a Fiber-like object (a DuckFiber).
|
19
|
+
# When that object receives the message resume, it will
|
20
|
+
# return a success context.
|
21
|
+
# @param _actuals [Array] MUST be empty array for nullary relation.
|
22
|
+
# @param ctx [Core::Context] Runtime context
|
23
|
+
# @return [Core::DuckFiber]
|
24
|
+
def solver_for(_actuals, ctx)
|
25
|
+
# Important: every `solver_for` call will result in a distinct Context.
|
26
|
+
DuckFiber.new(-> { ctx.succeeded! })
|
27
|
+
end
|
28
|
+
end # class
|
25
29
|
end # module
|
26
|
-
end #
|
30
|
+
end # module
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'scope'
|
4
|
+
|
5
|
+
module MiniKraken
|
6
|
+
module Core
|
7
|
+
# A symbol table is basically a mapping from a name onto an object
|
8
|
+
# that holds information associated with that name. It is a data structure
|
9
|
+
# that keeps track of variables and their respective scope where they are
|
10
|
+
# declared. The key requirements for the symbol are:
|
11
|
+
# - To perform fast lookup operations: given a name, retrieve the corresponding
|
12
|
+
# object.
|
13
|
+
# - To allow the efficient insertion of names and related information
|
14
|
+
# - To support the nesting of scopes
|
15
|
+
# - To handle the entry scope and exit scope events,
|
16
|
+
# - To cope with variable redefinition in nested scope
|
17
|
+
# The terminology 'symbol table' comes from the compiler design
|
18
|
+
# community.
|
19
|
+
class SymbolTable
|
20
|
+
# Mapping between a name and the scope(s) where it is defined
|
21
|
+
# @return [Hash{String => Array<Scope>}]
|
22
|
+
attr_reader :name2scopes
|
23
|
+
|
24
|
+
# @return [Scope] The top-level scope (= root of the tree of scopes)
|
25
|
+
attr_reader :root
|
26
|
+
|
27
|
+
# @return [Scope] The current scope.
|
28
|
+
attr_reader :current_scope
|
29
|
+
|
30
|
+
# Build symbol table with given scope as root.
|
31
|
+
# @param aScope [Core::Scope,NilClass] The top-level Scope
|
32
|
+
def initialize(aScope = nil)
|
33
|
+
@name2scopes = {}
|
34
|
+
init_root(aScope) # Set default (global) scope
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns iff there is no entry in the symbol table
|
38
|
+
# @return [Boolean]
|
39
|
+
def empty?
|
40
|
+
name2scopes.empty?
|
41
|
+
end
|
42
|
+
|
43
|
+
# Use this method to signal the interpreter that a given scope
|
44
|
+
# to be a child of current scope and to be itself the new current scope.
|
45
|
+
# @param aScope [Core::Scope] the Scope that
|
46
|
+
def enter_scope(aScope)
|
47
|
+
aScope.parent = current_scope
|
48
|
+
@current_scope = aScope
|
49
|
+
end
|
50
|
+
|
51
|
+
def leave_scope
|
52
|
+
# TODO: take dependencies between scopes into account
|
53
|
+
|
54
|
+
current_scope.defns.each_pair do |nm, _item|
|
55
|
+
scopes = name2scopes[nm]
|
56
|
+
if scopes.size == 1
|
57
|
+
name2scopes.delete(nm)
|
58
|
+
else
|
59
|
+
scopes.pop
|
60
|
+
name2scopes[nm] = scopes
|
61
|
+
end
|
62
|
+
end
|
63
|
+
raise StandardError, 'Cannot remove root scope.' if current_scope == root
|
64
|
+
|
65
|
+
@current_scope = current_scope.parent
|
66
|
+
end
|
67
|
+
|
68
|
+
# Add an entry with given name to current scope.
|
69
|
+
# @param anEntry [LogVar]
|
70
|
+
# @return [String] Internal name of the entry
|
71
|
+
def insert(anEntry)
|
72
|
+
current_scope.insert(anEntry)
|
73
|
+
name = anEntry.name
|
74
|
+
if name2scopes.include?(name)
|
75
|
+
name2scopes[name] << current_scope
|
76
|
+
else
|
77
|
+
name2scopes[name] = [current_scope]
|
78
|
+
end
|
79
|
+
|
80
|
+
anEntry.i_name
|
81
|
+
end
|
82
|
+
|
83
|
+
# Search for the object with the given name
|
84
|
+
# @param aName [String]
|
85
|
+
# @return [Core::LogVar]
|
86
|
+
def lookup(aName)
|
87
|
+
scopes = name2scopes.fetch(aName, nil)
|
88
|
+
return nil if scopes.nil?
|
89
|
+
|
90
|
+
sc = scopes.last
|
91
|
+
sc.defns[aName]
|
92
|
+
end
|
93
|
+
|
94
|
+
# Search for the object with the given i_name
|
95
|
+
# @param anIName [String]
|
96
|
+
# @return [Core::LogVar]
|
97
|
+
def lookup_i_name(anIName)
|
98
|
+
found = nil
|
99
|
+
scope = current_scope
|
100
|
+
|
101
|
+
begin
|
102
|
+
found = scope.defns.values.find { |e| e.i_name == anIName }
|
103
|
+
break if found
|
104
|
+
|
105
|
+
scope = scope.parent
|
106
|
+
end while scope
|
107
|
+
|
108
|
+
found
|
109
|
+
end
|
110
|
+
|
111
|
+
# Return all variables defined in the current .. root chain.
|
112
|
+
# Variables are sorted top-down and left-to-right.
|
113
|
+
def all_variables
|
114
|
+
vars = []
|
115
|
+
skope = current_scope
|
116
|
+
while skope
|
117
|
+
vars_of_scope = skope.defns.select { |_, item| item.kind_of?(LogVar) }
|
118
|
+
vars = vars_of_scope.values.concat(vars)
|
119
|
+
skope = skope.parent
|
120
|
+
end
|
121
|
+
|
122
|
+
vars
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
def init_root(aScope)
|
128
|
+
@root = valid_scope(aScope)
|
129
|
+
@current_scope = @root
|
130
|
+
end
|
131
|
+
|
132
|
+
def valid_scope(aScope)
|
133
|
+
aScope.nil? ? Scope.new : aScope
|
134
|
+
end
|
135
|
+
end # class
|
136
|
+
end # module
|
137
|
+
end # module
|
@@ -1,12 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'base_term'
|
4
4
|
|
5
5
|
module MiniKraken
|
6
6
|
module Core
|
7
|
-
# The generalization of any
|
8
|
-
# passed as
|
9
|
-
|
7
|
+
# The generalization of any object that can be:
|
8
|
+
# - passed as argument to a goal.
|
9
|
+
# - passed as argument to a MiniKraken procedure
|
10
|
+
# - contained in a compositer term,
|
11
|
+
# - associated with a logical variable.
|
12
|
+
class Term < BaseTerm
|
13
|
+
# Abstract method.
|
14
|
+
# Make a copy of self with all the variable reference being
|
15
|
+
# replaced by the corresponding value in the Hash.
|
16
|
+
# @param _substitutions [Hash {String => Term}]
|
17
|
+
# @return [Term]
|
18
|
+
def dup_cond(_substitutions)
|
19
|
+
raise NotImplementedError, "Not implementation for #{self.class}."
|
20
|
+
end
|
10
21
|
end # class
|
11
22
|
end # module
|
12
23
|
end # module
|
data/lib/mini_kraken/glue/dsl.rb
CHANGED
@@ -1,25 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'set'
|
4
|
-
require_relative '../core/any_value'
|
5
|
-
require_relative '../core/conde'
|
6
|
-
require_relative '../core/conj2'
|
7
|
-
require_relative '../core/cons_cell'
|
8
|
-
require_relative '../core/def_relation'
|
9
|
-
require_relative '../core/disj2'
|
10
|
-
require_relative '../core/equals'
|
11
|
-
require_relative '../core/fail'
|
12
|
-
require_relative '../core/formal_arg'
|
13
|
-
require_relative '../core/formal_ref'
|
14
|
-
require_relative '../glue/fresh_env'
|
15
|
-
require_relative '../core/goal_template'
|
16
|
-
require_relative '../core/k_boolean'
|
17
|
-
require_relative '../core/k_symbol'
|
18
|
-
require_relative '../core/succeed'
|
19
|
-
require_relative '../core/variable_ref'
|
20
|
-
require_relative 'fresh_env'
|
21
|
-
require_relative 'run_star_expression'
|
22
4
|
|
5
|
+
require_relative '../core/all_core'
|
6
|
+
require_relative '../atomic/all_atomic'
|
7
|
+
require_relative '../composite/cons_cell'
|
8
|
+
require_relative '../rela/all_rela'
|
9
|
+
require_relative 'run_star_expression'
|
23
10
|
|
24
11
|
module MiniKraken
|
25
12
|
module Glue
|
@@ -29,23 +16,22 @@ module MiniKraken
|
|
29
16
|
module DSL
|
30
17
|
# A run* expression tries to find all the solutions
|
31
18
|
# that meet the given goal.
|
32
|
-
# @return [
|
19
|
+
# @return [Composite::ConsCell] A list of solutions
|
33
20
|
def run_star(var_names, goal)
|
34
21
|
program = RunStarExpression.new(var_names, goal)
|
35
22
|
program.run
|
36
23
|
end
|
37
24
|
|
38
25
|
def conde(*goals)
|
39
|
-
# require 'debug'
|
40
26
|
args = goals.map do |goal_maybe|
|
41
27
|
if goal_maybe.kind_of?(Array)
|
42
|
-
goal_maybe.map { |g| convert(g)}
|
28
|
+
goal_maybe.map { |g| convert(g) }
|
43
29
|
else
|
44
30
|
convert(goal_maybe)
|
45
31
|
end
|
46
32
|
end
|
47
33
|
|
48
|
-
Core::Goal.new(
|
34
|
+
Core::Goal.new(Rela::Conde.instance, args)
|
49
35
|
end
|
50
36
|
|
51
37
|
# conj2 stands for conjunction of two arguments.
|
@@ -55,35 +41,31 @@ module MiniKraken
|
|
55
41
|
# @param arg2 [Core::Goal]
|
56
42
|
# @return [Core::Failure|Core::Success]
|
57
43
|
def conj2(arg1, arg2)
|
58
|
-
goal_class.new(
|
44
|
+
goal_class.new(Rela::Conj2.instance, [convert(arg1), convert(arg2)])
|
59
45
|
end
|
60
46
|
|
61
47
|
def cons(car_item, cdr_item = nil)
|
62
48
|
tail = cdr_item.nil? ? cdr_item : convert(cdr_item)
|
63
|
-
|
49
|
+
Composite::ConsCell.new(convert(car_item), tail)
|
64
50
|
end
|
65
51
|
|
66
|
-
def
|
67
|
-
|
52
|
+
def null_list
|
53
|
+
Composite::ConsCell.new(nil, nil)
|
54
|
+
end
|
68
55
|
|
56
|
+
def defrel(relationName, theFormals, aGoalExpr)
|
69
57
|
case theFormals
|
70
58
|
when String
|
71
|
-
|
59
|
+
formals = [theFormals]
|
72
60
|
when Array
|
73
|
-
|
61
|
+
formals = theFormals
|
74
62
|
end
|
75
|
-
|
76
|
-
|
77
|
-
g_template = aGoalTemplateExpr.call
|
78
|
-
result = Core::DefRelation.new(relationName, g_template, formals)
|
79
|
-
add_defrel(result)
|
80
|
-
|
81
|
-
end_defrel
|
82
|
-
result
|
63
|
+
rela = Rela::DefRelation.new(relationName, aGoalExpr, formals)
|
64
|
+
add_defrel(rela)
|
83
65
|
end
|
84
66
|
|
85
67
|
def disj2(arg1, arg2)
|
86
|
-
goal_class.new(
|
68
|
+
goal_class.new(Rela::Disj2.instance, [convert(arg1), convert(arg2)])
|
87
69
|
end
|
88
70
|
|
89
71
|
# @return [Core::Fail] A goal that unconditionally fails.
|
@@ -91,35 +73,26 @@ module MiniKraken
|
|
91
73
|
goal_class.new(Core::Fail.instance, [])
|
92
74
|
end
|
93
75
|
|
94
|
-
def
|
95
|
-
|
96
|
-
goal_class.new(Core::Equals.instance, [convert(arg1), convert(arg2)])
|
76
|
+
def unify(arg1, arg2)
|
77
|
+
goal_class.new(Rela::Unify.instance, [convert(arg1), convert(arg2)])
|
97
78
|
end
|
98
79
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
vars = [var_names]
|
104
|
-
else
|
105
|
-
vars = var_names
|
106
|
-
end
|
107
|
-
|
108
|
-
FreshEnv.new(vars, goal)
|
80
|
+
# @return [Core::Goal]
|
81
|
+
def fresh(names, subgoal)
|
82
|
+
# puts "#{__callee__} #{names}"
|
83
|
+
Rela::Fresh.build_goal(names, subgoal)
|
109
84
|
end
|
110
85
|
|
111
86
|
def list(*members)
|
112
87
|
return null if members.empty?
|
113
88
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
head
|
89
|
+
converted = members.map { |e| convert(e) }
|
90
|
+
Composite::List.make_list(converted)
|
118
91
|
end
|
119
92
|
|
120
93
|
# @return [ConsCell] Returns an empty list, that is, a pair whose members are nil.
|
121
94
|
def null
|
122
|
-
|
95
|
+
Composite::ConsCell.null
|
123
96
|
end
|
124
97
|
|
125
98
|
# @return [Core::Succeed] A goal that unconditionally succeeds.
|
@@ -134,38 +107,29 @@ module MiniKraken
|
|
134
107
|
|
135
108
|
case anArgument
|
136
109
|
when Symbol
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
110
|
+
case anArgument.id2name
|
111
|
+
when /_\d+/
|
112
|
+
rank = anArgument.id2name.slice(1..-1).to_i
|
113
|
+
any_val = Core::AnyValue.allocate
|
114
|
+
any_val.instance_variable_set(:@rank, rank)
|
115
|
+
converted = any_val
|
116
|
+
when /^"#[ft]"$/
|
117
|
+
converted = Atomic::KBoolean.new(anArgument)
|
118
|
+
else
|
119
|
+
converted = Atomic::KSymbol.new(anArgument)
|
146
120
|
end
|
147
121
|
when String
|
148
122
|
if anArgument =~ /^#[ft]$/
|
149
|
-
converted =
|
123
|
+
converted = Atomic::KBoolean.new(anArgument)
|
150
124
|
else
|
151
125
|
msg = "Internal error: undefined conversion for #{anArgument.class}"
|
152
126
|
raise StandardError, msg
|
153
127
|
end
|
154
128
|
when false, true
|
155
|
-
converted =
|
156
|
-
when
|
157
|
-
converted = anArgument
|
158
|
-
when Core::FormalRef
|
159
|
-
converted = anArgument
|
160
|
-
when FreshEnv
|
161
|
-
converted = anArgument
|
162
|
-
when Core::Goal
|
163
|
-
converted = anArgument
|
164
|
-
when Core::GoalTemplate
|
165
|
-
converted = anArgument
|
166
|
-
when Core::VariableRef
|
129
|
+
converted = Atomic::KBoolean.new(anArgument)
|
130
|
+
when NilClass, Atomic::KBoolean, Atomic::KSymbol
|
167
131
|
converted = anArgument
|
168
|
-
when Core::ConsCell
|
132
|
+
when Core::Goal, Core::LogVarRef, Composite::ConsCell
|
169
133
|
converted = anArgument
|
170
134
|
else
|
171
135
|
msg = "Internal error: undefined conversion for #{anArgument.class}"
|
@@ -195,7 +159,7 @@ module MiniKraken
|
|
195
159
|
end
|
196
160
|
|
197
161
|
def add_defrel(aDefRelation)
|
198
|
-
@defrels
|
162
|
+
@defrels ||= {}
|
199
163
|
@defrels[aDefRelation.name] = aDefRelation
|
200
164
|
end
|
201
165
|
|
@@ -206,7 +170,7 @@ module MiniKraken
|
|
206
170
|
result = super(mth, *args)
|
207
171
|
rescue NameError
|
208
172
|
name = mth.id2name
|
209
|
-
@defrels
|
173
|
+
@defrels ||= {}
|
210
174
|
if @defrels.include?(name)
|
211
175
|
def_relation = @defrels[name]
|
212
176
|
result = Core::Goal.new(def_relation, args.map { |el| convert(el) })
|
@@ -215,7 +179,7 @@ module MiniKraken
|
|
215
179
|
if @dsl_mode == :defrel && @defrel_formals.include?(name)
|
216
180
|
result = Core::FormalRef.new(name)
|
217
181
|
else
|
218
|
-
result = Core::
|
182
|
+
result = Core::LogVarRef.new(name)
|
219
183
|
end
|
220
184
|
end
|
221
185
|
end
|