Home | History | Annotate | Download | only in parser
      1 #!/usr/bin/ruby
      2 # encoding: utf-8
      3 
      4 require 'antlr3/test/functional'
      5 
      6 class TestParser001 < ANTLR3::Test::Functional
      7   inline_grammar( <<-'END' )
      8     grammar Identifiers;
      9     options { language = Ruby; }
     10     
     11     @parser::init {
     12       @identifiers = []
     13       @reported_errors = []
     14     }
     15     
     16     @parser::members {
     17       attr_reader :reported_errors, :identifiers
     18       
     19       def found_identifier(name)
     20           @identifiers << name
     21       end
     22       
     23       def emit_error_message(msg)
     24         @reported_errors << msg
     25       end
     26     }
     27     
     28     document:
     29             t=IDENTIFIER {found_identifier($t.text)}
     30             ;
     31     
     32     IDENTIFIER: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;
     33   END
     34   
     35   example "parsing 'blah_de_blah'" do
     36     # to build a parser, this is the standard chain of calls to prepare the input
     37     input = ANTLR3::StringStream.new( 'blah_de_blah', :file => 'blah.txt' )
     38     lexer  = Identifiers::Lexer.new( input )
     39     tokens = ANTLR3::CommonTokenStream.new( lexer )
     40     parser = Identifiers::Parser.new( tokens )
     41     
     42     parser.document
     43     
     44     parser.reported_errors.should be_empty
     45     parser.identifiers.should == %w(blah_de_blah)
     46   end
     47   
     48   example "error from empty input" do
     49     # if you don't need to use a customized stream, lexers and parsers will
     50     # automatically wrap input in the standard stream classes
     51     lexer = Identifiers::Lexer.new( '' )
     52     parser = Identifiers::Parser.new( lexer )
     53     parser.document
     54     
     55     parser.reported_errors.should have( 1 ).thing
     56   end
     57   
     58   example 'automatic input wrapping' do
     59     # if the parser is able to figure out what lexer class
     60     # to use (typically when it comes from a combined grammar),
     61     # and you don't need to do any special token processing
     62     # before making a parser, this is an extra shortcut for
     63     # parser construction
     64     parser = Identifiers::Parser.new( 'blah_de_blah', :file => 'blah.txt' )
     65     
     66     parser.document
     67     
     68     parser.reported_errors.should be_empty
     69     parser.identifiers.should == %w(blah_de_blah)
     70   end
     71 end
     72 
     73 class TestParser002 < ANTLR3::Test::Functional
     74   inline_grammar( <<-'END' )
     75     grammar SimpleLanguage;
     76     options {
     77       language = Ruby;
     78     }
     79     
     80     @parser::init {
     81       @events = []
     82       @reported_errors = []
     83     }
     84     
     85     @parser::members {
     86       attr_reader :reported_errors, :events
     87       
     88       def emit_error_message(msg)
     89         @reported_errors << msg
     90       end
     91     }
     92     
     93     document:
     94             ( declaration
     95             | call
     96             )*
     97             EOF
     98         ;
     99     
    100     declaration:
    101             'var' t=IDENTIFIER ';'
    102             {@events << ['decl', $t.text]}
    103         ;
    104     
    105     call:
    106             t=IDENTIFIER '(' ')' ';'
    107             {@events << ['call', $t.text]}
    108         ;
    109     
    110     IDENTIFIER: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;
    111     WS:  (' '|'\r'|'\t'|'\n') {$channel=HIDDEN;};
    112   END
    113   
    114   
    115   example "parsing decls and calls" do
    116     lexer  = SimpleLanguage::Lexer.new( "var foobar; gnarz(); var blupp; flupp ( ) ;" )
    117     parser = SimpleLanguage::Parser.new( lexer )
    118     
    119     parser.document
    120     
    121     parser.reported_errors.should be_empty
    122     parser.events.should == [ 
    123       %w(decl foobar),
    124       %w(call gnarz),
    125       %w(decl blupp),
    126       %w(call flupp)
    127     ]
    128   end
    129   
    130   example "bad declaration" do
    131     lexer  = SimpleLanguage::Lexer.new( 'var; foo()' )
    132     parser = SimpleLanguage::Parser.new( lexer )
    133     
    134     parser.document
    135     
    136     parser.reported_errors.should have( 1 ).thing
    137     parser.events.should be_empty
    138   end
    139   
    140   example "error recovery via token insertion" do
    141     lexer  = SimpleLanguage::Lexer.new( 'gnarz(; flupp();' )
    142     parser = SimpleLanguage::Parser.new( lexer )
    143     
    144     parser.document
    145     
    146     parser.reported_errors.should have( 1 ).thing
    147     parser.events.should == [ 
    148       %w(call gnarz),
    149       %w(call flupp)
    150     ]
    151   end
    152   
    153 end
    154 
    155 class TestParser003 < ANTLR3::Test::Functional
    156   inline_grammar( <<-'END' )
    157     grammar MoreComplicated;
    158     
    159     options { language = Ruby; }
    160     
    161     @init {
    162       @reported_errors = []
    163     }
    164     
    165     @members {
    166       attr_reader :reported_errors
    167       
    168       def emit_error_message(msg)
    169         @reported_errors << msg
    170       end
    171     }
    172     
    173     program
    174         :   declaration+
    175         ;
    176     
    177     declaration
    178         :   variable
    179         |   functionHeader ';'
    180         |   functionHeader block
    181         ;
    182     
    183     variable
    184         :   type declarator ';'
    185         ;
    186     
    187     declarator
    188         :   ID 
    189         ;
    190     
    191     functionHeader
    192         :   type ID '(' ( formalParameter ( ',' formalParameter )* )? ')'
    193         ;
    194     
    195     formalParameter
    196         :   type declarator        
    197         ;
    198     
    199     type
    200         :   'int'   
    201         |   'char'  
    202         |   'void'
    203         |   ID        
    204         ;
    205     
    206     block
    207         :   '{'
    208                 variable*
    209                 stat*
    210             '}'
    211         ;
    212     
    213     stat: forStat
    214         | expr ';'      
    215         | block
    216         | assignStat ';'
    217         | ';'
    218         ;
    219     
    220     forStat
    221         :   'for' '(' assignStat ';' expr ';' assignStat ')' block        
    222         ;
    223     
    224     assignStat
    225         :   ID '=' expr        
    226         ;
    227     
    228     expr:   condExpr
    229         ;
    230     
    231     condExpr
    232         :   aexpr ( ('==' | '<') aexpr )?
    233         ;
    234     
    235     aexpr
    236         :   atom ( '+' atom )*
    237         ;
    238     
    239     atom
    240         : ID      
    241         | INT      
    242         | '(' expr ')'
    243         ; 
    244     
    245     ID  :   ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
    246         ;
    247     
    248     INT :	('0'..'9')+
    249         ;
    250     
    251     WS  :   (   ' '
    252             |   '\t'
    253             |   '\r'
    254             |   '\n'
    255             )+
    256             {$channel=HIDDEN}
    257         ;    
    258   END
    259   
    260   example "parsing 'int foo;'" do
    261     lexer = MoreComplicated::Lexer.new "int foo;"
    262     parser = MoreComplicated::Parser.new lexer
    263     parser.program
    264     parser.reported_errors.should be_empty
    265   end
    266   
    267   
    268   example "catching badly formed input" do
    269     lexer = MoreComplicated::Lexer.new "int foo() { 1+2 }"
    270     parser = MoreComplicated::Parser.new lexer
    271     parser.program
    272     parser.reported_errors.should have( 1 ).thing
    273   end
    274   
    275   example "two instances of badly formed input" do
    276     lexer = MoreComplicated::Lexer.new "int foo() { 1+; 1+2 }"
    277     parser = MoreComplicated::Parser.new lexer
    278     parser.program
    279     parser.reported_errors.should have( 2 ).things
    280   end
    281   
    282 end
    283