antlr3 1.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module ANTLR3
4
+ module Template
5
+ Parameter = Struct.new( :name, :default )
6
+ class Parameter
7
+ def to_s
8
+ if block then "&#{ name }"
9
+ elsif splat then "*#{ name }"
10
+ elsif default then "#{ name } = #{ default }"
11
+ else name.dup
12
+ end
13
+ end
14
+ end
15
+
16
+ class ParameterList < ::Array
17
+ attr_accessor :splat, :block
18
+
19
+ def self.default
20
+ new.add( :values ) do | p |
21
+ p.default = '{}'
22
+ end
23
+ end
24
+
25
+ def names
26
+ names = map { | param | param.name.to_s }
27
+ @splat and names << @splat.to_s
28
+ @block and names << @block.to_s
29
+ return( names )
30
+ end
31
+
32
+ def add( name, default = nil )
33
+ param =
34
+ case name
35
+ when Parameter then name
36
+ else Parameter.new( name.to_s )
37
+ end
38
+ if options
39
+ default = options[ :default ] and param.default = default
40
+ param.splat = options.fetch( :splat, false )
41
+ param.block = options.fetch( :block, false )
42
+ end
43
+ block_given? and yield( param )
44
+ push( param )
45
+ return( self )
46
+ end
47
+
48
+ def to_s
49
+ signature = join( ', ' )
50
+ @splat and signature << ", *" << @splat.to_s
51
+ @block and signature << ", &" << @block.to_s
52
+ return( signature )
53
+ end
54
+ end
55
+ end
56
+ end
@@ -65,7 +65,7 @@ class Grammar
65
65
  ##################################################################
66
66
  def initialize(path, options = {})
67
67
  @path = path.to_s
68
- @source = prepare_source(File.read(@path))
68
+ @source = File.read( @path )
69
69
  @output_directory = options.fetch(:output_directory, '.')
70
70
  @verbose = options.fetch( :verbose, $VERBOSE )
71
71
  study
@@ -138,7 +138,6 @@ class Grammar
138
138
  @type == "combined"
139
139
  end
140
140
 
141
-
142
141
  def target_files(include_imports = true)
143
142
  targets = []
144
143
 
@@ -204,6 +203,7 @@ class Grammar
204
203
  end
205
204
 
206
205
  private
206
+
207
207
  def post_compile(options)
208
208
  # do nothing for now
209
209
  end
@@ -257,10 +257,6 @@ private
257
257
  parts.map! { |part| shell_escape(part) }.join(' ') << ' 2>&1'
258
258
  end
259
259
 
260
- def prepare_source(text)
261
- text.gsub(/([^\\])%/,'\1\\%').freeze
262
- end
263
-
264
260
  def study
265
261
  @source =~ /^\s*(lexer|parser|tree)?\s*grammar\s*(\S+)\s*;/ or
266
262
  raise Grammar::FormatError[source, path]
@@ -272,7 +268,7 @@ end # class Grammar
272
268
  class Grammar::InlineGrammar < Grammar
273
269
  attr_accessor :host_file, :host_line
274
270
 
275
- def initialize(source, options = {})
271
+ def initialize( source, options = {} )
276
272
  host = call_stack.find { |call| call.file != __FILE__ }
277
273
 
278
274
  @host_file = File.expand_path(options[:file] || host.file)
@@ -280,14 +276,14 @@ class Grammar::InlineGrammar < Grammar
280
276
  @output_directory = options.fetch(:output_directory, File.dirname(@host_file))
281
277
  @verbose = options.fetch( :verbose, $VERBOSE )
282
278
 
283
- source = source.to_s.fixed_indent(0)
284
- source.strip!
285
- @source = prepare_source(source)
279
+ @source = source.to_s.fixed_indent( 0 )
280
+ @source.strip!
281
+
286
282
  study
287
283
  write_to_disk
288
284
  build_dependencies
289
285
 
290
- yield(self) if block_given?
286
+ yield( self ) if block_given?
291
287
  end
292
288
 
293
289
  def output_directory
@@ -303,7 +299,9 @@ class Grammar::InlineGrammar < Grammar
303
299
  def inspect
