Add support for ATN tracing · antlr/antlr-php-runtime@30a0f09
@@ -24,6 +24,7 @@
2424use Antlr\Antlr4\Runtime\Error\Exceptions\RecognitionException;
2525use Antlr\Antlr4\Runtime\IntervalSet;
2626use Antlr\Antlr4\Runtime\IntStream;
27+use Antlr\Antlr4\Runtime\LoggerProvider;
2728use Antlr\Antlr4\Runtime\Parser;
2829use Antlr\Antlr4\Runtime\ParserRuleContext;
2930use Antlr\Antlr4\Runtime\PredictionContexts\PredictionContext;
@@ -35,6 +36,8 @@
3536use Antlr\Antlr4\Runtime\Utils\BitSet;
3637use Antlr\Antlr4\Runtime\Utils\DoubleKeyMap;
3738use Antlr\Antlr4\Runtime\Utils\Set;
39+use Psr\Log\LoggerInterface as Logger;
40+use Psr\Log\LogLevel;
38413942/**
4043 * The embodiment of the adaptive LL(*), ALL(*), parsing strategy.
231234 */
232235final class ParserATNSimulator extends ATNSimulator
233236{
237+public static bool $traceAtnSimulation = false;
238+234239protected Parser $parser;
235240236241/** @var array<DFA> */
@@ -260,6 +265,8 @@ final class ParserATNSimulator extends ATNSimulator
260265261266protected ?DFA $dfa = null;
262267268+private Logger $logger;
269+263270/**
264271 * @param array<DFA> $decisionToDFA
265272 */
@@ -273,6 +280,7 @@ public function __construct(
273280274281$this->parser = $parser;
275282$this->decisionToDFA = $decisionToDFA;
283+$this->logger = LoggerProvider::getLogger();
276284 }
277285278286public function reset(): void
@@ -296,6 +304,18 @@ public function clearDFA(): void
296304 */
297305public function adaptivePredict(TokenStream $input, int $decision, ParserRuleContext $outerContext): int
298306 {
307+if (self::$traceAtnSimulation) {
308+$this->logger->debug(
309+'adaptivePredict decision {decision} exec LA(1)=={token} line {line}:{pos}',
310+ [
311+'decision' => $decision,
312+'token' => $this->getTokenName($input->LA(1)),
313+'line' => $input->LT(1)?->getLine(),
314+'pos' => $input->LT(1)?->getCharPositionInLine(),
315+ ],
316+ );
317+ }
318+299319$this->input = $input;
300320$this->startIndex = $input->getIndex();
301321$this->outerContext = $outerContext;
@@ -404,6 +424,19 @@ public function execATN(
404424int $startIndex,
405425ParserRuleContext $outerContext,
406426 ): ?int {
427+if (self::$traceAtnSimulation) {
428+$this->logger->debug(
429+'execATN decision {decision}, DFA state {state}, LA(1)=={token} line {line}:{pos}',
430+ [
431+'decision' => $dfa->decision,
432+'state' => $s0->__toString(),
433+'token' => $this->getTokenName($input->LA(1)),
434+'line' => $input->LT(1)?->getLine(),
435+'pos' => $input->LT(1)?->getCharPositionInLine(),
436+ ],
437+ );
438+ }
439+407440$previousD = $s0;
408441409442$t = $input->LA(1);
@@ -655,6 +688,13 @@ protected function execATNWithFullContext(
655688int $startIndex,
656689ParserRuleContext $outerContext,
657690 ): int {
691+if (self::$traceAtnSimulation) {
692+$this->logger->debug('execATNWithFullContext {state}', [
693+'state' => $s0->__toString(),
694+ ]);
695+ }
696+697+658698$fullCtx = true;
659699$foundExactAmbig = false;
660700$reach = null;
@@ -899,6 +939,13 @@ protected function computeReachSet(ATNConfigSet $closure, int $t, bool $fullCtx)
899939 }
900940 }
901941942+if (self::$traceAtnSimulation) {
943+$this->logger->debug('computeReachSet {closure} -> {reach}', [
944+'closure' => $closure->__toString(),
945+'reach' => $reach?->__toString(),
946+ ]);
947+ }
948+902949if ($reach->isEmpty()) {
903950return null;
904951 }
@@ -964,6 +1011,13 @@ protected function computeStartState(ATNState $p, RuleContext $ctx, bool $fullCt
9641011$initialContext = PredictionContext::fromRuleContext($this->atn, $ctx);
9651012$configs = new ATNConfigSet($fullCtx);
96610131014+if (self::$traceAtnSimulation) {
1015+$this->logger->debug('computeStartState from ATN state {state} initialContext={initialContext}', [
1016+'state' => $p->__toString(),
1017+'initialContext' => $initialContext->__toString(),
1018+ ]);
1019+ }
1020+9671021foreach ($p->getTransitions() as $i => $t) {
9681022$c = new ATNConfig(null, $t->target, $initialContext, null, $i + 1);
9691023$closureBusy = new Set();
@@ -1464,6 +1518,12 @@ protected function closureCheckingStopState(
14641518int $depth,
14651519bool $treatEofAsEpsilon,
14661520 ): void {
1521+if (self::$traceAtnSimulation) {
1522+$this->logger->debug('closure({config})', [
1523+'config' => $config->toString(true),
1524+ ]);
1525+ }
1526+14671527if ($config->state instanceof RuleStopState) {
14681528// We hit rule end. If we have context info, use it run thru all possible stack tops in ctx
14691529$context = $config->context;
@@ -2150,6 +2210,12 @@ protected function addDFAState(DFA $dfa, DFAState $D): DFAState
21502210$existing = $dfa->states->get($D);
2151221121522212if ($existing instanceof DFAState) {
2213+if (self::$traceAtnSimulation) {
2214+$this->logger->debug('addDFAState {state} exists', [
2215+'state' => $D->__toString(),
2216+ ]);
2217+ }
2218+21532219return $existing;
21542220 }
21552221@@ -2160,6 +2226,12 @@ protected function addDFAState(DFA $dfa, DFAState $D): DFAState
21602226$D->configs->setReadonly(true);
21612227 }
216222282229+if (self::$traceAtnSimulation) {
2230+$this->logger->debug('addDFAState new {state}', [
2231+'state' => $D->__toString(),
2232+ ]);
2233+ }
2234+21632235$dfa->states->add($D);
2164223621652237return $D;