#!/usr/bin/ruby # encoding: utf-8 require 'antlr3/test/functional' class TestScopes1 < ANTLR3::Test::Functional inline_grammar( <<-'END' ) grammar SimpleScope; options { language = Ruby; } prog scope { name } : ID {$prog::name=$ID.text;} ; ID : ('a'..'z')+ ; WS : (' '|'\n'|'\r')+ {$channel=HIDDEN} ; END example "parsing 'foobar'" do lexer = SimpleScope::Lexer.new( 'foobar' ) parser = SimpleScope::Parser.new lexer parser.prog end end class TestScopes2 < ANTLR3::Test::Functional inline_grammar( <<-'END' ) grammar LotsaScopes; options { language = Ruby; } /* global scopes */ scope aScope { names; } @members { def emit_error_message(msg) # do nothing end def report_error(error) raise error end } a scope aScope; : {$aScope::names = []} ID* ; /* rule scopes, from the book, final beta, p.147 */ b[v] scope {x} : {$b::x = v;} b2 ; b2 : b3 ; b3 : {$b::x}?=> ID // only visible, if b was called with True | NUM ; /* rule scopes, from the book, final beta, p.148 */ c returns [res] scope { symbols } @init { $c::symbols = Set.new; } : '{' c1* c2+ '}' { $res = $c::symbols; } ; c1 : 'int' ID {$c::symbols.add($ID.text)} ';' ; c2 : ID '=' NUM ';' { $c::symbols.include?($ID.text) or raise RuntimeError, $ID.text } ; /* recursive rule scopes, from the book, final beta, p.150 */ d returns [res] scope { symbols } @init { $d::symbols = Set.new } : '{' d1* d2* '}' { $res = $d::symbols; } ; d1 : 'int' ID {$d::symbols.add($ID.text)} ';' ; d2 : ID '=' NUM ';' { catch(:found) do level = ($d.length - 1).downto(0) do |s| $d[s].symbols.include?($ID.text) and throw(:found) end raise $ID.text end } | d ; /* recursive rule scopes, access bottom-most scope */ e returns [res] scope { a } @after { $res = $e::a; } : NUM { $e[0]::a = Integer($NUM.text); } | '{' e '}' ; /* recursive rule scopes, access with negative index */ f returns [res] scope { a } @after { $res = $f::a; } : NUM { $f[-2]::a = Integer($NUM.text); } | '{' f '}' ; /* tokens */ ID : ('a'..'z')+ ; NUM : ('0'..'9')+ ; WS : (' '|'\n'|'\r')+ {$channel=HIDDEN} ; END example "parsing 'foobar' with rule a" do lexer = LotsaScopes::Lexer.new( "foobar" ) parser = LotsaScopes::Parser.new lexer parser.a end example "failing to parse 'foobar' with rule b[false]" do lexer = LotsaScopes::Lexer.new( "foobar" ) parser = LotsaScopes::Parser.new lexer proc { parser.b( false ) }.should raise_error( ANTLR3::RecognitionError ) end example "parsing 'foobar' with rule b[true]" do lexer = LotsaScopes::Lexer.new( "foobar" ) parser = LotsaScopes::Parser.new lexer parser.b( true ) end example "parsing a decl block with rule c" do lexer = LotsaScopes::Lexer.new( <<-END.here_indent! ) | { | int i; | int j; | i = 0; | } END parser = LotsaScopes::Parser.new lexer symbols = parser.c symbols.should have( 2 ).things symbols.should include 'i' symbols.should include 'j' end example "failing to parse undeclared symbols with rule c" do lexer = LotsaScopes::Lexer.new( <<-END.here_indent! ) | { | int i; | int j; | i = 0; | x = 4; | } END parser = LotsaScopes::Parser.new lexer proc { parser.c }.should raise_error RuntimeError, 'x' end example "parsing nested declaration blocks" do lexer = LotsaScopes::Lexer.new( <<-END.here_indent! ) | { | int i; | int j; | i = 0; | { | int i; | int x; | x = 5; | } | } END parser = LotsaScopes::Parser.new lexer symbols = parser.d symbols.should have( 2 ).things symbols.should include 'i' symbols.should include 'j' end example "parsing a deeply nested set of blocks with rule e" do lexer = LotsaScopes::Lexer.new( <<-END.here_indent! ) | { { { { 12 } } } } END parser = LotsaScopes::Parser.new lexer parser.e.should == 12 end example "parsing a deeply nested set of blocks with rule f" do lexer = LotsaScopes::Lexer.new( <<-END.here_indent! ) | { { { { 12 } } } } END parser = LotsaScopes::Parser.new lexer parser.f.should == nil end example "parsing a 2-level nested set of blocks with rule f" do lexer = LotsaScopes::Lexer.new( <<-END.here_indent! ) | { { 12 } } END parser = LotsaScopes::Parser.new lexer parser.f.should == nil end end