antlr3 1.3.1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|