class Upl::Tree

So Prolog terms are a rose tree. Who woulda thunkit?

Convert a term into a tree of ruby objects. This is necessary because queries give back their results as terms which are invalidated as soon as the next set of results is calculated. So we need to turn those terms into a ruby representation and keep them around. TODO rename to Ast

Attributes

args[R]
atom[R]

Public Class Methods

new( term ) click to toggle source

term is either a Term instance, or a Fiddle::Pointer to a term_t

# File lib/upl/tree.rb, line 11
def initialize( term )
  init term
end
of_term(term_t) click to toggle source
# File lib/upl/tree.rb, line 29
def self.of_term term_t
  term_to_ruby term_t
end
term_to_ruby(term_t) click to toggle source
# File lib/upl/tree.rb, line 35
def self.term_to_ruby term_t
  case term_t.term_type
  when Extern::PL_VARIABLE
    Variable.copy term_t

  when Extern::PL_ATOM
    Atom.of_term(term_t).to_ruby

  # I think integers > 63 bits can be fetched with PL_get_mpz
  # Other than PL_INTEGER, most of these seem to be unused?
  when Extern::PL_INTEGER, Extern::PL_LONG, Extern::PL_INT, Extern::PL_INT64, Extern::PL_SHORT
    rv = Extern.PL_get_int64 term_t, (int_ptr = Fiddle::Pointer[0].ref)
    rv == 1 or raise "Can't convert to int64. Maybe too large."
    int_ptr.ptr.to_i

  when Extern::PL_FLOAT
    rv = Extern.PL_get_float term_t, (double_ptr = Fiddle::Pointer[0].ref)
    rv == 1 or raise "Can't convert to double. Maybe too large."
    bytes = double_ptr[0,8]
    bytes.unpack('D').first

  when Extern::PL_RATIONAL
    raise NotImplemented, 'convert to rational'

  when Extern::PL_STRING
    # TODO could possibly get away with BUF_DISCARDABLE here?

    flag_mod = Upl::Extern::Convert
    rv = Extern.PL_get_nchars \
      term_t,
      (len_ptr = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP, Extern::ruby_free_fn)),
      (str_ptr = Fiddle::Pointer.malloc(Fiddle::SIZEOF_VOIDP, Extern::ruby_free_fn)),
      flag_mod::CVT_STRING | flag_mod::BUF_MALLOC | flag_mod::REP_UTF8

    # note that length here is number of octets, not number of utf8 chars
    string = String.new (str_ptr.ptr.to_s len_ptr.ptr.to_i), encoding: Encoding::UTF_8
    # eventually free the malloc'd memory for the string
    str_ptr.ptr.free = Extern::swipl_free_fn
    string

  when Extern::PL_NIL
    # TODO maybe this should be [] - see what happens when term_vars has no vars
    # although nil.to_a == []
    nil

  when Extern::PL_TERM
    Tree.new term_t

  when Extern::PL_LIST_PAIR
    Inter.each_of_list(term_t).map{|term_t| Term.new(term_t).to_ruby}

  when Extern::PL_DICT
    Dict.of_term term_t

  else
    :"#{term_t.type_string} NotImplemented"

  end
end

Public Instance Methods

arity() click to toggle source
# File lib/upl/tree.rb, line 95
def arity; args.size end
deconstruct() click to toggle source

for 2.7 case … in pattern matching for case term; in functor,arg1,arg; arg1

# File lib/upl/tree.rb, line 99
def deconstruct
  [atom, *args]
end
init(term) click to toggle source
# File lib/upl/tree.rb, line 15
def init term
  case term
  when Term
    @atom = term.atom
    @args = term.map do |arg|
      self.class.term_to_ruby arg
    end
  when Fiddle::Pointer
    init Term.new term
  end
end
inspect() click to toggle source
# File lib/upl/tree.rb, line 103
def inspect
  pp = PP.new
  pretty_print pp
  pp.output
end
pretty_print(pp) click to toggle source
# File lib/upl/tree.rb, line 109
def pretty_print(pp)
  unless atom.to_sym == :','
    pp.text atom.to_s
    if arity > 0
      pp.text ?/
      pp.text arity.to_s
    end
  end

  if arity > 0
    pp.group 1, ?(, ?) do
      args.each_with_index do |ruby_term,i|
        ruby_term.pretty_print pp
        pp.text ?, if i < arity - 1
      end
    end
  end
end
to_ruby() click to toggle source
# File lib/upl/tree.rb, line 33
def to_ruby; self end