304
300
  sprintf( 'inline grammar %s (%s:%s)', name, @host_file, @host_line )
305
301
  end
302
+
306
303
  private
304
+
307
305
  def write_to_disk
308
306
  @path ||= output_directory / @name + '.g'
309
307
  test(?d, output_directory) or Dir.mkdir( output_directory )
data/lib/antlr3/tree.rb CHANGED
@@ -1181,6 +1181,36 @@ class CommonTreeNodeStream
1181
1181
  return @nodes.dup
1182
1182
  end
1183
1183
 
1184
+ def extract_text( start = nil, stop = nil )
1185
+ @position == -1 and fill_buffer
1186
+ start ||= @nodes.first
1187
+ stop ||= @nodes.last
1188
+
1189
+ if @token_stream
1190
+ case @adaptor.type_of( stop )
1191
+ when UP
1192
+ stop_index = @adaptor.token_stop_index( start )
1193
+ when EOF
1194
+ return extract_text( start, @nodes[ - 2 ] )
1195
+ else
1196
+ stop_index = @adaptor.token_stop_index( stop )
1197
+ end
1198
+
1199
+ start_index = @adaptor.token_start_index( start )
1200
+ return @token_stream.extract_text( start_index, stop_index )
1201
+ else
1202
+ start_index = @nodes.index( start ) || @nodes.length
1203
+ stop_index = @nodes.index( stop ) || @nodes.length
1204
+ return(
1205
+ @nodes[ start_index .. stop_index ].map do | n |
1206
+ @adaptor.text_of( n ) or " " + @adaptor.type_of( n ).to_s
1207
+ end.join( '' )
1208
+ )
1209
+ end
1210
+ end
1211
+
1212
+ alias to_s extract_text
1213
+
1184
1214
  #private
1185
1215
  #
1186
1216
  # def linear_node_index( node )
@@ -19,8 +19,8 @@ module ANTLR3
19
19
  # The version data for the current state the library itself
20
20
  #
21
21
  MAJOR_VERSION = 1
22
- MINOR_VERSION = 3
23
- PATCH_VERSION = 1
22
+ MINOR_VERSION = 4
23
+ PATCH_VERSION = 0
24
24
  VERSION = [ MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION ]
25
25
  VERSION_STRING = VERSION.join('.').freeze
26
26
 
data/templates/Ruby.stg CHANGED
@@ -327,22 +327,21 @@ end
327
327
  >>
328
328
 
329
329
  catch(decl, action) ::= <<
330
- # - - - - - - @catch e.decl - - - - - -
330
+ # - - - - - - @catch <e.decl> - - - - - -
331
331
  rescue <e.decl>
332
332
  <e.action><\n>
333
333
  >>
334
334
 
335
-
336
335
  closureBlockLoop() ::= <<
337
- loop do #loop <decisionNumber>
336
+ loop do # decision <decisionNumber>
338
337
  alt_<decisionNumber> = <maxAlt>
339
338
  <@decisionBody><decision><@end>
340
339
  case alt_<decisionNumber>
341
340
  <alts:altSwitchCase(); separator="\n">
342
341
  else
343
- break #loop <decisionNumber>
342
+ break # out of loop for decision <decisionNumber>
344
343
  end
345
- end
344
+ end # loop for decision <decisionNumber>
346
345
  >>
347
346
 
348
347
  delegateName() ::= <<
@@ -555,7 +554,7 @@ memoize(__method__, <ruleDescriptor.name>_start_index, success) if @state.backtr
555
554
 
556
555
  /** helper template to format a ruby method call */
557
556
  methodCall(n, del, args) ::= <<
558
- <if(del)>@<del:delegateName()>.<endif><n><if(args)>(<args; seperator=", ">)<endif>
557
+ <if(del)>@<del:delegateName()>.<endif><n><if(args)>(<args; separator=", ">)<endif>
559
558
  >>
560
559
 
561
560
 
@@ -1148,7 +1147,7 @@ ruleLabelPropertyRef_text(scope, attr) ::= <<
1148
1147
  >>
1149
1148
 
1150
1149
 
