upl 0.0.1 → 0.0.2
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/README.md +23 -23
- data/lib/upl/dict.rb +61 -0
- data/lib/upl/extern.rb +6 -1
- data/lib/upl/inter.rb +42 -4
- data/lib/upl/runtime.rb +60 -73
- data/lib/upl/term.rb +34 -31
- data/lib/upl/term_vector.rb +67 -0
- data/lib/upl/tree.rb +24 -41
- data/lib/upl/variable.rb +3 -2
- data/lib/upl/version.rb +1 -1
- data/lib/upl.rb +45 -4
- metadata +4 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: dc30b39fd062308b8cbae9bcaeca09c2b4921ff888c42ba00d100c2a045b39bf
         | 
| 4 | 
            +
              data.tar.gz: 11adee909aee233bae48fe9ea7d1c33b25ba35ef33c1fabe6526e399e7920d81
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 5cc115b7e58995a480463b226df08d68fa54ee9a441d64b47efbc13546f184d3f4ee91fc14881f4f6df5773c2dd6b7f8f5268d86db2a7009bac036afa564b462
         | 
| 7 | 
            +
              data.tar.gz: cb405495fee3c55030f520c3be3c6305b8158848aa77c9d597233bf15a76c82b352d675d4277fc75acaec9c87d4e6ed21a977e79290301ec5882f500f86385c8
         | 
    
        data/README.md
    CHANGED
    
    | @@ -13,12 +13,6 @@ Also, do prolog-style queries on objects :-DD | |
| 13 13 |  | 
| 14 14 | 
             
            ### Queries
         | 
| 15 15 |  | 
| 16 | 
            -
            To read rules from a prolog file:
         | 
| 17 | 
            -
            ``` ruby
         | 
| 18 | 
            -
            [1] pry(main)> Upl.consult '/home/yours/funky_data.pl'
         | 
| 19 | 
            -
            => true
         | 
| 20 | 
            -
            ```
         | 
| 21 | 
            -
             | 
| 22 16 | 
             
            Query a built-in predicate, with a full expression:
         | 
| 23 17 | 
             
            ``` ruby
         | 
| 24 18 | 
             
            [1] pry(main)> enum = Upl.query 'current_prolog_flag(K,V), member(K,[home,executable,shared_object_extension])'
         | 
| @@ -29,12 +23,18 @@ Query a built-in predicate, with a full expression: | |
| 29 23 | 
             
             {:K=>shared_object_extension, :V=>so}]
         | 
| 30 24 | 
             
            ```
         | 
| 31 25 |  | 
| 26 | 
            +
            To read rules from a prolog file:
         | 
| 27 | 
            +
            ``` ruby
         | 
| 28 | 
            +
            [1] pry(main)> Upl.consult '/home/yours/funky_data.pl'
         | 
| 29 | 
            +
            => true
         | 
| 30 | 
            +
            ```
         | 
| 31 | 
            +
             | 
| 32 32 | 
             
            ### Facts
         | 
| 33 33 | 
             
            Also we want to be able to construct prolog-queryable facts from ruby objects.
         | 
| 34 34 | 
             
            In prolog:
         | 
| 35 35 |  | 
| 36 36 | 
             
            ``` prolog
         | 
| 37 | 
            -
            ?-  | 
| 37 | 
            +
            ?- assertz(person(john,anderson)).
         | 
| 38 38 | 
             
            true.
         | 
| 39 39 |  | 
| 40 40 | 
             
            ?- person(A,B).
         | 
| @@ -51,15 +51,15 @@ false. | |
| 51 51 | 
             
            And in Upl:
         | 
| 52 52 |  | 
| 53 53 | 
             
            ``` ruby
         | 
