Add support for ATN tracing · antlr/antlr-php-runtime@30a0f09

@@ -24,6 +24,7 @@

2424

use Antlr\Antlr4\Runtime\Error\Exceptions\RecognitionException;

2525

use Antlr\Antlr4\Runtime\IntervalSet;

2626

use Antlr\Antlr4\Runtime\IntStream;

27+

use Antlr\Antlr4\Runtime\LoggerProvider;

2728

use Antlr\Antlr4\Runtime\Parser;

2829

use Antlr\Antlr4\Runtime\ParserRuleContext;

2930

use Antlr\Antlr4\Runtime\PredictionContexts\PredictionContext;

@@ -35,6 +36,8 @@

3536

use Antlr\Antlr4\Runtime\Utils\BitSet;

3637

use Antlr\Antlr4\Runtime\Utils\DoubleKeyMap;

3738

use 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

*/

232235

final class ParserATNSimulator extends ATNSimulator

233236

{

237+

public static bool $traceAtnSimulation = false;

238+234239

protected Parser $parser;

235240236241

/** @var array<DFA> */

@@ -260,6 +265,8 @@ final class ParserATNSimulator extends ATNSimulator

260265261266

protected ?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

}

277285278286

public function reset(): void

@@ -296,6 +304,18 @@ public function clearDFA(): void

296304

*/

297305

public 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(

404424

int $startIndex,

405425

ParserRuleContext $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(

655688

int $startIndex,

656689

ParserRuleContext $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+902949

if ($reach->isEmpty()) {

903950

return 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+9671021

foreach ($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(

14641518

int $depth,

14651519

bool $treatEofAsEpsilon,

14661520

): void {

1521+

if (self::$traceAtnSimulation) {

1522+

$this->logger->debug('closure({config})', [

1523+

'config' => $config->toString(true),

1524+

]);

1525+

}

1526+14671527

if ($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);

2151221121522212

if ($existing instanceof DFAState) {

2213+

if (self::$traceAtnSimulation) {

2214+

$this->logger->debug('addDFAState {state} exists', [

2215+

'state' => $D->__toString(),

2216+

]);

2217+

}

2218+21532219

return $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);

2164223621652237

return $D;