swipl 0.4.0 → 0.5.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.
- checksums.yaml +7 -0
- data/lib/swipl.rb +94 -1
- data/lib/swipl/cffi.rb +28 -6
- data/lib/swipl/predicate.rb +4 -1
- data/lib/swipl/prologframe.rb +4 -0
- data/lib/swipl/query.rb +6 -1
- data/lib/swipl/term.rb +52 -5
- data/lib/swipl/version.rb +1 -1
- metadata +74 -70
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b73265ef1ec10d4379f3dbe6e660b8543a81fa3b
|
4
|
+
data.tar.gz: b11794f6bec59886a3feda9d32fe9d045edd41ff
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f547466be92fc88cf1cd0a60eeb8b4e16876f6c6140b783b9dc2385c34ab681becb237352bd0e868192ea1d72a6be3e54c8f7a08d1a513b5a8bb46c54b100247
|
7
|
+
data.tar.gz: e666f623c96acd290386859ee9214972432f0ec9ef4abcaf33fd1d4c8c97e42aee81dd9f72ed4f61aba00530aa56f0ba987ba0e6f6866d37da910765e6c9d1fd
|
data/lib/swipl.rb
CHANGED
@@ -6,11 +6,19 @@ require 'swipl/term'
|
|
6
6
|
require "swipl/version"
|
7
7
|
|
8
8
|
module SWIPL
|
9
|
+
PL_FALSE = 0
|
9
10
|
PL_TRUE = 1
|
10
|
-
PL_FALSE = 2
|
11
11
|
PL_FAIL = PL_FALSE
|
12
|
+
|
12
13
|
PL_Q_NORMAL = 2
|
13
14
|
|
15
|
+
PL_FA_VARARGS = 8
|
16
|
+
PL_FA_NONDETERMINISTIC = 4
|
17
|
+
|
18
|
+
PL_FIRST_CALL = 0
|
19
|
+
PL_PRUNED = 1
|
20
|
+
PL_REDO = 2
|
21
|
+
|
14
22
|
def self.verify( fact )
|
15
23
|
CFFI.init
|
16
24
|
PrologFrame.on do |frame|
|
@@ -40,4 +48,89 @@ module SWIPL
|
|
40
48
|
raise "Truth '#{fact}' failed"
|
41
49
|
end
|
42
50
|
end
|
51
|
+
|
52
|
+
def self.fallacy( fact )
|
53
|
+
if self.verify( fact )
|
54
|
+
raise "Fallacy '#{fact}' is true"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.deterministic( name, arity, &block )
|
59
|
+
@registered = {} unless @registered
|
60
|
+
raise "predicate by that name is already registered" if @registered[ name ]
|
61
|
+
|
62
|
+
trampoline = FFI::Function.new( :uint, [:ulong, :int, :pointer] ) do |arg_base, arity, control|
|
63
|
+
stage = CFFI.PL_foreign_control( control )
|
64
|
+
|
65
|
+
arguments = (0..(arity -1 )).map do |index|
|
66
|
+
Term.new( arg_base + index )
|
67
|
+
end
|
68
|
+
|
69
|
+
if block.call( arguments )
|
70
|
+
CFFI::PL_succeed()
|
71
|
+
else
|
72
|
+
PL_FALSE
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
name_ptr = FFI::MemoryPointer.from_string( name.to_s )
|
77
|
+
raise "Failed to register" unless CFFI.PL_register_foreign( name_ptr, arity, trampoline, PL_FA_VARARGS )
|
78
|
+
end
|
79
|
+
|
80
|
+
class ForeignControl
|
81
|
+
def initialize( state )
|
82
|
+
@state = state
|
83
|
+
end
|
84
|
+
|
85
|
+
def context; @context ; end
|
86
|
+
def context=( value ); @context = value ; end
|
87
|
+
def first_call?; @state == PL_FIRST_CALL; end
|
88
|
+
def pruning?; @state == PL_PRUNED; end
|
89
|
+
def redo?; @state == PL_REDO; end
|
90
|
+
end
|
91
|
+
|
92
|
+
class ForeignFrame
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.nondet( name, arity, &handler )
|
96
|
+
@registered = {} unless @registered
|
97
|
+
raise "predicate by that name is already registered" if @registered[ name ]
|
98
|
+
|
99
|
+
trampoline = CFFI::predicate_proc do |arg_base, arity, control|
|
100
|
+
result = nil
|
101
|
+
|
102
|
+
arguments = (0..(arity -1 )).map do |index|
|
103
|
+
Term.new( arg_base + index )
|
104
|
+
end
|
105
|
+
|
106
|
+
stage = ForeignControl.new CFFI.PL_foreign_control( control )
|
107
|
+
stage.context = CFFI.PL_foreign_context_address( control ) unless stage.first_call?
|
108
|
+
frame = ForeignFrame.new
|
109
|
+
handler.call( stage , arguments, frame, control )
|
110
|
+
end
|
111
|
+
@registered[name] = trampoline
|
112
|
+
|
113
|
+
name_ptr = FFI::MemoryPointer.from_string( name.to_s )
|
114
|
+
raise "Failed to register" unless CFFI.PL_register_foreign( name_ptr, arity, trampoline, PL_FA_VARARGS | PL_FA_NONDETERMINISTIC )
|
115
|
+
end
|
116
|
+
|
117
|
+
#
|
118
|
+
#
|
119
|
+
def self.find_all( name, args = [], &solution_handler )
|
120
|
+
solution_handler = Proc.new { |s| s } unless solution_handler
|
121
|
+
solutions = []
|
122
|
+
SWIPL::PrologFrame.on do |frame|
|
123
|
+
predicate = SWIPL::Predicate.find( name, args.length )
|
124
|
+
query = predicate.query_normally_with( frame, args )
|
125
|
+
begin
|
126
|
+
query.each_solution do |solution|
|
127
|
+
solutions.push( solution_handler.call(solution) )
|
128
|
+
end
|
129
|
+
ensure
|
130
|
+
query.close
|
131
|
+
end
|
132
|
+
end
|
133
|
+
solutions
|
134
|
+
end
|
43
135
|
end
|
136
|
+
|
data/lib/swipl/cffi.rb
CHANGED
@@ -3,6 +3,9 @@ require 'ffi'
|
|
3
3
|
module SWIPL
|
4
4
|
module CFFI
|
5
5
|
extend FFI::Library
|
6
|
+
typedef :pointer, :foreign_t
|
7
|
+
typedef :pointer, :control_t
|
8
|
+
typedef :ulong, :term_t
|
6
9
|
|
7
10
|
def self.import_symbols
|
8
11
|
attach_function :PL_open_foreign_frame, [], :ulong
|
@@ -14,20 +17,35 @@ module SWIPL
|
|
14
17
|
attach_function :PL_call, [:ulong, :pointer], :int
|
15
18
|
attach_function :PL_chars_to_term, [:pointer, :ulong], :int
|
16
19
|
attach_function :PL_close_query, [:ulong], :void
|
20
|
+
attach_function :PL_foreign_control, [:control_t], :int
|
21
|
+
attach_function :PL_foreign_context_address, [:control_t], :pointer
|
22
|
+
attach_function :long_PL_foreign_context_address, :PL_foreign_context_address, [:control_t], :ulong
|
17
23
|
attach_function :PL_get_atom_chars, [:ulong, :pointer], :int
|
18
24
|
attach_function :PL_initialise, [:int, :pointer], :int
|
19
|
-
attach_function :PL_is_atom, [:
|
20
|
-
attach_function :PL_is_ground, [:
|
25
|
+
attach_function :PL_is_atom, [:term_t], :int
|
26
|
+
attach_function :PL_is_ground, [:term_t], :int
|
21
27
|
attach_function :PL_new_atom, [:pointer], :ulong
|
22
|
-
attach_function :PL_new_term_ref, [], :
|
23
|
-
attach_function :PL_new_term_refs, [:int], :
|
28
|
+
attach_function :PL_new_term_ref, [], :term_t
|
29
|
+
attach_function :PL_new_term_refs, [:int], :term_t
|
24
30
|
attach_function :PL_next_solution, [:ulong], :int
|
25
|
-
attach_function :PL_open_query, [:pointer, :int, :ulong, :
|
31
|
+
attach_function :PL_open_query, [:pointer, :int, :ulong, :term_t], :ulong
|
32
|
+
attach_function :PL_put_atom_chars, [ :term_t, :string], :int
|
33
|
+
attach_function :PL_put_string_chars, [ :term_t, :string], :void
|
26
34
|
attach_function :PL_predicate, [:pointer, :int, :pointer], :ulong
|
35
|
+
attach_function :PL_register_foreign, [:pointer, :int, :pointer, :int], :foreign_t
|
36
|
+
attach_function :_PL_retry_address, [ :pointer ], :foreign_t
|
37
|
+
attach_function :_PL_retry, [ :pointer ], :foreign_t
|
38
|
+
attach_function :PL_term_type, [:term_t], :int
|
27
39
|
attach_function :PL_thread_self, [], :int
|
28
|
-
attach_function :PL_unify, [ :
|
40
|
+
attach_function :PL_unify, [ :term_t, :term_t ], :int
|
41
|
+
attach_function :PL_unify_string_chars, [ :ulong, :string], :void
|
42
|
+
attach_function :PL_unify_atom_chars, [ :term_t, :string], :void
|
29
43
|
end
|
30
44
|
|
45
|
+
def self.PL_succeed; PL_TRUE; end
|
46
|
+
def self.PL_retry_address( what ); _PL_retry_address( what ).address; end
|
47
|
+
def self.PL_retry( ptr ); _PL_retry( ptr ).address; end
|
48
|
+
|
31
49
|
def self.load( libraries )
|
32
50
|
ffi_lib libraries
|
33
51
|
self.import_symbols
|
@@ -56,5 +74,9 @@ module SWIPL
|
|
56
74
|
|
57
75
|
@is_initialized = true
|
58
76
|
end
|
77
|
+
|
78
|
+
def self.predicate_proc( &handler )
|
79
|
+
FFI::Function.new( :size_t, [:ulong, :int, :pointer], handler )
|
80
|
+
end
|
59
81
|
end
|
60
82
|
end
|
data/lib/swipl/predicate.rb
CHANGED
@@ -30,7 +30,10 @@ module SWIPL
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
|
33
|
+
base_ref = params.length > 0 ? params[0].id : 0
|
34
|
+
|
35
|
+
query_id = CFFI.PL_open_query( nil, PL_Q_NORMAL, @pred_id, base_ref )
|
36
|
+
raise "Failed to allocate query #{query_id}" if query_id == 0
|
34
37
|
Query.new( query_id, params )
|
35
38
|
end
|
36
39
|
end
|
data/lib/swipl/prologframe.rb
CHANGED
data/lib/swipl/query.rb
CHANGED
@@ -2,12 +2,13 @@
|
|
2
2
|
module SWIPL
|
3
3
|
class Query
|
4
4
|
def initialize( qid, terms )
|
5
|
+
raise "query_id is nil" unless qid
|
5
6
|
@query_id = qid
|
6
7
|
@terms = terms
|
7
8
|
end
|
8
9
|
|
9
10
|
def next_solution?
|
10
|
-
CFFI.PL_next_solution( @query_id ) == PL_TRUE
|
11
|
+
CFFI.PL_next_solution( @query_id ) == PL_TRUE
|
11
12
|
end
|
12
13
|
|
13
14
|
def each_solution
|
@@ -16,6 +17,10 @@ module SWIPL
|
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
20
|
+
def terms
|
21
|
+
@terms
|
22
|
+
end
|
23
|
+
|
19
24
|
def close
|
20
25
|
CFFI.PL_close_query( @query_id )
|
21
26
|
end
|
data/lib/swipl/term.rb
CHANGED
@@ -8,22 +8,69 @@ module SWIPL
|
|
8
8
|
def id; self.term_id; end
|
9
9
|
def term_id; @term_id; end
|
10
10
|
|
11
|
-
def unify_with( other_term )
|
12
|
-
CFFI.PL_unify( @term_id, other_term.term_id ) != PL_FAIL
|
11
|
+
def unify_with( other_term, control = nil )
|
12
|
+
result = CFFI.PL_unify( @term_id, other_term.term_id ) != PL_FAIL
|
13
|
+
control.failed if control and !result
|
14
|
+
result
|
15
|
+
end
|
16
|
+
|
17
|
+
def unify_string( string )
|
18
|
+
CFFI.PL_unify_string_chars( @term_id, string )
|
19
|
+
end
|
20
|
+
|
21
|
+
def unify_atom_chars( string )
|
22
|
+
CFFI.PL_unify_atom_chars( @term_id, string )
|
23
|
+
end
|
24
|
+
|
25
|
+
def put_string( string )
|
26
|
+
CFFI.PL_put_string_chars( @term_id, string )
|
27
|
+
end
|
28
|
+
|
29
|
+
def put_atom( string )
|
30
|
+
raise "Failed to put atom" if CFFI.PL_put_atom_chars( @term_id, string ) == PL_FALSE
|
13
31
|
end
|
14
32
|
|
15
33
|
def ground?
|
34
|
+
str_ptr = FFI::MemoryPointer.new( :pointer, 1 )
|
16
35
|
CFFI.PL_is_ground( @term_id ) == PL_TRUE
|
17
36
|
end
|
18
37
|
|
19
38
|
def atom?
|
20
|
-
CFFI.PL_is_atom( @term_id )
|
39
|
+
CFFI.PL_is_atom( @term_id ) == PL_TRUE
|
40
|
+
end
|
41
|
+
|
42
|
+
PL_VARIABLE = 1
|
43
|
+
PL_ATOM = 2
|
44
|
+
PL_NIL = 7
|
45
|
+
PL_BLOB = 8
|
46
|
+
PL_STRING = 5
|
47
|
+
PL_INTEGER = 3
|
48
|
+
|
49
|
+
def term_type
|
50
|
+
type_id = CFFI.PL_term_type( @term_id )
|
51
|
+
case type_id
|
52
|
+
when PL_VARIABLE
|
53
|
+
:variable
|
54
|
+
when PL_ATOM
|
55
|
+
:atom
|
56
|
+
when PL_NIL
|
57
|
+
:nil
|
58
|
+
when PL_BLOB
|
59
|
+
:blob
|
60
|
+
when PL_STRING
|
61
|
+
:string
|
62
|
+
when PL_INTEGER
|
63
|
+
:integer
|
64
|
+
else
|
65
|
+
:unknown
|
66
|
+
end
|
21
67
|
end
|
22
68
|
|
23
69
|
def as_atom
|
70
|
+
raise "not na atom" unless atom?
|
24
71
|
str_ptr = FFI::MemoryPointer.new( :pointer, 1 )
|
25
72
|
if CFFI.PL_get_atom_chars( @term_id, str_ptr ) == PL_FALSE
|
26
|
-
raise "failed to get term #{@term_id} as an atom"
|
73
|
+
raise "failed to get term #{@term_id} as an atom (type: #{term_type})"
|
27
74
|
end
|
28
75
|
str_ptr.read_pointer.read_string
|
29
76
|
end
|
@@ -33,7 +80,7 @@ module SWIPL
|
|
33
80
|
if self.atom?
|
34
81
|
self.as_atom
|
35
82
|
else
|
36
|
-
"ground"
|
83
|
+
"ground (#{term_type})"
|
37
84
|
end
|
38
85
|
else
|
39
86
|
"variable"
|
data/lib/swipl/version.rb
CHANGED
metadata
CHANGED
@@ -1,74 +1,82 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: swipl
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: 0.4.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.0
|
6
5
|
platform: ruby
|
7
|
-
authors:
|
6
|
+
authors:
|
8
7
|
- Mark Eschbach
|
9
8
|
autorequire:
|
10
9
|
bindir: exe
|
11
10
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
- !ruby/object:Gem::Dependency
|
11
|
+
date: 2016-02-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
16
14
|
name: bundler
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: "1.11"
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.11'
|
24
20
|
type: :development
|
25
|
-
version_requirements: *id001
|
26
|
-
- !ruby/object:Gem::Dependency
|
27
|
-
name: rake
|
28
21
|
prerelease: false
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
35
34
|
type: :development
|
36
|
-
version_requirements: *id002
|
37
|
-
- !ruby/object:Gem::Dependency
|
38
|
-
name: rspec
|
39
35
|
prerelease: false
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
46
48
|
type: :development
|
47
|
-
version_requirements: *id003
|
48
|
-
- !ruby/object:Gem::Dependency
|
49
|
-
name: ffi
|
50
49
|
prerelease: false
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: ffi
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.9'
|
57
62
|
type: :runtime
|
58
|
-
|
59
|
-
|
60
|
-
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.9'
|
69
|
+
description: Interact with the SWI Prolog system in ruby. Currently uses FFI to bind
|
70
|
+
using the C interface.
|
71
|
+
email:
|
61
72
|
- meschbach@gmail.com
|
62
73
|
executables: []
|
63
|
-
|
64
74
|
extensions: []
|
65
|
-
|
66
75
|
extra_rdoc_files: []
|
67
|
-
|
68
|
-
|
69
|
-
- .
|
70
|
-
- .
|
71
|
-
- .travis.yml
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- ".rspec"
|
79
|
+
- ".travis.yml"
|
72
80
|
- Gemfile
|
73
81
|
- LICENSE.txt
|
74
82
|
- README.md
|
@@ -83,31 +91,27 @@ files:
|
|
83
91
|
- lib/swipl/version.rb
|
84
92
|
- swipl.gemspec
|
85
93
|
homepage: https://github.com/meschbach/gem-swipl
|
86
|
-
licenses:
|
94
|
+
licenses:
|
87
95
|
- MIT
|
96
|
+
metadata: {}
|
88
97
|
post_install_message:
|
89
98
|
rdoc_options: []
|
90
|
-
|
91
|
-
require_paths:
|
99
|
+
require_paths:
|
92
100
|
- lib
|
93
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
-
|
95
|
-
requirements:
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
96
103
|
- - ">="
|
97
|
-
- !ruby/object:Gem::Version
|
98
|
-
version:
|
99
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
-
|
101
|
-
requirements:
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
102
108
|
- - ">="
|
103
|
-
- !ruby/object:Gem::Version
|
104
|
-
version:
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
105
111
|
requirements: []
|
106
|
-
|
107
112
|
rubyforge_project:
|
108
|
-
rubygems_version:
|
113
|
+
rubygems_version: 2.4.5.1
|
109
114
|
signing_key:
|
110
|
-
specification_version:
|
115
|
+
specification_version: 4
|
111
116
|
summary: Ruby bindings for SWI Prolog
|
112
117
|
test_files: []
|
113
|
-
|