| 54 | 
            -
            [ | 
| 54 | 
            +
            [2] pry(main)> fact = Upl::Term.functor :person, :john, :anderson
         | 
| 55 55 | 
             
            => person/2(john,anderson)
         | 
| 56 | 
            -
            [ | 
| 56 | 
            +
            [3] pry(main)> Upl.assertz fact
         | 
| 57 57 | 
             
            => true
         | 
| 58 | 
            -
            [ | 
| 58 | 
            +
            [4] pry(main)> Array Upl.query 'person(A,B)'
         | 
| 59 59 | 
             
            => [{:A=>john, :B=>anderson}]
         | 
| 60 | 
            -
            [ | 
| 60 | 
            +
            [5] pry(main)> Upl.retract fact
         | 
| 61 61 | 
             
            => true
         | 
| 62 | 
            -
            [ | 
| 62 | 
            +
            [6] pry(main)> Array Upl.query 'person(A,B)'
         | 
| 63 63 | 
             
            => []
         | 
| 64 64 | 
             
            ```
         | 
| 65 65 |  | 
| @@ -69,15 +69,15 @@ Also, with objects other than symbols. Obviously, this is a rabbit-hole of | |
| 69 69 | 
             
            Alician proportions. So, here we GOOOoooo...
         | 
| 70 70 |  | 
| 71 71 | 
             
            ``` ruby
         | 
| 72 | 
            -
            [ | 
| 72 | 
            +
            [2] pry(main)> fact = Upl::Term.functor :person, :john, :anderson, (o = Object.new)
         | 
| 73 73 | 
             
            => person/3(john,anderson,#<Object:0x0000563346a08e38 @_upl_atom=439429>)
         | 
| 74 | 
            -
            [ | 
| 74 | 
            +
            [3] pry(main)> Upl.assertz fact
         | 
| 75 75 | 
             
            => true
         | 
| 76 | 
            -
            [ | 
| 76 | 
            +
            [4] pry(main)> ha, = Array Upl.query 'person(A,B,C)'
         | 
| 77 77 | 
             
            => [{:A=>john,
         | 
| 78 78 | 
             
              :B=>anderson,
         | 
| 79 79 | 
             
              :C=>#<Object:0x0000563346a08e38 @_upl_atom=439429>}]
         | 
| 80 | 
            -
            [ | 
| 80 | 
            +
            [5] pry(main)> ha[:C].equal? o
         | 
| 81 81 | 
             
            => true
         | 
| 82 82 | 
             
            ```
         | 
| 83 83 |  | 
| @@ -88,24 +88,24 @@ And now, the pièce de résistance - using an object as an input term: | |
| 88 88 |  | 
| 89 89 | 
             
            ``` ruby
         | 
| 90 90 | 
             
            fact = Upl::Term.functor :person, :james, :madison, (o = Object.new)
         | 
| 91 | 
            -
            Upl | 
| 91 | 
            +
            Upl.assertz fact
         | 
| 92 92 |  | 
| 93 93 | 
             
            fact2 = Upl::Term.functor :person, :thomas, :paine, (thing2 = Object.new)
         | 
| 94 | 
            -
            Upl | 
| 94 | 
            +
            Upl.assertz fact2
         | 
| 95 95 |  | 
| 96 96 | 
             
            # Note that both facts are in the result
         | 
| 97 | 
            -
            query_term,  | 
| 98 | 
            -
            Array Upl::Runtime.term_vars_query query_term,  | 
| 97 | 
            +
            query_term, query_hash = Upl::Runtime.term_vars 'person(A,B,C)'
         | 
| 98 | 
            +
            Array Upl::Runtime.term_vars_query query_term, query_hash
         | 
| 99 99 | 
             
            =>[{:A=>james, :B=>madison, :C=>#<Object:0x0000563f56e35580 @_upl_atom=439429>},
         | 
| 100 100 | 
             
              {:A=>thomas, :B=>paine, :C=>#<Object:0x0000563f56d2b5b8 @_upl_atom=439813>}]
         | 
| 101 101 |  | 
| 102 102 | 
             
            # Unify C with thing2. This needs a nicer api :-\
         | 
| 103 | 
            -
            query_term,  | 
| 104 | 
            -
            Upl::Extern.PL_unify  | 
| 103 | 
            +
            query_term, query_hash = Upl::Runtime.term_vars 'person(A,B,C)'
         | 
| 104 | 
            +
            Upl::Extern.PL_unify query_hash[:C].term_t, thing2.to_term_t
         | 
| 105 105 |  | 
| 106 106 | 
             
            # ... and we get the correct result
         | 
| 107 107 | 
             
            # Note that the first fact is not in the result.
         | 
| 108 | 
            -
            Array Upl::Runtime.term_vars_query query_term,  | 
| 108 | 
            +
            Array Upl::Runtime.term_vars_query query_term, query_hash
         | 
| 109 109 | 
             
            => [{:A=>thomas, :B=>paine, :C=>#<Object:0x0000563f56d2b5b8 @_upl_atom=439813>}]
         | 
| 110 110 | 
             
            ```
         | 
| 111 111 |  | 
    
        data/lib/upl/dict.rb
    ADDED
    
    | @@ -0,0 +1,61 @@ | |
| 1 | 
            +
            module Upl
         | 
| 2 | 
            +
              class Dict < Hash
         | 
| 3 | 
            +
                def initialize( tag, default_value = nil, &default_blk )
         | 
| 4 | 
            +
                  @tag = tag
         | 
| 5 | 
            +
                  super default_value, &default_blk
         | 
| 6 | 
            +
                end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                # fetch the tag for the dict
         | 
| 9 | 
            +
                def self.dict_tag( dict_term_t )
         | 
| 10 | 
            +
                  args = TermVector[dict_term_t, nil]
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                  # TODO need a better api here as well, and other places
         | 
| 13 | 
            +
                  # eg, need to check that args.size == predicate.arity
         | 
| 14 | 
            +
                  # otherwise segfaults and other weird stuff ensue
         | 
| 15 | 
            +
                  rv = Extern::PL_call_predicate \
         | 
| 16 | 
            +
                    Extern::NULL, # module
         | 
| 17 | 
            +
                    0, # flags, see PL_open_query
         | 
| 18 | 
            +
                    (Runtime.predicate 'is_dict', args.size),
         | 
| 19 | 
            +
                    args.terms
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  rv == 1 or raise "can't retrieve dict tag"
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  # now retrieve the variable's value
         | 
| 24 | 
            +
                  args.last.to_ruby
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                # copy dict_term_t into a ruby structure
         | 
| 28 | 
            +
                def self.of_term( dict_term_t )
         | 
| 29 | 
            +
                  # Have to do a little hoop-jumping here. There are no c-level calls to
         | 
| 30 | 
            +
                  # access dicts, so we have to break them down with prolog predicates. But
         | 
| 31 | 
            +
                  # we can't process queries that have dicts in their results, otherwise we
         | 
| 32 | 
            +
                  # have an endless recursion.
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  query_term, query_hash = Runtime.term_vars 'get_dict(K,Dict,V)'
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  # So set the Dict value to dict_term_t above ...
         | 
| 37 | 
            +
                  query_term[1] = dict_term_t
         | 
| 38 | 
            +
                  # ...and remove it from the output variables
         | 
| 39 | 
            +
                  query_hash.delete :Dict
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  # now we have a result set with K,V values
         | 
| 42 | 
            +
                  en = Upl::Runtime.term_vars_query query_term, query_hash
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  # map to a hash-y thing
         | 
| 45 | 
            +
                  en.each_with_object Dict.new(dict_tag dict_term_t) do |row,values|
         | 
| 46 | 
            +
                    values[row[:K]] = row[:V]
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                attr_reader :tag, :values
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def == rhs
         | 
| 53 | 
            +
                  [tag,to_h] == [rhs.tag,rhs.to_h]
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                def pretty_print pp
         | 
| 57 | 
            +
                  tag.pretty_print pp
         | 
| 58 | 
            +
                  super
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
            end
         | 
    
        data/lib/upl/extern.rb
    CHANGED
    
    | @@ -196,12 +196,17 @@ module Upl | |
| 196 196 | 
             
                extern 'int PL_put_atom(term_t t, atom_t a)'
         | 
| 197 197 | 
             
                extern 'int PL_put_variable(term_t t)'
         | 
| 198 198 | 
             
                extern 'int PL_put_functor(term_t t, functor_t functor)'
         | 
| 199 | 
            +
                extern 'int PL_put_term(term_t t1, term_t t2)' # Make t1 point to the same term as t2.
         | 
| 199 200 |  | 
| 200 201 | 
             
                extern 'int PL_cons_functor_v(term_t h, functor_t fd, term_t a0)'
         | 
| 201 202 |  | 
| 203 | 
            +
                extern 'int PL_unify_arg(int index, term_t t, term_t a)' # set index-th arg of t to a
         | 
| 204 | 
            +
             | 
| 202 205 | 
             
                extern 'int PL_get_atom_chars(term_t t, char **a)'
         | 
| 203 206 | 
             
                extern 'int PL_get_string(term_t t, char **s, size_t *len)'
         | 
| 204 207 | 
             
                extern 'int PL_get_integer(term_t t, int *i)'
         | 
| 208 | 
            +
                extern 'int PL_get_int64(term_t t, int64_t *i)'
         | 
| 209 | 
            +
                extern 'int PL_get_float(term_t t, double *f)'
         | 
| 205 210 | 
             
                extern 'int PL_get_chars(term_t t, char **s, unsigned int flags)'
         | 
| 206 211 | 
             
                extern 'int PL_get_name_arity(term_t t, atom_t *name, int *arity)'
         | 
| 207 212 | 
             
                extern 'int PL_get_arg(int index, term_t t, term_t a)'
         | 
| @@ -230,7 +235,7 @@ module Upl | |
| 230 235 | 
             
                ####################
         | 
| 231 236 | 
             
                # looks like parsing of terms
         | 
| 232 237 | 
             
                # only >= 7.6.0
         | 
| 233 | 
            -
                # get version,  | 
| 238 | 
            +
                # get version, call current_prolog_flag(version_data,swi(M,I,P,E)). Major, mInor, Patch, Extra[]
         | 
| 234 239 | 
             
                # PL_EXPORT(int)  PL_put_term_from_chars(term_t t, int flags, size_t len, const char *s);
         | 
| 235 240 | 
             
                # extern 'int PL_put_term_from_chars(term_t t, int flags, size_t len, const char *s)'
         | 
| 236 241 |  | 
    
        data/lib/upl/inter.rb
    CHANGED
    
    | @@ -1,4 +1,39 @@ | |
| 1 | 
            -
             | 
| 1 | 
            +
            module Upl
         | 
| 2 | 
            +
              module Inter
         | 
| 3 | 
            +
                # Try Term, then Fiddle::Pointer, then to_term_t.
         | 
| 4 | 
            +
                # Return a term_t pointer
         | 
| 5 | 
            +
                def self.term_t_of term_or_ptr
         | 
| 6 | 
            +
                  case term_or_ptr
         | 
| 7 | 
            +
                  when Term
         | 
| 8 | 
            +
                    term_or_ptr.term_t
         | 
| 9 | 
            +
                  when Fiddle::Pointer
         | 
| 10 | 
            +
                    term_or_ptr
         | 
| 11 | 
            +
                  else
         | 
| 12 | 
            +
                    term_or_ptr.to_term_t
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                # lst_term is a Term, or a Fiddle::Pointer to term_t
         | 
| 17 | 
            +
                # yield term_t items of the lst_term
         | 
| 18 | 
            +
                def self.each_of_list lst_term, &blk
         | 
| 19 | 
            +
                  return enum_for __method__, lst_term unless block_given?
         | 
| 20 | 
            +
                  lst_term = Inter.term_t_of lst_term
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  while Extern::PL_get_nil(lst_term) != 1 # not end of list
         | 
| 23 | 
            +
                    res = Extern::PL_get_list \
         | 
| 24 | 
            +
                      lst_term,
         | 
| 25 | 
            +
                      (head_t = Extern.PL_new_term_ref),
         | 
| 26 | 
            +
                      (rst_t = Extern.PL_new_term_ref)
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    break unless res == 1
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    yield head_t
         | 
| 31 | 
            +
                    lst_term = rst_t
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| 36 | 
            +
             | 
| 2 37 | 
             
            class Object
         | 
| 3 38 | 
             
              def to_atom
         | 
| 4 39 | 
             
                if frozen?
         | 
| @@ -9,7 +44,13 @@ class Object | |
| 9 44 | 
             
                end
         | 
| 10 45 | 
             
              end
         | 
| 11 46 |  | 
| 47 | 
            +
              # return a Term object from to_term_t
         | 
| 12 48 | 
             
              def to_term
         | 
| 49 | 
            +
                Upl::Term.new to_term_t
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              # return a term_t pointer
         | 
| 53 | 
            +
              def to_term_t
         | 
| 13 54 | 
             
                if frozen?
         | 
| 14 55 | 
             
                  # TODO must check instance variable here
         | 
| 15 56 | 
             
                  _upl_termize
         | 
| @@ -43,6 +84,3 @@ class Symbol | |
| 43 84 | 
             
                Upl::Extern.PL_new_atom to_s
         | 
| 44 85 | 
             
              end
         | 
| 45 86 | 
             
            end
         | 
| 46 | 
            -
             | 
| 47 | 
            -
            module Inter
         | 
| 48 | 
            -
            end
         | 
    
        data/lib/upl/runtime.rb
    CHANGED
    
    | @@ -17,11 +17,26 @@ module Upl | |
| 17 17 | 
             
              module Runtime
         | 
| 18 18 | 
             
                Ptr = Fiddle::Pointer
         | 
| 19 19 |  | 
| 20 | 
            +
                def self.call st_or_term
         | 
| 21 | 
            +
                  term =
         | 
| 22 | 
            +
                  case st_or_term
         | 
| 23 | 
            +
                  when String
         | 
| 24 | 
            +
                    Term.new st_or_term
         | 
| 25 | 
            +
                  when Term
         | 
| 26 | 
            +
                    st_or_term
         | 
| 27 | 
            +
                  else
         | 
| 28 | 
            +
                    raise "dunno bout #{st_or_term}"
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  rv = Extern.PL_call term.term_t, Extern::NULL
         | 
| 32 | 
            +
                  rv == 1 # don't raise
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 20 35 | 
             
                def self.init
         | 
| 21 36 | 
             
                  # set up no output so we don't get swipl command line interfering in ruby
         | 
| 22 37 | 
             
                  # TODO exception handling should not kick off a prolog terminal
         | 
| 23 38 | 
             
                  # TODO see gem-swipl for more useful stuff here
         | 
| 24 | 
            -
                  args = %w[upl  | 
| 39 | 
            +
                  args = %w[upl --tty=false --signals=false --debug=false --quiet=true]
         | 
| 25 40 |  | 
| 26 41 | 
             
                  # convert args to char **
         | 
| 27 42 | 
             
                  ptr_size = Extern.sizeof 'char*'
         | 
| @@ -33,6 +48,9 @@ module Upl | |
| 33 48 | 
             
                  # call init
         | 
| 34 49 | 
             
                  rv = Extern.PL_initialise args.size, arg_ptrs
         | 
| 35 50 | 
             
                  rv == 1 or raise 'PL_initialise failed'
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  # we really don't want the prolog console showing up in ruby.
         | 
| 53 | 
            +
                  call 'set_prolog_flag(debug_on_error,false)'
         | 
| 36 54 | 
             
                end
         | 
| 37 55 |  | 
| 38 56 | 
             
                # once_only. Should probably be a singleton or something.
         | 
| @@ -42,26 +60,23 @@ module Upl | |
| 42 60 | 
             
                  Extern.PL_predicate Fiddle::Pointer[name.to_s], arity, NULL
         | 
| 43 61 | 
             
                end
         | 
| 44 62 |  | 
| 45 | 
            -
                # Use prolog predicate to parse the string into a term with its named variables
         | 
| 63 | 
            +
                # Use prolog predicate to parse the string into a term, with its named variables as a hash of Name => _variable
         | 
| 64 | 
            +
                # TODO maybe use read_term_from_chars, or at least don't force the term to be an atom
         | 
| 65 | 
            +
                # TODO need to use read_term_from_atom('retry(A,B,C)', Term, [variable_names(VarNames)]).
         | 
| 46 66 | 
             
                def self.term_vars st
         | 
| 47 | 
            -
                  # atom_to_term('your_pred(A,B,C,D)',Term,Options).
         | 
| 48 | 
            -
                  terms = Extern.PL_new_term_refs 3
         | 
| 49 | 
            -
                  atom, term, options = terms+0, terms+1, terms+2
         | 
| 50 | 
            -
             | 
| 51 | 
            -
                  Extern::PL_put_atom atom, (Extern::PL_new_atom Fiddle::Pointer[st])
         | 
| 52 | 
            -
                  Extern::PL_put_variable term
         | 
| 53 | 
            -
                  Extern::PL_put_variable options
         | 
| 54 | 
            -
             | 
| 55 | 
            -
                  # docs say to use read_term_from_atom/3, but it fails with uninstantiated variables for 7.7.18
         | 
| 56 67 | 
             
                  rv = Extern::PL_call_predicate \
         | 
| 57 68 | 
             
                    Extern::NULL, # module
         | 
| 58 69 | 
             
                    0, # flags, see PL_open_query
         | 
| 59 70 | 
             
                    (predicate 'atom_to_term', 3),
         | 
| 60 | 
            -
                    terms
         | 
| 71 | 
            +
                    (args = TermVector[st.to_sym, nil, nil]).terms
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                  vars_hash = Inter.each_of_list(args[2]).map do |term_t|
         | 
| 74 | 
            +
                    # each of these is =(Atom,variable), and we want Atom => variable
         | 
| 75 | 
            +
                    t = Term.new term_t
         | 
| 76 | 
            +
                    [t.first.atom.to_sym, t.last]
         | 
| 77 | 
            +
                  end.to_h
         | 
| 61 78 |  | 
| 62 | 
            -
                   | 
| 63 | 
            -
                  # vars *must* be unhooked though ¯\_(ツ)_/¯
         | 
| 64 | 
            -
                  return (Term.new term), (list_to_ary options do |elt| Term.new elt end)
         | 
| 79 | 
            +
                  return args[1], vars_hash
         | 
| 65 80 | 
             
                end
         | 
| 66 81 |  | 
| 67 82 | 
             
                def self.unify( term_a, term_b )
         | 
| @@ -70,21 +85,18 @@ module Upl | |
| 70 85 | 
             
                end
         | 
| 71 86 |  | 
| 72 87 | 
             
                # do a query for the given term and vars, as parsed by term_vars
         | 
| 73 | 
            -
                def self.term_vars_query qterm,  | 
| 88 | 
            +
                def self.term_vars_query qterm, qvars_hash
         | 
| 74 89 | 
             
                  raise "not a term" unless Term === qterm
         | 
| 75 | 
            -
                  return enum_for __method__,  qterm,  | 
| 90 | 
            +
                  return enum_for __method__,  qterm, qvars_hash unless block_given?
         | 
| 76 91 |  | 
| 77 92 | 
             
                  fid_t = Extern.PL_open_foreign_frame
         | 
| 78 93 |  | 
| 79 94 | 
             
                  begin
         | 
| 80 | 
            -
                    # input values
         | 
| 81 | 
            -
                     | 
| 82 | 
            -
                     qterm.args.each_with_index do |arg,idx|
         | 
| 83 | 
            -
                      Extern::PL_unify (terms_ptr+idx), arg
         | 
| 84 | 
            -
                    end
         | 
| 95 | 
            +
                    # populate input values from qterm
         | 
| 96 | 
            +
                    args = TermVector.new qterm.arity do |idx| qterm[idx] end
         | 
| 85 97 |  | 
| 86 98 | 
             
                    # module is NULL, flags is 0
         | 
| 87 | 
            -
                    query_id_p = Extern.PL_open_query Extern::NULL, 0, qterm.to_predicate,  | 
| 99 | 
            +
                    query_id_p = Extern.PL_open_query Extern::NULL, 0, qterm.to_predicate, args.terms
         | 
| 88 100 | 
             
                    query_id_p != 0 or raise 'no space on environment stack, see SWI-Prolog docs for PL_open_query'
         | 
| 89 101 |  | 
| 90 102 | 
             
                    loop do
         | 
| @@ -92,13 +104,10 @@ module Upl | |
| 92 104 | 
             
                      res = Extern.PL_next_solution query_id_p
         | 
| 93 105 | 
             
                      break if res == 0
         | 
| 94 106 |  | 
| 95 | 
            -
                      hash =  | 
| 96 | 
            -
                        name_term_t, var_term_t = name_var.args.to_a
         | 
| 97 | 
            -
                        name = Term.new name_term_t
         | 
| 98 | 
            -
             | 
| 107 | 
            +
                      hash = qvars_hash.each_with_object Hash.new do |(name_sym,var),ha|
         | 
| 99 108 | 
             
                        # term_t will be invalidated by the next call to PL_next_solution,
         | 
| 100 109 | 
             
                        # so we need to construct a ruby tree of the value term
         | 
| 101 | 
            -
                        val = ha[ | 
| 110 | 
            +
                        val = ha[name_sym] = var.to_ruby
         | 
| 102 111 | 
             
                        # binding.pry if val.to_sym == :query_debug_settings rescue false
         | 
| 103 112 | 
             
                      end
         | 
| 104 113 |  | 
| @@ -114,65 +123,43 @@ module Upl | |
| 114 123 | 
             
                  fid_t and Extern.PL_close_foreign_frame fid_t
         | 
| 115 124 | 
             
                end
         | 
| 116 125 |  | 
| 117 | 
            -
                def self.eval st_or_term
         | 
| 118 | 
            -
                  p_term =
         | 
| 119 | 
            -
                  case st_or_term
         | 
| 120 | 
            -
                  when String
         | 
| 121 | 
            -
                    rv = Extern.PL_chars_to_term Fiddle::Pointer[st_or_term], (p_term = Extern.PL_new_term_ref)
         | 
| 122 | 
            -
                    raise "failure parsing term #{st_or_term}" unless rv == 1
         | 
| 123 | 
            -
                    p_term
         | 
| 124 | 
            -
                  when Term
         | 
| 125 | 
            -
                    st_or_term.term_t
         | 
| 126 | 
            -
                  else
         | 
| 127 | 
            -
                    raise "dunno bout #{st_or_term}"
         | 
| 128 | 
            -
                  end
         | 
| 129 | 
            -
             | 
| 130 | 
            -
                  rv = Extern.PL_call p_term, Extern::NULL
         | 
| 131 | 
            -
                  rv == 1 or raise "failure executing term #{st}"
         | 
| 132 | 
            -
                end
         | 
| 133 | 
            -
             | 
| 134 126 | 
             
                def self.predicate name, arity
         | 
| 135 127 | 
             
                  pred_p = Extern.PL_predicate Ptr[name.to_s], arity, Extern::NULL
         | 
| 136 128 | 
             
                end
         | 
| 137 129 |  | 
| 138 | 
            -
                 | 
| 139 | 
            -
             | 
| 130 | 
            +
                # Simple query with predicate / arity
         | 
| 131 | 
            +
                # Returns an array of arrays.
         | 
| 132 | 
            +
                def self.squery predicate_str, arity
         | 
| 133 | 
            +
                  return enum_for :squery, predicate_str, arity unless block_given?
         | 
| 140 134 |  | 
| 141 | 
            -
                   | 
| 142 | 
            -
             | 
| 143 | 
            -
                      lst,
         | 
| 144 | 
            -
                      (head = Extern.PL_new_term_ref),
         | 
| 145 | 
            -
                      (rst = Extern.PL_new_term_ref)
         | 
| 135 | 
            +
                  p_functor = Extern::PL_new_functor predicate_str.to_sym.to_atom, arity
         | 
| 136 | 
            +
                  p_predicate = Extern::PL_pred p_functor, Extern::NULL
         | 
| 146 137 |  | 
| 147 | 
            -
             | 
| 138 | 
            +
                  answer_lst = TermVector.new arity
         | 
| 139 | 
            +
                  query_id_p = Extern.PL_open_query Extern::NULL, 0, p_predicate, answer_lst.terms
         | 
| 148 140 |  | 
| 149 | 
            -
             | 
| 150 | 
            -
                     | 
| 141 | 
            +
                  loop do
         | 
| 142 | 
            +
                    rv = Extern.PL_next_solution query_id_p
         | 
| 143 | 
            +
                    break if rv == 0
         | 
| 144 | 
            +
                    yield answer_lst.each_t.map{|term_t| Tree.of_term term_t}
         | 
| 151 145 | 
             
                  end
         | 
| 152 146 |  | 
| 153 | 
            -
             | 
| 147 | 
            +
                ensure
         | 
| 148 | 
            +
                  # NOTE this also gets called after enum_for
         | 
| 149 | 
            +
                  query_id_p&.to_i and Extern.PL_close_query query_id_p
         | 
| 154 150 | 
             
                end
         | 
| 155 151 |  | 
| 156 | 
            -
                 | 
| 157 | 
            -
             | 
| 158 | 
            -
                  return enum_for : | 
| 159 | 
            -
                  p_atom = Extern::PL_new_atom Fiddle::Pointer[predicate_str]
         | 
| 160 | 
            -
                  p_functor = Extern::PL_new_functor p_atom, arity
         | 
| 161 | 
            -
                  p_predicate = Extern::PL_pred p_functor, Extern::NULL
         | 
| 152 | 
            +
                def self.query term
         | 
| 153 | 
            +
                  raise "not a Term" unless Term === term
         | 
| 154 | 
            +
                  return enum_for :query_term, term unless block_given?
         | 
| 162 155 |  | 
| 163 | 
            -
                  answer_lst =  | 
| 164 | 
            -
                  query_id_p = Extern.PL_open_query Extern::NULL, 0,  | 
| 156 | 
            +
                  answer_lst = TermVector.new term.arity do |idx| term[idx] end
         | 
| 157 | 
            +
                  query_id_p = Extern.PL_open_query Extern::NULL, 0, term.to_predicate, answer_lst.terms
         | 
| 165 158 |  | 
| 166 159 | 
             
                  loop do
         | 
| 167 | 
            -
                     | 
| 168 | 
            -
                    break if  | 
| 169 | 
            -
             | 
| 170 | 
            -
                    answrs =
         | 
| 171 | 
            -
                    arity.times.map do |i|
         | 
| 172 | 
            -
                      term_to_ruby answer_lst+i
         | 
| 173 | 
            -
                    end
         | 
| 174 | 
            -
             | 
| 175 | 
            -
                    yield answrs
         | 
| 160 | 
            +
                    rv = Extern.PL_next_solution query_id_p
         | 
| 161 | 
            +
                    break if rv == 0
         | 
| 162 | 
            +
                    yield answer_lst.each_t.map{|term_t| Tree.of_term term_t}
         | 
| 176 163 | 
             
                  end
         | 
| 177 164 |  | 
| 178 165 | 
             
                ensure
         | 
    
        data/lib/upl/term.rb
    CHANGED
    
    | @@ -7,25 +7,21 @@ module Upl | |
| 7 7 | 
             
                def initialize term_or_string
         | 
| 8 8 | 
             
                  case term_or_string
         | 
| 9 9 | 
             
                  when String
         | 
| 10 | 
            -
                     | 
| 11 | 
            -
                     | 
| 10 | 
            +
                    @term_t = Extern.PL_new_term_ref
         | 
| 11 | 
            +
                    rv = Extern.PL_chars_to_term Fiddle::Pointer[term_or_string], @term_t
         | 
| 12 | 
            +
                    rv == 1 or raise "failure parsing term #{term_or_string}"
         | 
| 13 | 
            +
             | 
| 12 14 | 
             
                  when Fiddle::Pointer
         | 
| 13 15 | 
             
                    # assume this is a pointer to a term. Unsafe, but there's no choice really
         | 
| 14 16 | 
             
                    @term_t = term_or_string
         | 
| 17 | 
            +
             | 
| 15 18 | 
             
                  else
         | 
| 16 19 | 
             
                    raise "can't handle #{term_or_string}"
         | 
| 17 20 | 
             
                  end
         | 
| 18 21 | 
             
                end
         | 
| 19 22 |  | 
| 20 23 | 
             
                attr_reader :term_t
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                def to_term; term_t end
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                # Make a copy of all the term information. Useful for passing in to queries, apparently.
         | 
| 25 | 
            -
                def self.copy term_t
         | 
| 26 | 
            -
                  copy_term_t = Extern.PL_copy_term_ref term_t
         | 
| 27 | 
            -
                  new copy_term_t
         | 
| 28 | 
            -
                end
         | 
| 24 | 
            +
                alias to_term_t term_t
         | 
| 29 25 |  | 
| 30 26 | 
             
                def self.of_atom atom
         | 
| 31 27 | 
             
                  term_t = Extern.PL_new_term_ref
         | 
| @@ -34,14 +30,14 @@ module Upl | |
| 34 30 | 
             
                  term_t
         | 
| 35 31 | 
             
                end
         | 
| 36 32 |  | 
| 37 | 
            -
                # args are things that can be converted to term_t pointers using  | 
| 33 | 
            +
                # args are things that can be converted to term_t pointers using to_term_t method
         | 
| 38 34 | 
             
                def self.functor name, *args
         | 
| 39 35 | 
             
                  # TODO maybe use a frame or something because this allocates quite a few sub-terms
         | 
| 40 36 | 
             
                  functor_t = Extern.PL_new_functor name.to_sym.to_atom, args.size
         | 
| 41 37 |  | 
| 42 38 | 
             
                  arg_terms = Extern.PL_new_term_refs args.size
         | 
| 43 | 
            -
                  args.each_with_index do |arg, | 
| 44 | 
            -
                    Extern::PL_unify (arg_terms+ | 
| 39 | 
            +
                  args.each_with_index do |arg,idx|
         | 
| 40 | 
            +
                    Extern::PL_unify (arg_terms+idx), arg.to_term_t
         | 
| 45 41 | 
             
                  end
         | 
| 46 42 |  | 
| 47 43 | 
             
                  term_t = Extern.PL_new_term_ref
         | 
| @@ -54,9 +50,10 @@ module Upl | |
| 54 50 | 
             
                def populate
         | 
| 55 51 | 
             
                  int_ptr = Runtime::Ptr[0].ref
         | 
| 56 52 | 
             
                  atom_ptr = Runtime::Ptr[0].ref
         | 
| 53 | 
            +
             | 
| 57 54 | 
             
                  rv = Extern::PL_get_name_arity term_t, atom_ptr, int_ptr
         | 
| 58 55 | 
             
                  # This happens when the term_t is not a PL_TERM (ie a compound)
         | 
| 59 | 
            -
                  raise "can't populate term" | 
| 56 | 
            +
                  rv == 1 or raise "can't populate term"
         | 
| 60 57 |  | 
| 61 58 | 
             
                  @arity = int_ptr.ptr.to_i
         | 
| 62 59 | 
             
                  @atom = Atom.new atom_ptr
         | 
| @@ -72,8 +69,6 @@ module Upl | |
| 72 69 | 
             
                  [@atom, @arity] <=> [rhs.atom, rhs.arity]
         | 
| 73 70 | 
             
                end
         | 
| 74 71 |  | 
| 75 | 
            -
                # attr_reader :atom, :arity
         | 
| 76 | 
            -
             | 
| 77 72 | 
             
                def atom
         | 
| 78 73 | 
             
                  @atom or begin
         | 
| 79 74 | 
             
                    populate
         | 
| @@ -96,29 +91,37 @@ module Upl | |
| 96 91 | 
             
                  Extern::PL_pred to_functor, Extern::NULL
         | 
| 97 92 | 
             
                end
         | 
| 98 93 |  | 
| 99 | 
            -
                def tree; @tree || (Tree. | 
| 100 | 
            -
                 | 
| 94 | 
            +
                def tree; @tree || (Tree.of_term term_t) end
         | 
| 95 | 
            +
                alias to_ruby tree
         | 
| 101 96 |  | 
| 102 | 
            -
                # Assume that term_t still has a value. Which means we have to copy all
         | 
| 103 | 
            -
                # values before the underlying term_t is changed.
         | 
| 104 97 | 
             
                # TODO leaning hard towards each with Enumerable
         | 
| 105 | 
            -
                def  | 
| 98 | 
            +
                def each
         | 
| 106 99 | 
             
                  return enum_for :args unless block_given?
         | 
| 107 100 |  | 
| 108 | 
            -
                  (1..arity).each do | | 
| 109 | 
            -
                    rv = Extern::PL_get_arg  | 
| 110 | 
            -
                     | 
| 111 | 
            -
             | 
| 112 | 
            -
                    else
         | 
| 113 | 
            -
                      puts "#{rv}: can't convert #{i} arg of #{atom}"
         | 
| 114 | 
            -
                      yield subterm
         | 
| 115 | 
            -
                    end
         | 
| 101 | 
            +
                  (1..arity).each do |idx|
         | 
| 102 | 
            +
                    rv = Extern::PL_get_arg idx, term_t, (subterm = Extern.PL_new_term_ref)
         | 
| 103 | 
            +
                    rv == 1 or raise "#{rv}: can't convert #{i} arg of #{atom}"
         | 
| 104 | 
            +
                    yield subterm
         | 
| 116 105 | 
             
                  end
         | 
| 117 106 | 
             
                end
         | 
| 118 107 |  | 
| 108 | 
            +
                include Enumerable
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                def first; self[0] end
         | 
| 111 | 
            +
                def last; self[arity-1] end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                def [](idx)
         | 
| 114 | 
            +
                  # remember args for terms are 1-based
         | 
| 115 | 
            +
                  rv = Extern::PL_get_arg idx+1, term_t, (arg = Extern.PL_new_term_ref)
         | 
| 116 | 
            +
                  rv == 1 or raise "can't access term at #{idx}"
         | 
| 117 | 
            +
                  Term.new arg
         | 
| 118 | 
            +
                end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
                # set term_t[idx] = val_term_t
         | 
| 121 | 
            +
                # idx is zero-based, unlike the prolog calls
         | 
| 119 122 | 
             
                def []=( idx, val_term_t)
         | 
| 120 | 
            -
                   | 
| 121 | 
            -
                  rv = Extern. | 
| 123 | 
            +
                  raise IndexError, "max index is #{arity-1}" if idx >= arity
         | 
| 124 | 
            +
                  rv = Extern.PL_unify_arg idx+1, term_t, val_term_t
         | 
| 122 125 | 
             
                  rv == 1 or raise "can't set index #{idx}"
         | 
| 123 126 | 
             
                end
         | 
| 124 127 |  | 
| @@ -0,0 +1,67 @@ | |
| 1 | 
            +
            require 'fiddle'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Upl
         | 
| 4 | 
            +
              # Create a c-array of terms using PL_new_term_refs. Methods on this class
         | 
| 5 | 
            +
              # will return the term_t pointers wrapped in Term objects. If you want access
         | 
| 6 | 
            +
              # to the underlying term_t pointers, use terms + idx, or the term_t method of
         | 
| 7 | 
            +
              # the Term objects.
         | 
| 8 | 
            +
              class TermVector
         | 
| 9 | 
            +
                # args must all be convertible to term_t Fiddle::Pointers, via term_t_of.
         | 
| 10 | 
            +
                #
         | 
| 11 | 
            +
                # nil values are defaulted to Variable.new, but beware passing in the wrong
         | 
| 12 | 
            +
                # number of arguments.
         | 
| 13 | 
            +
                def self.[]( *args )
         | 
| 14 | 
            +
                  new args.size do |idx|
         | 
| 15 | 
            +
                    args[idx]
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                # similar to Array.new, but each value yielded from blk will be converted to
         | 
| 20 | 
            +
                # term_t using term_t_of
         | 
| 21 | 
            +
                def initialize size, &blk
         | 
| 22 | 
            +
                  @size = Integer size
         | 
| 23 | 
            +
                  @terms = Extern.PL_new_term_refs @size
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  if block_given?
         | 
| 26 | 
            +
                    @size.times do |idx|
         | 
| 27 | 
            +
                      termable = (yield idx) || Variable.new
         | 
| 28 | 
            +
                      term_t = Inter.term_t_of termable
         | 
| 29 | 
            +
                      # TODO not sure if Extern::PL_put_term should be available as a possibility here?
         | 
| 30 | 
            +
                      rv = Extern::PL_unify @terms+idx, term_t
         | 
| 31 | 
            +
                      rv == 1 or raise "can't set index #{idx} of term_vector to #{termable}"
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                attr_reader :size, :terms
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def each_t
         | 
| 39 | 
            +
                  return enum_for :each_t unless block_given?
         | 
| 40 | 
            +
                  size.times.each do |idx| yield @terms+idx end
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def each
         | 
| 44 | 
            +
                  return enum_for :each unless block_given?
         | 
| 45 | 
            +
                  size.times.each do |idx| yield Term.new @terms+idx end
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                include Enumerable
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                def first; Term.new @terms+0; end
         | 
| 51 | 
            +
                def last; Term.new @terms+(size-1); end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                def [](idx)
         | 
| 54 | 
            +
                  raise IndexError unless idx < @size
         | 
| 55 | 
            +
                  Term.new @terms+idx
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                def []=(idx, value)
         | 
| 59 | 
            +
                  raise IndexError unless idx < @size
         | 
| 60 | 
            +
                  Extern::PL_put_term @terms + idx, (Inter.term_t_of value)
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                def to_a
         | 
| 64 | 
            +
                  size.times.map{|idx| @terms+idx}
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
            end
         | 
    
        data/lib/upl/tree.rb
    CHANGED
    
    | @@ -13,7 +13,7 @@ module Upl | |
| 13 13 | 
             
                  case term
         | 
| 14 14 | 
             
                  when Term
         | 
| 15 15 | 
             
                    @atom = term.atom
         | 
| 16 | 
            -
                    @args = term. | 
| 16 | 
            +
                    @args = term.map do |arg|
         | 
| 17 17 | 
             
                      self.class.term_to_ruby arg
         | 
| 18 18 | 
             
                    end
         | 
| 19 19 | 
             
                  when Fiddle::Pointer
         | 
| @@ -27,25 +27,34 @@ module Upl | |
| 27 27 | 
             
                  term_to_ruby term_t
         | 
| 28 28 | 
             
                end
         | 
| 29 29 |  | 
| 30 | 
            -
                def self.term_to_ruby  | 
| 31 | 
            -
                  case  | 
| 30 | 
            +
                def self.term_to_ruby term_t
         | 
| 31 | 
            +
                  case term_t.term_type
         | 
| 32 32 | 
             
                  when Extern::PL_VARIABLE
         | 
| 33 | 
            -
                    Variable.copy  | 
| 33 | 
            +
                    Variable.copy term_t
         | 
| 34 34 |  | 
| 35 35 | 
             
                  when Extern::PL_ATOM
         | 
| 36 | 
            -
                    atom = Atom.of_term  | 
| 36 | 
            +
                    atom = Atom.of_term term_t
         | 
| 37 37 | 
             
                    if atom.to_s =~ /^ruby-(\d+)/
         | 
| 38 38 | 
             
                      ObjectSpace._id2ref $1.to_i
         | 
| 39 39 | 
             
                    else
         | 
| 40 | 
            -
                      atom
         | 
| 40 | 
            +
                      atom.to_sym
         | 
| 41 41 | 
             
                    end
         | 
| 42 42 |  | 
| 43 | 
            -
                   | 
| 44 | 
            -
             | 
| 43 | 
            +
                  # I think integers > 63 bits can be fetched with PL_get_mpz
         | 
| 44 | 
            +
                  # Other than PL_INTEGER, most of these seem to be unused?
         | 
| 45 | 
            +
                  when Extern::PL_INTEGER, Extern::PL_LONG, Extern::PL_INT, Extern::PL_INT64, Extern::PL_SHORT
         | 
| 46 | 
            +
                    rv = Extern.PL_get_int64 term_t, (int_ptr = Fiddle::Pointer[0].ref)
         | 
| 47 | 
            +
                    rv == 1 or raise "Can't convert to int64. Maybe too large."
         | 
| 45 48 | 
             
                    int_ptr.ptr.to_i
         | 
| 46 49 |  | 
| 50 | 
            +
                  when Extern::PL_FLOAT
         | 
| 51 | 
            +
                    rv = Extern.PL_get_float term_t, (double_ptr = Fiddle::Pointer[0].ref)
         | 
| 52 | 
            +
                    rv == 1 or raise "Can't convert to double. Maybe too large."
         | 
| 53 | 
            +
                    bytes = double_ptr[0,8]
         | 
| 54 | 
            +
                    bytes.unpack('D').first
         | 
| 55 | 
            +
             | 
| 47 56 | 
             
                  when Extern::PL_STRING
         | 
| 48 | 
            -
                    rv = Extern.PL_get_string  | 
| 57 | 
            +
                    rv = Extern.PL_get_string term_t, (str_ptr = Fiddle::Pointer[0].ref), (len_ptr = Fiddle::Pointer[0].ref)
         | 
| 49 58 | 
             
                    value_ptr = Fiddle::Pointer.new str_ptr.ptr, len_ptr.ptr.to_i
         | 
| 50 59 | 
             
                    value_ptr.to_s
         | 
| 51 60 |  | 
| @@ -55,30 +64,18 @@ module Upl | |
| 55 64 | 
             
                    nil
         | 
| 56 65 |  | 
| 57 66 | 
             
                  when Extern::PL_TERM
         | 
| 58 | 
            -
                    Tree.new  | 
| 67 | 
            +
                    Tree.new term_t
         | 
| 59 68 |  | 
| 60 69 | 
             
                  when Extern::PL_LIST_PAIR
         | 
| 61 | 
            -
                     | 
| 62 | 
            -
             | 
| 63 | 
            -
                  end
         | 
| 64 | 
            -
                end
         | 
| 65 | 
            -
             | 
| 66 | 
            -
                def self.list_to_ary lst
         | 
| 67 | 
            -
                  rv = []
         | 
| 70 | 
            +
                    Inter.each_of_list(term_t).to_a
         | 
| 68 71 |  | 
| 69 | 
            -
                   | 
| 70 | 
            -
                     | 
| 71 | 
            -
                      lst,
         | 
| 72 | 
            -
                      (head = Extern.PL_new_term_ref),
         | 
| 73 | 
            -
                      (rst = Extern.PL_new_term_ref)
         | 
| 72 | 
            +
                  when Extern::PL_DICT
         | 
| 73 | 
            +
                    Dict.of_term term_t
         | 
| 74 74 |  | 
| 75 | 
            -
             | 
| 75 | 
            +
                  else
         | 
| 76 | 
            +
                    :NotImplemented
         | 
| 76 77 |  | 
| 77 | 
            -
                    rv << (term_to_ruby head)
         | 
| 78 | 
            -
                    lst = rst
         | 
| 79 78 | 
             
                  end
         | 
| 80 | 
            -
             | 
| 81 | 
            -
                  rv
         | 
| 82 79 | 
             
                end
         | 
| 83 80 |  | 
| 84 81 | 
             
                def arity; args.size end
         | 
| @@ -101,19 +98,5 @@ module Upl | |
| 101 98 | 
             
                    end
         | 
| 102 99 | 
             
                  end
         | 
| 103 100 | 
             
                end
         | 
| 104 | 
            -
             | 
| 105 | 
            -
                protected
         | 
| 106 | 
            -
             | 
| 107 | 
            -
                def populate_args count
         | 
| 108 | 
            -
                  (1..arity).each do |i|
         | 
| 109 | 
            -
                    rv = Extern::PL_get_arg i, term_t, (subterm = Extern.PL_new_term_ref)
         | 
| 110 | 
            -
                    if rv == 1
         | 
| 111 | 
            -
                      yield subterm
         | 
| 112 | 
            -
                    else
         | 
| 113 | 
            -
                      puts "#{rv}: can't convert #{i} arg of #{atom}"
         | 
| 114 | 
            -
                      yield subterm
         | 
| 115 | 
            -
                    end
         | 
| 116 | 
            -
                  end
         | 
| 117 | 
            -
                end
         | 
| 118 101 | 
             
              end
         | 
| 119 102 | 
             
            end
         | 
    
        data/lib/upl/variable.rb
    CHANGED
    
    | @@ -2,10 +2,11 @@ module Upl | |
| 2 2 | 
             
              # Really this is just an empty term.
         | 
| 3 3 | 
             
              class Variable
         | 
| 4 4 | 
             
                def initialize term_t = nil
         | 
| 5 | 
            -
                  @term_t = term_t ||  | 
| 5 | 
            +
                  @term_t = term_t || self.class.to_term
         | 
| 6 6 | 
             
                end
         | 
| 7 7 |  | 
| 8 8 | 
             
                attr_reader :term_t
         | 
| 9 | 
            +
                alias to_term_t term_t
         | 
| 9 10 |  | 
| 10 11 | 
             
                def self.copy term_t
         | 
| 11 12 | 
             
                  inst = new term_t
         | 
| @@ -18,7 +19,7 @@ module Upl | |
| 18 19 |  | 
| 19 20 | 
             
                # bit of a hack to create empty variables for a functor
         | 
| 20 21 | 
             
                def self.to_term
         | 
| 21 | 
            -
                   | 
| 22 | 
            +
                  Extern.PL_new_term_ref
         | 
| 22 23 | 
             
                end
         | 
| 23 24 |  | 
| 24 25 | 
             
                def to_s; _string end
         | 
    
        data/lib/upl/version.rb
    CHANGED
    
    
    
        data/lib/upl.rb
    CHANGED
    
    | @@ -6,17 +6,58 @@ require_relative 'upl/term' | |
| 6 6 | 
             
            require_relative 'upl/variable'
         | 
| 7 7 | 
             
            require_relative 'upl/atom'
         | 
| 8 8 | 
             
            require_relative 'upl/runtime'
         | 
| 9 | 
            +
            require_relative 'upl/dict'
         | 
| 9 10 | 
             
            require_relative 'upl/tree'
         | 
| 10 11 | 
             
            require_relative 'upl/inter'
         | 
| 12 | 
            +
            require_relative 'upl/term_vector'
         | 
| 11 13 |  | 
| 12 14 | 
             
            module Upl
         | 
| 13 | 
            -
              def self.query  | 
| 14 | 
            -
                 | 
| 15 | 
            -
                 | 
| 15 | 
            +
              def self.query string_or_term, &blk
         | 
| 16 | 
            +
                case string_or_term
         | 
| 17 | 
            +
                when Term
         | 
| 18 | 
            +
                  Runtime.query string_or_term
         | 
| 19 | 
            +
                when String
         | 
| 20 | 
            +
                  term, vars = Runtime.term_vars string_or_term
         | 
| 21 | 
            +
                  Runtime.term_vars_query term, vars, &blk
         | 
| 22 | 
            +
                else
         | 
| 23 | 
            +
                  raise "dunno about #{string_or_term.inspect}"
         | 
| 24 | 
            +
                end
         | 
| 16 25 | 
             
              end
         | 
| 17 26 |  | 
| 18 27 | 
             
              def self.consult filename
         | 
| 19 28 | 
             
                p = Pathname filename
         | 
| 20 | 
            -
                Runtime:: | 
| 29 | 
            +
                Runtime::call %Q{["#{p.realpath.to_s}"]}
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              def self.asserta term
         | 
| 33 | 
            +
                Runtime.call Term.functor :asserta, term
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
              def self.assertz term
         | 
| 37 | 
            +
                Runtime.call Term.functor :assertz, term
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              # behaves as if run under once, cos of the way call works
         | 
| 41 | 
            +
              def self.retract term
         | 
| 42 | 
            +
                Runtime.call Term.functor :retract, term
         | 
| 43 | 
            +
              end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              def self.listing
         | 
| 46 | 
            +
                (Upl.query 'with_output_to(string(Buffer),listing)').first[:Buffer]
         | 
| 47 | 
            +
              end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
              # Nicer syntax for Term.functor. Construct a Term from a symbol and args that
         | 
| 50 | 
            +
              # all respond to 'to_term_t'.
         | 
| 51 | 
            +
              #
         | 
| 52 | 
            +
              # In other words:
         | 
| 53 | 
            +
              #
         | 
| 54 | 
            +
              #   Upl.query 'current_prolog_flag(A,B)'
         | 
| 55 | 
            +
              #
         | 
| 56 | 
            +
              # is moreorless the same as
         | 
| 57 | 
            +
              #
         | 
| 58 | 
            +
              #   Upl.query Term :current_prolog_flag, Variable.new, Variable.new
         | 
| 59 | 
            +
              #
         | 
| 60 | 
            +
              def self.Term name, *args
         | 
| 61 | 
            +
                Term.functor name, *args
         | 
| 21 62 | 
             
              end
         | 
| 22 63 | 
             
            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.0. | 
| 4 | 
            +
              version: 0.0.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: 2018-09- | 
| 11 | 
            +
            date: 2018-09-17 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -98,11 +98,13 @@ files: | |
| 98 98 | 
             
            - bin/setup
         | 
| 99 99 | 
             
            - lib/upl.rb
         | 
| 100 100 | 
             
            - lib/upl/atom.rb
         | 
| 101 | 
            +
            - lib/upl/dict.rb
         | 
| 101 102 | 
             
            - lib/upl/extern.rb
         | 
| 102 103 | 
             
            - lib/upl/functor.rb
         | 
| 103 104 | 
             
            - lib/upl/inter.rb
         | 
| 104 105 | 
             
            - lib/upl/runtime.rb
         | 
| 105 106 | 
             
            - lib/upl/term.rb
         | 
| 107 | 
            +
            - lib/upl/term_vector.rb
         | 
| 106 108 | 
             
            - lib/upl/tree.rb
         | 
| 107 109 | 
             
            - lib/upl/variable.rb
         | 
| 108 110 | 
             
            - lib/upl/version.rb
         |