1151
- ruleLabelPropertyRef_st(scope, attr) ::= "(<scope; format=\"label\">.nil? ? nil : <scope; format=\"label\">.st)"
1150
+ ruleLabelPropertyRef_st(scope, attr) ::= "(<scope; format=\"label\">.nil? ? nil : <scope; format=\"label\">.template)"
1152
1151
 
1153
1152
  /******************************************************************************
1154
1153
  ***************** L E X E R - O N L Y T E M P L A T E S ******************
@@ -1430,11 +1429,11 @@ rulePropertyRef_tree(scope, attr) ::= "return_value.tree"
1430
1429
  rulePropertyRef_text(scope, attr) ::= "@input.to_s(return_value.start, @input.look(-1))"
1431
1430
 
1432
1431
  /** $template in parser rule */
1433
- rulePropertyRef_st(scope, attr) ::= "return_value.st"
1432
+ rulePropertyRef_st(scope, attr) ::= "return_value.template"
1434
1433
 
1435
1434
  ruleSetPropertyRef_tree(scope, attr, expr) ::= "return_value.tree = <expr>"
1436
1435
 
1437
- ruleSetPropertyRef_st(scope, attr, expr) ::= "return_value.st = <expr>"
1436
+ ruleSetPropertyRef_st(scope, attr, expr) ::= "return_value.template = <expr>"
1438
1437
 
1439
1438
  /** How to execute an action */
1440
1439
  execAction(action) ::= <<
@@ -1498,4 +1497,4 @@ placeAction(scope, name) ::= <<
1498
1497
  <endif>
1499
1498
  >>
1500
1499
 
1501
- runtimeLibraryVersion() ::= "1.3.1"
1500
+ runtimeLibraryVersion() ::= "1.4.0"
data/templates/ST.stg ADDED
@@ -0,0 +1,128 @@
1
+ group ST;
2
+
3
+ @parserBody.mixins() ::= <<
4
+ <@super.mixins()>
5
+ <if(rewriteMode)>
6
+ include ANTLR3::Template::RewriteBuilder
7
+ <else>
8
+ include ANTLR3::Template::Builder
9
+ <endif>
10
+ >>
11
+
12
+ gatedAction( block ) ::= <<
13
+ <if(backtracking)>
14
+ if <actions.(actionScope).synpredgate>
15
+ <block>
16
+ end
17
+ <else>
18
+ <block>
19
+ <endif>
20
+ >>
21
+
22
+ /** x+=rule when output=template */
23
+ ruleRefAndListLabel(rule,label,elementIndex,args,scope) ::= <<
24
+ <ruleRef(...)>
25
+ <listLabel(elem={<label; format="label">.template}, ...)>
26
+ >>
27
+
28
+ rewriteTemplate(alts) ::= <<
29
+ <gatedAction({
30
+ <first(alts):rewriteTemplateAltFirst(); anchor>
31
+ <rest(alts):{a| els<rewriteTemplateAltRest(a)>}; anchor, separator="\n\n">
32
+ <if(rewriteMode)><replaceTextInLine()><endif>
33
+ })>
34
+ >>
35
+
36
+ rewriteTemplateAltFirst(a) ::= <<
37
+ <if(a.pred)>
38
+ if <a.pred>
39
+ # <a.description>
40
+ return_value.template = <a.alt>
41
+ <else>
42
+ # <a.description>
43
+ return_value.template = <a.alt>
44
+ <endif>
45
+ >>
46
+
47
+ rewriteTemplateAltRest(a) ::= <<
48
+ <if(a.pred)>
49
+ if <a.pred>
50
+ # <a.description>
51
+ return_value.template = <a.alt>
52
+ <else>
53
+ e <! little hack to get if .. elsif .. else block right !>
54
+ # <a.description>
55
+ return_value.template = <a.alt>
56
+ end
57
+ <endif>
58
+ >>
59
+
60
+ replaceTextInLine() ::= <<
61
+ <if(TREE_PARSER)>
62
+ @input.token_stream.replace(
63
+ @input.adaptor.token_start_index( return_value.start ),
64
+ @input.adaptor.token_stop_index( return_value.start ),
65
+ return_value.template
66
+ )
67
+ <else>
68
+ @input.replace(
69
+ return_value.start.index,
70
+ @input.look( -1 ).index,
71
+ return_value.template
72
+ )
73
+ <endif>
74
+ >>
75
+
76
+ rewriteEmptyTemplate(alts) ::= <<
77
+ nil
78
+ >>
79
+
80
+ /** Invoke a template with a set of attribute name/value pairs.
81
+ * Set the value of the rule's template *after* having set
82
+ * the attributes because the rule's template might be used as
83
+ * an attribute to build a bigger template; you get a self-embedded
84
+ * template.
85
+ */
86
+ rewriteExternalTemplate(name,args) ::= <<
87
+ fetch_template( "<name>" <if(args)>,
88
+ <argumentMap(args)>
89
+ <endif>)
90
+ >>
91
+
92
+ /** expr is a string expression that says what template to load */
93
+ rewriteIndirectTemplate(expr,args) ::= <<
94
+ fetch_template( <expr><if(args)>, <argumentMap(args)><endif> )
95
+ >>
96
+
97
+ /** Invoke an inline template with a set of attribute name/value pairs */
98
+ rewriteInlineTemplate(args, template) ::= <<
99
+ create_template( "<template>"<if(args)>, <argumentMap(args)><endif> )
100
+ >>
101
+
102
+ /** plain -> {foo} action */
103
+ rewriteAction(action) ::= <<
104
+ <action>
105
+ >>
106
+
107
+ /** An action has %st.attrName=expr; or %{st}.attrName=expr; */
108
+ actionSetAttribute(st,attrName,expr) ::= <<
109
+ ( <st> )[ :<attrName> ] = <expr>
110
+ >>
111
+
112
+ /** Translate %{stringExpr} */
113
+ actionStringConstructor(stringExpr) ::= <<
114
+ create_template( <stringExpr> )
115
+ >>
116
+
117
+ /*
118
+ rulePropertyRef_text(scope, attr) ::= <<
119
+ @input.to_s(return_value.start, @input.look(-1))
120
+ >>
121
+ */
122
+
123
+ argumentMap(args) ::= <<
124
+ <args:{a|:<a.name> => <a.value>}; separator=",\n">
125
+ >>
126
+
127
+
128
+
@@ -726,7 +726,7 @@ class TestAutoAST < ANTLR3::Test::Functional
726
726
  grammar RuleListLabelRuleRoot;
