Class: Gullah::Node

Inherits:
Object
  • Object
show all
Defined in:
lib/gullah/node.rb

Overview

a node in an AST

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#attributesObject (readonly) Also known as: atts

A hash of attributes, including indicators of tests that passed or failed. The atts alias of attributes exists for when a more telegraphic coding style is useful.



16
17
18
# File 'lib/gullah/node.rb', line 16

def attributes
  @attributes
end

#childrenObject (readonly)

The children of this node, if any, as an array.



20
21
22
# File 'lib/gullah/node.rb', line 20

def children
  @children
end

#parentObject (readonly)

The parent node of this node, if any.



8
9
10
# File 'lib/gullah/node.rb', line 8

def parent
  @parent
end

#summaryObject (readonly)

A concise stringification of the structure of this node’s subtree.



24
25
26
# File 'lib/gullah/node.rb', line 24

def summary
  @summary
end

Instance Method Details

#ancestorsObject

Returns an Enumerable enumerating the nodes immediately above this node in the tree: its parent, its parent’s parent, etc.



254
255
256
# File 'lib/gullah/node.rb', line 254

def ancestors
  _ancestors self
end

#boundary?Boolean

Is this node one that cannot be the child of another node?

Returns:

  • (Boolean)


88
89
90
# File 'lib/gullah/node.rb', line 88

def boundary?
  false
end

#contains?(offset) ⇒ Boolean

Does this node contain the given text offset?

Returns:

  • (Boolean)


208
209
210
# File 'lib/gullah/node.rb', line 208

def contains?(offset)
  start <= offset && offset < self.end
end

#dbg(so: false) ⇒ Object

Produces a simplified representation of the node to facilitate debugging. The so named parameter, if true, will cause the representation to drop ignored nodes. The name “so” stands for “significant only”.

> pp root.dbg

{:name=>:S,
 :pos=>{:start=>0, :end=>11, :depth=>0},
 :children=>
  [{:name=>:NP,
    :pos=>{:start=>0, :end=>7, :depth=>1},
    :children=>
     [{:name=>:D, :pos=>{:start=>0, :end=>3, :depth=>2}, :text=>"the"},
      {:name=>:_ws,
       :pos=>{:start=>3, :end=>4, :depth=>2},
       :ignorable=>true,
       :text=>" "},
      {:name=>:N, :pos=>{:start=>4, :end=>7, :depth=>2}, :text=>"cat"}]},
   {:name=>:_ws,
    :pos=>{:start=>7, :end=>8, :depth=>1},
    :ignorable=>true,
    :text=>" "},
   {:name=>:VP,
    :pos=>{:start=>8, :end=>11, :depth=>1},
    :children=>
     [{:name=>:V, :pos=>{:start=>8, :end=>11, :depth=>2}, :text=>"sat"}]}]}

> pp root.dbg so: true

{:name=>:S,
 :pos=>{:start=>0, :end=>11, :depth=>0},
 :children=>
  [{:name=>:NP,
    :pos=>{:start=>0, :end=>7, :depth=>1},
    :children=>
     [{:name=>:D, :pos=>{:start=>0, :end=>3, :depth=>2}, :text=>"the"},
      {:name=>:_ws, :pos=>{:start=>3, :end=>4, :depth=>2}, :text=>" "},
      {:name=>:N, :pos=>{:start=>4, :end=>7, :depth=>2}, :text=>"cat"}]},
   {:name=>:_ws, :pos=>{:start=>7, :end=>8, :depth=>1}, :text=>" "},
   {:name=>:VP,
    :pos=>{:start=>8, :end=>11, :depth=>1},
    :children=>
     [{:name=>:V, :pos=>{:start=>8, :end=>11, :depth=>2}, :text=>"sat"}]}]}


399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
# File 'lib/gullah/node.rb', line 399

def dbg(so: false)
  {
    name: name,
    pos: {
      start: start,
      end: self.end,
      depth: depth
    }
  }.tap do |simpleton|
    simpleton[:failed] = true if @failed_test
    simpleton[:attributes] = deep_clone attributes if attributes.any?
    if leaf?
      simpleton[:trash] = true if trash?
      simpleton[:ignorable] = true unless so || significant?
      simpleton[:text] = text
    else
      simpleton[:children] = children.map { |c| c.dbg so: so }
    end
  end
