Class: Spectre::Node

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

Overview

A Node in the parse tree. Nodes keep the parsing tree consistent by applying some control mechanisms to the parsing process and taking away responsibility from the Parsers. They keep the Closures and parent-child relations between the Parsers as well as the symbol-identified Parsers of the Grammars.

Direct Known Subclasses

Directive, Grammar

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parser, left = nil, right = nil) ⇒ Node

Initializes the Node’s parser property and registers the Node with the given Parser, as well as the left and right child.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/spectre/base/node.rb', line 77

def initialize parser, left = nil, right = nil
    if left
        @left = left.to_p
        @left.parent = self
    end

    if right
        @right = right.to_p
        @right.parent = self
    end

    @parser, @symbols, @actions = parser, {}, []
    parser.node = self
end

Instance Attribute Details

#actionsObject

The semantic actions that are associated with this Node - Array.



33
34
35
# File 'lib/spectre/base/node.rb', line 33

def actions
  @actions
end

#backtraceObject

The location the InputIterator was at, before the Parser started matching.



37
38
39
# File 'lib/spectre/base/node.rb', line 37

def backtrace
  @backtrace
end

#leftObject

The left child Node of this Node or nil if none.



41
42
43
# File 'lib/spectre/base/node.rb', line 41

def left
  @left
end

#parentObject

The parent Node of this Node.



49
50
51
# File 'lib/spectre/base/node.rb', line 49

def parent
  @parent
end

#parserObject

The Parser that resides in this Node.



57
58
59
# File 'lib/spectre/base/node.rb', line 57

def parser
  @parser
end

#policyObject

Recursively ascends to the top of the parsing chain and returns the first policy it finds or the default policy.



71
72
73
# File 'lib/spectre/base/node.rb', line 71

def policy
  @policy
end

#rightObject

The right child Node of this Node or nil if none.



45
46
47
# File 'lib/spectre/base/node.rb', line 45

def right
  @right
end

#symbolsObject

The symbol-identified Parsers for this Node - Hash.



53
54
55
# File 'lib/spectre/base/node.rb', line 53

def symbols
  @symbols
end

Instance Method Details

#%(right) ⇒ Object

See Operators::List.



348
349
350
# File 'lib/spectre/base/node.rb', line 348

def % right
    Node.new Operators::List.new, self, right.to_p
end

#&(right) ⇒ Object

See Operators::Intersection.



327
328
329
# File 'lib/spectre/base/node.rb', line 327

def & right
    Node.new Operators::Intersection.new, self, right.to_p
end

#*Object

See Operators::KleeneStar.



362
363
364
# File 'lib/spectre/base/node.rb', line 362

def *
    Node.new Operators::KleeneStar.new, self
end

#**(right) ⇒ Object

See Operators::SequentialOr.



355
356
357
# File 'lib/spectre/base/node.rb', line 355

def ** right
    Node.new Operators::SequentialOr.new, self, right.to_p
end

#+Object

See Operators::Positive.



369
370
371
# File 'lib/spectre/base/node.rb', line 369

def +
    Node.new Operators::Positive.new, self
end

#-(right) ⇒ Object

See Operators::Difference.



334
335
336
# File 'lib/spectre/base/node.rb', line 334

def - right
    Node.new Operators::Difference.new, self, right.to_p
end

#-@Object

See Operators::Optional.



376
377
378
# File 'lib/spectre/base/node.rb', line 376

def -@
    Node.new Operators::Optional.new, self
end

#>>(right) ⇒ Object

See Operators::Sequence.



313
314
315
# File 'lib/spectre/base/node.rb', line 313

def >> right
    Node.new Operators::Sequence.new, self, right.to_p
end

#[](action) ⇒ Object

Adds a semantic action to the Node. A semantic action is nothing but an object that implements the call method (most simple example being a lambda block), which will accept two parameters: The match made by the Parser and the Closure associated with the Parser.



300
301
302
303
304
305
306
307
308
# File 'lib/spectre/base/node.rb', line 300

def [] action
    @actions ||= []

    if action.is_a? Symbol then @actions << ClosureAction.new(action)
    else @actions << action
    end
    
    self
end

#^(right) ⇒ Object

See Operators::Xor.



341
342
343
# File 'lib/spectre/base/node.rb', line 341

def ^ right
    Node.new Operators::Difference.new, self, right.to_p
end

#backtrack(iter) ⇒ Object

If parsing fails, the parent of the Node will instruct it to backtrack. I.e. it will return the InputIterator to the position before the failed parsing attempt. If no backtrace has been saved, nothing is done. Returns the modified InputIterator.



203
204
205
# File 'lib/spectre/base/node.rb', line 203

def backtrack iter
    iter.to @backtrace.pos if @backtrace
end

#chainObject

Returns a multy-line String representing the parse-chain the current Parser is in.



278
279
280
281
# File 'lib/spectre/base/node.rb', line 278

def chain
    ( @parent ? @parent.inspect + "\n  " : '' ) + 
    self.inspect
end

