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.
- data/java/antlr-full-3.2.1.jar +0 -0
- data/lib/antlr3.rb +2 -0
- data/lib/antlr3/main.rb +3 -5
- data/lib/antlr3/modes/ast-builder.rb +1 -22
- data/lib/antlr3/streams/rewrite.rb +3 -3
- data/lib/antlr3/task.rb +12 -1
- data/lib/antlr3/template.rb +319 -0
- data/lib/antlr3/template/group-lexer.rb +992 -0
- data/lib/antlr3/template/group-parser.rb +627 -0
- data/lib/antlr3/template/parameter.rb +56 -0
- data/lib/antlr3/test/grammar.rb +9 -11
- data/lib/antlr3/tree.rb +30 -0
- data/lib/antlr3/version.rb +2 -2
- data/templates/Ruby.stg +9 -10
- data/templates/ST.stg +128 -0
- data/test/functional/ast-output/auto-ast.rb +1 -1
- data/test/functional/ast-output/hetero-nodes.rb +2 -1
- data/test/functional/template-output/template-output.rb +404 -0
- data/test/unit/sample-input/template-group +38 -0
- data/test/unit/test-template.rb +248 -0
- metadata +12 -2
@@ -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
|
data/lib/antlr3/test/grammar.rb
CHANGED
@@ -65,7 +65,7 @@ class Grammar
|
|
65
65
|
##################################################################
|
66
66
|
def initialize(path, options = {})
|
67
67
|
@path = path.to_s
|
68
|
-
@source =
|
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
|
-
|
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 )
|
data/lib/antlr3/version.rb
CHANGED
@@ -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 =
|
23
|
-
PATCH_VERSION =
|
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
|
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;
|
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\">.
|
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.
|
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.
|
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.
|
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
|
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"
|
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
|