end

#depthObject

Distance of the node from the root node of the parse tree. During parsing, while nodes are being added, this distance may change, unlike the height.

The root node has a depth of 0. It’s children have a depth of 1. Their children have a depth of 2. And so forth.



187
188
189
# File 'lib/gullah/node.rb', line 187

def depth
  parent ? 1 + parent.depth : 0
end

#descendantsObject

Returns an Enumerable over the descendants of this node: its children, its children’s children, etc. This enumeration is depth-first.



261
262
263
# File 'lib/gullah/node.rb', line 261

def descendants
  _descendants self
end

#endObject

The node’s end text offset. For a non-terminal node, this will be the same as the end of the last leaf node of its subtree.



176
177
178
# File 'lib/gullah/node.rb', line 176

def end
  @end ||= @children[-1].end
end

#error?Boolean

Does this node have some failed test?

Returns:

  • (Boolean)


112
113
114
# File 'lib/gullah/node.rb', line 112

def error?
  @failed_test
end

#failed?Boolean

Does this node have some failed test or does it represent characters no leaf rule mached?

Returns:

  • (Boolean)


100
101
102
# File 'lib/gullah/node.rb', line 100

def failed?
  trash? || error?
end

#find(pos) ⇒ Object

Finds the node at the given position within this node’s subtree.



214
215
216
217
218
219
220
221
222
223
# File 'lib/gullah/node.rb', line 214

def find(pos)
  offset = pos.first
  return nil unless contains?(offset)

  return self if pos == position

  if (child = children&.find { |c| c.contains? offset })
    child.find(pos)
  end
end

#first_child?Boolean

Is this node the first of its parent’s children?

Returns:

  • (Boolean)


304
305
306
# File 'lib/gullah/node.rb', line 304

def first_child?
  sibling_index.zero?
end

#full_textObject

A reference to the full text the node’s text is embedded in.



150
151
152
# File 'lib/gullah/node.rb', line 150

def full_text
  @text
end

#heightObject

The distance of a node from the first leaf node in its subtree. If the node is the immediate parent of this leaf, its distance will be one. Leaves have a height of zero.



195
196
197
# File 'lib/gullah/node.rb', line 195

def height
  @height ||= @leaf ? 0 : 1 + children[0].height
end

#ignorable?Boolean

Was this node created by an ignore rule?

Returns:

  • (Boolean)


125
126
127
# File 'lib/gullah/node.rb', line 125

def ignorable?
  @leaf && rule.ignorable
end

#last_child?Boolean

Is this node the last of its parent’s children?

Returns:

  • (Boolean)


298
299
300
# File 'lib/gullah/node.rb', line 298

def last_child?
  parent && sibling_index == parent.children.length - 1
end

#laterObject

The collection of nodes in the subtree containing this node whose start offset is at or after its end offset.



339
340
341
# File 'lib/gullah/node.rb', line 339

def later
  root.descendants.select { |n| n.start >= self.end }
end

#later_siblingObject

The immediately following sibling to this node.



318
319
320
# File 'lib/gullah/node.rb', line 318

def later_sibling
  parent && parent.children[sibling_index + 1]
end

#later_siblingsObject

Returns the children of this node’s parent that follow it.



292
293
294
# File 'lib/gullah/node.rb', line 292

def later_siblings
  parent && siblings[(sibling_index + 1)..]
end

#leaf?Boolean

Is this a leaf node?

Returns:

  • (Boolean)


94
95
96
# File 'lib/gullah/node.rb', line 94

def leaf?
  @leaf
end

#leavesObject

The leaves of this node’s subtree. If the node is a leaf, this returns a single-member array containing the node itself.



325
326
327
# File 'lib/gullah/node.rb', line 325

def leaves
  @leaf ? [self] : descendants.select(&:leaf?)
end

#nameObject

The name of the rule that created this node.



76
77
78
# File 'lib/gullah/node.rb', line 76

def name
  rule.name
end

#nonterminal?Boolean

Is this a node that has other nodes as children?

