upl 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '098024c977917fd375c9743595fbee2063227946d6c2df8110ca5a7d76dd7cca'
4
- data.tar.gz: b3a4df0143e5847a303fbef5dbbdb0f639c5270cb577c1bff932b5e15ed52c2d
3
+ metadata.gz: a3f3986baaa4caf8654ae53619fc3606dd9f608f7f7722cd3860d6ec2af8a1fe
4
+ data.tar.gz: 18e8d59804dd3802da05df95d667ffff47d71e73af82d3bbad509dc0ab4f2930
5
5
  SHA512:
6
- metadata.gz: 21f5784f9b8c8699c75728cff0f57bf66f6eec802d613fb5018d224d4376d57702b570a7eb1210218bfd828f954e283a265f3885474eb1cd4c1a8c9599270936
7
- data.tar.gz: 25ad0f5cfa693432e3ceee531eefa7d8ebde8f587ae8d7b80eacc57fb68b7baab72c21491e45a27c98c886bd458193d1c71627b4c6a7c038c548d853a47393d5
6
+ metadata.gz: f34cf6fafe347a3f7494108bf286abbff5771e51450594858d455d13630ac7645f36f1b26c3f45757a611bdca52dbe604dbd5e4c63c54ee4cb3cf176d22de7a8
7
+ data.tar.gz: c4524355fa328c53fe99c56a1a99553e0a9cecff4b31c177571f4c6b895bc229388829d406a714e34b61667f975b046dde2507236c473d565f415634a130f604
@@ -1,3 +1,6 @@
1
+ == 0.2.2
2
+ * restrict to <=swi-prolog-8.1.22
3
+
1
4
  == 0.2.1
2
5
  * Query map_blk for transforms
3
6
  * frames for Query reuse
data/lib/upl.rb CHANGED
@@ -15,12 +15,11 @@ require_relative 'upl/foreign'
15
15
  require_relative 'upl/query'
16
16
 
17
17
  module Upl
18
- # todo need .call and .consult at this level?
19
-
18
+ # You probably want to use Query.new instead of this.
20
19
  # an enumerator yielding hashes keyed by the variables, mapping to the term
21
20
  module_function def query string_or_term, vars = nil, &blk
22
21
  if string_or_term.is_a?(Term) && vars
23
- Runtime.term_vars_query string_or_term, vars
22
+ Runtime.query string_or_term, vars
24
23
  else
25
24
  case string_or_term
26
25
  when Term
@@ -29,13 +28,19 @@ module Upl
29
28
  Runtime.query string_or_term
30
29
  when String
31
30
  term, vars = Runtime.term_vars string_or_term
32
- Runtime.term_vars_query term, vars, &blk
31
+ Runtime.query term, vars, &blk
33
32
  else
34
33
  raise "dunno about #{string_or_term.inspect}"
35
34
  end
36
35
  end
37
36
  end
38
37
 
38
+ # For semidet predicates, ie that have only one result.
39
+ # You have to extract values using Upl::Variable#to_ruby.
40
+ module_function def call term
41
+ Runtime::call term
42
+ end
43
+
39
44
  module_function def consult filename
40
45
  p = Pathname filename
41
46
  Runtime::call %Q{["#{p.realpath.to_s}"]}
@@ -38,7 +38,7 @@ module Upl
38
38
  query_hash.delete :Dict
39
39
 
40
40
  # now we have a result set with K,V values
41
- en = Upl::Runtime.term_vars_query query_term, query_hash
41
+ en = Upl::Runtime.query query_term, query_hash
42
42
 
43
43
  # map to a hash-y thing
44
44
  en.each_with_object Dict.new(tag: dict_tag(dict_term_t)) do |row,values|
@@ -9,11 +9,13 @@ module Upl
9
9
 
10
10
  # fetch config values from swipl executable
11
11
  def self.swipl_config_values
