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 ;
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 ;
3840
3941/**
4042 * The embodiment of the adaptive LL(*), ALL(*), parsing strategy.
231233 */
232234final class ParserATNSimulator extends ATNSimulator
233235{
236+ public static bool $ traceAtnSimulation = false ;
237+
234238 protected Parser $ parser ;
235239
236240 /** @var array<DFA> */
@@ -260,6 +264,8 @@ final class ParserATNSimulator extends ATNSimulator
260264
261265 protected ?DFA $ dfa = null ;
262266
267+ private Logger $ logger ;
268+
263269 /**
264270 * @param array<DFA> $decisionToDFA
265271 */
@@ -273,6 +279,7 @@ public function __construct(
273279
274280 $ this ->parser = $ parser ;
275281 $ this ->decisionToDFA = $ decisionToDFA ;
282+ $ this ->logger = LoggerProvider::getLogger ();
276283 }
277284
278285 public function reset (): void
@@ -296,6 +303,18 @@ public function clearDFA(): void
296303 */
297304 public function adaptivePredict (TokenStream $ input , int $ decision , ParserRuleContext $ outerContext ): int
298305 {
306+ if (self ::$ traceAtnSimulation ) {
307+ $ this ->logger ->debug (
308+ 'adaptivePredict decision {decision} exec LA(1)=={token} line {line}:{pos} ' ,
309+ [
310+ 'decision ' => $ decision ,
311+ 'token ' => $ this ->getTokenName ($ input ->LA (1 )),
312+ 'line ' => $ input ->LT (1 )?->getLine(),
313+ 'pos ' => $ input ->LT (1 )?->getCharPositionInLine(),
314+ ],
315+ );
316+ }
317+
299318 $ this ->input = $ input ;
300319 $ this ->startIndex = $ input ->getIndex ();
301320 $ this ->outerContext = $ outerContext ;
@@ -404,6 +423,19 @@ public function execATN(
404423 int $ startIndex ,
405424 ParserRuleContext $ outerContext ,
406425 ): ?int {
426+ if (self ::$ traceAtnSimulation ) {
427+ $ this ->logger ->debug (
428+ 'execATN decision {decision}, DFA state {state}, LA(1)=={token} line {line}:{pos} ' ,
429+ [
430+ 'decision ' => $ dfa ->decision ,
431+ 'state ' => $ s0 ->__toString (),
432+ 'token ' => $ this ->getTokenName ($ input ->LA (1 )),
433+ 'line ' => $ input ->LT (1 )?->getLine(),
434+ 'pos ' => $ input ->LT (1 )?->getCharPositionInLine(),
435+ ],
436+ );
437+ }
438+
407439 $ previousD = $ s0 ;
408440
409441 $ t = $ input ->LA (1 );
@@ -655,6 +687,12 @@ protected function execATNWithFullContext(
655687 int $ startIndex ,
656688 ParserRuleContext $ outerContext ,
657689 ): int {
690+ if (self ::$ traceAtnSimulation ) {
691+ $ this ->logger ->debug ('execATNWithFullContext {state} ' , [
692+ 'state ' => $ s0 ->__toString (),
693+ ]);
694+ }
695+
658696 $ fullCtx = true ;
659697 $ foundExactAmbig = false ;
660698 $ reach = null ;
@@ -890,15 +928,18 @@ protected function computeReachSet(ATNConfigSet $closure, int $t, bool $fullCtx)
890928 * multiple alternatives are viable.*/
891929
892930 if ($ skippedStopStates !== null && (!$ fullCtx || !PredictionMode::hasConfigInRuleStopState ($ reach ))) {
893- if (\count ($ skippedStopStates ) === 0 ) {
894- throw new \LogicException ('Skipped stop states cannot be empty. ' );
895- }
896-
897931 foreach ($ skippedStopStates as $ lValue ) {
898932 $ reach ->add ($ lValue , $ this ->mergeCache );
899933 }
900934 }
901935
936+ if (self ::$ traceAtnSimulation ) {
937+ $ this ->logger ->debug ('computeReachSet {closure} -> {reach} ' , [
938+ 'closure ' => $ closure ->__toString (),
939+ 'reach ' => $ reach ->__toString (),
940+ ]);
941+ }
942+
902943 if ($ reach ->isEmpty ()) {
903944 return null ;
904945 }
@@ -964,6 +1005,13 @@ protected function computeStartState(ATNState $p, RuleContext $ctx, bool $fullCt
9641005 $ initialContext = PredictionContext::fromRuleContext ($ this ->atn , $ ctx );
9651006 $ configs = new ATNConfigSet ($ fullCtx );
9661007
1008+ if (self ::$ traceAtnSimulation ) {
1009+ $ this ->logger ->debug ('computeStartState from ATN state {state} initialContext={initialContext} ' , [
1010+ 'state ' => $ p ->__toString (),
1011+ 'initialContext ' => $ initialContext ->__toString (),
1012+ ]);
1013+ }
1014+
9671015 foreach ($ p ->getTransitions () as $ i => $ t ) {
9681016 $ c = new ATNConfig (null , $ t ->target , $ initialContext , null , $ i + 1 );
9691017 $ closureBusy = new Set ();
@@ -1464,6 +1512,12 @@ protected function closureCheckingStopState(
14641512 int $ depth ,
14651513 bool $ treatEofAsEpsilon ,
14661514 ): void {
1515+ if (self ::$ traceAtnSimulation ) {
1516+ $ this ->logger ->debug ('closure({config}) ' , [
1517+ 'config ' => $ config ->toString (true ),
1518+ ]);
1519+ }
1520+
14671521 if ($ config ->state instanceof RuleStopState) {
14681522 // We hit rule end. If we have context info, use it run thru all possible stack tops in ctx
14691523 $ context = $ config ->context ;
@@ -2150,6 +2204,12 @@ protected function addDFAState(DFA $dfa, DFAState $D): DFAState
21502204 $ existing = $ dfa ->states ->get ($ D );
21512205
21522206 if ($ existing instanceof DFAState) {
2207+ if (self ::$ traceAtnSimulation ) {
2208+ $ this ->logger ->debug ('addDFAState {state} exists ' , [
2209+ 'state ' => $ D ->__toString (),
2210+ ]);
2211+ }
2212+
21532213 return $ existing ;
21542214 }
21552215
@@ -2160,6 +2220,12 @@ protected function addDFAState(DFA $dfa, DFAState $D): DFAState
21602220 $ D ->configs ->setReadonly (true );
21612221 }
21622222
2223+ if (self ::$ traceAtnSimulation ) {
2224+ $ this ->logger ->debug ('addDFAState new {state} ' , [
2225+ 'state ' => $ D ->__toString (),
2226+ ]);
2227+ }
2228+
21632229 $ dfa ->states ->add ($ D );
21642230
21652231 return $ D ;
0 commit comments