xref: /aosp_15_r20/external/antlr/runtime/Ruby/lib/antlr3/tree.rb (revision 16467b971bd3e2009fad32dd79016f2c7e421deb)
1*16467b97STreehugger Robot#!/usr/bin/ruby
2*16467b97STreehugger Robot# encoding: utf-8
3*16467b97STreehugger Robot
4*16467b97STreehugger Robot=begin LICENSE
5*16467b97STreehugger Robot
6*16467b97STreehugger Robot[The "BSD licence"]
7*16467b97STreehugger RobotCopyright (c) 2009-2010 Kyle Yetter
8*16467b97STreehugger RobotAll rights reserved.
9*16467b97STreehugger Robot
10*16467b97STreehugger RobotRedistribution and use in source and binary forms, with or without
11*16467b97STreehugger Robotmodification, are permitted provided that the following conditions
12*16467b97STreehugger Robotare met:
13*16467b97STreehugger Robot
14*16467b97STreehugger Robot 1. Redistributions of source code must retain the above copyright
15*16467b97STreehugger Robot    notice, this list of conditions and the following disclaimer.
16*16467b97STreehugger Robot 2. Redistributions in binary form must reproduce the above copyright
17*16467b97STreehugger Robot    notice, this list of conditions and the following disclaimer in the
18*16467b97STreehugger Robot    documentation and/or other materials provided with the distribution.
19*16467b97STreehugger Robot 3. The name of the author may not be used to endorse or promote products
20*16467b97STreehugger Robot    derived from this software without specific prior written permission.
21*16467b97STreehugger Robot
22*16467b97STreehugger RobotTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23*16467b97STreehugger RobotIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24*16467b97STreehugger RobotOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25*16467b97STreehugger RobotIN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26*16467b97STreehugger RobotINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27*16467b97STreehugger RobotNOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28*16467b97STreehugger RobotDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29*16467b97STreehugger RobotTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30*16467b97STreehugger Robot(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31*16467b97STreehugger RobotTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32*16467b97STreehugger Robot
33*16467b97STreehugger Robot=end
34*16467b97STreehugger Robot
35*16467b97STreehugger Robotrequire 'antlr3'
36*16467b97STreehugger Robot
37*16467b97STreehugger Robotmodule ANTLR3
38*16467b97STreehugger Robot
39*16467b97STreehugger Robot=begin rdoc ANTLR3::AST
40*16467b97STreehugger Robot
41*16467b97STreehugger RobotName space containing all of the entities pertaining to tree construction and
42*16467b97STreehugger Robottree parsing.
43*16467b97STreehugger Robot
44*16467b97STreehugger Robot=end
45*16467b97STreehugger Robot
46*16467b97STreehugger Robotmodule AST
47*16467b97STreehugger Robot
48*16467b97STreehugger Robotautoload :Wizard, 'antlr3/tree/wizard'
49*16467b97STreehugger Robotautoload :Visitor, 'antlr3/tree/visitor'
50*16467b97STreehugger Robot
51*16467b97STreehugger Robot####################################################################################################
52*16467b97STreehugger Robot############################################ Tree Parser ###########################################
53*16467b97STreehugger Robot####################################################################################################
54*16467b97STreehugger Robot
55*16467b97STreehugger Robot=begin rdoc ANTLR3::AST::TreeParser
56*16467b97STreehugger Robot
57*16467b97STreehugger Robot= TreeParser
58*16467b97STreehugger Robot
59*16467b97STreehugger RobotTreeParser is the default base class of ANTLR-generated tree parsers. The class
60*16467b97STreehugger Robottailors the functionality provided by Recognizer to the task of tree-pattern
61*16467b97STreehugger Robotrecognition.
62*16467b97STreehugger Robot
63*16467b97STreehugger Robot== About Tree Parsers
64*16467b97STreehugger Robot
65*16467b97STreehugger RobotANTLR generates three basic types of recognizers:
66*16467b97STreehugger Robot* lexers
67*16467b97STreehugger Robot* parsers
68*16467b97STreehugger Robot* tree parsers
69*16467b97STreehugger Robot
70*16467b97STreehugger RobotFurthermore, it is capable of generating several different flavors of parser,
71*16467b97STreehugger Robotincluding parsers that take token input and use it to build Abstract Syntax
72*16467b97STreehugger RobotTrees (ASTs), tree structures that reflect the high-level syntactic and semantic
73*16467b97STreehugger Robotstructures defined by the language.
74*16467b97STreehugger Robot
75*16467b97STreehugger RobotYou can take the information encapsulated by the AST and process it directly in
76*16467b97STreehugger Robota program. However, ANTLR also provides a means to create a recognizer which is
77*16467b97STreehugger Robotcapable of walking through the AST, verifying its structure and performing
78*16467b97STreehugger Robotcustom actions along the way -- tree parsers.
79*16467b97STreehugger Robot
80*16467b97STreehugger RobotTree parsers are created from tree grammars. ANTLR-generated tree parsers
81*16467b97STreehugger Robotclosely mirror the general structure of regular parsers and lexers.
82*16467b97STreehugger Robot
83*16467b97STreehugger RobotFor more in-depth coverage of the topic, check out the ANTLR documentation
84*16467b97STreehugger Robot(http://www.antlr.org).
85*16467b97STreehugger Robot
86*16467b97STreehugger Robot== The Tree Parser API
87*16467b97STreehugger Robot
88*16467b97STreehugger RobotLike Parser, the class does not stray too far from the Recognizer API.
89*16467b97STreehugger RobotMainly, it customizes a few methods specifically to deal with tree nodes
90*16467b97STreehugger Robot(instead of basic tokens), and adds some helper methods for working with trees.
91*16467b97STreehugger Robot
92*16467b97STreehugger RobotLike all ANTLR recognizers, tree parsers contained a shared state structure and
93*16467b97STreehugger Robotan input stream, which should be a TreeNodeStream. ANTLR intends to keep its
94*16467b97STreehugger Robottree features flexible and customizable, and thus it does not make any
95*16467b97STreehugger Robotassumptions about the class of the actual nodes it processes. One consequence of
96*16467b97STreehugger Robotthis flexibility is that tree parsers also require an extra tree adaptor object,
97*16467b97STreehugger Robotthe purpose of which is to provide a homogeneous interface for handling tree
98*16467b97STreehugger Robotconstruction and analysis of your tree nodes.
99*16467b97STreehugger Robot
100*16467b97STreehugger RobotSee Tree and TreeAdaptor for more information.
101*16467b97STreehugger Robot
102*16467b97STreehugger Robot=end
103*16467b97STreehugger Robot
104*16467b97STreehugger Robotclass TreeParser < Recognizer
105*16467b97STreehugger Robot  def self.main( argv = ARGV, options = {} )
106*16467b97STreehugger Robot    if ::Hash === argv then argv, options = ARGV, argv end
107*16467b97STreehugger Robot    main = ANTLR3::Main::WalkerMain.new( self, options )
108*16467b97STreehugger Robot    block_given? ? yield( main ) : main.execute( argv )
109*16467b97STreehugger Robot  end
110*16467b97STreehugger Robot
111*16467b97STreehugger Robot  def initialize( input, options = {} )
112*16467b97STreehugger Robot    super( options )
113*16467b97STreehugger Robot    @input = input
114*16467b97STreehugger Robot  end
115*16467b97STreehugger Robot
116*16467b97STreehugger Robot  alias tree_node_stream input
117*16467b97STreehugger Robot  alias tree_node_stream= input=
118*16467b97STreehugger Robot
119*16467b97STreehugger Robot  def source_name
120*16467b97STreehugger Robot    @input.source_name
121*16467b97STreehugger Robot  end
122*16467b97STreehugger Robot
123*16467b97STreehugger Robot  def missing_symbol( error, expected_token_type, follow )
124*16467b97STreehugger Robot    name = token_name( expected_token_type ).to_s
125*16467b97STreehugger Robot    text = "<missing " << name << '>'
126*16467b97STreehugger Robot    tk = create_token do |t|
127*16467b97STreehugger Robot      t.text = text
128*16467b97STreehugger Robot      t.type = expected_token_type
129*16467b97STreehugger Robot    end
130*16467b97STreehugger Robot    return( CommonTree.new( tk ) )
131*16467b97STreehugger Robot  end
132*16467b97STreehugger Robot
133*16467b97STreehugger Robot  def match_any( ignore = nil )
134*16467b97STreehugger Robot    @state.error_recovery = false
135*16467b97STreehugger Robot
136*16467b97STreehugger Robot    look, adaptor = @input.look, @input.tree_adaptor
137*16467b97STreehugger Robot    if adaptor.child_count( look ) == 0
138*16467b97STreehugger Robot      @input.consume
139*16467b97STreehugger Robot      return
140*16467b97STreehugger Robot    end
141*16467b97STreehugger Robot
142*16467b97STreehugger Robot    level = 0
143*16467b97STreehugger Robot    while type = @input.peek and type != EOF
144*16467b97STreehugger Robot      #token_type == EOF or ( token_type == UP && level == 0 )
145*16467b97STreehugger Robot      @input.consume
146*16467b97STreehugger Robot      case type
147*16467b97STreehugger Robot      when DOWN then level += 1
148*16467b97STreehugger Robot      when UP
149*16467b97STreehugger Robot        level -= 1
150*16467b97STreehugger Robot        level.zero? and break
151*16467b97STreehugger Robot      end
152*16467b97STreehugger Robot    end
153*16467b97STreehugger Robot  end
154*16467b97STreehugger Robot
155*16467b97STreehugger Robot  def mismatch( input, type, follow = nil )
156*16467b97STreehugger Robot    raise MismatchedTreeNode.new( type, input )
157*16467b97STreehugger Robot  end
158*16467b97STreehugger Robot
159*16467b97STreehugger Robot  def error_header( e )
160*16467b97STreehugger Robot    <<-END.strip!
161*16467b97STreehugger Robot    #{ grammar_file_name }: node from #{
162*16467b97STreehugger Robot      e.approximate_line_info? ? 'after ' : ''
163*16467b97STreehugger Robot    } line #{ e.line }:#{ e.column }
164*16467b97STreehugger Robot    END
165*16467b97STreehugger Robot  end
166*16467b97STreehugger Robot
167*16467b97STreehugger Robot  def error_message( e )
168*16467b97STreehugger Robot    adaptor = e.input.adaptor
169*16467b97STreehugger Robot    e.token = adaptor.token( e.node )
170*16467b97STreehugger Robot    e.token ||= create_token do | tok |
171*16467b97STreehugger Robot      tok.type = adaptor.type_of( e.node )
172*16467b97STreehugger Robot      tok.text = adaptor.text_of( e.node )
173*16467b97STreehugger Robot    end
174*16467b97STreehugger Robot    return super( e )
175*16467b97STreehugger Robot  end
176*16467b97STreehugger Robot
177*16467b97STreehugger Robot  def trace_in( rule_name, rule_index )
178*16467b97STreehugger Robot    super( rule_name, rule_index, @input.look )
179*16467b97STreehugger Robot  end
180*16467b97STreehugger Robot
181*16467b97STreehugger Robot  def trace_out( rule_name, rule_index )
182*16467b97STreehugger Robot    super( rule_name, rule_index, @input.look )
183*16467b97STreehugger Robot  end
184*16467b97STreehugger Robotend
185*16467b97STreehugger Robot
186*16467b97STreehugger Robot####################################################################################################
187*16467b97STreehugger Robot############################################ Tree Nodes ############################################
188*16467b97STreehugger Robot####################################################################################################
189*16467b97STreehugger Robot
190*16467b97STreehugger Robot=begin rdoc ANTLR3::AST::Tree
191*16467b97STreehugger Robot
192*16467b97STreehugger Robot= ANTLR Abstract Syntax Trees
193*16467b97STreehugger Robot
194*16467b97STreehugger RobotAs ANTLR is concerned, an Abstract Syntax Tree (AST) node is an object that
195*16467b97STreehugger Robotwraps a token, a list of child trees, and some information about the collective
196*16467b97STreehugger Robotsource text embodied within the tree and its children.
197*16467b97STreehugger Robot
198*16467b97STreehugger RobotThe Tree module, like the Token and Stream modules, emulates an abstract base
199*16467b97STreehugger Robotclass for AST classes; it specifies the attributes that are expected of basic
200*16467b97STreehugger Robottree nodes as well as the methods trees need to implement.
201*16467b97STreehugger Robot
202*16467b97STreehugger Robot== Terminology
203*16467b97STreehugger Robot
204*16467b97STreehugger RobotWhile much of this terminology is probably familiar to most developers, the
205*16467b97STreehugger Robotfollowing brief glossary is intended to clarify terminology used in code
206*16467b97STreehugger Robotthroughout the AST library:
207*16467b97STreehugger Robot
208*16467b97STreehugger Robot[payload] either a token value contained within a node or +nil+
209*16467b97STreehugger Robot[flat list (nil tree)] a tree node without a token payload, but with more
210*16467b97STreehugger Robot                       than one children -- functions like an array of
211*16467b97STreehugger Robot                       tree nodes
212*16467b97STreehugger Robot[root] a top-level tree node, i.e. a node that does not have a parent
213*16467b97STreehugger Robot[leaf] a node that does not have any children
214*16467b97STreehugger Robot[siblings] all other nodes sharing the same parent as some node
215*16467b97STreehugger Robot[ancestors] the list of successive parents from a tree node to the root node
216*16467b97STreehugger Robot[error node] a special node used to represent an erroneous series of tokens
217*16467b97STreehugger Robot             from an input stream
218*16467b97STreehugger Robot
219*16467b97STreehugger Robot=end
220*16467b97STreehugger Robot
221*16467b97STreehugger Robotmodule Tree
222*16467b97STreehugger Robot
223*16467b97STreehugger Robot  #attr_accessor :parent
224*16467b97STreehugger Robot  attr_accessor :start_index
225*16467b97STreehugger Robot  attr_accessor :stop_index
226*16467b97STreehugger Robot  attr_accessor :child_index
227*16467b97STreehugger Robot  attr_reader :type
228*16467b97STreehugger Robot  attr_reader :text
229*16467b97STreehugger Robot  attr_reader :line
230*16467b97STreehugger Robot  attr_reader :column
231*16467b97STreehugger Robot  #attr_reader :children
232*16467b97STreehugger Robot  attr_reader :token
233*16467b97STreehugger Robot
234*16467b97STreehugger Robot
235*16467b97STreehugger Robot  def root?
236*16467b97STreehugger Robot    parent.nil?
237*16467b97STreehugger Robot  end
238*16467b97STreehugger Robot  alias detached? root?
239*16467b97STreehugger Robot
240*16467b97STreehugger Robot  def root
241*16467b97STreehugger Robot    cursor = self
242*16467b97STreehugger Robot    until cursor.root?
243*16467b97STreehugger Robot      yield( parent_node = cursor.parent )
244*16467b97STreehugger Robot      cursor = parent_node
245*16467b97STreehugger Robot    end
246*16467b97STreehugger Robot    return( cursor )
247*16467b97STreehugger Robot  end
248*16467b97STreehugger Robot
249*16467b97STreehugger Robot  #
250*16467b97STreehugger Robot  def leaf?
251*16467b97STreehugger Robot    children.nil? or children.empty?
252*16467b97STreehugger Robot  end
253*16467b97STreehugger Robot
254*16467b97STreehugger Robot  def has_child?( node )
255*16467b97STreehugger Robot    children and children.include?( node )
256*16467b97STreehugger Robot  end
257*16467b97STreehugger Robot
258*16467b97STreehugger Robot  def depth
259*16467b97STreehugger Robot    root? ? 0 : parent.depth + 1
260*16467b97STreehugger Robot  end
261*16467b97STreehugger Robot
262*16467b97STreehugger Robot  def siblings
263*16467b97STreehugger Robot    root? and return []
264*16467b97STreehugger Robot    parent.children.reject { | c | c.equal?( self ) }
265*16467b97STreehugger Robot  end
266*16467b97STreehugger Robot
267*16467b97STreehugger Robot  def each_ancestor
268*16467b97STreehugger Robot    block_given? or return( enum_for( :each_ancestor ) )
269*16467b97STreehugger Robot    cursor = self
270*16467b97STreehugger Robot    until cursor.root?
271*16467b97STreehugger Robot      yield( parent_node = cursor.parent )
272*16467b97STreehugger Robot      cursor = parent_node
273*16467b97STreehugger Robot    end
274*16467b97STreehugger Robot    return( self )
275*16467b97STreehugger Robot  end
276*16467b97STreehugger Robot
277*16467b97STreehugger Robot  def ancestors
278*16467b97STreehugger Robot    each_ancestor.to_a
279*16467b97STreehugger Robot  end
280*16467b97STreehugger Robot
281*16467b97STreehugger Robot  def walk
282*16467b97STreehugger Robot    block_given? or return( enum_for( :walk ) )
283*16467b97STreehugger Robot    stack = []
284*16467b97STreehugger Robot    cursor = self
285*16467b97STreehugger Robot    while true
286*16467b97STreehugger Robot      begin
287*16467b97STreehugger Robot        yield( cursor )
288*16467b97STreehugger Robot        stack.push( cursor.children.dup ) unless cursor.empty?
289*16467b97STreehugger Robot      rescue StopIteration
290*16467b97STreehugger Robot        # skips adding children to prune the node
291*16467b97STreehugger Robot      ensure
292*16467b97STreehugger Robot        break if stack.empty?
293*16467b97STreehugger Robot        cursor = stack.last.shift
294*16467b97STreehugger Robot        stack.pop if stack.last.empty?
295*16467b97STreehugger Robot      end
296*16467b97STreehugger Robot    end
297*16467b97STreehugger Robot    return self
298*16467b97STreehugger Robot  end
299*16467b97STreehugger Robot
300*16467b97STreehugger Robotend
301*16467b97STreehugger Robot
302*16467b97STreehugger Robot
303*16467b97STreehugger Robot=begin rdoc ANTLR3::AST::BaseTree
304*16467b97STreehugger Robot
305*16467b97STreehugger RobotA base implementation of an Abstract Syntax Tree Node. It mainly defines the
306*16467b97STreehugger Robotmethods and attributes required to implement the parent-node-children
307*16467b97STreehugger Robotrelationship that characterize a tree; it does not provide any logic concerning
308*16467b97STreehugger Robota node's token <i>payload</i>.
309*16467b97STreehugger Robot
310*16467b97STreehugger Robot=end
311*16467b97STreehugger Robot
312*16467b97STreehugger Robotclass BaseTree < ::Array
313*16467b97STreehugger Robot  attr_accessor :parent
314*16467b97STreehugger Robot  extend ClassMacros
315*16467b97STreehugger Robot  include Tree
316*16467b97STreehugger Robot
317*16467b97STreehugger Robot  def initialize( node = nil )
318*16467b97STreehugger Robot    super()
319*16467b97STreehugger Robot    @parent = nil
320*16467b97STreehugger Robot    @child_index = 0
321*16467b97STreehugger Robot  end
322*16467b97STreehugger Robot
323*16467b97STreehugger Robot  def children() self end
324*16467b97STreehugger Robot
325*16467b97STreehugger Robot  alias child at
326*16467b97STreehugger Robot  alias child_count length
327*16467b97STreehugger Robot
328*16467b97STreehugger Robot  def first_with_type( tree_type )
329*16467b97STreehugger Robot    find { | child | child.type == tree_type }
330*16467b97STreehugger Robot  end
331*16467b97STreehugger Robot
332*16467b97STreehugger Robot  def add_child( child_tree )
333*16467b97STreehugger Robot    child_tree.nil? and return
334*16467b97STreehugger Robot    if child_tree.flat_list?
335*16467b97STreehugger Robot      self.equal?( child_tree.children ) and
336*16467b97STreehugger Robot        raise ArgumentError, "attempt to add child list to itself"
337*16467b97STreehugger Robot      child_tree.each_with_index do | child, index |
338*16467b97STreehugger Robot        child.parent = self
339*16467b97STreehugger Robot        child.child_index = length + index
340*16467b97STreehugger Robot      end
341*16467b97STreehugger Robot      concat( child_tree )
342*16467b97STreehugger Robot    else
343*16467b97STreehugger Robot      child_tree.child_index = length
344*16467b97STreehugger Robot      child_tree.parent = self
345*16467b97STreehugger Robot      self << child_tree
346*16467b97STreehugger Robot    end
347*16467b97STreehugger Robot    return( self )
348*16467b97STreehugger Robot  end
349*16467b97STreehugger Robot
350*16467b97STreehugger Robot  def detach
351*16467b97STreehugger Robot    @parent = nil
352*16467b97STreehugger Robot    @child_index = -1
353*16467b97STreehugger Robot    return( self )
354*16467b97STreehugger Robot  end
355*16467b97STreehugger Robot
356*16467b97STreehugger Robot  alias add_children concat
357*16467b97STreehugger Robot  alias each_child each
358*16467b97STreehugger Robot
359*16467b97STreehugger Robot  def set_child( index, tree )
360*16467b97STreehugger Robot    return if tree.nil?
361*16467b97STreehugger Robot    tree.flat_list? and raise ArgumentError, "Can't set single child to a list"
362*16467b97STreehugger Robot    tree.parent = self
363*16467b97STreehugger Robot    tree.child_index = index
364*16467b97STreehugger Robot    self[ index ] = tree
365*16467b97STreehugger Robot  end
366*16467b97STreehugger Robot
367*16467b97STreehugger Robot  def delete_child( index )
368*16467b97STreehugger Robot    killed = delete_at( index ) and freshen( index )
369*16467b97STreehugger Robot    return killed
370*16467b97STreehugger Robot  end
371*16467b97STreehugger Robot
372*16467b97STreehugger Robot  def replace_children( start, stop, new_tree )
373*16467b97STreehugger Robot    start >= length or stop >= length and
374*16467b97STreehugger Robot      raise IndexError, ( <<-END ).gsub!( /^\s+\| /,'' )
375*16467b97STreehugger Robot      | indices span beyond the number of children:
376*16467b97STreehugger Robot      |  children.length = #{ length }
377*16467b97STreehugger Robot      |  start = #{ start_index.inspect }
378*16467b97STreehugger Robot      |  stop  = #{ stop_index.inspect }
379*16467b97STreehugger Robot      END
380*16467b97STreehugger Robot    new_children = new_tree.flat_list? ? new_tree : [ new_tree ]
381*16467b97STreehugger Robot    self[ start .. stop ] = new_children
382*16467b97STreehugger Robot    freshen( start_index )
383*16467b97STreehugger Robot    return self
384*16467b97STreehugger Robot  end
385*16467b97STreehugger Robot
386*16467b97STreehugger Robot  def flat_list?
387*16467b97STreehugger Robot    false
388*16467b97STreehugger Robot  end
389*16467b97STreehugger Robot
390*16467b97STreehugger Robot  def freshen( offset = 0 )
391*16467b97STreehugger Robot    for i in offset ... length
392*16467b97STreehugger Robot      node = self[ i ]
393*16467b97STreehugger Robot      node.child_index = i
394*16467b97STreehugger Robot      node.parent = self
395*16467b97STreehugger Robot    end
396*16467b97STreehugger Robot  end
397*16467b97STreehugger Robot
398*16467b97STreehugger Robot  def sanity_check( parent = nil, i = -1 )
399*16467b97STreehugger Robot    parent == @parent or
400*16467b97STreehugger Robot      raise TreeInconsistency.failed_parent_check!( parent, @parent )
401*16467b97STreehugger Robot    i == @child_index or
402*16467b97STreehugger Robot      raise TreeInconsistency.failed_index_check!( i, @child_index )
403*16467b97STreehugger Robot    each_with_index do | child, index |
404*16467b97STreehugger Robot      child.sanity_check( self, index )
405*16467b97STreehugger Robot    end
406*16467b97STreehugger Robot  end
407*16467b97STreehugger Robot
408*16467b97STreehugger Robot  def inspect
409*16467b97STreehugger Robot    empty? and return to_s
410*16467b97STreehugger Robot    buffer = ''
411*16467b97STreehugger Robot    buffer << '(' << to_s << ' ' unless flat_list?
412*16467b97STreehugger Robot    buffer << map { | c | c.inspect }.join( ' ' )
413*16467b97STreehugger Robot    buffer << ')' unless flat_list?
414*16467b97STreehugger Robot    return( buffer )
415*16467b97STreehugger Robot  end
416*16467b97STreehugger Robot
417*16467b97STreehugger Robot  def walk
418*16467b97STreehugger Robot    block_given? or return( enum_for( :walk ) )
419*16467b97STreehugger Robot    stack = []
420*16467b97STreehugger Robot    cursor = self
421*16467b97STreehugger Robot    while true
422*16467b97STreehugger Robot      begin
423*16467b97STreehugger Robot        yield( cursor )
424*16467b97STreehugger Robot        stack.push( Array[ *cursor ] ) unless cursor.empty?
425*16467b97STreehugger Robot      rescue StopIteration
426*16467b97STreehugger Robot        # skips adding children to prune the node
427*16467b97STreehugger Robot      ensure
428*16467b97STreehugger Robot        break if stack.empty?
429*16467b97STreehugger Robot        cursor = stack.last.shift
430*16467b97STreehugger Robot        stack.pop if stack.last.empty?
431*16467b97STreehugger Robot      end
432*16467b97STreehugger Robot    end
433*16467b97STreehugger Robot    return self
434*16467b97STreehugger Robot  end
435*16467b97STreehugger Robot
436*16467b97STreehugger Robot  def prune
437*16467b97STreehugger Robot    raise StopIteration
438*16467b97STreehugger Robot  end
439*16467b97STreehugger Robot
440*16467b97STreehugger Robot  abstract :to_s
441*16467b97STreehugger Robot  #protected :sanity_check, :freshen
442*16467b97STreehugger Robot
443*16467b97STreehugger Robot  def root?() @parent.nil? end
444*16467b97STreehugger Robot  alias leaf? empty?
445*16467b97STreehugger Robotend
446*16467b97STreehugger Robot
447*16467b97STreehugger Robot
448*16467b97STreehugger Robot=begin rdoc ANTLR3::AST::CommonTree
449*16467b97STreehugger Robot
450*16467b97STreehugger RobotThe default Tree class implementation used by ANTLR tree-related code.
451*16467b97STreehugger Robot
452*16467b97STreehugger RobotA CommonTree object is a tree node that wraps a token <i>payload</i> (or a +nil+
453*16467b97STreehugger Robotvalue) and contains zero or more child tree nodes. Additionally, it tracks
454*16467b97STreehugger Robotinformation about the range of data collectively spanned by the tree node:
455*16467b97STreehugger Robot
456*16467b97STreehugger Robot* the token stream start and stop indexes of tokens contained throughout
457*16467b97STreehugger Robot  the tree
458*16467b97STreehugger Robot* that start and stop positions of the character input stream from which
459*16467b97STreehugger Robot  the tokens were defined
460*16467b97STreehugger Robot
461*16467b97STreehugger RobotTracking this information simplifies tasks like extracting a block of code or
462*16467b97STreehugger Robotrewriting the input stream. However, depending on the purpose of the
463*16467b97STreehugger Robotapplication, building trees with all of this extra information may be
464*16467b97STreehugger Robotunnecessary. In such a case, a more bare-bones tree class could be written
465*16467b97STreehugger Robot(optionally using the BaseTree class or the Token module). Define a customized
466*16467b97STreehugger RobotTreeAdaptor class to handle tree construction and manipulation for the
467*16467b97STreehugger Robotcustomized node class, and recognizers will be able to build, rewrite, and parse
468*16467b97STreehugger Robotthe customized lighter-weight trees.
469*16467b97STreehugger Robot
470*16467b97STreehugger Robot=end
471*16467b97STreehugger Robot
472*16467b97STreehugger Robotclass CommonTree < BaseTree
473*16467b97STreehugger Robot  def initialize( payload = nil )
474*16467b97STreehugger Robot    super()
475*16467b97STreehugger Robot    @start_index = -1
476*16467b97STreehugger Robot    @stop_index = -1
477*16467b97STreehugger Robot    @child_index = -1
478*16467b97STreehugger Robot    case payload
479*16467b97STreehugger Robot    when CommonTree then   # copy-constructor style init
480*16467b97STreehugger Robot      @token       = payload.token
481*16467b97STreehugger Robot      @start_index = payload.start_index
482*16467b97STreehugger Robot      @stop_index  = payload.stop_index
483*16467b97STreehugger Robot    when nil, Token then @token = payload
484*16467b97STreehugger Robot    else raise ArgumentError,
485*16467b97STreehugger Robot      "Invalid argument type: %s (%p)" % [ payload.class, payload ]
486*16467b97STreehugger Robot    end
487*16467b97STreehugger Robot  end
488*16467b97STreehugger Robot
489*16467b97STreehugger Robot  def initialize_copy( orig )
490*16467b97STreehugger Robot    super
491*16467b97STreehugger Robot    clear
492*16467b97STreehugger Robot    @parent = nil
493*16467b97STreehugger Robot  end
494*16467b97STreehugger Robot
495*16467b97STreehugger Robot  def copy_node
496*16467b97STreehugger Robot    return self.class.new( @token )
497*16467b97STreehugger Robot  end
498*16467b97STreehugger Robot
499*16467b97STreehugger Robot  def flat_list?
500*16467b97STreehugger Robot    @token.nil?
501*16467b97STreehugger Robot  end
502*16467b97STreehugger Robot
503*16467b97STreehugger Robot  def type
504*16467b97STreehugger Robot    @token ? @token.type : 0
505*16467b97STreehugger Robot  end
506*16467b97STreehugger Robot
507*16467b97STreehugger Robot  def text
508*16467b97STreehugger Robot    @token.text rescue nil
509*16467b97STreehugger Robot  end
510*16467b97STreehugger Robot
511*16467b97STreehugger Robot  def line
512*16467b97STreehugger Robot    if @token.nil? or @token.line == 0
513*16467b97STreehugger Robot      return ( empty? ? 0 : first.line )
514*16467b97STreehugger Robot    end
515*16467b97STreehugger Robot    return @token.line
516*16467b97STreehugger Robot  end
517*16467b97STreehugger Robot
518*16467b97STreehugger Robot  def column
519*16467b97STreehugger Robot    if @token.nil? or @token.column == -1
520*16467b97STreehugger Robot      return( empty? ? 0 : first.column )
521*16467b97STreehugger Robot    end
522*16467b97STreehugger Robot    return @token.column
523*16467b97STreehugger Robot  end
524*16467b97STreehugger Robot
525*16467b97STreehugger Robot  def start_index
526*16467b97STreehugger Robot    @start_index == -1 and @token and return @token.index
527*16467b97STreehugger Robot    return @start_index
528*16467b97STreehugger Robot  end
529*16467b97STreehugger Robot
530*16467b97STreehugger Robot  def stop_index
531*16467b97STreehugger Robot    @stop_index == -1 and @token and return @token.index
532*16467b97STreehugger Robot    return @stop_index
533*16467b97STreehugger Robot  end
534*16467b97STreehugger Robot
535*16467b97STreehugger Robot  alias token_start_index= start_index=
536*16467b97STreehugger Robot  alias token_stop_index= stop_index=
537*16467b97STreehugger Robot  alias token_start_index start_index
538*16467b97STreehugger Robot  alias token_stop_index stop_index
539*16467b97STreehugger Robot
540*16467b97STreehugger Robot  def name
541*16467b97STreehugger Robot    @token.name rescue 'INVALID'
542*16467b97STreehugger Robot  end
543*16467b97STreehugger Robot
544*16467b97STreehugger Robot  def token_range
545*16467b97STreehugger Robot    unknown_boundaries? and infer_boundaries
546*16467b97STreehugger Robot    @start_index .. @stop_index
547*16467b97STreehugger Robot  end
548*16467b97STreehugger Robot
549*16467b97STreehugger Robot  def source_range
550*16467b97STreehugger Robot    unknown_boundaries? and infer_boundaries
551*16467b97STreehugger Robot    tokens = map do | node |
552*16467b97STreehugger Robot      tk = node.token and tk.index >= 0 ? tk : nil
553*16467b97STreehugger Robot    end
554*16467b97STreehugger Robot    tokens.compact!
555*16467b97STreehugger Robot    first, last = tokens.minmax_by { |t| t.index }
556*16467b97STreehugger Robot    first.start .. last.stop
557*16467b97STreehugger Robot  end
558*16467b97STreehugger Robot
559*16467b97STreehugger Robot  def infer_boundaries
560*16467b97STreehugger Robot    if empty? and @start_index < 0 || @stop_index < 0
561*16467b97STreehugger Robot      @start_index = @stop_index = @token.index rescue -1
562*16467b97STreehugger Robot      return
563*16467b97STreehugger Robot    end
564*16467b97STreehugger Robot    for child in self do child.infer_boundaries end
565*16467b97STreehugger Robot    return if @start_index >= 0 and @stop_index >= 0
566*16467b97STreehugger Robot
567*16467b97STreehugger Robot    @start_index = first.start_index
568*16467b97STreehugger Robot    @stop_index  = last.stop_index
569*16467b97STreehugger Robot    return nil
570*16467b97STreehugger Robot  end
571*16467b97STreehugger Robot
572*16467b97STreehugger Robot  def unknown_boundaries?
573*16467b97STreehugger Robot    @start_index < 0 or @stop_index < 0
574*16467b97STreehugger Robot  end
575*16467b97STreehugger Robot
576*16467b97STreehugger Robot  def to_s
577*16467b97STreehugger Robot    flat_list? ? 'nil' : @token.text.to_s
578*16467b97STreehugger Robot  end
579*16467b97STreehugger Robot
580*16467b97STreehugger Robot  def pretty_print( printer )
581*16467b97STreehugger Robot    text = @token ? @token.text : 'nil'
582*16467b97STreehugger Robot    text =~ /\s+/ and
583*16467b97STreehugger Robot      text = text.dump
584*16467b97STreehugger Robot
585*16467b97STreehugger Robot    if empty?
586*16467b97STreehugger Robot      printer.text( text )
587*16467b97STreehugger Robot    else
588*16467b97STreehugger Robot      endpoints = @token ? [ "(#{ text }", ')' ] : [ '', '' ]
589*16467b97STreehugger Robot      printer.group( 1, *endpoints ) do
590*16467b97STreehugger Robot        for child in self
591*16467b97STreehugger Robot          printer.breakable
592*16467b97STreehugger Robot          printer.pp( child )
593*16467b97STreehugger Robot        end
594*16467b97STreehugger Robot      end
595*16467b97STreehugger Robot    end
596*16467b97STreehugger Robot  end
597*16467b97STreehugger Robot
598*16467b97STreehugger Robotend
599*16467b97STreehugger Robot
600*16467b97STreehugger Robot=begin rdoc ANTLR3::AST::CommonErrorNode
601*16467b97STreehugger Robot
602*16467b97STreehugger RobotRepresents a series of erroneous tokens from a token stream input
603*16467b97STreehugger Robot
604*16467b97STreehugger Robot=end
605*16467b97STreehugger Robot
606*16467b97STreehugger Robotclass CommonErrorNode < CommonTree
607*16467b97STreehugger Robot  include ANTLR3::Error
608*16467b97STreehugger Robot  include ANTLR3::Constants
609*16467b97STreehugger Robot
610*16467b97STreehugger Robot  attr_accessor :input, :start, :stop, :error
611*16467b97STreehugger Robot
612*16467b97STreehugger Robot  def initialize( input, start, stop, error )
613*16467b97STreehugger Robot    super( nil )
614*16467b97STreehugger Robot    stop = start if stop.nil? or
615*16467b97STreehugger Robot      ( stop.token_index < start.token_index and stop.type != EOF )
616*16467b97STreehugger Robot    @input = input
617*16467b97STreehugger Robot    @start = start
618*16467b97STreehugger Robot    @stop = stop
619*16467b97STreehugger Robot    @error = error
620*16467b97STreehugger Robot  end
621*16467b97STreehugger Robot
622*16467b97STreehugger Robot  def flat_list?
623*16467b97STreehugger Robot    return false
624*16467b97STreehugger Robot  end
625*16467b97STreehugger Robot
626*16467b97STreehugger Robot  def type
627*16467b97STreehugger Robot    INVALID_TOKEN_TYPE
628*16467b97STreehugger Robot  end
629*16467b97STreehugger Robot
630*16467b97STreehugger Robot  def text
631*16467b97STreehugger Robot    case @start
632*16467b97STreehugger Robot    when Token
633*16467b97STreehugger Robot      i = @start.token_index
634*16467b97STreehugger Robot      j = ( @stop.type == EOF ) ? @input.size : @stop.token_index
635*16467b97STreehugger Robot      @input.to_s( i, j )            # <- the bad text
636*16467b97STreehugger Robot    when Tree
637*16467b97STreehugger Robot      @input.to_s( @start, @stop )   # <- the bad text
638*16467b97STreehugger Robot    else
639*16467b97STreehugger Robot      "<unknown>"
640*16467b97STreehugger Robot    end
641*16467b97STreehugger Robot  end
642*16467b97STreehugger Robot
643*16467b97STreehugger Robot  def to_s
644*16467b97STreehugger Robot    case @error
645*16467b97STreehugger Robot    when MissingToken
646*16467b97STreehugger Robot      "<missing type: #{ @error.missing_type }>"
647*16467b97STreehugger Robot    when UnwantedToken
648*16467b97STreehugger Robot      "<extraneous: #{ @error.token.inspect }, resync = #{ text }>"
649*16467b97STreehugger Robot    when MismatchedToken
650*16467b97STreehugger Robot      "<mismatched token: #{ @error.token.inspect }, resync = #{ text }>"
651*16467b97STreehugger Robot    when NoViableAlternative
652*16467b97STreehugger Robot      "<unexpected: #{ @error.token.inspect }, resync = #{ text }>"
653*16467b97STreehugger Robot    else "<error: #{ text }>"
654*16467b97STreehugger Robot    end
655*16467b97STreehugger Robot  end
656*16467b97STreehugger Robot
657*16467b97STreehugger Robotend
658*16467b97STreehugger Robot
659*16467b97STreehugger RobotConstants::INVALID_NODE = CommonTree.new( ANTLR3::INVALID_TOKEN )
660*16467b97STreehugger Robot
661*16467b97STreehugger Robot####################################################################################################
662*16467b97STreehugger Robot########################################### Tree Adaptors ##########################################
663*16467b97STreehugger Robot####################################################################################################
664*16467b97STreehugger Robot
665*16467b97STreehugger Robot=begin rdoc ANTLR3::AST::TreeAdaptor
666*16467b97STreehugger Robot
667*16467b97STreehugger RobotSince a tree can be represented by a multitude of formats, ANTLR's tree-related
668*16467b97STreehugger Robotcode mandates the use of Tree Adaptor objects to build and manipulate any actual
669*16467b97STreehugger Robottrees. Using an adaptor object permits a single recognizer to work with any
670*16467b97STreehugger Robotnumber of different tree structures without adding rigid interface requirements
671*16467b97STreehugger Roboton customized tree structures. For example, if you want to represent trees using
672*16467b97STreehugger Robotsimple arrays of arrays, you just need to design an appropriate tree adaptor and
673*16467b97STreehugger Robotprovide it to the parser.
674*16467b97STreehugger Robot
675*16467b97STreehugger RobotTree adaptors are tasked with:
676*16467b97STreehugger Robot
677*16467b97STreehugger Robot* copying and creating tree nodes and tokens
678*16467b97STreehugger Robot* defining parent-child relationships between nodes
679*16467b97STreehugger Robot* cleaning up / normalizing a full tree structure after construction
680*16467b97STreehugger Robot* reading and writing the attributes ANTLR expects of tree nodes
681*16467b97STreehugger Robot* providing node access and iteration
682*16467b97STreehugger Robot
683*16467b97STreehugger Robot=end
684*16467b97STreehugger Robot
685*16467b97STreehugger Robotmodule TreeAdaptor
686*16467b97STreehugger Robot  include TokenFactory
687*16467b97STreehugger Robot  include Constants
688*16467b97STreehugger Robot  include Error
689*16467b97STreehugger Robot
690*16467b97STreehugger Robot  def add_child( tree, child )
691*16467b97STreehugger Robot    tree.add_child( child ) if tree and child
692*16467b97STreehugger Robot  end
693*16467b97STreehugger Robot
694*16467b97STreehugger Robot  def child_count( tree )
695*16467b97STreehugger Robot    tree.child_count
696*16467b97STreehugger Robot  end
697*16467b97STreehugger Robot
698*16467b97STreehugger Robot  def child_index( tree )
699*16467b97STreehugger Robot    tree.child_index rescue 0
700*16467b97STreehugger Robot  end
701*16467b97STreehugger Robot
702*16467b97STreehugger Robot  def child_of( tree, index )
703*16467b97STreehugger Robot    tree.nil? ? nil : tree.child( index )
704*16467b97STreehugger Robot  end
705*16467b97STreehugger Robot
706*16467b97STreehugger Robot  def copy_node( tree_node )
707*16467b97STreehugger Robot    tree_node and tree_node.dup
708*16467b97STreehugger Robot  end
709*16467b97STreehugger Robot
710*16467b97STreehugger Robot  def copy_tree( tree, parent = nil )
711*16467b97STreehugger Robot    tree or return nil
712*16467b97STreehugger Robot    new_tree = copy_node( tree )
713*16467b97STreehugger Robot    set_child_index( new_tree, child_index( tree ) )
714*16467b97STreehugger Robot    set_parent( new_tree, parent )
715*16467b97STreehugger Robot    each_child( tree ) do | child |
716*16467b97STreehugger Robot      new_sub_tree = copy_tree( child, new_tree )
717*16467b97STreehugger Robot      add_child( new_tree, new_sub_tree )
718*16467b97STreehugger Robot    end
719*16467b97STreehugger Robot    return new_tree
720*16467b97STreehugger Robot  end
721*16467b97STreehugger Robot
722*16467b97STreehugger Robot  def delete_child( tree, index )
723*16467b97STreehugger Robot    tree.delete_child( index )
724*16467b97STreehugger Robot  end
725*16467b97STreehugger Robot
726*16467b97STreehugger Robot
727*16467b97STreehugger Robot  def each_child( tree )
728*16467b97STreehugger Robot    block_given? or return enum_for( :each_child, tree )
729*16467b97STreehugger Robot    for i in 0 ... child_count( tree )
730*16467b97STreehugger Robot      yield( child_of( tree, i ) )
731*16467b97STreehugger Robot    end
732*16467b97STreehugger Robot    return tree
733*16467b97STreehugger Robot  end
734*16467b97STreehugger Robot
735*16467b97STreehugger Robot  def each_ancestor( tree, include_tree = true )
736*16467b97STreehugger Robot    block_given? or return enum_for( :each_ancestor, tree, include_tree )
737*16467b97STreehugger Robot    if include_tree
738*16467b97STreehugger Robot      begin yield( tree ) end while tree = parent_of( tree )
739*16467b97STreehugger Robot    else
740*16467b97STreehugger Robot      while tree = parent_of( tree ) do yield( tree ) end
741*16467b97STreehugger Robot    end
742*16467b97STreehugger Robot  end
743*16467b97STreehugger Robot
744*16467b97STreehugger Robot  def flat_list?( tree )
745*16467b97STreehugger Robot    tree.flat_list?
746*16467b97STreehugger Robot  end
747*16467b97STreehugger Robot
748*16467b97STreehugger Robot  def empty?( tree )
749*16467b97STreehugger Robot    child_count( tree ).zero?
750*16467b97STreehugger Robot  end
751*16467b97STreehugger Robot
752*16467b97STreehugger Robot  def parent( tree )
753*16467b97STreehugger Robot    tree.parent
754*16467b97STreehugger Robot  end
755*16467b97STreehugger Robot
756*16467b97STreehugger Robot  def replace_children( parent, start, stop, replacement )
757*16467b97STreehugger Robot    parent and parent.replace_children( start, stop, replacement )
758*16467b97STreehugger Robot  end
759*16467b97STreehugger Robot
760*16467b97STreehugger Robot  def rule_post_processing( root )
761*16467b97STreehugger Robot    if root and root.flat_list?
762*16467b97STreehugger Robot      case root.child_count
763*16467b97STreehugger Robot      when 0 then root = nil
764*16467b97STreehugger Robot      when 1
765*16467b97STreehugger Robot        root = root.child( 0 ).detach
766*16467b97STreehugger Robot      end
767*16467b97STreehugger Robot    end
768*16467b97STreehugger Robot    return root
769*16467b97STreehugger Robot  end
770*16467b97STreehugger Robot
771*16467b97STreehugger Robot  def set_child_index( tree, index )
772*16467b97STreehugger Robot    tree.child_index = index
773*16467b97STreehugger Robot  end
774*16467b97STreehugger Robot
775*16467b97STreehugger Robot  def set_parent( tree, parent )
776*16467b97STreehugger Robot    tree.parent = parent
777*16467b97STreehugger Robot  end
778*16467b97STreehugger Robot
779*16467b97STreehugger Robot  def set_token_boundaries( tree, start_token = nil, stop_token = nil )
780*16467b97STreehugger Robot    return unless tree
781*16467b97STreehugger Robot    start = stop = 0
782*16467b97STreehugger Robot    start_token and start = start_token.index
783*16467b97STreehugger Robot    stop_token  and stop  = stop_token.index
784*16467b97STreehugger Robot    tree.start_index = start
785*16467b97STreehugger Robot    tree.stop_index = stop
786*16467b97STreehugger Robot    return tree
787*16467b97STreehugger Robot  end
788*16467b97STreehugger Robot
789*16467b97STreehugger Robot  def text_of( tree )
790*16467b97STreehugger Robot    tree.text rescue nil
791*16467b97STreehugger Robot  end
792*16467b97STreehugger Robot
793*16467b97STreehugger Robot  def token( tree )
794*16467b97STreehugger Robot    CommonTree === tree ? tree.token : nil
795*16467b97STreehugger Robot  end
796*16467b97STreehugger Robot
797*16467b97STreehugger Robot  def token_start_index( tree )
798*16467b97STreehugger Robot    tree ? tree.token_start_index : -1
799*16467b97STreehugger Robot  end
800*16467b97STreehugger Robot
801*16467b97STreehugger Robot  def token_stop_index( tree )
802*16467b97STreehugger Robot    tree ? tree.token_stop_index : -1
803*16467b97STreehugger Robot  end
804*16467b97STreehugger Robot
805*16467b97STreehugger Robot  def type_name( tree )
806*16467b97STreehugger Robot    tree.name rescue 'INVALID'
807*16467b97STreehugger Robot  end
808*16467b97STreehugger Robot
809*16467b97STreehugger Robot  def type_of( tree )
810*16467b97STreehugger Robot    tree.type rescue INVALID_TOKEN_TYPE
811*16467b97STreehugger Robot  end
812*16467b97STreehugger Robot
813*16467b97STreehugger Robot  def unique_id( node )
814*16467b97STreehugger Robot    node.hash
815*16467b97STreehugger Robot  end
816*16467b97STreehugger Robot
817*16467b97STreehugger Robotend
818*16467b97STreehugger Robot
819*16467b97STreehugger Robot=begin rdoc ANTLR3::AST::CommonTreeAdaptor
820*16467b97STreehugger Robot
821*16467b97STreehugger RobotThe default tree adaptor used by ANTLR-generated tree code. It, of course,
822*16467b97STreehugger Robotbuilds and manipulates CommonTree nodes.
823*16467b97STreehugger Robot
824*16467b97STreehugger Robot=end
825*16467b97STreehugger Robot
826*16467b97STreehugger Robotclass CommonTreeAdaptor
827*16467b97STreehugger Robot  extend ClassMacros
828*16467b97STreehugger Robot  include TreeAdaptor
829*16467b97STreehugger Robot  include ANTLR3::Constants
830*16467b97STreehugger Robot
831*16467b97STreehugger Robot  def initialize( token_class = ANTLR3::CommonToken )
832*16467b97STreehugger Robot    @token_class = token_class
833*16467b97STreehugger Robot  end
834*16467b97STreehugger Robot
835*16467b97STreehugger Robot  def create_flat_list
836*16467b97STreehugger Robot    return create_with_payload( nil )
837*16467b97STreehugger Robot  end
838*16467b97STreehugger Robot  alias create_flat_list! create_flat_list
839*16467b97STreehugger Robot
840*16467b97STreehugger Robot  def become_root( new_root, old_root )
841*16467b97STreehugger Robot    new_root = create( new_root ) if new_root.is_a?( Token )
842*16467b97STreehugger Robot    old_root or return( new_root )
843*16467b97STreehugger Robot
844*16467b97STreehugger Robot    new_root = create_with_payload( new_root ) unless CommonTree === new_root
845*16467b97STreehugger Robot    if new_root.flat_list?
846*16467b97STreehugger Robot      count = new_root.child_count
847*16467b97STreehugger Robot      if count == 1
848*16467b97STreehugger Robot        new_root = new_root.child( 0 )
849*16467b97STreehugger Robot      elsif count > 1
850*16467b97STreehugger Robot        raise TreeInconsistency.multiple_roots!
851*16467b97STreehugger Robot      end
852*16467b97STreehugger Robot    end
853*16467b97STreehugger Robot
854*16467b97STreehugger Robot    new_root.add_child( old_root )
855*16467b97STreehugger Robot    return new_root
856*16467b97STreehugger Robot  end
857*16467b97STreehugger Robot
858*16467b97STreehugger Robot  def create_from_token( token_type, from_token, text = nil )
859*16467b97STreehugger Robot    from_token = from_token.dup
860*16467b97STreehugger Robot    from_token.type = token_type
861*16467b97STreehugger Robot    from_token.text = text.to_s if text
862*16467b97STreehugger Robot    tree = create_with_payload( from_token )
863*16467b97STreehugger Robot    return tree
864*16467b97STreehugger Robot  end
865*16467b97STreehugger Robot
866*16467b97STreehugger Robot  def create_from_type( token_type, text )
867*16467b97STreehugger Robot    from_token = create_token( token_type, DEFAULT_CHANNEL, text )
868*16467b97STreehugger Robot    create_with_payload( from_token )
869*16467b97STreehugger Robot  end
870*16467b97STreehugger Robot
871*16467b97STreehugger Robot  def create_error_node( input, start, stop, exc )
872*16467b97STreehugger Robot    CommonErrorNode.new( input, start, stop, exc )
873*16467b97STreehugger Robot  end
874*16467b97STreehugger Robot
875*16467b97STreehugger Robot  def create_with_payload( payload )
876*16467b97STreehugger Robot    return CommonTree.new( payload )
877*16467b97STreehugger Robot  end
878*16467b97STreehugger Robot
879*16467b97STreehugger Robot  def create( *args )
880*16467b97STreehugger Robot    n = args.length
881*16467b97STreehugger Robot    if n == 1 and args.first.is_a?( Token ) then create_with_payload( args[ 0 ] )
882*16467b97STreehugger Robot    elsif n == 2 and Integer === args.first and String === args[ 1 ]
883*16467b97STreehugger Robot      create_from_type( *args )
884*16467b97STreehugger Robot    elsif n >= 2 and Integer === args.first
885*16467b97STreehugger Robot      create_from_token( *args )
886*16467b97STreehugger Robot    else
887*16467b97STreehugger Robot      sig = args.map { |f| f.class }.join( ', ' )
888*16467b97STreehugger Robot      raise TypeError, "No create method with this signature found: (#{ sig })"
889*16467b97STreehugger Robot    end
890*16467b97STreehugger Robot  end
891*16467b97STreehugger Robot
892*16467b97STreehugger Robot  creation_methods = %w(
893*16467b97STreehugger Robot    create_from_token create_from_type
894*16467b97STreehugger Robot    create_error_node create_with_payload
895*16467b97STreehugger Robot    create
896*16467b97STreehugger Robot  )
897*16467b97STreehugger Robot
898*16467b97STreehugger Robot  for method_name in creation_methods
899*16467b97STreehugger Robot    bang_method = method_name + '!'
900*16467b97STreehugger Robot    alias_method( bang_method, method_name )
901*16467b97STreehugger Robot    deprecate( bang_method, "use method ##{ method_name } instead" )
902*16467b97STreehugger Robot  end
903*16467b97STreehugger Robot
904*16467b97STreehugger Robot  def rule_post_processing( root )
905*16467b97STreehugger Robot    if root and root.flat_list?
906*16467b97STreehugger Robot      if root.empty? then root = nil
907*16467b97STreehugger Robot      elsif root.child_count == 1 then root = root.first.detach
908*16467b97STreehugger Robot      end
909*16467b97STreehugger Robot    end
910*16467b97STreehugger Robot    return root
911*16467b97STreehugger Robot  end
912*16467b97STreehugger Robot
913*16467b97STreehugger Robot  def empty?( tree )
914*16467b97STreehugger Robot    tree.empty?
915*16467b97STreehugger Robot  end
916*16467b97STreehugger Robot
917*16467b97STreehugger Robot  def each_child( tree )
918*16467b97STreehugger Robot    block_given? or return enum_for( :each_child, tree )
919*16467b97STreehugger Robot    tree.each do | child |
920*16467b97STreehugger Robot      yield( child )
921*16467b97STreehugger Robot    end
922*16467b97STreehugger Robot  end
923*16467b97STreehugger Robot
924*16467b97STreehugger Robotend
925*16467b97STreehugger Robot
926*16467b97STreehugger Robot
927*16467b97STreehugger Robot####################################################################################################
928*16467b97STreehugger Robot########################################### Tree Streams ###########################################
929*16467b97STreehugger Robot####################################################################################################
930*16467b97STreehugger Robot
931*16467b97STreehugger Robot=begin rdoc ANTLR3::AST::TreeNodeStream
932*16467b97STreehugger Robot
933*16467b97STreehugger RobotTreeNodeStreams flatten two-dimensional tree structures into one-dimensional
934*16467b97STreehugger Robotsequences. They preserve the two-dimensional structure of the tree by inserting
935*16467b97STreehugger Robotspecial +UP+ and +DOWN+ nodes.
936*16467b97STreehugger Robot
937*16467b97STreehugger RobotConsider a hypothetical tree:
938*16467b97STreehugger Robot
939*16467b97STreehugger Robot  [A]
940*16467b97STreehugger Robot   +--[B]
941*16467b97STreehugger Robot   |   +--[C]
942*16467b97STreehugger Robot   |   `--[D]
943*16467b97STreehugger Robot   `--[E]
944*16467b97STreehugger Robot       `--[F]
945*16467b97STreehugger Robot
946*16467b97STreehugger RobotA tree node stream would serialize the tree into the following sequence:
947*16467b97STreehugger Robot
948*16467b97STreehugger Robot  A DOWN B DOWN C D UP E DOWN F UP UP EOF
949*16467b97STreehugger Robot
950*16467b97STreehugger RobotOther than serializing a tree into a sequence of nodes, a tree node stream
951*16467b97STreehugger Robotoperates similarly to other streams. They are commonly used by tree parsers as
952*16467b97STreehugger Robotthe main form of input. #peek, like token streams, returns the type of the token
953*16467b97STreehugger Robotof the next node. #look returns the next full tree node.
954*16467b97STreehugger Robot
955*16467b97STreehugger Robot=end
956*16467b97STreehugger Robot
957*16467b97STreehugger Robotmodule TreeNodeStream
958*16467b97STreehugger Robot  extend ClassMacros
959*16467b97STreehugger Robot  include Stream
960*16467b97STreehugger Robot  include Constants
961*16467b97STreehugger Robot
962*16467b97STreehugger Robot  abstract :at
963*16467b97STreehugger Robot  abstract :look
964*16467b97STreehugger Robot  abstract :tree_source
965*16467b97STreehugger Robot  abstract :token_stream
966*16467b97STreehugger Robot  abstract :tree_adaptor
967*16467b97STreehugger Robot  abstract :unique_navigation_nodes=
968*16467b97STreehugger Robot  abstract :to_s
969*16467b97STreehugger Robot  abstract :replace_children
970*16467b97STreehugger Robotend
971*16467b97STreehugger Robot
972*16467b97STreehugger Robot=begin rdoc ANTLR3::AST::CommonTreeNodeStream
973*16467b97STreehugger Robot
974*16467b97STreehugger RobotAn implementation of TreeNodeStream tailed for streams based on CommonTree
975*16467b97STreehugger Robotobjects. CommonTreeNodeStreams are the default input streams for tree parsers.
976*16467b97STreehugger Robot
977*16467b97STreehugger Robot=end
978*16467b97STreehugger Robot
979*16467b97STreehugger Robotclass CommonTreeNodeStream
980*16467b97STreehugger Robot  include TreeNodeStream
981*16467b97STreehugger Robot
982*16467b97STreehugger Robot  attr_accessor :token_stream
983*16467b97STreehugger Robot  attr_reader :adaptor, :position
984*16467b97STreehugger Robot
985*16467b97STreehugger Robot  def initialize( *args )
986*16467b97STreehugger Robot    options = args.last.is_a?( ::Hash ) ? args.pop : {}
987*16467b97STreehugger Robot    case n = args.length
988*16467b97STreehugger Robot    when 1
989*16467b97STreehugger Robot      @root = args.first
990*16467b97STreehugger Robot      @token_stream = @adaptor = @nodes = @down = @up = @eof = nil
991*16467b97STreehugger Robot    when 2
992*16467b97STreehugger Robot      @adaptor, @root = args
993*16467b97STreehugger Robot      @token_stream = @nodes = @down = @up = @eof = nil
994*16467b97STreehugger Robot    when 3
995*16467b97STreehugger Robot      parent, start, stop = *args
996*16467b97STreehugger Robot      @adaptor = parent.adaptor
997*16467b97STreehugger Robot      @root = parent.root
998*16467b97STreehugger Robot      @nodes = parent.nodes[ start ... stop ]
999*16467b97STreehugger Robot      @down = parent.down
1000*16467b97STreehugger Robot      @up = parent.up
1001*16467b97STreehugger Robot      @eof = parent.eof
1002*16467b97STreehugger Robot      @token_stream = parent.token_stream
1003*16467b97STreehugger Robot    when 0
1004*16467b97STreehugger Robot      raise ArgumentError, "wrong number of arguments (0 for 1)"
1005*16467b97STreehugger Robot    else raise ArgumentError, "wrong number of arguments (#{ n } for 3)"
1006*16467b97STreehugger Robot    end
1007*16467b97STreehugger Robot    @adaptor ||= options.fetch( :adaptor ) { CommonTreeAdaptor.new }
1008*16467b97STreehugger Robot    @token_stream ||= options[ :token_stream ]
1009*16467b97STreehugger Robot    @down  ||= options.fetch( :down ) { @adaptor.create_from_type( DOWN, 'DOWN' ) }
1010*16467b97STreehugger Robot    @up    ||= options.fetch( :up )   { @adaptor.create_from_type( UP, 'UP' ) }
1011*16467b97STreehugger Robot    @eof   ||= options.fetch( :eof )  { @adaptor.create_from_type( EOF, 'EOF' ) }
1012*16467b97STreehugger Robot    @nodes ||= []
1013*16467b97STreehugger Robot
1014*16467b97STreehugger Robot    @unique_navigation_nodes = options.fetch( :unique_navigation_nodes, false )
1015*16467b97STreehugger Robot    @position = -1
1016*16467b97STreehugger Robot    @last_marker = nil
1017*16467b97STreehugger Robot    @calls = []
1018*16467b97STreehugger Robot  end
1019*16467b97STreehugger Robot
1020*16467b97STreehugger Robot  def fill_buffer( tree = @root )
1021*16467b97STreehugger Robot    @nodes << tree unless nil_tree = @adaptor.flat_list?( tree )
1022*16467b97STreehugger Robot    unless @adaptor.empty?( tree )
1023*16467b97STreehugger Robot      add_navigation_node( DOWN ) unless nil_tree
1024*16467b97STreehugger Robot      @adaptor.each_child( tree ) { | c | fill_buffer( c ) }
1025*16467b97STreehugger Robot      add_navigation_node( UP ) unless nil_tree
1026*16467b97STreehugger Robot    end
1027*16467b97STreehugger Robot    @position = 0 if tree == @root
1028*16467b97STreehugger Robot    return( self )
1029*16467b97STreehugger Robot  end
1030*16467b97STreehugger Robot
1031*16467b97STreehugger Robot  def node_index( node )
1032*16467b97STreehugger Robot    @position == -1 and fill_buffer
1033*16467b97STreehugger Robot    return @nodes.index( node )
1034*16467b97STreehugger Robot  end
1035*16467b97STreehugger Robot
1036*16467b97STreehugger Robot  def add_navigation_node( type )
1037*16467b97STreehugger Robot    navigation_node =
1038*16467b97STreehugger Robot      case type
1039*16467b97STreehugger Robot      when DOWN
1040*16467b97STreehugger Robot        has_unique_navigation_nodes? ? @adaptor.create_from_type( DOWN, 'DOWN' ) : @down
1041*16467b97STreehugger Robot      else
1042*16467b97STreehugger Robot        has_unique_navigation_nodes? ? @adaptor.create_from_type( UP, 'UP' ) : @up
1043*16467b97STreehugger Robot      end
1044*16467b97STreehugger Robot    @nodes << navigation_node
1045*16467b97STreehugger Robot  end
1046*16467b97STreehugger Robot
1047*16467b97STreehugger Robot  def at( index )
1048*16467b97STreehugger Robot    @position == -1 and fill_buffer
1049*16467b97STreehugger Robot    @nodes.at( index )
1050*16467b97STreehugger Robot  end
1051*16467b97STreehugger Robot
1052*16467b97STreehugger Robot  def look( k = 1 )
1053*16467b97STreehugger Robot    @position == -1 and fill_buffer
1054*16467b97STreehugger Robot    k == 0 and return nil
1055*16467b97STreehugger Robot    k < 0 and return self.look_behind( -k )
1056*16467b97STreehugger Robot
1057*16467b97STreehugger Robot    absolute = @position + k - 1
1058*16467b97STreehugger Robot    @nodes.fetch( absolute, @eof )
1059*16467b97STreehugger Robot  end
1060*16467b97STreehugger Robot
1061*16467b97STreehugger Robot  def current_symbol
1062*16467b97STreehugger Robot    look
1063*16467b97STreehugger Robot  end
1064*16467b97STreehugger Robot
1065*16467b97STreehugger Robot  def look_behind( k = 1 )
1066*16467b97STreehugger Robot    k == 0 and return nil
1067*16467b97STreehugger Robot    absolute = @position - k
1068*16467b97STreehugger Robot    return( absolute < 0 ? nil : @nodes.fetch( absolute, @eof ) )
1069*16467b97STreehugger Robot  end
1070*16467b97STreehugger Robot
1071*16467b97STreehugger Robot  def tree_source
1072*16467b97STreehugger Robot    @root
1073*16467b97STreehugger Robot  end
1074*16467b97STreehugger Robot
1075*16467b97STreehugger Robot  def source_name
1076*16467b97STreehugger Robot    self.token_stream.source_name
1077*16467b97STreehugger Robot  end
1078*16467b97STreehugger Robot
1079*16467b97STreehugger Robot  def tree_adaptor
1080*16467b97STreehugger Robot    @adaptor
1081*16467b97STreehugger Robot  end
1082*16467b97STreehugger Robot
1083*16467b97STreehugger Robot  def has_unique_navigation_nodes?
1084*16467b97STreehugger Robot    return @unique_navigation_nodes
1085*16467b97STreehugger Robot  end
1086*16467b97STreehugger Robot  attr_writer :unique_navigation_nodes
1087*16467b97STreehugger Robot
1088*16467b97STreehugger Robot  def consume
1089*16467b97STreehugger Robot    @position == -1 and fill_buffer
1090*16467b97STreehugger Robot    node = @nodes.fetch( @position, @eof )
1091*16467b97STreehugger Robot    @position += 1
1092*16467b97STreehugger Robot    return( node )
1093*16467b97STreehugger Robot  end
1094*16467b97STreehugger Robot
1095*16467b97STreehugger Robot  def peek( i = 1 )
1096*16467b97STreehugger Robot    @adaptor.type_of look( i )
1097*16467b97STreehugger Robot  end
1098*16467b97STreehugger Robot
1099*16467b97STreehugger Robot  alias >> peek
1100*16467b97STreehugger Robot  def <<( k )
1101*16467b97STreehugger Robot    self >> -k
1102*16467b97STreehugger Robot  end
1103*16467b97STreehugger Robot
1104*16467b97STreehugger Robot  def mark
1105*16467b97STreehugger Robot    @position == -1 and fill_buffer
1106*16467b97STreehugger Robot    @last_marker = @position
1107*16467b97STreehugger Robot    return @last_marker
1108*16467b97STreehugger Robot  end
1109*16467b97STreehugger Robot
1110*16467b97STreehugger Robot  def release( marker = nil )
1111*16467b97STreehugger Robot    # do nothing?
1112*16467b97STreehugger Robot  end
1113*16467b97STreehugger Robot
1114*16467b97STreehugger Robot  alias index position
1115*16467b97STreehugger Robot
1116*16467b97STreehugger Robot  def rewind( marker = @last_marker, release = true )
1117*16467b97STreehugger Robot    seek( marker )
1118*16467b97STreehugger Robot  end
1119*16467b97STreehugger Robot
1120*16467b97STreehugger Robot  def seek( index )
1121*16467b97STreehugger Robot    @position == -1 and fill_buffer
1122*16467b97STreehugger Robot    @position = index
1123*16467b97STreehugger Robot  end
1124*16467b97STreehugger Robot
1125*16467b97STreehugger Robot  def push( index )
1126*16467b97STreehugger Robot    @calls << @position
1127*16467b97STreehugger Robot    seek( index )
1128*16467b97STreehugger Robot  end
1129*16467b97STreehugger Robot
1130*16467b97STreehugger Robot  def pop
1131*16467b97STreehugger Robot    pos = @calls.pop and seek( pos )
1132*16467b97STreehugger Robot    return pos
1133*16467b97STreehugger Robot  end
1134*16467b97STreehugger Robot
1135*16467b97STreehugger Robot  def reset
1136*16467b97STreehugger Robot    @position = 0
1137*16467b97STreehugger Robot    @last_marker = 0
1138*16467b97STreehugger Robot    @calls = []
1139*16467b97STreehugger Robot  end
1140*16467b97STreehugger Robot
1141*16467b97STreehugger Robot  def replace_children( parent, start, stop, replacement )
1142*16467b97STreehugger Robot    parent and @adaptor.replace_children( parent, start, stop, replacement )
1143*16467b97STreehugger Robot  end
1144*16467b97STreehugger Robot
1145*16467b97STreehugger Robot  def size
1146*16467b97STreehugger Robot    @position == -1 and fill_buffer
1147*16467b97STreehugger Robot    return @nodes.length
1148*16467b97STreehugger Robot  end
1149*16467b97STreehugger Robot
1150*16467b97STreehugger Robot  def inspect
1151*16467b97STreehugger Robot    @position == -1 and fill_buffer
1152*16467b97STreehugger Robot    @nodes.map { |nd| @adaptor.type_name( nd ) }.join( ' ' )
1153*16467b97STreehugger Robot  end
1154*16467b97STreehugger Robot
1155*16467b97STreehugger Robot  def extract_text( start = nil, stop = nil )
1156*16467b97STreehugger Robot    start.nil? || stop.nil? and return nil
1157*16467b97STreehugger Robot    @position == -1 and fill_buffer
1158*16467b97STreehugger Robot
1159*16467b97STreehugger Robot    if @token_stream
1160*16467b97STreehugger Robot      from = @adaptor.token_start_index( start )
1161*16467b97STreehugger Robot      to =
1162*16467b97STreehugger Robot        case @adaptor.type_of( stop )
1163*16467b97STreehugger Robot        when UP then @adaptor.token_stop_index( start )
1164*16467b97STreehugger Robot        when EOF then to = @nodes.length - 2
1165*16467b97STreehugger Robot        else @adaptor.token_stop_index( stop )
1166*16467b97STreehugger Robot        end
1167*16467b97STreehugger Robot      return @token_stream.extract_text( from, to )
1168*16467b97STreehugger Robot    end
1169*16467b97STreehugger Robot
1170*16467b97STreehugger Robot    buffer = ''
1171*16467b97STreehugger Robot    for node in @nodes
1172*16467b97STreehugger Robot      if node == start ... node == stop  # <-- hey look, it's the flip flop operator
1173*16467b97STreehugger Robot        buffer << @adaptor.text_of( node ) #|| ' ' << @adaptor.type_of( node ).to_s )
1174*16467b97STreehugger Robot      end
1175*16467b97STreehugger Robot    end
1176*16467b97STreehugger Robot    return( buffer )
1177*16467b97STreehugger Robot  end
1178*16467b97STreehugger Robot
1179*16467b97STreehugger Robot  def each
1180*16467b97STreehugger Robot    @position == -1 and fill_buffer
1181*16467b97STreehugger Robot    block_given? or return enum_for( :each )
1182*16467b97STreehugger Robot    for node in @nodes do yield( node ) end
1183*16467b97STreehugger Robot    self
1184*16467b97STreehugger Robot  end
1185*16467b97STreehugger Robot
1186*16467b97STreehugger Robot  include Enumerable
1187*16467b97STreehugger Robot
1188*16467b97STreehugger Robot  def to_a
1189*16467b97STreehugger Robot    return @nodes.dup
1190*16467b97STreehugger Robot  end
1191*16467b97STreehugger Robot
1192*16467b97STreehugger Robot  def extract_text( start = nil, stop = nil )
1193*16467b97STreehugger Robot    @position == -1 and fill_buffer
1194*16467b97STreehugger Robot    start ||= @nodes.first
1195*16467b97STreehugger Robot    stop  ||= @nodes.last
1196*16467b97STreehugger Robot
1197*16467b97STreehugger Robot    if @token_stream
1198*16467b97STreehugger Robot      case @adaptor.type_of( stop )
1199*16467b97STreehugger Robot      when UP
1200*16467b97STreehugger Robot        stop_index = @adaptor.token_stop_index( start )
1201*16467b97STreehugger Robot      when EOF
1202*16467b97STreehugger Robot        return extract_text( start, @nodes[ - 2 ] )
1203*16467b97STreehugger Robot      else
1204*16467b97STreehugger Robot        stop_index = @adaptor.token_stop_index( stop )
1205*16467b97STreehugger Robot      end
1206*16467b97STreehugger Robot
1207*16467b97STreehugger Robot      start_index = @adaptor.token_start_index( start )
1208*16467b97STreehugger Robot      return @token_stream.extract_text( start_index, stop_index )
1209*16467b97STreehugger Robot    else
1210*16467b97STreehugger Robot      start_index = @nodes.index( start ) || @nodes.length
1211*16467b97STreehugger Robot      stop_index  = @nodes.index( stop )  || @nodes.length
1212*16467b97STreehugger Robot      return(
1213*16467b97STreehugger Robot        @nodes[ start_index .. stop_index ].map do | n |
1214*16467b97STreehugger Robot          @adaptor.text_of( n ) or " " + @adaptor.type_of( n ).to_s
1215*16467b97STreehugger Robot        end.join( '' )
1216*16467b97STreehugger Robot      )
1217*16467b97STreehugger Robot    end
1218*16467b97STreehugger Robot  end
1219*16467b97STreehugger Robot
1220*16467b97STreehugger Robot  alias to_s extract_text
1221*16467b97STreehugger Robot
1222*16467b97STreehugger Robot#private
1223*16467b97STreehugger Robot#
1224*16467b97STreehugger Robot#  def linear_node_index( node )
1225*16467b97STreehugger Robot#    @position == -1 and fill_buffer
1226*16467b97STreehugger Robot#    @nodes.each_with_index do |n, i|
1227*16467b97STreehugger Robot#      node == n and return(i)
1228*16467b97STreehugger Robot#    end
1229*16467b97STreehugger Robot#    return -1
1230*16467b97STreehugger Robot#  end
1231*16467b97STreehugger Robotend
1232*16467b97STreehugger Robot
1233*16467b97STreehugger Robot=begin rdoc ANTLR3::AST::RewriteRuleElementStream
1234*16467b97STreehugger Robot
1235*16467b97STreehugger RobotSpecial type of stream that is used internally by tree-building and tree-
1236*16467b97STreehugger Robotrewriting parsers.
1237*16467b97STreehugger Robot
1238*16467b97STreehugger Robot=end
1239*16467b97STreehugger Robot
1240*16467b97STreehugger Robotclass RewriteRuleElementStream # < Array
1241*16467b97STreehugger Robot  extend ClassMacros
1242*16467b97STreehugger Robot  include Error
1243*16467b97STreehugger Robot
1244*16467b97STreehugger Robot  def initialize( adaptor, element_description, elements = nil )
1245*16467b97STreehugger Robot    @cursor = 0
1246*16467b97STreehugger Robot    @single_element = nil
1247*16467b97STreehugger Robot    @elements = nil
1248*16467b97STreehugger Robot    @dirty = false
1249*16467b97STreehugger Robot    @element_description = element_description
1250*16467b97STreehugger Robot    @adaptor = adaptor
1251*16467b97STreehugger Robot    if elements.instance_of?( Array )
1252*16467b97STreehugger Robot      @elements = elements
1253*16467b97STreehugger Robot    else
1254*16467b97STreehugger Robot      add( elements )
1255*16467b97STreehugger Robot    end
1256*16467b97STreehugger Robot  end
1257*16467b97STreehugger Robot
1258*16467b97STreehugger Robot  def reset
1259*16467b97STreehugger Robot    @cursor = 0
1260*16467b97STreehugger Robot    @dirty = true
1261*16467b97STreehugger Robot  end
1262*16467b97STreehugger Robot
1263*16467b97STreehugger Robot  def add( el )
1264*16467b97STreehugger Robot    return( nil ) unless el
1265*16467b97STreehugger Robot    case
1266*16467b97STreehugger Robot    when ! el then return( nil )
1267*16467b97STreehugger Robot    when @elements then @elements << el
1268*16467b97STreehugger Robot    when @single_element.nil? then @single_element = el
1269*16467b97STreehugger Robot    else
1270*16467b97STreehugger Robot      @elements = [ @single_element, el ]
1271*16467b97STreehugger Robot      @single_element = nil
1272*16467b97STreehugger Robot      return( @elements )
1273*16467b97STreehugger Robot    end
1274*16467b97STreehugger Robot  end
1275*16467b97STreehugger Robot
1276*16467b97STreehugger Robot  def next_tree
1277*16467b97STreehugger Robot    if @dirty or @cursor >= length && length == 1
1278*16467b97STreehugger Robot      return dup( __next__ )
1279*16467b97STreehugger Robot    end
1280*16467b97STreehugger Robot    __next__
1281*16467b97STreehugger Robot  end
1282*16467b97STreehugger Robot
1283*16467b97STreehugger Robot  abstract :dup
1284*16467b97STreehugger Robot
1285*16467b97STreehugger Robot  def to_tree( el )
1286*16467b97STreehugger Robot    return el
1287*16467b97STreehugger Robot  end
1288*16467b97STreehugger Robot
1289*16467b97STreehugger Robot  def has_next?
1290*16467b97STreehugger Robot    return( @single_element && @cursor < 1 or
1291*16467b97STreehugger Robot           @elements && @cursor < @elements.length )
1292*16467b97STreehugger Robot  end
1293*16467b97STreehugger Robot
1294*16467b97STreehugger Robot  def size
1295*16467b97STreehugger Robot    @single_element and return 1
1296*16467b97STreehugger Robot    @elements and return @elements.length
1297*16467b97STreehugger Robot    return 0
1298*16467b97STreehugger Robot  end
1299*16467b97STreehugger Robot
1300*16467b97STreehugger Robot  alias length size
1301*16467b97STreehugger Robot
1302*16467b97STreehugger Robotprivate
1303*16467b97STreehugger Robot
1304*16467b97STreehugger Robot  def __next__
1305*16467b97STreehugger Robot    l = length
1306*16467b97STreehugger Robot    case
1307*16467b97STreehugger Robot    when l.zero?
1308*16467b97STreehugger Robot      raise Error::RewriteEmptyStream.new( @element_description )
1309*16467b97STreehugger Robot    when @cursor >= l
1310*16467b97STreehugger Robot      l == 1 and return to_tree( @single_element )
1311*16467b97STreehugger Robot      raise RewriteCardinalityError.new( @element_description )
1312*16467b97STreehugger Robot    when @single_element
1313*16467b97STreehugger Robot      @cursor += 1
1314*16467b97STreehugger Robot      return( to_tree( @single_element ) )
1315*16467b97STreehugger Robot    else
1316*16467b97STreehugger Robot      out = to_tree( @elements.at( @cursor ) )
1317*16467b97STreehugger Robot      @cursor += 1
1318*16467b97STreehugger Robot      return( out )
1319*16467b97STreehugger Robot    end
1320*16467b97STreehugger Robot  end
1321*16467b97STreehugger Robotend
1322*16467b97STreehugger Robot
1323*16467b97STreehugger Robot
1324*16467b97STreehugger Robot=begin rdoc ANTLR3::AST::RewriteRuleTokenStream
1325*16467b97STreehugger Robot
1326*16467b97STreehugger RobotSpecial type of stream that is used internally by tree-building and tree-
1327*16467b97STreehugger Robotrewriting parsers.
1328*16467b97STreehugger Robot
1329*16467b97STreehugger Robot=end
1330*16467b97STreehugger Robotclass RewriteRuleTokenStream < RewriteRuleElementStream
1331*16467b97STreehugger Robot  def next_node
1332*16467b97STreehugger Robot    return @adaptor.create_with_payload( __next__ )
1333*16467b97STreehugger Robot  end
1334*16467b97STreehugger Robot
1335*16467b97STreehugger Robot  alias :next :__next__
1336*16467b97STreehugger Robot  public :next
1337*16467b97STreehugger Robot
1338*16467b97STreehugger Robot  def dup( el )
1339*16467b97STreehugger Robot    raise TypeError, "dup can't be called for a token stream"
1340*16467b97STreehugger Robot  end
1341*16467b97STreehugger Robotend
1342*16467b97STreehugger Robot
1343*16467b97STreehugger Robot=begin rdoc ANTLR3::AST::RewriteRuleSubtreeStream
1344*16467b97STreehugger Robot
1345*16467b97STreehugger RobotSpecial type of stream that is used internally by tree-building and tree-
1346*16467b97STreehugger Robotrewriting parsers.
1347*16467b97STreehugger Robot
1348*16467b97STreehugger Robot=end
1349*16467b97STreehugger Robot
1350*16467b97STreehugger Robotclass RewriteRuleSubtreeStream < RewriteRuleElementStream
1351*16467b97STreehugger Robot  def next_node
1352*16467b97STreehugger Robot    if @dirty or @cursor >= length && length == 1
1353*16467b97STreehugger Robot      return @adaptor.copy_node( __next__ )
1354*16467b97STreehugger Robot    end
1355*16467b97STreehugger Robot    return __next__
1356*16467b97STreehugger Robot  end
1357*16467b97STreehugger Robot
1358*16467b97STreehugger Robot  def dup( el )
1359*16467b97STreehugger Robot    @adaptor.copy_tree( el )
1360*16467b97STreehugger Robot  end
1361*16467b97STreehugger Robotend
1362*16467b97STreehugger Robot
1363*16467b97STreehugger Robot=begin rdoc ANTLR3::AST::RewriteRuleNodeStream
1364*16467b97STreehugger Robot
1365*16467b97STreehugger RobotSpecial type of stream that is used internally by tree-building and tree-
1366*16467b97STreehugger Robotrewriting parsers.
1367*16467b97STreehugger Robot
1368*16467b97STreehugger Robot=end
1369*16467b97STreehugger Robot
1370*16467b97STreehugger Robotclass RewriteRuleNodeStream < RewriteRuleElementStream
1371*16467b97STreehugger Robot  alias next_node __next__
1372*16467b97STreehugger Robot  public :next_node
1373*16467b97STreehugger Robot  def to_tree( el )
1374*16467b97STreehugger Robot    @adaptor.copy_node( el )
1375*16467b97STreehugger Robot  end
1376*16467b97STreehugger Robot
1377*16467b97STreehugger Robot  def dup( el )
1378*16467b97STreehugger Robot    raise TypeError, "dup can't be called for a node stream"
1379*16467b97STreehugger Robot  end
1380*16467b97STreehugger Robotend
1381*16467b97STreehugger Robotend
1382*16467b97STreehugger Robot
1383*16467b97STreehugger Robotinclude AST
1384*16467b97STreehugger Robotend
1385