#closureObject

Recursively ascends to the top of the parsing chain and returns the first closure it finds or nil if none.



151
152
153
# File 'lib/spectre/base/node.rb', line 151

def closure
    @closure || ( @parent ? @parent.closure : nil )
end

#closure=(clos) ⇒ Object

Sets the closure and registers the Node and it’s Parser with it.



166
167
168
169
170
# File 'lib/spectre/base/node.rb', line 166

def closure= clos
    @closure = clos
    clos.parser = @parser
    clos.node = self
end

#closure?Boolean

Returns true if this Node has a closure set, i.e. unlike #closure it will not query the parent for it’s closure.

Returns:

  • (Boolean)


159
160
161
# File 'lib/spectre/base/node.rb', line 159

def closure?
    @closure ? true : false
end

#find(sym) ⇒ Object

Tries to find the Parser referenced by the symbol sym by walking up the parse tree. If a Parser is found, it is #dupped and returned, nil otherwise.



288
289
290
291
292
# File 'lib/spectre/base/node.rb', line 288

def find sym
    ret = @symbols[sym] || ( @parent ? @parent.find(sym) : nil )
    ret = ret.dup if ret
    ret
end

#initialize_copy(other) ⇒ Object

Initializes a new Node by dupping the other Node’s Parser, as well as its Closure and actions and the whole parse tree under it. The backtrace will not be copied.



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/spectre/base/node.rb', line 97

def initialize_copy other
    if other.parser
        @parser = other.parser.dup
        @parser.node = self
    end
    if other.closure?
        @closure = other.closure.dup
        @closure.node = self
        @closure.parser = @parser
    end
    if other.symbols
        @symbols = other.symbols.dup
    end
    if other.actions
        @actions = other.actions.dup
    end
    if other.left
        @left = other.left.dup
        @left.parent = self
    end
    if other.right
        @right = other.right.dup
        @right.parent = self
    end
end

#inspectObject



387
388
389
# File 'lib/spectre/base/node.rb', line 387

def inspect
    @parser.inspect
end

#leaf?Boolean

Returns true, if this Node is a leaf Node, else false.

Returns:

  • (Boolean)


143
144
145
# File 'lib/spectre/base/node.rb', line 143

def leaf?
    @left.nil? and @right.nil?
end

#parse(iter, pre_skip = true) ⇒ Object

Saves the backtrace and calls #scan on the Parser to do the actual parsing of the InputIterator iter. This method will backtrack automatically when the result of the Parser is nil.

If pre_skip is false, InputIterator#skip! will not be called before the Parser invocation. Please note: pre_skip being true does not mean that pre-skipping is done. Other factors may prohibit that, e.g. a LexemeDirective.



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/spectre/base/node.rb', line 217

def parse iter, pre_skip = true
    @backtrace = iter.dup

    iter.skip! if @parser.pre_skip? and pre_skip
    ret = @parser.scan iter
    backtrack iter unless ret
    
    pol = policy

    ##TODO: simplify this?
    # test on min and or max
    if ret and ret.value
        # min
        if pol[:min]
            ret = nil if pol[:min] > ret.value
        end

        # max if not reset
        if ret and pol[:max]
            ret = nil if pol[:max] < ret.value
        end
    # reset if value == nil and min or max specified
    elsif ret
        ret = nil if pol[:min] or pol[:max]
    end

    @actions ||= []
    @actions.each { |action|
        action.call ret, self.closure
    } if ret and pol[:actions]

    ret
end

#replace_with(rep) ⇒ Object

Replaces this Node with rep and returns the modified replacement Node. If this is called during parsing process, the calling function should #backtrack and call #parse for the replacement Node.



263
264
265
266
267
268
269
270
271
272
273
# File 'lib/spectre/base/node.rb', line 263

def replace_with rep
    rep.parent = @parent

    if @parent
        if self == @parent.left then @parent.left = rep
        else @parent.right = rep
        end
    end

    rep
end

#root?Boolean

Returns true, if this Node is the root Node, else false.

Returns:

  • (Boolean)


136
137
138
# File 'lib/spectre/base/node.rb', line 136

def root?
    @parent.nil?
end

#shallow_copy(other) ⇒ Object

Unlike #initialize_copy this method does not dup the elments contained in the other Node, but rather only copies references. The backtrace will not be copied.



128
129
130
131
# File 'lib/spectre/base/node.rb', line 128

def shallow_copy other
    @parser, @closure, @symbols, @actions, @left, @right =
        other.parser, other.closure, other.symbols, other.actions, other.left, other.right
end

#to_pObject

Converts this Node to a Node, i.e. returns self.



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

def to_p
    self
end

#|(right) ⇒ Object

See Operators::Union.



320
321
322
# File 'lib/spectre/base/node.rb', line 320

def | right
    Node.new Operators::Union.new, self, right.to_p
end

#~@Object

See Operators::Negation.



383
384
385
# File 'lib/spectre/base/node.rb', line 383

def ~@
    Node.new Operators::Negation.new, self
end