Module: Upl::Runtime
- Defined in:
- lib/upl/runtime.rb
Defined Under Namespace
Classes: PrologException
Constant Summary collapse
- Ptr =
shortcuttery
Fiddle::Pointer
Class Method Summary collapse
- .call(st_or_term) ⇒ Object
- .init ⇒ Object
-
.open_query(qterm, args, mod: nil, flags: nil, &blk) ⇒ Object
just to make sure the query handle pointer is properly closed TODO should be private, because args are gnarly.
- .predicate(name, arity) ⇒ Object
-
.query(term) ⇒ Object
TODO much duplication between this and .term_vars_query Only used by the term branch of Upl.query.
- .raise_prolog_or_ruby(query_id_p) ⇒ Object
-
.squery(predicate_str, arity) ⇒ Object
Simple query with predicate / arity Returns an array of arrays.
-
.term_vars(st) ⇒ Object
Use prolog predicate to parse the string into a term (containing variables), along with its named variables as a hash of Name => _variable.
-
.term_vars_query(qterm, qvars_hash) ⇒ Object
do a query for the given term and vars, as parsed by term_vars qvars_hash is a hash of :VariableName => Term(PL_VARIABLE) and each variable is already bound in term.
- .unify(term_a, term_b) ⇒ Object
-
.with_frame(&blk) ⇒ Object
blk takes a fid_t.
Class Method Details
.call(st_or_term) ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/upl/runtime.rb', line 37 def self.call st_or_term term = case st_or_term when String Term.new st_or_term when Term st_or_term else raise "dunno bout #{st_or_term}" end rv = Extern.PL_call term.term_t, Fiddle::NULL rv == 1 # don't raise end |
.init ⇒ Object
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/upl/runtime.rb', line 52 def self.init # set up no output so we don't get swipl command line interfering in ruby # TODO exception handling should not kick off a prolog terminal # TODO from gem-swipl args = [ @swipl_lib, "-tty", "-q", "-t", "true", "-g", "true", "--nodebug", "--nosignals" ] args = %w[upl --tty=false --signals=false --debug=false --quiet=true] # convert args to char ** # TODO Fiddle::SIZEOF_VOIDP would be faster ptr_size = Extern.sizeof 'char*' arg_ptrs = Ptr.malloc ptr_size * args.size, Extern::ruby_free_fn args.each_with_index do |rg,i| (arg_ptrs + i*ptr_size)[0,ptr_size] = Ptr[rg].ref end # call init rv = Extern.PL_initialise args.size, arg_ptrs rv == 1 or raise 'PL_initialise failed' # we really don't want the prolog console showing up in ruby. call 'set_prolog_flag(debug_on_error,false)' end |
.open_query(qterm, args, mod: nil, flags: nil, &blk) ⇒ Object
just to make sure the query handle pointer is properly closed TODO should be private, because args are gnarly
125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/upl/runtime.rb', line 125 def self.open_query qterm, args, mod: nil, flags: nil, &blk # This will need a string for the module, eventually # module is NULL, flags is 0 mod ||= Fiddle::NULL flags ||= flags=Extern::Flags::PL_Q_EXT_STATUS | Extern::Flags::PL_Q_CATCH_EXCEPTION query_id_p = Extern.PL_open_query mod, flags, qterm.to_predicate, args.terms query_id_p != 0 or raise 'no space on environment stack, see SWI-Prolog docs for PL_open_query' yield query_id_p ensure query_id_p&.to_i and Extern.PL_close_query query_id_p end |
.predicate(name, arity) ⇒ Object
80 81 82 |
# File 'lib/upl/runtime.rb', line 80 def self.predicate name, arity, module_name = 0 Extern.PL_predicate Ptr[name.to_s], arity, Fiddle::Pointer[module_name] end |
.query(term) ⇒ Object
TODO much duplication between this and .term_vars_query Only used by the term branch of Upl.query
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
# File 'lib/upl/runtime.rb', line 220 def self.query term raise "not a Term" unless Term === term return enum_for :query, term unless block_given? answer_lst = TermVector.new term.arity do |idx| term[idx] end open_query term, answer_lst do |query_id_p| loop do case Extern.PL_next_solution query_id_p when Extern::ExtStatus::FALSE break when Extern::ExtStatus::EXCEPTION raise_prolog_or_ruby query_id_p # when Extern::ExtStatus::TRUE # when Extern::ExtStatus::LAST else yield answer_lst.each_t.map{|term_t| Tree.of_term term_t} end end end end |
.raise_prolog_or_ruby(query_id_p) ⇒ Object
139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/upl/runtime.rb', line 139 def self.raise_prolog_or_ruby query_id_p tree = Tree.of_term Extern::PL_exception(query_id_p) case tree.atom.to_ruby # special case for errors that originated inside a predicate # that was defined in ruby. when :ruby_error # re-raise the actual exception object from the predicate raise tree.args.first else raise PrologException, tree end end |
.squery(predicate_str, arity) ⇒ Object
Simple query with predicate / arity Returns an array of arrays. TODO remove, not really used
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/upl/runtime.rb', line 196 def self.squery predicate_str, arity return enum_for :squery, predicate_str, arity unless block_given? # bit of a hack because open_query wants to call to_predicate # and we have to construct that manually here because Upl::Term # is slightly ill-suited. qterm = Object.new qterm.define_singleton_method :to_predicate do p_functor = Extern::PL_new_functor predicate_str.to_sym.to_atom, arity Extern::PL_pred p_functor, Fiddle::NULL end args = TermVector.new arity open_query qterm, args do |query_id_p| loop do rv = Extern.PL_next_solution query_id_p break if rv == 0 yield args.each_t.map{|term_t| Tree.of_term term_t} end end end |
.term_vars(st) ⇒ Object
Use prolog predicate to parse the string into a term (containing variables), along with its named variables as a hash of Name => _variable
TODO need to use read_term_from_atom(‘pred(A,B,C)’, Term, [variable_names(VarNames)]). remember Atom can also be a string for swipl
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/upl/runtime.rb', line 105 def self.term_vars st rv = Extern::PL_call_predicate \ Fiddle::NULL, # module 0, # flags, see PL_open_query (predicate 'atom_to_term', 3), # 3 variables, first one determined (args = TermVector[st.to_sym, nil, nil]).terms vars = Inter.each_of_list(args[2]).each_with_object Variables.new do |term_t, vars| # each of these is =(Atom,variable), and we want Atom => variable t = Term.new term_t vars.store t.first.atom.to_sym, (Variable.new t.last.term_t, name: t.first.atom.to_sym) end # return term, {name => var...} return args[1], vars end |
.term_vars_query(qterm, qvars_hash) ⇒ Object
do a query for the given term and vars, as parsed by term_vars qvars_hash is a hash of :VariableName => Term(PL_VARIABLE) and each variable is already bound in term. TODO much duplication between this and .query below
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/upl/runtime.rb', line 157 def self.term_vars_query qterm, qvars_hash raise "not a term" unless Term === qterm return enum_for __method__, qterm, qvars_hash unless block_given? with_frame do |fid_t| # populate input values from qterm args = TermVector.new qterm.arity do |idx| qterm[idx] end open_query qterm, args do |query_id_p| loop do case Extern.PL_next_solution query_id_p when Extern::ExtStatus::FALSE break when Extern::ExtStatus::EXCEPTION raise_prolog_or_ruby query_id_p # when Extern::ExtStatus::TRUE # when Extern::ExtStatus::LAST else hash = qvars_hash.each_with_object Hash.new do |(name_sym,var),ha| # var will be invalidated by the next call to PL_next_solution, # so we need to construct a ruby tree copy of the value term. ha[name_sym] = var.to_ruby end yield hash end end end end end |
.unify(term_a, term_b) ⇒ Object
84 85 86 87 |
# File 'lib/upl/runtime.rb', line 84 def self.unify( term_a, term_b ) rv = Extern::PL_unify term_a.term_t, term_a.term_t rv == 1 or raise "can't unify #{term_a} and #{term_b}" end |
.with_frame(&blk) ⇒ Object
blk takes a fid_t
90 91 92 93 94 95 96 97 98 |
# File 'lib/upl/runtime.rb', line 90 def self.with_frame &blk fid_t = Extern.PL_open_foreign_frame yield fid_t ensure # discards term references, but keeps bindings # fid_t and Extern.PL_close_foreign_frame fid_t # same as close and also undo bindings fid_t and Extern.PL_discard_foreign_frame fid_t end |