diff --git a/runtime/Swift/Antlr4/org/antlr/v4/runtime/BufferedTokenStream.swift b/runtime/Swift/Antlr4/org/antlr/v4/runtime/BufferedTokenStream.swift index 1c1122812..1f0ed2c44 100644 --- a/runtime/Swift/Antlr4/org/antlr/v4/runtime/BufferedTokenStream.swift +++ b/runtime/Swift/Antlr4/org/antlr/v4/runtime/BufferedTokenStream.swift @@ -473,8 +473,6 @@ public class BufferedTokenStream: TokenStream { public func getText() throws -> String { - try lazyInit() - try fill() return try getText(Interval.of(0, size() - 1)) } @@ -485,7 +483,7 @@ public class BufferedTokenStream: TokenStream { if start < 0 || stop < 0 { return "" } - try lazyInit() + try fill() if stop >= tokens.count { stop = tokens.count - 1 } diff --git a/runtime/Swift/Antlr4/org/antlr/v4/runtime/atn/ParserATNSimulator.swift b/runtime/Swift/Antlr4/org/antlr/v4/runtime/atn/ParserATNSimulator.swift index 4e7ff246c..3488bff0a 100644 --- a/runtime/Swift/Antlr4/org/antlr/v4/runtime/atn/ParserATNSimulator.swift +++ b/runtime/Swift/Antlr4/org/antlr/v4/runtime/atn/ParserATNSimulator.swift @@ -232,13 +232,20 @@ * both SLL and LL parsing. Erroneous input will therefore require 2 passes over * the input.

*/ +import Foundation open class ParserATNSimulator: ATNSimulator { public let debug: Bool = false public let debug_list_atn_decisions: Bool = false public let dfa_debug: Bool = false public let retry_debug: Bool = false - + /** Just in case this optimization is bad, add an ENV variable to turn it off */ + public static let TURN_OFF_LR_LOOP_ENTRY_BRANCH_OPT: Bool = { + if let value = ProcessInfo.processInfo.environment["TURN_OFF_LR_LOOP_ENTRY_BRANCH_OPT"] { + return NSString(string: value).boolValue + } + return false + }() internal final var parser: Parser public final var decisionToDFA: [DFA] @@ -1441,6 +1448,10 @@ open class ParserATNSimulator: ATNSimulator { } let length = p.getNumberOfTransitions() for i in 0.. Bool { + if ParserATNSimulator.TURN_OFF_LR_LOOP_ENTRY_BRANCH_OPT { + return false + } + let p: ATNState = config.state + guard let configContext = config.context else { + return false + } + // First check to see if we are in StarLoopEntryState generated during + // left-recursion elimination. For efficiency, also check if + // the context has an empty stack case. If so, it would mean + // global FOLLOW so we can't perform optimization + if p.getStateType() != ATNState.STAR_LOOP_ENTRY || + !( (p as! StarLoopEntryState)).precedenceRuleDecision || // Are we the special loop entry/exit state? + configContext.isEmpty() || // If SLL wildcard + configContext.hasEmptyPath(){ + return false + } + + // Require all return states to return back to the same rule + // that p is in. + let numCtxs: Int = configContext.size() + for i in 0 ..< numCtxs { // for each stack context + let returnState: ATNState = atn.states[configContext.getReturnState(i)]! + if returnState.ruleIndex != p.ruleIndex + {return false} + } + + let decisionStartState: BlockStartState = (p.transition(0).target as! BlockStartState) + let blockEndStateNum: Int = decisionStartState.endState!.stateNumber + let blockEndState: BlockEndState = (atn.states[blockEndStateNum] as! BlockEndState) + + // Verify that the top of each stack context leads to loop entry/exit + // state through epsilon edges and w/o leaving rule. + for i in 0 ..< numCtxs { // for each stack context + let returnStateNumber: Int = configContext.getReturnState(i) + let returnState: ATNState = atn.states[returnStateNumber]! + // all states must have single outgoing epsilon edge + if returnState.getNumberOfTransitions() != 1 || !returnState.transition(0).isEpsilon(){ + return false + } + // Look for prefix op case like 'not expr', (' type ')' expr + let returnStateTarget: ATNState = returnState.transition(0).target + if returnState.getStateType() == ATNState.BLOCK_END && + returnStateTarget == p { + continue + } + // Look for 'expr op expr' or case where expr's return state is block end + // of (...)* internal block; the block end points to loop back + // which points to p but we don't need to check that + if returnState == blockEndState{ + continue + } + // Look for ternary expr ? expr : expr. The return state points at block end, + // which points at loop entry state + if returnStateTarget == blockEndState{ + continue + } + // Look for complex prefix 'between expr and expr' case where 2nd expr's + // return state points at block end state of (...)* internal block + if returnStateTarget.getStateType() == ATNState.BLOCK_END && + returnStateTarget.getNumberOfTransitions() == 1 && + returnStateTarget.transition(0).isEpsilon() && + returnStateTarget.transition(0).target == p{ + continue + } + + // anything else ain't conforming + return false + } + + return true + } + open func getRuleName(_ index: Int) -> String { if index >= 0 { return parser.getRuleNames()[index]