Class: Upl::Term

Inherits:
Object show all
Includes:
Enumerable
Defined in:
lib/upl/term.rb

Overview

This thing’s job is interacting with term_t, whereas Tree’s job is being a ruby copy of a term-tree.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(term_or_string) ⇒ Term

Returns a new instance of Term.



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/upl/term.rb', line 5

def initialize term_or_string
  case term_or_string
  when String
    # sadly, this doesn't keep variable names
    rv = Extern.PL_put_term_from_chars \
      (@term_t = Extern.PL_new_term_ref),
      Extern::Convert::REP_UTF8,
      term_or_string.bytesize,
      Fiddle::Pointer[term_or_string]

    case rv
    when 1; true # all ok
    when 0
      raise "failure parsing term #{term_or_string}, #{Tree.of_term(@term_t).inspect}"
    else
      raise "unknown api return value #{rv}"
    end

  when Fiddle::Pointer
    # assume this is a pointer to a term. Unsafe, but there's no choice really
    @term_t = term_or_string

  else
    raise "can't handle #{term_or_string}"
  end
end

Instance Attribute Details

#term_tObject (readonly) Also known as: to_term_t

Returns the value of attribute term_t.



32
33
34
# File 'lib/upl/term.rb', line 32

def term_t
  @term_t
end

Class Method Details

.of_atom(atom) ⇒ Object



35
36
37
38
39
40
# File 'lib/upl/term.rb', line 35

def self.of_atom atom
  term_t = Extern.PL_new_term_ref
  rv = Extern.PL_put_atom term_t, atom.to_atom
  rv == 1 or raise "can't set term to atom #{atom}"
  term_t
end

.predicate(name, *args) ⇒ Object

returns a term

args are things that can be converted to term_t pointers using to_term_t method TODO misnamed. functor means pred_name/n and this is actually :pred_name, arg1, arg2…



47
48
49
50
51
52
53
54
55
56
# File 'lib/upl/term.rb', line 47

def self.predicate name, *args
  # TODO maybe use a frame or something because this allocates quite a few sub-terms
  rv = Extern.PL_cons_functor_v \
    (term_t = Extern.PL_new_term_ref),
    Extern.PL_new_functor(name.to_sym.to_atom, args.size),
    TermVector[*args].terms
  rv == 1 or raise "can't populate functor #{name}"

  new term_t
end

Instance Method Details

#<=>(rhs) ⇒ Object



77
78
79
# File 'lib/upl/term.rb', line 77

def <=> rhs
  [@atom, @arity] <=> [rhs.atom, rhs.arity]
end

#==(rhs) ⇒ Object



73
74
75
# File 'lib/upl/term.rb', line 73

def == rhs
  @atom == rhs.atom && @arity == rhs.arity && args == rhs.args
end

#[](idx) ⇒ Object



125
126
127
128
129
130
# File 'lib/upl/term.rb', line 125

def [](idx)
  # remember args for terms are 1-based
  rv = Extern::PL_get_arg idx+1, term_t, (arg = Extern.PL_new_term_ref)
  rv == 1 or raise "can't access term at #{idx}"
  Term.new arg
end

#[]=(idx, val_term_t) ⇒ Object

set term_t = val_term_t idx is zero-based, unlike the prolog calls

Raises:

  • (IndexError)


134
135
136
137
138
# File 'lib/upl/term.rb', line 134

def []=( idx, val_term_t)
  raise IndexError, "max index is #{arity-1}" if idx >= arity
  rv = Extern.PL_unify_arg idx+1, term_t, val_term_t
  rv == 1 or raise "can't set index #{idx}"
end

#arityObject



88
89
90
91
92
93
# File 'lib/upl/term.rb', line 88

def arity
  @arity or begin
    populate
    @arity
  end
end

#atomObject



81
82
83
84
85
86
# File 'lib/upl/term.rb', line 81

def atom
  @atom or begin
    populate
    @atom
  end
end

#deconstructObject



121
122
123
# File 'lib/upl/term.rb', line 121

def deconstruct
  map{|t| Term.new t}
end

#eachObject



106
107
108
109
110
111
112
113
114
# File 'lib/upl/term.rb', line 106

def each
  return enum_for :args unless block_given?

  (1..arity).each do |idx|
    rv = Extern::PL_get_arg idx, term_t, (subterm = Extern.PL_new_term_ref)
    rv == 1 or raise "#{rv}: can't convert #{i} arg of #{atom}"
    yield subterm
  end
end

#firstObject



118
# File 'lib/upl/term.rb', line 118

def first; self[0] end

#lastObject



119
# File 'lib/upl/term.rb', line 119

def last; self[arity-1] end

#populateObject



58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/upl/term.rb', line 58

def populate
  rv = Extern::PL_get_name_arity \
    term_t,
    (atom_ptr = Fiddle::Pointer[0].ref),
    (int_ptr = Fiddle::Pointer[0].ref)

  # This happens when the term_t is not a PL_TERM (ie a compound)
  rv == 1 or raise "can't populate term"

  @arity = int_ptr.ptr.to_i
  @atom = Atom.new atom_ptr.ptr

  self
end

#pretty_print(pp) ⇒ Object



140
141
142
143
144
145
# File 'lib/upl/term.rb', line 140

def pretty_print(pp)
  # to_ruby.pretty_print pp
  pp.text atom.to_s
  pp.text ?/
  pp.text arity.to_s
end

#to_functorObject



95
96
97
# File 'lib/upl/term.rb', line 95

def to_functor
  Extern::PL_new_functor atom.atom_t, arity
end

#to_predicateObject



99
100
101
# File 'lib/upl/term.rb', line 99

def to_predicate
  Extern::PL_pred to_functor, Fiddle::NULL
end

#treeObject Also known as: to_ruby



103
# File 'lib/upl/term.rb', line 103

def tree; @tree || (Tree.of_term term_t) end