antlr3 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. data/ANTLR-LICENSE.txt +26 -0
  2. data/History.txt +66 -0
  3. data/README.txt +139 -0
  4. data/bin/antlr4ruby +33 -0
  5. data/java/RubyTarget.java +524 -0
  6. data/java/antlr-full-3.2.1.jar +0 -0
  7. data/lib/antlr3.rb +176 -0
  8. data/lib/antlr3/constants.rb +88 -0
  9. data/lib/antlr3/debug.rb +701 -0
  10. data/lib/antlr3/debug/event-hub.rb +210 -0
  11. data/lib/antlr3/debug/record-event-listener.rb +25 -0
  12. data/lib/antlr3/debug/rule-tracer.rb +55 -0
  13. data/lib/antlr3/debug/socket.rb +360 -0
  14. data/lib/antlr3/debug/trace-event-listener.rb +92 -0
  15. data/lib/antlr3/dfa.rb +247 -0
  16. data/lib/antlr3/dot.rb +174 -0
  17. data/lib/antlr3/error.rb +657 -0
  18. data/lib/antlr3/main.rb +561 -0
  19. data/lib/antlr3/modes/ast-builder.rb +41 -0
  20. data/lib/antlr3/modes/filter.rb +56 -0
  21. data/lib/antlr3/profile.rb +322 -0
  22. data/lib/antlr3/recognizers.rb +1280 -0
  23. data/lib/antlr3/streams.rb +985 -0
  24. data/lib/antlr3/streams/interactive.rb +91 -0
  25. data/lib/antlr3/streams/rewrite.rb +412 -0
  26. data/lib/antlr3/test/call-stack.rb +57 -0
  27. data/lib/antlr3/test/config.rb +23 -0
  28. data/lib/antlr3/test/core-extensions.rb +269 -0
  29. data/lib/antlr3/test/diff.rb +165 -0
  30. data/lib/antlr3/test/functional.rb +207 -0
  31. data/lib/antlr3/test/grammar.rb +371 -0
  32. data/lib/antlr3/token.rb +592 -0
  33. data/lib/antlr3/tree.rb +1415 -0
  34. data/lib/antlr3/tree/debug.rb +163 -0
  35. data/lib/antlr3/tree/visitor.rb +84 -0
  36. data/lib/antlr3/tree/wizard.rb +481 -0
  37. data/lib/antlr3/util.rb +149 -0
  38. data/lib/antlr3/version.rb +27 -0
  39. data/samples/ANTLRv3Grammar.g +621 -0
  40. data/samples/Cpp.g +749 -0
  41. data/templates/AST.stg +335 -0
  42. data/templates/ASTDbg.stg +40 -0
  43. data/templates/ASTParser.stg +153 -0
  44. data/templates/ASTTreeParser.stg +272 -0
  45. data/templates/Dbg.stg +192 -0
  46. data/templates/Ruby.stg +1514 -0
  47. data/test/functional/ast-output/auto-ast.rb +797 -0
  48. data/test/functional/ast-output/construction.rb +555 -0
  49. data/test/functional/ast-output/hetero-nodes.rb +753 -0
  50. data/test/functional/ast-output/rewrites.rb +1327 -0
  51. data/test/functional/ast-output/tree-rewrite.rb +1662 -0
  52. data/test/functional/debugging/debug-mode.rb +689 -0
  53. data/test/functional/debugging/profile-mode.rb +165 -0
  54. data/test/functional/debugging/rule-tracing.rb +74 -0
  55. data/test/functional/delegation/import.rb +379 -0
  56. data/test/functional/lexer/basic.rb +559 -0
  57. data/test/functional/lexer/filter-mode.rb +245 -0
  58. data/test/functional/lexer/nuances.rb +47 -0
  59. data/test/functional/lexer/properties.rb +104 -0
  60. data/test/functional/lexer/syn-pred.rb +32 -0
  61. data/test/functional/lexer/xml.rb +206 -0
  62. data/test/functional/main/main-scripts.rb +245 -0
  63. data/test/functional/parser/actions.rb +224 -0
  64. data/test/functional/parser/backtracking.rb +244 -0
  65. data/test/functional/parser/basic.rb +282 -0
  66. data/test/functional/parser/calc.rb +98 -0
  67. data/test/functional/parser/ll-star.rb +143 -0
  68. data/test/functional/parser/nuances.rb +165 -0
  69. data/test/functional/parser/predicates.rb +103 -0
  70. data/test/functional/parser/properties.rb +242 -0
  71. data/test/functional/parser/rule-methods.rb +132 -0
  72. data/test/functional/parser/scopes.rb +274 -0
  73. data/test/functional/token-rewrite/basic.rb +318 -0
  74. data/test/functional/token-rewrite/via-parser.rb +100 -0
  75. data/test/functional/tree-parser/basic.rb +750 -0
  76. data/test/unit/sample-input/file-stream-1 +2 -0
  77. data/test/unit/sample-input/teststreams.input2 +2 -0
  78. data/test/unit/test-dfa.rb +52 -0
  79. data/test/unit/test-exceptions.rb +44 -0
  80. data/test/unit/test-recognizers.rb +55 -0
  81. data/test/unit/test-scheme.rb +62 -0
  82. data/test/unit/test-streams.rb +459 -0
  83. data/test/unit/test-tree-wizard.rb +535 -0
  84. data/test/unit/test-trees.rb +854 -0
  85. metadata +205 -0
