1<?php 2 3declare(strict_types=1); 4 5namespace Antlr\Antlr4\Runtime\Error; 6 7use Antlr\Antlr4\Runtime\Error\Exceptions\InputMismatchException; 8use Antlr\Antlr4\Runtime\Error\Exceptions\ParseCancellationException; 9use Antlr\Antlr4\Runtime\Error\Exceptions\RecognitionException; 10use Antlr\Antlr4\Runtime\Parser; 11use Antlr\Antlr4\Runtime\ParserRuleContext; 12use Antlr\Antlr4\Runtime\Token; 13 14/** 15 * This implementation of {@see ANTLRErrorStrategy} responds to syntax errors 16 * by immediately canceling the parse operation with a 17 * {@see ParseCancellationException}. The implementation ensures that the 18 * {@see ParserRuleContext::$exception} field is set for all parse tree nodes 19 * that were not completed prior to encountering the error. 20 * 21 * This error strategy is useful in the following scenarios. 22 * 23 * - Two-stage parsing: This error strategy allows the first stage of two-stage 24 * parsing to immediately terminate if an error is encountered, and immediately 25 * fall back to the second stage. In addition to avoiding wasted work by 26 * attempting to recover from errors here, the empty implementation of 27 * {@see BailErrorStrategy::sync()} improves the performance of the first stage. 28 * - Silent validation: When syntax errors are not being reported or logged, 29 * and the parse result is simply ignored if errors occur, the 30 * {@see BailErrorStrategy} avoids wasting work on recovering from errors 31 * when the result will be ignored either way.</li> 32 * 33 * `$myparser->setErrorHandler(new BailErrorStrategy());` 34 * 35 * @see Parser::setErrorHandler() 36 */ 37class BailErrorStrategy extends DefaultErrorStrategy 38{ 39 /** 40 * Instead of recovering from exception `e`, re-throw it wrapped 41 * in a {@see ParseCancellationException} so it is not caught by the 42 * rule function catches. Use {@see Exception::getCause()} to get the 43 * original {@see RecognitionException}. 44 */ 45 public function recover(Parser $recognizer, RecognitionException $e) : void 46 { 47 $context = $recognizer->getContext(); 48 49 while ($context !== null) { 50 if (!$context instanceof ParserRuleContext) { 51 throw new \RuntimeException('Unexpected context type.'); 52 } 53 54 $context->exception = $e; 55 $context = $context->getParent(); 56 } 57 58 throw ParseCancellationException::from($e); 59 } 60 61 /** 62 * Make sure we don't attempt to recover inline; if the parser successfully 63 * recovers, it won't throw an exception. 64 * 65 * @throws ParseCancellationException 66 */ 67 public function recoverInline(Parser $recognizer) : Token 68 { 69 $e = new InputMismatchException($recognizer); 70 71 for ($context = $recognizer->getContext(); $context; $context = $context->getParent()) { 72 if (!$context instanceof ParserRuleContext) { 73 throw new \RuntimeException('Unexpected context type.'); 74 } 75 76 $context->exception = $e; 77 } 78 79 throw ParseCancellationException::from($e); 80 } 81 82 /** 83 * Make sure we don't attempt to recover from problems in subrules. 84 */ 85 public function sync(Parser $recognizer) : void 86 { 87 } 88} 89