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