@@ -0,0 +1,163 @@
1
+ #!/usr/bin/ruby
2
+ # encoding: utf-8
3
+
4
+ module ANTLR3
5
+ module Debug
6
+ =begin rdoc ANTLR3::Debug::TreeAdaptor
7
+
8
+ Adds debugging event hooks to TreeAdaptor objects
9
+
10
+ =end
11
+ module TreeAdaptor
12
+ def self.wrap(adaptor, debug_listener = nil)
13
+ adaptor.extend(self)
14
+ adaptor.debug_listener = debug_listener
15
+ return(adaptor)
16
+ end
17
+
18
+ attr_accessor :debug_listener
19
+
20
+ def create_with_payload!(payload)
21
+ node = super
22
+ @debug_listener.create_node(node, payload)
23
+ return node
24
+ end
25
+
26
+ def create_from_token!(token_type, from_token, text = nil)
27
+ node = super
28
+ @debug_listener.create_node(node)
29
+ return node
30
+ end
31
+
32
+ def create_from_type!(token_type, text)
33
+ node = super
34
+ @debug_listener.create_node(node)
35
+ return node
36
+ end
37
+
38
+ def create_error_node!(input, start, stop, exc)
39
+ node = super
40
+ node.nil? or @debug_listener.error_node(node)
41
+ return node
42
+ end
43
+
44
+ def copy_tree(tree)
45
+ t = super
46
+ simulate_tree_construction(t)
47
+ return t
48
+ end
49
+
50
+ def simulate_tree_construction(tree)
51
+ @debug_listener.create_node(tree)
52
+ child_count(tree).times do |i|
53
+ child = self.child_of(tree, i)
54
+ simulate_tree_construction(child)
55
+ @debug_listener.add_child(tree, child)
56
+ end
57
+ end
58
+
59
+ def copy_node(tree_node)
60
+ duplicate = super
61
+ @debug_listener.create_node duplicate
62
+ return duplicate
63
+ end
64
+
65
+ def create_flat_list!
66
+ node = super
67
+ @debug_listener.flat_node(node)
68
+ return node
69
+ end
70
+
71
+ def add_child(tree, child)
72
+ case child
73
+ when Token
74
+ node = create_with_payload!(child)
75
+ add_child(tree, node)
76
+ else
77
+ tree.nil? || child.nil? and return
78
+ super(tree, child)
79
+ @debug_listener.add_child(tree, child)
80
+ end
81
+ end
82
+
83
+ def become_root(new_root, old_root)
84
+ case new_root
85
+ when Token
86
+ n = create_with_payload!(new_root)
87
+ super(n, old_root)
88
+ else
89
+ n = super(new_root, old_root)
90
+ end
91
+ @debug_listener.become_root(new_root, old_root)
92
+ return n
93
+ end
94
+
95
+ def set_token_boundaries(tree, start_token, stop_token)
96
+ super(tree, start_token, stop_token)
97
+ return unless tree && start_token && stop_token
98
+ @debug_listener.set_token_boundaries(tree,
99
+ start_token.token_index, stop_token.token_index)
100
+ end
101
+ end
102
+
103
+ =begin rdoc ANTLR3::Debug::TreeNodeStream
104
+
105
+ A module that wraps token stream methods with debugging event code. A debuggable
106
+ parser will <tt>extend</tt> its input stream with this module if the stream is
107
+ not already a Debug::TreeNodeStream.
108
+
109
+ =end
110
+ class TreeNodeStream
111
+
112
+ def self.wrap(stream, debug_listener = nil)
113
+ stream.extend(self)
114
+ stream.debug_listener ||= debug_listener
115
+ end
116
+ attr_accessor :debug_listener
117
+
118
+ def consume
119
+ node = @input >> 1
120
+ super
121
+ @debug_listener.consume_node(node)
122
+ end
123
+
124
+ def look(i = 1)
125
+ node = super
126
+ id = @adaptor.unique_id(node)
127
+ text = @adaptor.text_of(node)
128
+ type = @adaptor.type_of(node)
129
+ @debug_listener.look(i, node)
130
+ return(node)
131
+ end
132
+
133
+ def peek(i = 1)
134
+ node = self >> 1
135
+ id = @adaptor.unique_id(node)
136
+ text = @adaptor.text_of(node)
137
+ type = @adaptor.type_of(node)
138
+ @debug_listener.look(i, node)
139
+ return(type)
140
+ end
141
+
142
+ def mark
143
+ @last_marker = super
144
+ @debug_listener.mark(@last_marker)
145
+ return(@last_marker)
146
+ end
147
+
148
+ def rewind(marker = nil)
149
+ @debug_listener.rewind(marker)
150
+ super(marker || @last_marker)
151
+ end
152
+
153
+ =begin This actually differs with reset in CommonTreeNodeStream -- why is this one blank?
154
+ def reset
155
+ # do nothing
156
+ end
157
+ =end
158
+
159
+ end
160
+
161
+
162
+ end
163
+ end
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/ruby
2
+ # encoding: utf-8
3
+
4
+ =begin LICENSE
5
+
6
+ [The "BSD licence"]
7
+ Copyright (c) 2009 Kyle Yetter
8
+ All rights reserved.
9
+
10
+ Redistribution and use in source and binary forms, with or without
11
+ modification, are permitted provided that the following conditions
12
+ are met:
13
+
14
+ 1. Redistributions of source code must retain the above copyright
15
+ notice, this list of conditions and the following disclaimer.
16
+ 2. Redistributions in binary form must reproduce the above copyright
17
+ notice, this list of conditions and the following disclaimer in the
18
+ documentation and/or other materials provided with the distribution.
19
+ 3. The name of the author may not be used to endorse or promote products
20
+ derived from this software without specific prior written permission.
21
+
22
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
+
33
+ =end
34
+
35
+ module ANTLR3
36
+ module AST
37
+
38
+ =begin rdoc ANTLR3::AST::Visitor
39
+
40
+ AST::Visitor is an extra utility class for working with tree objects. Visitor
41
+ objects are similar to plain vanilla iterators, but provide two action hooks,
42
+ instead a standard single iteration block. The <tt>visit(tree)</tt> method walks
43
+ through each node of the tree (top-down left-to-right). If +pre_action+ is
44
+ defined, a node is yielded to the block when it has been initially entered. If
45
+ +post_action+ is defined, a node is yielded to the block after all of its
46
+ children have been visited.
47
+
48
+ =end
49
+
50
+ class Visitor
51
+ def initialize(adaptor = nil)
52
+ @adaptor = adaptor || CommonTreeAdaptor.new()
53
+ @pre_action = nil
54
+ @post_action = nil
55
+ block_given? and yield(self)
56
+ end
57
+
58
+ def pre_action(&block)
59
+ block_given? and @pre_action = block
60
+ return @pre_action
61
+ end
62
+
63
+ def post_action(&block)
64
+ block_given? and @post_action = block
65
+ return @post_action
66
+ end
67
+
68
+ def visit(tree, pre_action = nil, post_action = nil)
69
+ flat = @adaptor.flat_list?(tree)
70
+ before = pre_action || @pre_action
71
+ after = post_action || @post_action
72
+
73
+ tree = before.call(tree) unless before.nil? or flat
74
+ @adaptor.child_count(tree).times do |index|
75
+ child = @adaptor.child_of(tree, index)
76
+ visit(child, pre_action, post_action)
77
+ end
78
+ tree = after.call(tree) unless after.nil? or flat
79
+
80
+ return tree
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,481 @@
1
+ #!/usr/bin/ruby
2
+ # encoding: utf-8
3
+
4
+ =begin LICENSE
5
+
6
+ [The "BSD licence"]
7
+ Copyright (c) 2009 Kyle Yetter
8
+ All rights reserved.
9
+
10
+ Redistribution and use in source and binary forms, with or without
11
+ modification, are permitted provided that the following conditions
12
+ are met:
13
+
14
+ 1. Redistributions of source code must retain the above copyright
15
+ notice, this list of conditions and the following disclaimer.
16
+ 2. Redistributions in binary form must reproduce the above copyright
17
+ notice, this list of conditions and the following disclaimer in the
18
+ documentation and/or other materials provided with the distribution.
19
+ 3. The name of the author may not be used to endorse or promote products
20
+ derived from this software without specific prior written permission.
21
+
22
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
+
33
+ =end
34
+
35
+ require 'antlr3'
36
+
37
+ module ANTLR3
38
+ module AST
39
+
40
+ =begin rdoc ANTLR3::AST::Wizard
41
+
42
+ AST::Wizard is an extra utility class that allows quick creation of AST objects
43
+ using definitions writing in ANTLR-style tree definition syntax. It can also
44
+ define <i>tree patterns</i>, objects that are conceptually similar to regular
45
+ expressions. Patterns allow a simple method for recursively searching through an
46
+ AST for a particular node structure. These features make tree wizards useful
47
+ while testing and debugging AST constructing parsers and tree parsers. This
48
+ library has been ported to Ruby directly from the ANTLR Python runtime API.
49
+
50
+ See
51
+ http://www.antlr.org/wiki/display/~admin/2007/07/02/Exploring+Concept+of+TreeWizard
52
+ for more background on the concept of a tree wizard.
53
+
54
+ == Usage
55
+
56
+ # setting up and creating a tree wizard
57
+ token_names = Array.new(4, '') + %w(VAR NUMBER EQ PLUS MINUS MULT DIV)
58
+ adaptor = ANTLR3::AST::CommonTreeAdaptor.new
59
+ wizard = ANTLR3::AST::Wizard.new(adaptor, token_names)
60
+
61
+ # building trees
62
+ lone_node = wizard.create "VAR[x]" # => x
63
+ lone_node.type # => 4 # = VAR
64
+ lone_node.text # => "x"
65
+
66
+ expression_node = wizard.create "(MINUS VAR NUMBER)"
67
+ # => (MINUS VAR NUMBER)
68
+ statement_node = wizard.create "(EQ[=] VAR[x] (PLUS[+] NUMBER[1] NUMBER[2]))"
69
+ # => (= x (+ 1 2))
70
+ deep_node = wizard.create(<<-TREE)
71
+ (MULT[*] NUMBER[1]
72
+ (MINUS[-]
73
+ (MULT[*] NUMBER[3] VAR[x])
74
+ (DIV[/] VAR[y] NUMBER[3.14])
75
+ (MULT[*] NUMBER[4] VAR[z])
76
+ )
77
+ )
78
+ TREE
79
+ # => (* 1 (- (* 3 x) (/ y 3.14) (* 4 z))
80
+
81
+ bad_tree_syntax = wizard.create "(+ 1 2)"
82
+ # => nil - invalid node names
83
+
84
+ # test whether a tree matches a pattern
85
+ wizard.parse(expression_node, '(MINUS VAR .)') # => true
86
+ wizard.parse(lone_node, 'NUMBER NUMBER') # => false
87
+
88
+ # extract nodes matching a pattern
89
+ wizard.find(statement_node, '(PLUS . .)')
90
+ # => [(+ 1 2)]
91
+ wizard.find(deep_node, 4) # where 4 is the value of type VAR
92
+ # => [x, y, z]
93
+
94
+ # iterate through the tree and extract nodes with pattern labels
95
+ wizard.visit(deep_node, '(MULT %n:NUMBER %v:.)') do |node, parent, local_index, labels|
96
+ printf "n = %p\n, v = %p\n", labels['n'], labels['v']
97
+ end
98
+ # => prints out:
99
+ # n = 3, v = x
100
+ # n = 4, v = z
101
+
102
+ == Tree Construction Syntax
103
+
104
+ Simple Token Node: TK
105
+ Token Node With Text: TK[text]
106
+ Flat Node List: (nil TK1 TK2)
107
+ General Node: (RT TK1 TK2)
108
+ Complex Nested Node: (RT (SUB1[sometext] TK1) TK2 (SUB2 TK3 TK4[moretext]))
109
+
110
+ === Additional Syntax for Tree Matching Patterns
111
+
112
+ Match Any Token Node: .
113
+ Label a Node: %name:TK
114
+
115
+ =end
116
+
117
+ class Wizard
118
+
119
+ include ANTLR3::Constants
120
+
121
+ =begin rdoc ANTLR3::AST::Wizard::TreePatternLexer
122
+
123
+ A class that is used internally by AST::Wizard to tokenize tree patterns
124
+
125
+ =end
126
+
127
+ class TreePatternLexer
128
+ include ANTLR3::Constants
129
+
130
+ autoload :StringScanner, 'strscan'
131
+
132
+ PATTERNS = [
133
+ [:space, /\s+/],
134
+ [:identifier, /[a-z_]\w*/i],
135
+ [:open, /\(/],
136
+ [:close, /\)/],
137
+ [:percent, /%/],
138
+ [:colon, /:/],
139
+ [:dot, /\./],
140
+ [:argument, /\[((?:[^\[\]\\]|\\\[|\\\]|\\.)*?)\]/]
141
+ ]
142
+
143
+ attr_reader :text, :error, :pattern
144
+ def initialize(pattern)
145
+ @pattern = pattern.to_s
146
+ @scanner = StringScanner.new(pattern)
147
+ @text = ''
148
+ @error = false
149
+ end
150
+
151
+ def next_token
152
+ begin
153
+ @scanner.eos? and return EOF
154
+
155
+ type, = PATTERNS.find do |type, pattern|
156
+ @scanner.scan(pattern)
157
+ end
158
+
159
+ case type
160
+ when nil
161
+ type, @text, @error = EOF, '', true
162
+ break
163
+ when :identifier then @text = @scanner.matched
164
+ when :argument
165
+ # remove escapes from \] sequences in the text argument
166
+ (@text = @scanner[1]).gsub!(/\\(?=[\[\]])/, '')
167
+ end
168
+ end while type == :space
169
+
170
+ return type
171
+ end
172
+
173
+ alias error? error
174
+ end
175
+
176
+
177
+ =begin rdoc ANTLR3::AST::Wizard::TreePatternParser
178
+
179
+ A class that is used internally by AST::Wizard to construct AST tree objects
180
+ from a tokenized tree pattern
181
+
182
+ =end
183
+
184
+ class TreePatternParser
185
+ include ANTLR3::Constants
186
+
187
+ def initialize(tokenizer, wizard, adaptor)
188
+ @tokenizer = tokenizer
189
+ @wizard = wizard
190
+ @adaptor = adaptor
191
+ @token_type = tokenizer.next_token
192
+ end
193
+
194
+ def pattern
195
+ case @token_type
196
+ when :open then return parse_tree
197
+ when :identifier
198
+ node = parse_node
199
+ @token_type == EOF and return node
200
+ return nil
201
+ end
202
+ return nil
203
+ end
204
+
205
+ CONTINUE_TYPES = [:open, :identifier, :percent, :dot]
206
+
207
+ def parse_tree
208
+ @token_type != :open and return nil
209
+ @token_type = @tokenizer.next_token
210
+ root = parse_node or return nil
211
+
212
+ loop do
213
+ case @token_type
214
+ when :open
215
+ subtree = parse_tree()
216
+ @adaptor.add_child(root, subtree)
217
+ when :identifier, :percent, :dot
218
+ child = parse_node or return nil
219
+ @adaptor.add_child(root, child)
220
+ else break
221
+ end
222
+ end
223
+ @token_type == :close or return nil
224
+ @token_type = @tokenizer.next_token
225
+ return root
226
+ end
227
+
228
+ def parse_node
229
+ label = nil
230
+ if @token_type == :percent
231
+ (@token_type = @tokenizer.next_token) == :identifier or return nil
232
+ label = @tokenizer.text
233
+ (@token_type = @tokenizer.next_token) == :colon or return nil
234
+ @token_type = @tokenizer.next_token
235
+ end
236
+
237
+ if @token_type == :dot
238
+ @token_type = @tokenizer.next_token
239
+ wildcard_payload = CommonToken.create(:type => 0, :text => '.')
240
+ node = WildcardTreePattern.new(wildcard_payload)
241
+ label and node.label = label
242
+ return node
243
+ end
244
+
245
+ @token_type == :identifier or return nil
246
+ token_name = @tokenizer.text
247
+ @token_type = @tokenizer.next_token
248
+ token_name == 'nil' and return @adaptor.create_flat_list!
249
+
250
+ text = token_name
251
+ arg = nil
252
+ if @token_type == :argument
253
+ arg = @tokenizer.text
254
+ text = arg
255
+ @token_type = @tokenizer.next_token
256
+ end
257
+
258
+ tree_node_type = @wizard.token_type(token_name)
259
+ tree_node_type == INVALID_TOKEN_TYPE and return nil
260
+
261
+ node = @adaptor.create_from_type!(tree_node_type, text)
262
+ label && node.is_a?(TreePattern) and node.label = label
263
+ arg && node.is_a?(TreePattern) and node.has_text_arg = true
264
+ return node
265
+ end
266
+ end
267
+
268
+
269
+ =begin rdoc ANTLR3::AST::Wizard::TreePattern
270
+
271
+ A simple tree class that represents the skeletal structure of tree. It is used
272
+ to validate tree structures as well as to extract nodes that match the pattern.
273
+
274
+ =end
275
+
276
+ class TreePattern < CommonTree
277
+ attr_accessor :label, :has_text_arg
278
+ def initialize(payload)
279
+ super(payload)
280
+ @label = nil
281
+ @has_text_arg = nil
282
+ end
283
+
284
+ def to_s
285
+ prefix = @label ? '%' << @label << ':' : ''
286
+ return prefix << super()
287
+ end
288
+
289
+ end
290
+
291
+ =begin rdoc ANTLR3::AST::Wizard::WildcardTreePattern
292
+
293
+ A simple tree node used to represent the operation "match any tree node type" in
294
+ a tree pattern. They are represented by '.' in tree pattern specifications.
295
+
296
+ =end
297
+
298
+ class WildcardTreePattern < TreePattern; end
299
+
300
+
301
+ =begin rdoc ANTLR3::AST::Wizard::TreePatternTreeAdaptor
302
+
303
+ A customized TreeAdaptor used by AST::Wizards to build tree patterns.
304
+
305
+ =end
306
+
307
+ class TreePatternTreeAdaptor < CommonTreeAdaptor
308
+ def create_with_payload!(payload)
309
+ return TreePattern.new(payload)
310
+ end
311
+ end
312
+
313
+ attr_accessor :token_name_to_type_map, :adaptor
314
+
315
+ def initialize(adaptor = CommonTreeAdaptor.new, token_names_or_type_map = {})
316
+ @adaptor = adaptor
317
+ @token_name_to_type_map =
318
+ case token_names_or_type_map
319
+ when Array, nil then compute_token_types(token_names_or_type_map)
320
+ else token_names_or_type_map
321
+ end
322
+ end
323
+
324
+ def token_type(name)
325
+ @token_name_to_type_map[name]
326
+ end
327
+
328
+ def create(pattern)
329
+ tokenizer = TreePatternLexer.new(pattern)
330
+ parser = TreePatternParser.new(tokenizer, self, @adaptor)
331
+ return parser.pattern
332
+ end
333
+
334
+ def index(tree)
335
+ m = {}
336
+ index!(tree, m)
337
+ return(m)
338
+ end
339
+
340
+ def find(tree, what)
341
+ case what
342
+ when Integer then find_token_type(tree, what)
343
+ when String then find_pattern(tree, what)
344
+ else raise ArgumentError, "search subject must be a token type (integer) or a string"
345
+ end
346
+ end
347
+
348
+ def find_token_type(tree, type)
349
+ nodes = []
350
+ visit(tree, type) do |t, parent, child_index, labels|
351
+ nodes << t
352
+ end
353
+ return nodes
354
+ end
355
+
356
+ def find_pattern(tree, pattern)
357
+ subtrees = []
358
+ tokenizer = TreePatternLexer.new(pattern)
359
+ parser = TreePatternParser.new(tokenizer, self, TreePatternTreeAdaptor.new)
360
+ pattern = parser.pattern()
361
+
362
+ return nil if pattern.nil? or pattern.flat_list? or
363
+ pattern.is_a?(WildcardTreePattern)
364
+
365
+ root_token_type = pattern.type
366
+ visit(tree, root_token_type) do |t, parent, child_index, label|
367
+ ( parse! t, pattern, nil ) and subtrees << t
368
+ end
369
+ return subtrees
370
+ end
371
+
372
+ def visit(tree, what, &block)
373
+ case what
374
+ when Integer then self.visit_type(tree, nil, 0, what, &block)
375
+ when String then self.visit_pattern(tree, what, &block)
376
+ else raise ArgumentError,
377
+ "the 'what' filter argument must be a tree pattern (String) or a token type (Integer) -- got #{what.inspect}"
378
+ end
379
+ end
380
+
381
+ def visit_type(tree, parent, child_index, type, &block)
382
+ tree.nil? and return(nil)
383
+ @adaptor.type_of(tree) == type and yield(tree, parent, child_index, nil)
384
+ @adaptor.child_count(tree).times do |i|
385
+ child = @adaptor.child_of(tree, i)
386
+ visit_type(child, tree, i, type, &block)
387
+ end
388
+ end
389
+
390
+ def visit_pattern(tree, pattern, &block)
391
+ tokenizer = TreePatternLexer.new(pattern)
392
+ parser = TreePatternParser.new(tokenizer, self, TreePatternTreeAdaptor.new)
393
+ pattern = parser.pattern()
394
+
395
+ return nil if pattern.nil? or pattern.flat_list? or
396
+ pattern.is_a?(WildcardTreePattern)
397
+
398
+ root_token_type = pattern.type
399
+
400
+ visit tree, root_token_type do |tree, parent, child_index, labels|
401
+ labels = {}
402
+ ( parse! tree, pattern, labels ) and yield(tree, parent, child_index, labels)
403
+ end
404
+ end
405
+
406
+ def parse(tree, pattern, labels = nil)
407
+ tokenizer = TreePatternLexer.new(pattern)
408
+ parser = TreePatternParser.new(tokenizer, self, TreePatternTreeAdaptor.new)
409
+ pattern = parser.pattern
410
+
411
+ parse! tree, pattern, labels
412
+ end
413
+
414
+ def parse!(tree, pattern, labels)
415
+ tree.nil? || pattern.nil? and return false
416
+ unless pattern.is_a? WildcardTreePattern
417
+ @adaptor.type_of(tree) == pattern.type or return false
418
+ pattern.has_text_arg && (@adaptor.text_of(tree) != pattern.text) and
419
+ return false
420
+ end
421
+ labels[pattern.label] = tree if labels && pattern.label
422
+
423
+ number_of_children = @adaptor.child_count(tree)
424
+ return false unless number_of_children == pattern.child_count
425
+
426
+ number_of_children.times do |index|
427
+ actual_child = @adaptor.child_of(tree, index)
428
+ pattern_child = pattern.child(index)
429
+ return false unless parse! actual_child, pattern_child, labels
430
+ end
431
+
432
+ return true
433
+ end
434
+
435
+ def equals(tree_a, tree_b, adaptor = nil)
436
+ adaptor ||= @adaptor
437
+ return equals!(tree_a, tree_b, adaptor)
438
+ end
439
+
440
+ def equals! tree_a, tree_b, adaptor
441
+ tree_a && tree_b or return false # -> if either argument is nil, return false
442
+
443
+ adaptor.type_of(tree_a) == adaptor.type_of(tree_b) or return false
444
+ adaptor.text_of(tree_a) == adaptor.text_of(tree_b) or return false
445
+
446
+ child_count_a = adaptor.child_count(tree_a)
447
+ child_count_b = adaptor.child_count(tree_b)
448
+ child_count_a == child_count_b or return false
449
+
450
+ child_count_a.times do |index|
451
+ child_a = adaptor.child_of(tree_a, index)
452
+ child_b = adaptor.child_of(tree_b, index)
453
+ equals!(child_a, child_b, adaptor) or return false
454
+ end
455
+ return true
456
+ end
457
+
458
+ def index!(tree, m)
459
+ tree or return nil
460
+ type = @adaptor.type_of(tree)
461
+ elements = (m[type] ||= [])
462
+ elements << tree
463
+ @adaptor.child_count(tree).times do |i|
464
+ child = @adaptor.child_of(tree, i)
465
+ index!(child, m)
466
+ end
467
+ end
468
+
469
+ def compute_token_types(token_names)
470
+ token_names or return({})
471
+ map = Hash.new(INVALID_TOKEN_TYPE)
472
+ token_names.each_with_index do |name, index|
473
+ map[name] = index
474
+ end
475
+ return map
476
+ end
477
+
478
+ private :parse!, :index!, :equals!
479
+ end
480
+ end
481
+ end