1324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver#!/usr/bin/ruby
2324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver# encoding: utf-8
3324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
4324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=begin LICENSE
5324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
6324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver[The "BSD licence"]
7324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverCopyright (c) 2009-2010 Kyle Yetter
8324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverAll rights reserved.
9324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
10324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverRedistribution and use in source and binary forms, with or without
11324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvermodification, are permitted provided that the following conditions
12324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverare met:
13324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
14324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1. Redistributions of source code must retain the above copyright
15324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    notice, this list of conditions and the following disclaimer.
16324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 2. Redistributions in binary form must reproduce the above copyright
17324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    notice, this list of conditions and the following disclaimer in the
18324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    documentation and/or other materials provided with the distribution.
19324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 3. The name of the author may not be used to endorse or promote products
20324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    derived from this software without specific prior written permission.
21324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
22324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverTHIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverIN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverINCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverNOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverTHIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
33324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=end
34324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
35324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverrequire 'antlr3'
36324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
37324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvermodule ANTLR3
38324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvermodule AST
39324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
40324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=begin rdoc ANTLR3::AST::Wizard
41324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
42324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverAST::Wizard is an extra utility class that allows quick creation of AST objects
43324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverusing definitions writing in ANTLR-style tree definition syntax. It can also
44324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverdefine <i>tree patterns</i>, objects that are conceptually similar to regular
45324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverexpressions. Patterns allow a simple method for recursively searching through an
46324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverAST for a particular node structure. These features make tree wizards useful
47324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverwhile testing and debugging AST constructing parsers and tree parsers. This
48324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverlibrary has been ported to Ruby directly from the ANTLR Python runtime API.
49324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
50324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverSee
51324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverhttp://www.antlr.org/wiki/display/~admin/2007/07/02/Exploring+Concept+of+TreeWizard
52324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverfor more background on the concept of a tree wizard.
53324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
54324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver== Usage
55324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
56324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # setting up and creating a tree wizard
57324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  token_names = Array.new(4, '') + %w(VAR NUMBER EQ PLUS MINUS MULT DIV)
58324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  adaptor     = ANTLR3::AST::CommonTreeAdaptor.new
59324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  wizard      = ANTLR3::AST::Wizard.new(adaptor, token_names)
60324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
61324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # building trees
62324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  lone_node = wizard.create "VAR[x]"   # => x
63324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  lone_node.type                       # => 4  # = VAR
64324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  lone_node.text                       # => "x"
65324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
66324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  expression_node = wizard.create "(MINUS VAR NUMBER)"
67324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    # => (MINUS VAR NUMBER)
68324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  statement_node = wizard.create "(EQ[=] VAR[x] (PLUS[+] NUMBER[1] NUMBER[2]))" 
69324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    # => (= x (+ 1 2))
70324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  deep_node = wizard.create(<<-TREE)
71324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    (MULT[*] NUMBER[1] 
72324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      (MINUS[-] 
73324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        (MULT[*] NUMBER[3]    VAR[x])
74324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        (DIV[/]  VAR[y] NUMBER[3.14])
75324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        (MULT[*] NUMBER[4]    VAR[z])
76324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      )
77324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    )
78324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  TREE
79324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    # => (* 1 (- (* 3 x) (/ y 3.14) (* 4 z))
80324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
81324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  bad_tree_syntax = wizard.create "(+ 1 2)"
82324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    # => nil - invalid node names
83324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
84324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # test whether a tree matches a pattern
85324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  wizard.match(expression_node, '(MINUS VAR .)') # => true
86324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  wizard.match(lone_node, 'NUMBER NUMBER')       # => false
87324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
88324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # extract nodes matching a pattern
89324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  wizard.find(statement_node, '(PLUS . .)')
90324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # => [(+ 1 2)]
91324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  wizard.find(deep_node, 4)  # where 4 is the value of type VAR
92324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # => [x, y, z]
93324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
94324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  # iterate through the tree and extract nodes with pattern labels
95324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  wizard.visit(deep_node, '(MULT %n:NUMBER %v:.)') do |node, parent, local_index, labels|
96324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    printf "n = %p\n, v = %p\n", labels['n'], labels['v']
97324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
98324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    # => prints out:
99324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    # n = 3, v = x
100324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    # n = 4, v = z
101324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
102324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver== Tree Construction Syntax
103324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
104324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  Simple Token Node:     TK
105324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  Token Node With Text:  TK[text]
106324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  Flat Node List:        (nil TK1 TK2)
107324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  General Node:          (RT TK1 TK2)
108324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  Complex Nested Node:   (RT (SUB1[sometext] TK1) TK2 (SUB2 TK3 TK4[moretext]))
109324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
110324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=== Additional Syntax for Tree Matching Patterns
111324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
112324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  Match Any Token Node:  .
113324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  Label a Node:          %name:TK
114324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
115324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=end
116324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
117324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverclass Wizard
118324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
119324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  include Constants
120324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  include Util
121324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
122324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=begin rdoc ANTLR3::AST::Wizard::PatternLexer
123324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
124324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverA class that is used internally by AST::Wizard to tokenize tree patterns
125324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
126324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=end
127324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
128324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  class PatternLexer
129324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    include ANTLR3::Constants
130324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
131324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    autoload :StringScanner, 'strscan'
132324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
133324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    PATTERNS = [ 
134324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      [ :space, /\s+/ ],
135324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      [ :identifier, /[a-z_]\w*/i ],
136324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      [ :open, /\(/ ],
137324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      [ :close, /\)/ ],
138324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      [ :percent, /%/ ],
139324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      [ :colon, /:/ ],
140324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      [ :dot, /\./ ],
141324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      [ :argument, /\[((?:[^\[\]\\]|\\\[|\\\]|\\.)*?)\]/ ]
142324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    ]
143324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
144324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    attr_reader :text, :error, :pattern
145324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def initialize( pattern )
146324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @pattern = pattern.to_s
147324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @scanner = StringScanner.new( pattern )
148324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @text = ''
149324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @error = false
150324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
151324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
152324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def next_token
153324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      begin
154324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        @scanner.eos? and return EOF
155324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        
156324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        type, = PATTERNS.find do |type, pattern|
157324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          @scanner.scan( pattern )
158324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        end
159324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        
160324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        case type
161324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        when nil
162324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          type, @text, @error = EOF, '', true
163324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          break
164324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        when :identifier then @text = @scanner.matched
165324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        when :argument
166324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          # remove escapes from \] sequences in the text argument
167324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          ( @text = @scanner[ 1 ] ).gsub!( /\\(?=[\[\]])/, '' )
168324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        end
169324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      end while type == :space
170324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      
171324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      return type
172324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
173324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
174324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    alias error? error
175324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
176324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
177324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
178324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=begin rdoc ANTLR3::AST::Wizard::Pattern
179324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
180324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverA class that is used internally by AST::Wizard to construct AST tree objects
181324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverfrom a tokenized tree pattern
182324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
183324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=end
184324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
185324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  class PatternParser
186324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def self.parse( pattern, token_scheme, adaptor )
187324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      lexer = PatternLexer.new( pattern )
188324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      new( lexer, token_scheme, adaptor ).pattern
189324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
190324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
191324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    include ANTLR3::Constants
192324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
193324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def initialize( tokenizer, token_scheme, adaptor )
194324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @tokenizer = tokenizer
195324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @token_scheme = token_scheme
196324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @adaptor   = adaptor
197324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @token_type = tokenizer.next_token
198324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
199324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
200324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def pattern
201324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      case @token_type
202324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      when :open then return parse_tree
203324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      when :identifier
204324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        node = parse_node
205324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        @token_type == EOF and return node
206324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return nil
207324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      end
208324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      return nil
209324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
210324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
211324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    CONTINUE_TYPES = [ :open, :identifier, :percent, :dot ]
212324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
213324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def parse_tree
214324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @token_type != :open and return nil
215324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @token_type = @tokenizer.next_token
216324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      root = parse_node or return nil
217324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      
218324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      loop do
219324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        case @token_type
220324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        when :open
221324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          subtree = parse_tree
222324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          @adaptor.add_child( root, subtree )
223324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        when :identifier, :percent, :dot
224324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          child = parse_node or return nil
225324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          @adaptor.add_child( root, child )
226324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        else break
227324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        end
228324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      end
229324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @token_type == :close or return nil
230324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @token_type = @tokenizer.next_token
231324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      return root
232324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
233324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
234324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def parse_node
235324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      label = nil
236324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      if @token_type == :percent
237324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        ( @token_type = @tokenizer.next_token ) == :identifier or return nil
238324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        label = @tokenizer.text
239324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        ( @token_type = @tokenizer.next_token ) == :colon or return nil
240324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        @token_type = @tokenizer.next_token
241324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      end
242324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      
243324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      if @token_type == :dot
244324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        @token_type = @tokenizer.next_token
245324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        wildcard_payload = CommonToken.create( :type => 0, :text => '.' )
246324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        node = WildcardPattern.new( wildcard_payload )
247324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        label and node.label = label
248324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return node
249324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      end
250324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      
251324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @token_type == :identifier or return nil
252324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      token_name = @tokenizer.text
253324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @token_type = @tokenizer.next_token
254324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      token_name == 'nil' and return @adaptor.create_flat_list
255324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      
256324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      text = token_name
257324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      arg = nil
258324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      if @token_type == :argument
259324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        arg = @tokenizer.text
260324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        text = arg
261324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        @token_type = @tokenizer.next_token
262324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      end
263324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      
264324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      node_type = @token_scheme[ token_name ] || INVALID_TOKEN_TYPE
265324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      node = @adaptor.create_from_type( node_type, text )
266324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      
267324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      if Pattern === node
268324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        node.label, node.has_text_arg = label, arg
269324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      end
270324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      return node
271324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
272324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
273324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
274324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
275324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=begin rdoc ANTLR3::AST::Wizard::Pattern
276324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
277324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverA simple tree class that represents the skeletal structure of tree. It is used
278324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverto validate tree structures as well as to extract nodes that match the pattern.
279324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
280324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=end
281324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
282324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  class Pattern < CommonTree
283324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def self.parse( pattern_str, scheme )
284324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      PatternParser.parse( 
285324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        pattern_str, scheme, PatternAdaptor.new( scheme.token_class )
286324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      )
287324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
288324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
289324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    attr_accessor :label, :has_text_arg
290324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    alias :has_text_arg? :has_text_arg
291324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
292324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def initialize( payload )
293324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      super( payload )
294324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @label = nil
295324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @has_text_arg = nil
296324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
297324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
298324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def to_s
299324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      prefix = @label ? '%' << @label << ':' : ''
300324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      return( prefix << super )
301324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
302324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
303324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
304324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=begin rdoc ANTLR3::AST::Wizard::WildcardPattern
305324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
306324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverA simple tree node used to represent the operation "match any tree node type" in
307324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvera tree pattern. They are represented by '.' in tree pattern specifications.
308324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
309324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=end
310324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
311324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  class WildcardPattern < Pattern; end
312324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
313324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
314324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=begin rdoc ANTLR3::AST::Wizard::PatternAdaptor
315324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
316324c4644fee44b9898524c09511bd33c3f12e2dfBen GruverA customized TreeAdaptor used by AST::Wizards to build tree patterns.
317324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
318324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver=end
319324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
320324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  class PatternAdaptor < CommonTreeAdaptor
321324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    def create_with_payload( payload )
322324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      return Pattern.new( payload )
323324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
324324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
325324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
326324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  attr_accessor :token_scheme, :adaptor
327324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
328324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def initialize( options = {} )
329324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @token_scheme = options.fetch( :token_scheme ) do
330324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      TokenScheme.build( options[ :token_class ], options[ :tokens ] )
331324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
332324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @adaptor = options.fetch( :adaptor ) do
333324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      CommonTreeAdaptor.new( @token_scheme.token_class )
334324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
335324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
336324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
337324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def create( pattern )
338324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    PatternParser.parse( pattern, @token_scheme, @adaptor )
339324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
340324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
341324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def index( tree, map = {} )
342324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    tree or return( map )
343324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    type = @adaptor.type_of( tree )
344324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    elements = map[ type ] ||= []
345324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    elements << tree
346324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @adaptor.each_child( tree ) { | child | index( child, map ) }
347324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return( map )
348324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
349324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
350324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def find( tree, what )
351324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    case what
352324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    when Integer then find_token_type( tree, what )
353324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    when String  then find_pattern( tree, what )
354324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    when Symbol  then find_token_type( tree, @token_scheme[ what ] )
355324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    else raise ArgumentError, "search subject must be a token type (integer) or a string"
356324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
357324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
358324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
359324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def find_token_type( tree, type )
360324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    nodes = []
361324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    visit( tree, type ) { | t, | nodes << t }
362324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return nodes
363324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
364324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
365324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def find_pattern( tree, pattern )
366324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    subtrees = []
367324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    visit_pattern( tree, pattern ) { | t, | subtrees << t }
368324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return( subtrees )
369324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
370324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
371324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def visit( tree, what = nil, &block )
372324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    block_given? or return enum_for( :visit, tree, what )
373324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    Symbol === what and what = @token_scheme[ what ]
374324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    case what
375324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    when nil then visit_all( tree, &block )
376324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    when Integer then visit_type( tree, nil, what, &block )
377324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    when String  then visit_pattern( tree, what, &block )
378324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    else raise( ArgumentError, tidy( <<-'END', true ) )
379324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      | The 'what' filter argument must be a tree
380324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      | pattern (String) or a token type (Integer)
381324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      | -- got #{ what.inspect }
382324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      END
383324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
384324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
385324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
386324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def visit_all( tree, parent = nil, &block )
387324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    index = @adaptor.child_index( tree )
388324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    yield( tree, parent, index, nil )
389324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @adaptor.each_child( tree ) do | child |
390324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      visit_all( child, tree, &block )
391324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
392324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
393324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
394324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def visit_type( tree, parent, type, &block )
395324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    tree.nil? and return( nil )
396324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    index = @adaptor.child_index( tree )
397324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @adaptor.type_of( tree ) == type and yield( tree, parent, index, nil )
398324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    @adaptor.each_child( tree ) do | child |
399324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      visit_type( child, tree, type, &block )
400324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
401324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
402324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
403324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def visit_pattern( tree, pattern, &block )
404324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    pattern = Pattern.parse( pattern, @token_scheme )
405324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
406324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    if pattern.nil? or pattern.flat_list? or pattern.is_a?( WildcardPattern )
407324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      return( nil )
408324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
409324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
410324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    visit( tree, pattern.type ) do | tree, parent, child_index, labels |
411324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      labels = match!( tree, pattern ) and
412324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        yield( tree, parent, child_index, labels )
413324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
414324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
415324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
416324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def match( tree, pattern )
417324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    pattern = Pattern.parse( pattern, @token_scheme )
418324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
419324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return( match!( tree, pattern ) )
420324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
421324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
422324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def match!( tree, pattern, labels = {} )
423324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    tree.nil? || pattern.nil? and return false
424324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    unless pattern.is_a? WildcardPattern
425324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @adaptor.type_of( tree ) == pattern.type or return false
426324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      pattern.has_text_arg && ( @adaptor.text_of( tree ) != pattern.text ) and
427324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        return false
428324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
429324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    labels[ pattern.label ] = tree if labels && pattern.label
430324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
431324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    number_of_children = @adaptor.child_count( tree )
432324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return false unless number_of_children == pattern.child_count
433324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
434324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    number_of_children.times do |index|
435324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      actual_child = @adaptor.child_of( tree, index )
436324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      pattern_child = pattern.child( index )
437324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      
438324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      return( false ) unless match!( actual_child, pattern_child, labels )
439324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
440324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
441324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return labels
442324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
443324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
444324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def equals( tree_a, tree_b, adaptor = @adaptor )
445324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    tree_a && tree_b or return( false )
446324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
447324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    adaptor.type_of( tree_a ) == adaptor.type_of( tree_b ) or return false
448324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    adaptor.text_of( tree_a ) == adaptor.text_of( tree_b ) or return false
449324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
450324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    child_count_a = adaptor.child_count( tree_a )
451324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    child_count_b = adaptor.child_count( tree_b )
452324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    child_count_a == child_count_b or return false
453324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
454324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    child_count_a.times do | i |
455324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      child_a = adaptor.child_of( tree_a, i )
456324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      child_b = adaptor.child_of( tree_b, i )
457324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      equals( child_a, child_b, adaptor ) or return false
458324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
459324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return true
460324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
461324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
462324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
463324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  DOT_DOT_PATTERN = /.*[^\.]\\.{2}[^\.].*/
464324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  DOUBLE_ETC_PATTERN = /.*\.{3}\s+\.{3}.*/
465324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
466324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  def in_context?( tree, context )
467324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    case context
468324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    when DOT_DOT_PATTERN then raise ArgumentError, "invalid syntax: .."
469324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    when DOUBLE_ETC_PATTERN then raise ArgumentError, "invalid syntax: ... ..."
470324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
471324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
472324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    context = context.gsub( /([^\.\s])\.{3}([^\.])/, '\1 ... \2' )
473324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    context.strip!
474324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    nodes = context.split( /\s+/ )
475324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
476324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    while tree = @adaptor.parent( tree ) and node = nodes.pop
477324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      if node == '...'
478324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        node = nodes.pop or return( true )
479324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        tree = @adaptor.each_ancestor( tree ).find do | t |
480324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver          @adaptor.type_name( t ) == node
481324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        end or return( false )
482324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      end
483324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver      @adaptor.type_name( tree ) == node or return( false )
484324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    end
485324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    
486324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return( false ) if tree.nil? and not nodes.empty?
487324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    return true
488324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  end
489324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  
490324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver  private :match!
491324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend
492324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend
493324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverend
494