Returns:

  • (Boolean)


137
138
139
# File 'lib/gullah/node.rb', line 137

def nonterminal?
  !@leaf
end

#pending_tests?Boolean

Does this node’s subtree contain unsatisfied syntactic requirements? These are tests that depend on nodes not in the node’s own subtree.

Returns:

  • (Boolean)


119
120
121
# File 'lib/gullah/node.rb', line 119

def pending_tests?
  !!attributes[:pending]
end

#positionObject

A pair consisting of the nodes start and height. This will be a unique identifier for the node in its parse and is constant at all stages of parsing.



202
203
204
# File 'lib/gullah/node.rb', line 202

def position
  @position ||= [start, height]
end

#priorObject

The collection of nodes in the subtree containing this node that do not contain the node and whose start offset precedes its start offset.



332
333
334
# File 'lib/gullah/node.rb', line 332

def prior
  root.descendants.reject { |n| n.contains? start }.select { |n| n.start < start }
end

#prior_siblingObject

The immediately prior sibling to this node.



310
311
312
313
314
# File 'lib/gullah/node.rb', line 310

def prior_sibling
  if parent
    first_child? ? nil : parent.children[sibling_index - 1]
  end
end

#prior_siblingsObject

Returns the children of this node’s parent that precede it.



286
287
288
# File 'lib/gullah/node.rb', line 286

def prior_siblings
  parent && siblings[0...sibling_index]
end

#rootObject

The root of this node’s current parse tree.

Note, if you use this in a node test the root will always be the same as the node itself because these tests are run when the node is being added to the tree. If you use it in structure tests, it will be some ancestor of the node but not necessarily the final root. The current root is always the first argument to structure tests. Using this argument is more efficient than using the root method. Really, the root method is only useful in completed parses.



241
242
243
# File 'lib/gullah/node.rb', line 241

def root
  parent ? parent.root : self
end

#root?Boolean

Does this node have any parent? If not, it is a root.

Returns:

  • (Boolean)


247
248
249
# File 'lib/gullah/node.rb', line 247

def root?
  parent.nil?
end

#sibling_indexObject

The index of this node among its parent’s children.



280
281
282
# File 'lib/gullah/node.rb', line 280

def sibling_index
  @sibling_index ||= parent.children.index self if parent
end

#siblingsObject

Returns the children of this node’s parent’s children minus this node itself.



274
275
276
# File 'lib/gullah/node.rb', line 274

def siblings
  parent&.children&.reject { |n| n == self }
end

#significant?Boolean

Was this node created by something other than an ignore rule?

Returns:

  • (Boolean)


131
132
133
# File 'lib/gullah/node.rb', line 131

def significant?
  !ignorable?
end

#sizeObject

The number of nodes in this node’s subtree. Leaves always have a size of 1.



227
228
229
# File 'lib/gullah/node.rb', line 227

def size
  @size ||= @leaf ? 1 : @children.map(&:size).sum + 1
end

#startObject

The node’s start text offset. For a non-terminal node, this will be the same as the start of the first leaf node of its subtree.



169
170
171
# File 'lib/gullah/node.rb', line 169

def start
  @start ||= @children[0].start
end

#subtreeObject

Returns an Enumerable over this node and its descendants. The node itself is the first node returned.



268
269
270
# File 'lib/gullah/node.rb', line 268

def subtree
  _descendants nil
end

#textObject

The portion of the original text covered by this node. This is in effect the text of the leaves of its subtree.



144
145
146
# File 'lib/gullah/node.rb', line 144

def text
  @text[start...self.end]
end

#text_afterObject

The text following this node’s text. Useful for lookaround tests and preconditions.



162
163
164
# File 'lib/gullah/node.rb', line 162

def text_after
  @text[self.end..]
end

#text_beforeObject

The text preceding this node’s text. Useful for lookaround tests and preconditions.



156
157
158
# File 'lib/gullah/node.rb', line 156

def text_before
  @text[0...start]
end

#trash?Boolean

Does this node represent a character sequence no leaf rule matched?

Returns:

  • (Boolean)


82
83
84
# File 'lib/gullah/node.rb', line 82

def trash?
  false
end