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