Class: Upl::Tree

Inherits:
Object show all
Defined in:
lib/upl/tree.rb

Overview

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

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(term) ⇒ Tree

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



11
12
13
# File 'lib/upl/tree.rb', line 11

def initialize( term )
  init term
end

Instance Attribute Details

#argsObject (readonly)

Returns the value of attribute args.



27
28
29
# File 'lib/upl/tree.rb', line 27

def args
  @args
end

#atomObject (readonly)

Returns the value of attribute atom.



27
28
29
# File 'lib/upl/tree.rb', line 27

def atom
  @atom
end

Class Method Details

.of_term(term_t) ⇒ Object



29
30
31
# File 'lib/upl/tree.rb', line 29

def self.of_term term_t
  term_to_ruby term_t
end

.term_to_ruby(term_t) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# 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_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

Instance Method Details

#arityObject



92
# File 'lib/upl/tree.rb', line 92

def arity; args.size end

#deconstructObject

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



96
97
98
# File 'lib/upl/tree.rb', line 96

def deconstruct
  [atom, *args]
end

#init(term) ⇒ Object



15
16
17
18
19
20
21
22
23
24
25
# 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

#inspectObject



100
101
102
103
104
# File 'lib/upl/tree.rb', line 100

def inspect
  pp = PP.new
  pretty_print pp
  pp.output
end

#pretty_print(pp) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/upl/tree.rb', line 106

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_rubyObject



33
# File 'lib/upl/tree.rb', line 33

def to_ruby; self end