From 18deed5a66da329d852d9d25b19e000972034af9 Mon Sep 17 00:00:00 2001 From: Eric Vergnaud Date: Mon, 26 Feb 2024 13:25:33 +0100 Subject: [PATCH] complete migration of #39 --- .../v5/runtime/core/atn/ATNDeserializer.kt | 28 +++++++---- .../antlr/v5/runtime/core/state/ATNState.kt | 47 +++++++++++-------- .../core/transition/CodePointTransitions.kt | 7 +-- 3 files changed, 49 insertions(+), 33 deletions(-) diff --git a/runtime/Core/src/main/kotlin/org/antlr/v5/runtime/core/atn/ATNDeserializer.kt b/runtime/Core/src/main/kotlin/org/antlr/v5/runtime/core/atn/ATNDeserializer.kt index 698f64003..1d4fa5557 100644 --- a/runtime/Core/src/main/kotlin/org/antlr/v5/runtime/core/atn/ATNDeserializer.kt +++ b/runtime/Core/src/main/kotlin/org/antlr/v5/runtime/core/atn/ATNDeserializer.kt @@ -13,6 +13,7 @@ import org.antlr.v5.runtime.core.misc.decodeIntsEncodedAs16BitWords import org.antlr.v5.runtime.core.state.* import org.antlr.v5.runtime.core.transition.* + /** * @author Sam Harwell */ @@ -265,8 +266,8 @@ public open class ATNDeserializer(deserializationOptions: ATNDeserializationOpti var endState: ATNState? var excludeTransition: Transition? = null - - if (atn.ruleToStartState!![i].isLeftRecursiveRule) { + val ruleStartState = atn.ruleToStartState!![i] + if (ruleStartState.isLeftRecursiveRule) { // Wrap from the beginning of the rule to the StarLoopEntryState endState = null @@ -285,7 +286,7 @@ public open class ATNDeserializer(deserializationOptions: ATNDeserializationOpti continue } - if (maybeLoopEndState.epsilonOnlyTransitions && maybeLoopEndState.transition(0).target is RuleStopState) { + if (maybeLoopEndState.onlyHasEpsilonTransitions() && maybeLoopEndState.transition(0).target is RuleStopState) { endState = state break } @@ -314,19 +315,30 @@ public open class ATNDeserializer(deserializationOptions: ATNDeserializationOpti } // All transitions leaving the rule start state need to leave blockStart instead - while (atn.ruleToStartState!![i].numberOfTransitions > 0) { - val transition = atn.ruleToStartState!![i].removeTransition(atn.ruleToStartState!![i].numberOfTransitions - 1) + while (ruleStartState.numberOfTransitions > 0) { + val transition = ruleStartState.removeTransition(ruleStartState.numberOfTransitions - 1) bypassStart.addTransition(transition) } // Link the new states - atn.ruleToStartState!![i].addTransition(EpsilonTransition(bypassStart)) + ruleStartState.addTransition(EpsilonTransition(bypassStart)) bypassStop.addTransition(EpsilonTransition(endState!!)) val matchState = BasicState() atn.addState(matchState) matchState.addTransition(AtomTransition(bypassStop, atn.ruleToTokenType!![i])) - bypassStart.addTransition(EpsilonTransition(matchState)) + + if (bypassStart.onlyHasEpsilonTransitions()) { + bypassStart.addTransition(EpsilonTransition(matchState)) + } else { + val matchState2: ATNState = BasicState() + atn.addState(matchState2) + matchState2.addTransition(bypassStart.transition(0)) + + bypassStart.removeTransition(0) + bypassStart.addTransition(EpsilonTransition(matchState)) + bypassStart.addTransition(EpsilonTransition(matchState2)) + } } if (deserializationOptions.isVerifyATN) { @@ -384,7 +396,7 @@ public open class ATNDeserializer(deserializationOptions: ATNDeserializationOpti val maybeLoopEndState = state.transition(state.numberOfTransitions - 1).target if (maybeLoopEndState is LoopEndState) { - if (maybeLoopEndState.epsilonOnlyTransitions && maybeLoopEndState.transition(0).target is RuleStopState) { + if (maybeLoopEndState.onlyHasEpsilonTransitions() && maybeLoopEndState.transition(0).target is RuleStopState) { state.isPrecedenceDecision = true } } diff --git a/runtime/Core/src/main/kotlin/org/antlr/v5/runtime/core/state/ATNState.kt b/runtime/Core/src/main/kotlin/org/antlr/v5/runtime/core/state/ATNState.kt index 8249f29ad..dc75c9ba2 100644 --- a/runtime/Core/src/main/kotlin/org/antlr/v5/runtime/core/state/ATNState.kt +++ b/runtime/Core/src/main/kotlin/org/antlr/v5/runtime/core/state/ATNState.kt @@ -65,7 +65,7 @@ public abstract class ATNState { public var atn: ATN? = null public var stateNumber: Int = INVALID_STATE_NUMBER public var ruleIndex: Int = 0 // at runtime, we don't have Rule objects - public var epsilonOnlyTransitions: Boolean = false + public var epsilonOnlyTransitions: Boolean? = null /** * Track the transitions emanating from this ATN state. @@ -102,14 +102,10 @@ public abstract class ATNState { addTransition(transitions.size, e) public fun addTransition(index: Int, e: Transition) { - if (transitions.isEmpty()) { - epsilonOnlyTransitions = e.isEpsilon - } else if (epsilonOnlyTransitions != e.isEpsilon) { - System.err.println("ATN state $stateNumber has both epsilon and non-epsilon transitions.") - epsilonOnlyTransitions = false - } - - var alreadyPresent = false + if(epsilonOnlyTransitions != null && epsilonOnlyTransitions != e.isEpsilon) { + System.err.println("ATN state $stateNumber has both epsilon and non-epsilon transitions.") + } + var alreadyPresent = false for (t in transitions) { if (t.target.stateNumber == e.target.stateNumber) { @@ -125,6 +121,7 @@ public abstract class ATNState { if (!alreadyPresent) { transitions.add(index, e) + recalculateEpsilonOnlyTransitions(); } } @@ -135,32 +132,44 @@ public abstract class ATNState { return transitions.indexOf(transition) } - fun findTransition(predicate: java.util.function.Predicate?): Transition? { - return transitions.stream().filter(predicate).findFirst().orElse(null) - } + public fun setTransition(i: Int, e: Transition) { + transitions.removeAt(i); + recalculateEpsilonOnlyTransitions(); + if (epsilonOnlyTransitions != null && epsilonOnlyTransitions != e.isEpsilon) { + System.err.println("ATN state $stateNumber has both epsilon and non-epsilon transitions.\n"); + } + transitions.add(i, e); + recalculateEpsilonOnlyTransitions(); + } + public fun removeTransition(index: Int): Transition { + val result = transitions.removeAt(index) + recalculateEpsilonOnlyTransitions() + return result - public fun setTransition(i: Int, e: Transition) { - transitions[i] = e } - public fun removeTransition(index: Int): Transition = - transitions.removeAt(index) - public fun removeTransition(transition: Transition): Boolean { val result = transitions.remove(transition) recalculateEpsilonOnlyTransitions() return result } + + fun findTransition(predicate: java.util.function.Predicate?): Transition? { + return transitions.stream().filter(predicate).findFirst().orElse(null) + } + + + public fun clearTransitions() { transitions.clear() } public fun onlyHasEpsilonTransitions(): Boolean = - epsilonOnlyTransitions + epsilonOnlyTransitions != null && epsilonOnlyTransitions!! fun recalculateEpsilonOnlyTransitions() { if (transitions.size == 0) { - epsilonOnlyTransitions = false + epsilonOnlyTransitions = null } else { epsilonOnlyTransitions = transitions.stream().allMatch(Transition::isEpsilon) } diff --git a/runtime/Core/src/main/kotlin/org/antlr/v5/runtime/core/transition/CodePointTransitions.kt b/runtime/Core/src/main/kotlin/org/antlr/v5/runtime/core/transition/CodePointTransitions.kt index 92a4be01e..f3c56e0c3 100644 --- a/runtime/Core/src/main/kotlin/org/antlr/v5/runtime/core/transition/CodePointTransitions.kt +++ b/runtime/Core/src/main/kotlin/org/antlr/v5/runtime/core/transition/CodePointTransitions.kt @@ -19,13 +19,8 @@ import org.antlr.v5.runtime.core.state.ATNState */ @Suppress("MemberVisibilityCanBePrivate") public object CodePointTransitions { - /** - * Return new [AtomTransition]. - */ - public fun createWithCodePoint(target: ATNState, codePoint: Int): Transition = - createWithCodePointRange(target, codePoint, codePoint) - /** + /** * Return new [AtomTransition] if range represents one atom, else [SetTransition]. */ public fun createWithCodePointRange(target: ATNState, codePointFrom: Int, codePointTo: Int): Transition =