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 405