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