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.
@@ -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
@@ -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
+
@@ -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, [:ulong], :int
20
- attach_function :PL_is_ground, [:ulong], :int
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, [], :ulong
23
- attach_function :PL_new_term_refs, [:int], :ulong
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, :ulong], :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, [ :ulong, :ulong ], :int
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
@@ -30,7 +30,10 @@ module SWIPL
30
30
  end
31
31
  end
32
32
 
33
- query_id = CFFI.PL_open_query( nil, PL_Q_NORMAL, @pred_id, params[0].id )
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
@@ -43,6 +43,10 @@ module SWIPL
43
43
  end
44
44
  end
45
45
 
46
+ def ref
47
+ refs(1)[0]
48
+ end
49
+
46
50
  def atom_from_string( string )
47
51
  atom_ptr = FFI::MemoryPointer.from_string( string.to_s )
48
52
  atom_term = CFFI.PL_new_term_ref
@@ -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
@@ -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"
@@ -1,3 +1,3 @@
1
1
  module SWIPL
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
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
- prerelease:
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
- date: 2016-02-08 00:00:00 Z
14
- dependencies:
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
- prerelease: false
18
- requirement: &id001 !ruby/object:Gem::Requirement
19
- none: false
20
- requirements:
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
- requirement: &id002 !ruby/object:Gem::Requirement
30
- none: false
31
- requirements:
32
- - - ~>
33
- - !ruby/object:Gem::Version
34
- version: "10.0"
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
- requirement: &id003 !ruby/object:Gem::Requirement
41
- none: false
42
- requirements:
43
- - - ~>
44
- - !ruby/object:Gem::Version
45
- version: "3.0"
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
- requirement: &id004 !ruby/object:Gem::Requirement
52
- none: false
53
- requirements:
54
- - - ~>
55
- - !ruby/object:Gem::Version
56
- version: "1.9"
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
- version_requirements: *id004
59
- description: Interact with the SWI Prolog system in ruby. Currently uses FFI to bind using the C interface.
60
- email:
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
- files:
69
- - .gitignore
70
- - .rspec
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
- none: false
95
- requirements:
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
96
103
  - - ">="
97
- - !ruby/object:Gem::Version
98
- version: "0"
99
- required_rubygems_version: !ruby/object:Gem::Requirement
100
- none: false
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: "0"
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
105
111
  requirements: []
106
-
107
112
  rubyforge_project:
108
- rubygems_version: 1.8.23
113
+ rubygems_version: 2.4.5.1
109
114
  signing_key:
110
- specification_version: 3
115
+ specification_version: 4
111
116
  summary: Ruby bindings for SWI Prolog
112
117
  test_files: []
113
-