antlr3 1.3.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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