727
727
  options {language=Ruby;output=AST;}
728
728
  a returns [result] : ( x+=b^ )+ {
729
- $result = "x=%s," \% $x[1].inspect
729
+ $result = "x=\%s," \% $x[1].inspect
730
730
  } ;
731
731
  b : ID;
732
732
  ID : 'a'..'z'+ ;
@@ -202,8 +202,9 @@ class TestHeterogeneousNodeTypes < ANTLR3::Test::Functional
202
202
  end
203
203
  super(token)
204
204
  end
205
+
205
206
  def to_s
206
- (@token.text.to_s rescue '') << "<V>;\%d\%d\%d" % [@x, @y, @z]
207
+ (@token.text.to_s rescue '') << "<V>;\%d\%d\%d" \% [@x, @y, @z]
207
208
  end
208
209
  end
209
210
 
@@ -0,0 +1,404 @@
1
+ #!/usr/bin/ruby
2
+ # encoding: utf-8
3
+
4
+ require 'antlr3/test/functional'
5
+
6
+ class TestTemplateOutput < ANTLR3::Test::Functional
7
+
8
+ def parse( grammar, input, options = nil )
9
+ @grammar = inline_grammar( grammar )
10
+ compile_and_load( @grammar )
11
+ grammar_module = self.class.const_get( @grammar.name )
12
+
13
+ parser_options = {}
14
+ if options
15
+ rule = options.fetch( :rule ) { grammar_module::Parser.default_rule }
16
+ group = options[ :templates ] and parser_options[ :templates ] = group
17
+ else
18
+ rule = grammar_module::Parser.default_rule
19
+ end
20
+
21
+ @lexer = grammar_module::Lexer.new( input )
22
+ @parser = grammar_module::Parser.new( @lexer, parser_options )
23
+
24
+ out = @parser.send( rule ).template
25
+ return( out ? out.to_s : out )
26
+ end
27
+
28
+ def parse_templates( source )
29
+ ANTLR3::Template::Group.parse( source.fixed_indent( 0 ) )
30
+ end
31
+
32
+
33
+ example 'inline templates' do
34
+ text = parse( <<-'END', "abc 34" )
35
+ grammar InlineTemplates;
36
+ options {
37
+ language = Ruby;
38
+ output = template;
39
+ }
40
+
41
+ a : ID INT
42
+ -> template(id={$ID.text}, int={$INT.text})
43
+ "id=<%= @id %>, int=<%= @int %>"
44
+ ;
45
+
46
+ ID : 'a'..'z'+;
47
+ INT : '0'..'9'+;
48
+ WS : (' '|'\n') {$channel=HIDDEN;} ;
49
+ END
50
+
51
+ text.should == "id=abc, int=34"
52
+ end
53
+
54
+ example 'external template' do
55
+ templates = ANTLR3::Template::Group.new do
56
+ define_template( :expr, <<-'END'.strip )
57
+ [<%= @args.join( @op.to_s ) %>]
58
+ END
59
+ end
60
+
61
+ text = parse( <<-'END', 'a + b', :templates => templates )
62
+ grammar ExternalTemplate;
63
+ options {
64
+ language = Ruby;
65
+ output = template;
66
+ }
67
+
68
+ a : r+=arg OP r+=arg
69
+ -> expr( op={$OP.text}, args={$r} )
70
+ ;
71
+ arg: ID -> template(t={$ID.text}) "<%= @t %>";
72
+
73
+ ID : 'a'..'z'+;
74
+ OP: '+';
75
+ WS : (' '|'\n') {$channel=HIDDEN;} ;
76
+ END
77
+
78
+ text.should == '[a+b]'
79
+ end
80
+
81
+ example "empty template" do
82
+ text = parse( <<-'END', 'abc 34' )
83
+ grammar EmptyTemplate;
84
+ options {
85
+ language=Ruby;
86
+ output=template;
87
+ }
88
+ a : ID INT
89
+ ->
90
+ ;
91
+
92
+ ID : 'a'..'z'+;
93
+ INT : '0'..'9'+;
94
+ WS : (' '|'\n') {$channel=HIDDEN;} ;
95
+
96
+ END
97
+ text.should be_nil
98
+ end
99
+
100
+ example "list" do
101
+ text = parse( <<-'END', "abc def ghi" )
102
+ grammar List;
103
+ options {
104
+ language=Ruby;
105
+ output=template;
106
+ }
107
+ a: (r+=b)* EOF
108
+ -> template(r={$r}) "<%= @r.join(',') %>"
109
+ ;
110
+
111
+ b: ID
112
+ -> template(t={$ID.text}) "<%= @t %>"
113
+ ;
114
+
115
+ ID : 'a'..'z'+;
116
+ WS : (' '|'\n') {$channel=HIDDEN;} ;
117
+ END
118
+ text.should == 'abc,def,ghi'
119
+ end
120
+
121
+ example 'action' do
122
+ text = parse( <<-'END', "abc" )
123
+ grammar Action;
124
+ options {
125
+ language=Ruby;
126
+ output=template;
127
+ }
128
+ a: ID
129
+ -> { create_template( "hello" ) }
130
+ ;
131
+
132
+ ID : 'a'..'z'+;
133
+ WS : (' '|'\n') {$channel=HIDDEN;} ;
134
+ END
135
+
136
+ text.should == 'hello'
137
+ end
138
+
139
+ example "template expression in action" do
140
+ text = parse( <<-'END', 'abc' )
141
+ grammar TemplateExpressionInAction;
142
+ options {
143
+ language=Ruby;
144
+ output=template;
145
+ }
146
+ a: ID
147
+ { $st = %{"hello"} }
148
+ ;
149
+
150
+ ID : 'a'..'z'+;
151
+ WS : (' '|'\n') {$channel=HIDDEN;} ;
152
+ END
153
+ text.should == 'hello'
154
+ end
155
+
156
+ #example "template expression in action2" do
157
+ # text = parse( <<-'END', 'abc' )
158
+ # grammar TemplateExpressionInAction2;
159
+ # options {
160
+ # language=Ruby;
161
+ # output=template;
162
+ # }
163
+ # a: ID
164
+ # {
165
+ # res = %{"hello <%= @foo %>"}
166
+ # %res.foo = "world";
167
+ # }
168
+ # -> { res }
169
+ # ;
170
+ #
171
+ # ID : 'a'..'z'+;
172
+ # WS : (' '|'\n') {$channel=HIDDEN;} ;
173
+ # END
174
+ #
175
+ # text.should == 'hello world'
176
+ #end
177
+
178
+ example "indirect template constructor" do
179
+ templates = ANTLR3::Template::Group.new do
180
+ define_template( :expr, <<-'END'.strip )
181
+ [<%= @args.join( @op.to_s ) %>]
182
+ END
183
+ end
184
+
185
+ text = parse( <<-'END', 'abc', :templates => templates )
186
+ grammar IndirectTemplateConstructor;
187
+ options {
188
+ language=Ruby;
189
+ output=template;
190
+ }
191
+
192
+ a: ID
193
+ {
194
+ $st = %({"expr"})(args={[1, 2, 3]}, op={"+"})
195
+ }
196
+ ;
197
+
198
+ ID : 'a'..'z'+;
199
+ WS : (' '|'\n') {$channel=HIDDEN;} ;
200
+ END
201
+
202
+ text.should == '[1+2+3]'
203
+ end
204
+
205
+ example "predicates" do
206
+ text = parse( <<-'END', 'b 34' )
207
+ grammar Predicates;
208
+ options {
209
+ language=Ruby;
210
+ output=template;
211
+ }
212
+ a : ID INT
213
+ -> {$ID.text=='a'}? template(int={$INT.text})
214
+ "A: <%= @int %>"
215
+ -> {$ID.text=='b'}? template(int={$INT.text})
216
+ "B: <%= @int %>"
217
+ -> template(int={$INT.text})
218
+ "C: <%= @int %>"
219
+ ;
220
+
221
+ ID : 'a'..'z'+;
222
+ INT : '0'..'9'+;
223
+ WS : (' '|'\n') {$channel=HIDDEN;} ;
224
+ END
225
+
226
+ text.should == 'B: 34'
227
+ end
228
+
229
+ example "backtracking mode" do
230
+ text = parse( <<-'END', 'abc 34' )
231
+ grammar BacktrackingMode;
232
+ options {
233
+ language=Ruby;
234
+ output=template;
235
+ backtrack=true;
236
+ }
237
+ a : (ID INT)=> ID INT
238
+ -> template(id={$ID.text}, int={$INT.text})
239
+ "id=<%= @id %>, int=<%= @int %>"
240
+ ;
241
+
242
+ ID : 'a'..'z'+;
243
+ INT : '0'..'9'+;
244
+ WS : (' '|'\n') {$channel=HIDDEN;} ;
245
+ END
246
+
247
+ text.should == "id=abc, int=34"
248
+ end
249
+
250
+ example "rewrite" do
251
+ input = <<-'END'.here_indent!
252
+ | if ( foo ) {
253
+ | b = /* bla */ 2;
254
+ | return 1 /* foo */;
255
+ | }
256
+ |
257
+ | /* gnurz */
258
+ | return 12;
259
+ END
260
+ expected = <<-'END'.here_indent!
261
+ | if ( foo ) {
262
+ | b = /* bla */ 2;
263
+ | return boom(1) /* foo */;
264
+ | }
265
+ |
266
+ | /* gnurz */
267
+ | return boom(12);
268
+ END
269
+
270
+ parse( <<-'END', input )
271
+ grammar Rewrite;
272
+ options {
273
+ language=Ruby;
274
+ output=template;
275
+ rewrite=true;
276
+ }
277
+
278
+ prog: stat+;
279
+
280
+ stat
281
+ : 'if' '(' expr ')' stat
282
+ | 'return' return_expr ';'
283
+ | '{' stat* '}'
284
+ | ID '=' expr ';'
285
+ ;
286
+
287
+ return_expr
288
+ : expr
289
+ -> template(t={$text}) <<boom(<%= @t %>)>>
290
+ ;
291
+
292
+ expr
293
+ : ID
294
+ | INT
295
+ ;
296
+
297
+ ID: 'a'..'z'+;
298
+ INT: '0'..'9'+;
299
+ WS: (' '|'\n')+ {$channel=HIDDEN;} ;
300
+ COMMENT: '/*' (options {greedy=false;} : .)* '*/' {$channel = HIDDEN;} ;
301
+ END
302
+
303
+ @parser.input.render.should == expected
304
+ end
305
+
306
+ example "tree rewrite" do
307
+ input = <<-'END'.here_indent!
308
+ | if ( foo ) {
309
+ | b = /* bla */ 2;
310
+ | return 1 /* foo */;
311
+ | }
312
+ |
313
+ | /* gnurz */
314
+ | return 12;
315
+ END
316
+ expected = <<-'END'.here_indent!
317
+ | if ( foo ) {
318
+ | b = /* bla */ 2;
319
+ | return boom(1) /* foo */;
320
+ | }
321
+ |
322
+ | /* gnurz */
323
+ | return boom(12);
324
+ END
325
+
326
+ compile_and_load( inline_grammar( <<-'END' ) )
327
+ grammar TreeRewrite;
328
+ options {
329
+ language=Ruby;
330
+ output=AST;
331
+ }
332
+
333
+ tokens {
334
+ BLOCK;
335
+ ASSIGN;
336
+ }
337
+
338
+ prog: stat+;
339
+
340
+ stat
341
+ : IF '(' e=expr ')' s=stat
342
+ -> ^(IF $e $s)
343
+ | RETURN expr ';'
344
+ -> ^(RETURN expr)
345
+ | '{' stat* '}'
346
+ -> ^(BLOCK stat*)
347
+ | ID '=' expr ';'
348
+ -> ^(ASSIGN ID expr)
349
+ ;
350
+
351
+ expr
352
+ : ID
353
+ | INT
354
+ ;
355
+
356
+ IF: 'if';
357
+ RETURN: 'return';
358
+ ID: 'a'..'z'+;
359
+ INT: '0'..'9'+;
360
+ WS: (' '|'\n')+ {$channel=HIDDEN;} ;
361
+ COMMENT: '/*' (options {greedy=false;} : .)* '*/' {$channel = HIDDEN;} ;
362
+ END
363
+
364
+ compile_and_load( inline_grammar( <<-'END' ) )
365
+ tree grammar TreeRewriteTG;
366
+ options {
367
+ language=Ruby;
368
+ tokenVocab=TreeRewrite;
369
+ ASTLabelType=CommonTree;
370
+ output=template;
371
+ rewrite=true;
372
+ }
373
+
374
+ prog: stat+;
375
+
376
+ stat
377
+ : ^(IF expr stat)
378
+ | ^(RETURN return_expr)
379
+ | ^(BLOCK stat*)
380
+ | ^(ASSIGN ID expr)
381
+ ;
382
+
383
+ return_expr
384
+ : expr
385
+ -> template(t={$text}) <<boom(<%= @t %>)>>
386
+ ;
387
+
388
+ expr
389
+ : ID
390
+ | INT
391
+ ;
392
+ END
393
+
394
+ lexer = TreeRewrite::Lexer.new( input )
395
+ tokens = ANTLR3::TokenRewriteStream.new( lexer )
396
+ parser = TreeRewrite::Parser.new( tokens )
397
+ tree = parser.prog.tree
398
+ nodes = ANTLR3::AST::CommonTreeNodeStream.new( tree )
399
+ nodes.token_stream = tokens
400
+ tree_parser = TreeRewriteTG::TreeParser.new( nodes )
401
+ tree_parser.prog
402
+ tokens.render.should == expected
403
+ end
404
+ end