12
- swipl_exe = 'swipl'
13
- values = `#{swipl_exe} --dump-runtime-variables=sh`.each_line.with_object Hash.new do |line,ha|
14
- # split by = and for rhs strip surrounding quotes and trailing ;
15
- line =~ /^([^=]+)="([^"]*)";\s*$/
16
- ha[$1] = $2.strip
12
+ @swipl_config_value ||= begin
13
+ swipl_exe = 'swipl'
14
+ values = `#{swipl_exe} --dump-runtime-variables=sh`.each_line.with_object Hash.new do |line,ha|
15
+ # split by = and for rhs strip surrounding quotes and trailing ;
16
+ line =~ /^([^=]+)="([^"]*)";\s*$/
17
+ ha[$1] = $2.strip
18
+ end
17
19
  end
18
20
  rescue Errno::ENOENT => ex
19
21
  puts "#{swipl_exe} not found on path #{ENV['PATH']}"
@@ -33,6 +35,11 @@ module Upl
33
35
  exit 1
34
36
  end
35
37
 
38
+ if (version = swipl_config_values['PLVERSION']) >= '80100'
39
+ # 801xx seems to have changed some calls. Not sure yet what they are.
40
+ raise "unsupported version #{version}"
41
+ end
42
+
36
43
  dlload so_path
37
44
 
38
45
  def self.ruby_free_fn
@@ -40,7 +40,7 @@ module Upl
40
40
  end
41
41
 
42
42
  def call
43
- @results ||= Upl::Runtime.term_vars_query @term, @vars
43
+ @results ||= Upl::Runtime.query @term, @vars
44
44
  end
45
45
 
46
46
  def each &blk
@@ -72,10 +72,7 @@ module Upl
72
72
  end
73
73
 
74
74
  # once_only. Should probably be a singleton or something.
75
- # TODO Nope, wrong. init is for the entire engine.
76
- # PL_thread_attach_engine is for one-to-one threads,
77
- # PL_create_engine is for engine pool
78
- Thread::current[:upl] ||= init
75
+ @_upl_runtime ||= init
79
76
 
80
77
  def self.predicate name, arity, module_name = 0
81
78
  Extern.PL_predicate Ptr[name.to_s], arity, Fiddle::Pointer[module_name]
@@ -122,11 +119,12 @@ module Upl
122
119
 
123
120
  # just to make sure the query handle pointer is properly closed
124
121
  # TODO should be private, because args are gnarly
125
- def self.open_query qterm, args, mod: nil, flags: nil, &blk
122
+ def self.open_query qterm, mod: nil, flags: nil, &blk
126
123
  # This will need a string for the module, eventually
127
124
  # module is NULL, flags is 0
128
125
  mod ||= Fiddle::NULL
129
126
  flags ||= flags=Extern::Flags::PL_Q_EXT_STATUS | Extern::Flags::PL_Q_CATCH_EXCEPTION
127
+ args = TermVector.new qterm.arity do |idx| qterm[idx] end
130
128
 
131
129
  query_id_p = Extern.PL_open_query mod, flags, qterm.to_predicate, args.terms
132
130
  query_id_p != 0 or raise 'no space on environment stack, see SWI-Prolog docs for PL_open_query'
@@ -150,93 +148,43 @@ module Upl
150
148
  end
151
149
  end
152
150
 
153
- # do a query for the given term and vars, as parsed by term_vars
151
+ # Do a query for the given term and vars, as parsed by term_vars.
154
152
  # qvars_hash is a hash of :VariableName => Term(PL_VARIABLE)
155
- # and each variable is already bound in term.
153
+ # and each variable is already bound in qterm.
156
154
  # TODO much duplication between this and .query below
157
- def self.term_vars_query qterm, qvars_hash
155
+ def self.query qterm, qvars_hash = nil
158
156
  raise "not a term" unless Term === qterm
159
157
  return enum_for __method__, qterm, qvars_hash unless block_given?
160
158
 
