1 #!/usr/bin/ruby 2 # encoding: utf-8 3 4 =begin LICENSE 5 6 [The "BSD licence"] 7 Copyright (c) 2009-2010 Kyle Yetter 8 All rights reserved. 9 10 Redistribution and use in source and binary forms, with or without 11 modification, are permitted provided that the following conditions 12 are met: 13 14 1. Redistributions of source code must retain the above copyright 15 notice, this list of conditions and the following disclaimer. 16 2. Redistributions in binary form must reproduce the above copyright 17 notice, this list of conditions and the following disclaimer in the 18 documentation and/or other materials provided with the distribution. 19 3. The name of the author may not be used to endorse or promote products 20 derived from this software without specific prior written permission. 21 22 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 33 =end 34 35 # ANTLR3 exception hierarchy 36 # - ported from the ANTLR3 Python Runtime library by 37 # Kyle Yetter (kcy5b (at] yahoo.com) 38 module ANTLR3 39 40 # for compatibility with rubinius, which does not implement StopIteration yet 41 unless defined?( StopIteration ) 42 StopIteration = Class.new( StandardError ) 43 end 44 45 module Error 46 47 =begin rdoc ANTLR3::Error::BacktrackingFailed 48 49 error:: BacktrackingFailed 50 used by:: all recognizers 51 occurs when:: 52 recognizer is in backtracking mode (i.e. r.state.backtracking > 0) 53 and the decision path the recognizer is currently attempting 54 hit a point of failure 55 notes:: 56 - functions more as an internal signal, simillar to exception 57 classes such as StopIteration and SystemExit 58 - used to inform the recognizer that it needs to rewind 59 the input to the point at which it started the decision 60 and then either try another possible decision path or 61 declare failure 62 - not a subclass of RecognitionError 63 64 =end 65 66 class BacktrackingFailed < StandardError; end 67 68 # To avoid English-only error messages and to generally make things 69 # as flexible as possible, these exceptions are not created with strings, 70 # but rather the information necessary to generate an error. Then 71 # the various reporting methods in Parser and Lexer can be overridden 72 # to generate a localized error message. For example, MismatchedToken 73 # exceptions are built with the expected token type. 74 # So, don't expect getMessage() to return anything. 75 # 76 # Note that as of Java 1.4, you can access the stack trace, which means 77 # that you can compute the complete trace of rules from the start symbol. 78 # This gives you considerable context information with which to generate 79 # useful error messages. 80 # 81 # ANTLR generates code that throws exceptions upon recognition error and 82 # also generates code to catch these exceptions in each rule. If you 83 # want to quit upon first error, you can turn off the automatic error 84 # handling mechanism using rulecatch action, but you still need to 85 # override methods mismatch and recoverFromMismatchSet. 86 # 87 # In general, the recognition exceptions can track where in a grammar a 88 # problem occurred and/or what was the expected input. While the parser 89 # knows its state (such as current input symbol and line info) that 90 # state can change before the exception is reported so current token index 91 # is computed and stored at exception time. From this info, you can 92 # perhaps print an entire line of input not just a single token, for example. 93 # Better to just say the recognizer had a problem and then let the parser 94 # figure out a fancy report. 95 96 =begin rdoc ANTLR3::Error::RecognitionError 97 98 The base class of the variety of syntax errors that can occur during the 99 recognition process. These errors all typically concern an expectation built in 100 to the recognizer by the rules of a grammar and an input symbol which failed to 101 fit the expectation. 102 103 =end 104 105 class RecognitionError < StandardError 106 include ANTLR3::Constants 107 attr_accessor :input, :index, :line, :column, :symbol, :token, :source_name 108 109 def initialize( input = nil ) 110 @index = @line = @column = nil 111 @approximate_line_info = false 112 if @input = input 113 @index = input.index 114 @source_name = @input.source_name rescue nil 115 case @input 116 when TokenStream 117 @token = @symbol = input.look 118 @line = @symbol.line 119 @column = @symbol.column 120 when CharacterStream 121 @token = @symbol = input.peek || EOF 122 @line = @input.line 123 @column = @input.column 124 when AST::TreeNodeStream 125 @symbol = @input.look 126 if @symbol.respond_to?( :line ) and @symbol.respond_to?( :column ) 127 @line, @column = @symbol.line, @symbol.column 128 else 129 extract_from_node_stream( @input ) 130 end 131 else 132 @symbol = @input.look 133 if @symbol.respond_to?( :line ) and @symbol.respond_to?( :column ) 134 @line, @column = @symbol.line, @symbol.column 135 elsif @input.respond_to?( :line ) and @input.respond_to?( :column ) 136 @line, @column = @input.line, @input.column 137 end 138 end 139 end 140 super( message ) 141 end 142 143 def approximate_line_info? 144 @approximate_line_info 145 end 146 147 def unexpected_type 148 case @input 149 when TokenStream 150 @symbol.type 151 when AST::TreeNodeStream 152 adaptor = @input.adaptor 153 return adaptor.type( @symbol ) 154 else 155 return @symbol 156 end 157 end 158 159 def location 160 if @source_name then "in #@source_name @ line #@line:#@column" 161 else "line #@line:#@column" 162 end 163 end 164 165 alias inspect message 166 167 private 168 169 def extract_from_node_stream( nodes ) 170 adaptor = nodes.adaptor 171 payload = adaptor.token( @symbol ) 172 173 if payload 174 @token = payload 175 if payload.line <= 0 176 i = -1 177 while prior_node = nodes.look( i ) 178 prior_payload = adaptor.token( prior_node ) 179 if prior_payload and prior_payload.line > 0 180 @line = prior_payload.line 181 @column = prior_payload.column 182 @approximate_line_info = true 183 break 184 end 185 i -= 1 186 end 187 else 188 @line = payload.line 189 @column = payload.column 190 end 191 elsif @symbol.is_a?( AST::Tree ) 192 @line = @symbol.line 193 @column = @symbol.column 194 @symbol.is_a?( AST::CommonTree ) and @token = @symbol.token 195 else 196 type = adaptor.type( @symbol ) 197 text = adaptor.text( @symbol ) 198 token_class = @input.token_class rescue CommonToken 199 @token = token_class.new 200 @token.type = type 201 @token.text = text 202 @token 203 end 204 end 205 end 206 207 =begin rdoc ANTLR3::Error::MismatchedToken 208 209 type:: MismatchedToken 210 used by:: lexers and parsers 211 occurs when:: 212 The recognizer expected to match a symbol <tt>x</tt> at the current input 213 position, but it saw a different symbol <tt>y</tt> instead. 214 215 =end 216 217 class MismatchedToken < RecognitionError 218 attr_reader :expecting 219 220 def initialize( expecting, input ) 221 @expecting = expecting 222 super( input ) 223 end 224 225 def message 226 "%s: %p %p" % [ self.class, unexpected_type, @expecting.inspect ] 227 end 228 end 229 230 =begin rdoc ANTLR3::Error::UnwantedToken 231 232 TODO: this does not appear to be used by any code 233 234 =end 235 236 class UnwantedToken < MismatchedToken 237 def unexpected_token 238 return @token 239 end 240 241 def message 242 exp = @expecting == INVALID_TOKEN_TYPE ? '' : ", expected %p" % @expecting 243 text = @symbol.text rescue nil 244 "%s: found=%p%s" % [ self.class, text, exp ] 245 end 246 end 247 248 =begin rdoc ANTLR3::Error::MissingToken 249 250 error:: MissingToken 251 used by:: parsers and tree parsers 252 occurs when:: 253 The recognizer expected to match some symbol, but it sees a different symbol. 254 The symbol it sees is actually what the recognizer expected to match next. 255 256 === Example 257 258 grammar: 259 260 grammar MissingTokenExample; 261 262 options { language = Ruby; } 263 264 @members { 265 def report_error(e) 266 raise e 267 end 268 } 269 270 missing: A B C; 271 272 A: 'a'; 273 B: 'b'; 274 C: 'c'; 275 276 in ruby: 277 278 require 'MissingTokenExampleLexer' 279 require 'MissingTokenExampleParser' 280 281 lexer = MissingTokenExample::Lexer.new( "ac" ) # <= notice the missing 'b' 282 tokens = ANTLR3::CommonTokenStream.new( lexer ) 283 parser = MissingTokenExample::Parser.new( tokens ) 284 285 parser.missing 286 # raises ANTLR3::Error::MissingToken: at "c" 287 288 =end 289 290 class MissingToken < MismatchedToken 291 attr_accessor :inserted 292 def initialize( expecting, input, inserted ) 293 super( expecting, input ) 294 @inserted = inserted 295 end 296 297 def missing_type 298 return @expecting 299 end 300 301 def message 302 if @inserted and @symbol 303 "%s: inserted %p at %p" % 304 [ self.class, @inserted, @symbol.text ] 305 else 306 msg = self.class.to_s 307 msg << ': at %p' % token.text unless @token.nil? 308 return msg 309 end 310 end 311 end 312 313 =begin rdoc ANTLR3::Error::MismatchedRange 314 315 error:: MismatchedRange 316 used by:: all recognizers 317 occurs when:: 318 A recognizer expected to match an input symbol (either a character value or 319 an integer token type value) that falls into a range of possible values, but 320 instead it saw a symbol that falls outside the expected range. 321 322 =end 323 324 class MismatchedRange < RecognitionError 325 attr_accessor :min, :max 326 def initialize( min, max, input ) 327 @min = min 328 @max = max 329 super( input ) 330 end 331 332 def message 333 "%s: %p not in %p..%p" % 334 [ self.class, unexpected_type, @min, @max ] 335 end 336 end 337 338 =begin rdoc ANTLR3::Error::MismatchedSet 339 340 error:: MismatchedSet 341 used by:: all recognizers 342 occurs when:: 343 A recognizer expects the current input symbol to be a member of a set of 344 possible symbol values, but the current symbol does not match. 345 346 =end 347 348 class MismatchedSet < RecognitionError 349 attr_accessor :expecting 350 def initialize( expecting, input ) 351 super( input ) 352 @expecting = expecting 353 end 354 355 def message 356 "%s: %p not in %p" % 357 [ self.class, unexpected_type, @expecting ] 358 end 359 end 360 361 =begin rdoc ANTLR3::Error::MismatchedNotSet 362 363 error:: MismatchedNotSet 364 used by:: all recognizers 365 occurs when:: 366 A recognizer expected to match symbol that is not in some set of symbols but 367 failed. 368 369 =end 370 371 class MismatchedNotSet < MismatchedSet 372 def message 373 '%s: %p != %p' % 374 [ self.class, unexpected_type, @expecting ] 375 end 376 end 377 378 =begin rdoc ANTLR3::Error::NoViableAlternative 379 380 error:: NoViableAlternative 381 used by:: all recognizers 382 occurs when:: 383 A recognizer must choose between multiple possible recognition paths based 384 upon the current and future input symbols, but it has determined that 385 the input does not suit any of the possible recognition alternatives. 386 387 In ANTLR terminology, a rule is composed of one or more _alternatives_, 388 specifications seperated by <tt>|</tt> characters. An alternative is composed of 389 a series of elements, including _subrules_ -- rule specifications enclosed 390 within parentheses. When recognition code enters a rule method (or a subrule 391 block) that has multiple alternatives, the recognizer must decide which one of 392 the multiple possible paths to follow by checking a number of future input 393 symbols. Thus, NoViableAlternative errors indicate that the current input does 394 not fit any of the possible paths. 395 396 In lexers, this error is often raised by the main +tokens!+ rule, which must 397 choose between all possible token rules. If raised by +tokens+, it means the 398 current input does not appear to be part of any token specification. 399 400 =end 401 402 class NoViableAlternative < RecognitionError 403 attr_accessor :grammar_decision_description, :decision_number, :state_number 404 def initialize( grammar_decision_description, decision_number, state_number, input ) 405 @grammar_decision_description = grammar_decision_description 406 @decision_number = decision_number 407 @state_number = state_number 408 super( input ) 409 end 410 411 def message 412 '%s: %p != [%p]' % 413 [ self.class, unexpected_type, @grammar_decision_description ] 414 end 415 end 416 417 =begin rdoc ANTLR3::Error::EarlyExit 418 419 error:: EarlyExit 420 used by:: all recognizers 421 occurs when:: 422 The recognizer is in a <tt>(..)+</tt> subrule, meaning the recognizer must 423 match the body of the subrule one or more times. If it fails to match at least 424 one occurence of the subrule, the recognizer will raise an EarlyExit 425 exception. 426 427 == Example 428 429 consider a grammar like: 430 lexer grammar EarlyExitDemo; 431 ... 432 ID: 'a'..'z' ('0'..'9')+; 433 434 now in ruby 435 436 require 'EarlyExitDemo' 437 438 input = ANTLR3::StringStream.new( "ab" ) 439 lexer = EarlyExitDemo::Lexer.new( input ) 440 lexer.next_token 441 # -> raises EarlyExit: line 1:1 required (...)+ loop did not match 442 # anything at character "b" 443 444 =end 445 446 class EarlyExit < RecognitionError 447 attr_accessor :decision_number 448 449 def initialize( decision_number, input ) 450 @decision_number = decision_number 451 super( input ) 452 end 453 454 def message 455 "The recognizer did not match anything for a (..)+ loop." 456 end 457 458 end 459 460 =begin rdoc ANTLR3::Error::FailedPredicate 461 462 error:: FailedPredicate 463 used by:: all recognizers 464 occurs when:: 465 A recognizer is in a rule with a predicate action element, and the predicating 466 action code evaluated to a +false+ value. 467 468 =end 469 470 class FailedPredicate < RecognitionError 471 attr_accessor :input, :rule_name, :predicate_text 472 def initialize( input, rule_name, predicate_text ) 473 @rule_name = rule_name 474 @predicate_text = predicate_text 475 super( input ) 476 end 477 478 def inspect 479 '%s(%s, { %s }?)' % [ self.class.name, @rule_name, @predicate_text ] 480 end 481 482 def message 483 "rule #@rule_name failed predicate: { #@predicate_text }?" 484 end 485 end 486 487 =begin rdoc ANTLR3::Error::MismatchedTreeNode 488 489 error:: MismatchedTreeNode 490 used by:: tree parsers 491 occurs when:: 492 A tree parser expects to match a tree node containing a specific type of 493 token, but the current tree node's token type does not match. It's essentially 494 the same as MismatchedToken, but used specifically for tree nodes. 495 496 =end 497 498 class MismatchedTreeNode < RecognitionError 499 attr_accessor :expecting, :input 500 def initialize( expecting, input ) 501 @expecting = expecting 502 super( input ) 503 end 504 505 def message 506 '%s: %p != %p' % 507 [ self.class, unexpected_type, @expecting ] 508 end 509 end 510 511 =begin rdoc ANTLR3::Error::RewriteCardinalityError 512 513 error:: RewriteCardinalityError 514 used by:: tree-rewriting parsers and tree parsers 515 occurs when:: 516 There is an inconsistency between the number of appearances of some symbol 517 on the left side of a rewrite rule and the number of the same symbol 518 seen on the right side of a rewrite rule 519 520 =end 521 522 class RewriteCardinalityError < StandardError 523 attr_accessor :element_description 524 def initialize( element_description ) 525 @element_description = element_description 526 super( message ) 527 end 528 529 def message 530 "%s: %s" % [ self.class, @element_description ] 531 end 532 end 533 534 =begin rdoc ANTLR3::Error::RewriteEarlyExit 535 536 error:: RewriteEarlyExit 537 used by:: tree-rewriting parsers and tree parsers 538 occurs when:: 539 A tree-rewrite rule requires one or more occurence of a symbol, but none 540 have been seen. 541 542 =end 543 544 class RewriteEarlyExit < RewriteCardinalityError 545 attr_accessor :element_description 546 def initialize( element_description = nil ) 547 super( element_description ) 548 end 549 end 550 551 =begin rdoc ANTLR3::Error::RewriteEmptyStream 552 553 error:: RewriteEmptyStream 554 used by:: tree-rewriting parsers and tree parsers 555 556 =end 557 558 class RewriteEmptyStream < RewriteCardinalityError; end 559 560 =begin rdoc ANTLR3::Error::TreeInconsistency 561 562 error:: TreeInconsistency 563 used by:: classes that deal with tree structures 564 occurs when:: 565 A tree node's data is inconsistent with the overall structure to which it 566 belongs. 567 568 situations that result in tree inconsistencies: 569 570 1. A node has a child node with a +@parent+ attribute different than the node. 571 2. A node has a child at index +n+, but the child's +@child_index+ value is not 572 +n+ 573 3. An adaptor encountered a situation where multiple tree nodes have been 574 simultaneously requested as a new tree root. 575 576 =end 577 578 class TreeInconsistency < StandardError 579 def self.failed_index_check!( expected, real ) 580 new( 581 "%s: child indexes don't match -> expected %d found %d" % 582 [ self, expected, real ] 583 ) 584 end 585 586 def self.failed_parent_check!( expected, real ) 587 new( 588 "%s: parents don't match; expected %p found %p" % 589 [ self, expected, real ] 590 ) 591 end 592 593 def self.multiple_roots! 594 new "%s: attempted to change more than one node to root" % self 595 end 596 end 597 598 module_function 599 600 def MismatchedToken( expecting, input = @input ) 601 MismatchedToken.new( expecting, input ) 602 end 603 604 def UnwantedToken( expecting, input = @input ) 605 UnwantedToken.new( expecting, input ) 606 end 607 608 def MissingToken( expecting, inserted, input = @input ) 609 MissingToken.new( expecting, input, inserted ) 610 end 611 612 def MismatchedRange( min, max, input = @input ) 613 MismatchedRange.new( min, max, input ) 614 end 615 616 def MismatchedSet( expecting, input = @input ) 617 MismatchedSet.new( expecting, input ) 618 end 619 620 def MismatchedNotSet( expecting, input = @input ) 621 MismatchedNotSet.new( expecting, input ) 622 end 623 624 def NoViableAlternative( description, decision, state, input = @input ) 625 NoViableAlternative.new( description, decision, state, input ) 626 end 627 628 def EarlyExit( decision, input = @input ) 629 EarlyExit.new( decision, input ) 630 end 631 632 def FailedPredicate( rule, predicate, input = @input ) 633 FailedPredicate.new( input, rule, predicate ) 634 end 635 636 def MismatchedTreeNode( expecting, input = @input ) 637 MismatchedTreeNode.new( expecting, input ) 638 end 639 640 def RewriteCardinalityError( element_description ) 641 RewriteCardinalityError.new( element_description ) 642 end 643 644 def RewriteEarlyExit( element_description = nil ) 645 RewriteEarlyExit.new( element_description ) 646 end 647 648 def RewriteEmptyStream( element_description ) 649 RewriteEmptyStream.new( element_description ) 650 end 651 652 end 653 654 include Error 655 656 =begin rdoc ANTLR3::Bug 657 658 659 660 =end 661 662 class Bug < StandardError 663 def initialize( message = nil, *args ) 664 message = "something occurred that should not occur within unmodified, " << 665 "ANTLR-generated source code: #{ message }" 666 super( message, *args ) 667 end 668 end 669 670 end 671