161
- with_frame do |fid_t|
162
- # populate input values from qterm
163
- args = TermVector.new qterm.arity do |idx| qterm[idx] end
164
- open_query qterm, args do |query_id_p|
165
- loop do
166
- case Extern.PL_next_solution query_id_p
167
- when Extern::ExtStatus::FALSE
168
- break
169
-
170
- when Extern::ExtStatus::EXCEPTION
171
- raise_prolog_or_ruby query_id_p
172
-
173
- # when Extern::ExtStatus::TRUE
174
- # when Extern::ExtStatus::LAST
175
- else
176
- hash = qvars_hash.each_with_object Hash.new do |(name_sym,var),ha|
177
- # var will be invalidated by the next call to PL_next_solution,
178
- # so we need to construct a ruby tree copy of the value term.
179
- ha[name_sym] = var.to_ruby
180
- end
181
-
182
- yield hash
183
- end
159
+ result_map =
160
+ if qvars_hash
161
+ lambda do
162
+ # construct map of given variable names to their values
163
+ qvars_hash.each_with_object Hash.new do |(name_sym,var),ha|
164
+ ha[name_sym] = var.to_ruby
184
165
  end
185
166
  end
167
+ else
168
+ # no variable names provided so just get the values
169
+ ->{ qterm.map{|term_t| Tree.of_term term_t} }
186
170
  end
187
- end
188
-
189
- def self.predicate name, arity
190
- pred_p = Extern.PL_predicate Ptr[name.to_s], arity, Fiddle::NULL
191
- end
192
-
193
- # Simple query with predicate / arity
194
- # Returns an array of arrays.
195
- # TODO remove, not really used
196
- def self.squery predicate_str, arity
197
- return enum_for :squery, predicate_str, arity unless block_given?
198
-
199
- # bit of a hack because open_query wants to call to_predicate
200
- # and we have to construct that manually here because Upl::Term
201
- # is slightly ill-suited.
202
- qterm = Object.new
203
- qterm.define_singleton_method :to_predicate do
204
- p_functor = Extern::PL_new_functor predicate_str.to_sym.to_atom, arity
205
- Extern::PL_pred p_functor, Fiddle::NULL
206
- end
207
-
208
- args = TermVector.new arity
209
- open_query qterm, args do |query_id_p|
210
- loop do
211
- rv = Extern.PL_next_solution query_id_p
212
- break if rv == 0
213
- yield args.each_t.map{|term_t| Tree.of_term term_t}
214
- end
215
- end
216
- end
217
-
218
- # TODO much duplication between this and .term_vars_query
219
- # Only used by the term branch of Upl.query
220
- def self.query term
221
- raise "not a Term" unless Term === term
222
- return enum_for :query, term unless block_given?
223
171
 
224
- answer_lst = TermVector.new term.arity do |idx| term[idx] end
225
-
226
- open_query term, answer_lst do |query_id_p|
172
+ open_query qterm do |query_id_p|
227
173
  loop do
228
- case Extern.PL_next_solution query_id_p
174
+ case (status = Extern.PL_next_solution query_id_p)
229
175
  when Extern::ExtStatus::FALSE
230
176
  break
231
177
 
232
178
  when Extern::ExtStatus::EXCEPTION
233
179
  raise_prolog_or_ruby query_id_p
234
180
 
235
- # when Extern::ExtStatus::TRUE
236
- # when Extern::ExtStatus::LAST
237
- else
238
- yield answer_lst.each_t.map{|term_t| Tree.of_term term_t}
181
+ when Extern::ExtStatus::TRUE, Extern::ExtStatus::LAST
182
+ # var will be invalidated by the next call to PL_next_solution,
183
+ # so we need to construct a ruby tree copy of the value term immediately.
184
+ yield result_map[]
239
185
 
186
+ else
187
+ raise "unknown PL_next_solution status #{status}"
240
188
  end
241
189
  end
242
190
  end
@@ -1,3 +1,3 @@
1
1
  module Upl
2
- VERSION = '0.2.1'
2
+ VERSION = '0.2.2'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: upl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Anderson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-02-16 00:00:00.000000000 Z
11
+ date: 2020-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler