Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't Panic! 50% plus performance improvement #4192

Merged
merged 2 commits into from
Mar 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ s
[input]
b

[skip]
Go

Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,9 @@ AppendStr(a,b) ::= "<a> + <b>"
Concat(a,b) ::= "<a><b>"

AssertIsList(v) ::= <<
// A noddy range over the list will not compile if it is not getting a slice
// however, Go will not compile the generated code if the slice vs single value is wrong.
// Makes the Java based tests suite work though.
j1__ := make([]interface{}, len(<v>))
j2__ := <v>
for j3__ := range j2__ {
j1__[j3__] = j2__[j3__]
// Go will not compile this generated code if the slice vs single value is wrong.
for i := range localctx.(*ExpressionContext).GetArgs() {
_ = localctx.(*ExpressionContext).GetArgs()[i]
}
>>

Expand Down
9 changes: 5 additions & 4 deletions runtime/Go/antlr/v4/error_strategy.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func (d *DefaultErrorStrategy) ReportError(recognizer Parser, e RecognitionExcep
// It reSynchronizes the parser by consuming tokens until we find one in the reSynchronization set -
// loosely the set of tokens that can follow the current rule.
func (d *DefaultErrorStrategy) Recover(recognizer Parser, _ RecognitionException) {

if d.lastErrorIndex == recognizer.GetInputStream().Index() &&
d.lastErrorStates != nil && d.lastErrorStates.contains(recognizer.GetState()) {
// uh oh, another error at same token index and previously-Visited
Expand Down Expand Up @@ -206,7 +206,7 @@ func (d *DefaultErrorStrategy) Sync(recognizer Parser) {
if d.SingleTokenDeletion(recognizer) != nil {
return
}
panic(NewInputMisMatchException(recognizer))
recognizer.SetError(NewInputMisMatchException(recognizer))
case ATNStatePlusLoopBack, ATNStateStarLoopBack:
d.ReportUnwantedToken(recognizer)
expecting := NewIntervalSet()
Expand Down Expand Up @@ -362,7 +362,8 @@ func (d *DefaultErrorStrategy) RecoverInline(recognizer Parser) Token {
return d.GetMissingSymbol(recognizer)
}
// even that didn't work must panic the exception
panic(NewInputMisMatchException(recognizer))
recognizer.SetError(NewInputMisMatchException(recognizer))
return nil
}

// SingleTokenInsertion implements the single-token insertion inline error recovery
Expand Down Expand Up @@ -685,7 +686,7 @@ func (b *BailErrorStrategy) Recover(recognizer Parser, e RecognitionException) {
context = nil
}
}
panic(NewParseCancellationException()) // TODO: we don't emit e properly
recognizer.SetError(NewParseCancellationException()) // TODO: we don't emit e properly
}

// RecoverInline makes sure we don't attempt to recover inline if the parser
Expand Down
21 changes: 18 additions & 3 deletions runtime/Go/antlr/v4/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ func NewBaseRecognitionException(message string, recognizer Recognizer, input In
t.recognizer = recognizer
t.input = input
t.ctx = ctx

// The current Token when an error occurred. Since not all streams
// support accessing symbols by index, we have to track the {@link Token}
// instance itself.
//
t.offendingToken = nil

// Get the ATN state number the parser was in at the time the error
// occurred. For NoViableAltException and LexerNoViableAltException exceptions, this is the
// DecisionState number. For others, it is the state whose outgoing edge we couldn't Match.
Expand Down Expand Up @@ -162,7 +162,7 @@ func NewNoViableAltException(recognizer Parser, input TokenStream, startToken To
// Which configurations did we try at input.Index() that couldn't Match
// input.LT(1)
n.deadEndConfigs = deadEndConfigs

// The token object at the start index the input stream might
// not be buffering tokens so get a reference to it.
//
Expand Down Expand Up @@ -236,6 +236,21 @@ func (f *FailedPredicateException) formatMessage(predicate, message string) stri
type ParseCancellationException struct {
}

func (p ParseCancellationException) GetOffendingToken() Token {
//TODO implement me
panic("implement me")
}

func (p ParseCancellationException) GetMessage() string {
//TODO implement me
panic("implement me")
}

func (p ParseCancellationException) GetInputStream() IntStream {
//TODO implement me
panic("implement me")
}

func NewParseCancellationException() *ParseCancellationException {
// Error.call(this)
// Error.captureStackTrace(this, ParseCancellationException)
Expand Down
3 changes: 3 additions & 0 deletions runtime/Go/antlr/v4/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ func (p *BaseParser) Match(ttype int) Token {
p.Consume()
} else {
t = p.errHandler.RecoverInline(p)
if p.HasError() {
return nil
}
if p.BuildParseTrees && t.GetTokenIndex() == -1 {

// we must have conjured up a new token during single token
Expand Down
41 changes: 20 additions & 21 deletions runtime/Go/antlr/v4/parser_atn_simulator.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func (p *ParserATNSimulator) reset() {
}

//goland:noinspection GoBoolExpressions
func (p *ParserATNSimulator) AdaptivePredict(input TokenStream, decision int, outerContext ParserRuleContext) int {
func (p *ParserATNSimulator) AdaptivePredict(parser *BaseParser, input TokenStream, decision int, outerContext ParserRuleContext) int {
if ParserATNSimulatorDebug || ParserATNSimulatorTraceATNSim {
fmt.Println("adaptivePredict decision " + strconv.Itoa(decision) +
" exec LA(1)==" + p.getLookaheadName(input) +
Expand Down Expand Up @@ -147,7 +147,8 @@ func (p *ParserATNSimulator) AdaptivePredict(input TokenStream, decision int, ou
p.atn.stateMu.Unlock()
}

alt := p.execATN(dfa, s0, input, index, outerContext)
alt, re := p.execATN(dfa, s0, input, index, outerContext)
parser.SetError(re)
if ParserATNSimulatorDebug {
fmt.Println("DFA after predictATN: " + dfa.String(p.parser.GetLiteralNames(), nil))
}
Expand Down Expand Up @@ -189,7 +190,7 @@ func (p *ParserATNSimulator) AdaptivePredict(input TokenStream, decision int, ou
// - conflict + predicates
//
//goland:noinspection GoBoolExpressions
func (p *ParserATNSimulator) execATN(dfa *DFA, s0 *DFAState, input TokenStream, startIndex int, outerContext ParserRuleContext) int {
func (p *ParserATNSimulator) execATN(dfa *DFA, s0 *DFAState, input TokenStream, startIndex int, outerContext ParserRuleContext) (int, RecognitionException) {

if ParserATNSimulatorDebug || ParserATNSimulatorTraceATNSim {
fmt.Println("execATN decision " + strconv.Itoa(dfa.decision) +
Expand Down Expand Up @@ -223,10 +224,10 @@ func (p *ParserATNSimulator) execATN(dfa *DFA, s0 *DFAState, input TokenStream,
input.Seek(startIndex)
alt := p.getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule(previousD.configs, outerContext)
if alt != ATNInvalidAltNumber {
return alt
return alt, nil
}

panic(e)
p.parser.SetError(e)
return ATNInvalidAltNumber, e
}
if D.requiresFullContext && p.predictionMode != PredictionModeSLL {
// IF PREDS, MIGHT RESOLVE TO SINGLE ALT => SLL (or syntax error)
Expand All @@ -244,7 +245,7 @@ func (p *ParserATNSimulator) execATN(dfa *DFA, s0 *DFAState, input TokenStream,
if ParserATNSimulatorDebug {
fmt.Println("Full LL avoided")
}
return conflictingAlts.minValue()
return conflictingAlts.minValue(), nil
}
if conflictIndex != startIndex {
// restore the index so Reporting the fallback to full
Expand All @@ -258,26 +259,26 @@ func (p *ParserATNSimulator) execATN(dfa *DFA, s0 *DFAState, input TokenStream,
fullCtx := true
s0Closure := p.computeStartState(dfa.atnStartState, outerContext, fullCtx)
p.ReportAttemptingFullContext(dfa, conflictingAlts, D.configs, startIndex, input.Index())
alt := p.execATNWithFullContext(dfa, D, s0Closure, input, startIndex, outerContext)
return alt
alt, re := p.execATNWithFullContext(dfa, D, s0Closure, input, startIndex, outerContext)
return alt, re
}
if D.isAcceptState {
if D.predicates == nil {
return D.prediction
return D.prediction, nil
}
stopIndex := input.Index()
input.Seek(startIndex)
alts := p.evalSemanticContext(D.predicates, outerContext, true)

switch alts.length() {
case 0:
panic(p.noViableAlt(input, outerContext, D.configs, startIndex))
return ATNInvalidAltNumber, p.noViableAlt(input, outerContext, D.configs, startIndex)
case 1:
return alts.minValue()
return alts.minValue(), nil
default:
// Report ambiguity after predicate evaluation to make sure the correct set of ambig alts is Reported.
p.ReportAmbiguity(dfa, D, startIndex, stopIndex, false, alts, D.configs)
return alts.minValue()
return alts.minValue(), nil
}
}
previousD = D
Expand Down Expand Up @@ -393,7 +394,7 @@ func (p *ParserATNSimulator) predicateDFAState(dfaState *DFAState, decisionState
// comes back with reach.uniqueAlt set to a valid alt
//
//goland:noinspection GoBoolExpressions
func (p *ParserATNSimulator) execATNWithFullContext(dfa *DFA, D *DFAState, s0 ATNConfigSet, input TokenStream, startIndex int, outerContext ParserRuleContext) int {
func (p *ParserATNSimulator) execATNWithFullContext(dfa *DFA, D *DFAState, s0 ATNConfigSet, input TokenStream, startIndex int, outerContext ParserRuleContext) (int, RecognitionException) {

if ParserATNSimulatorDebug || ParserATNSimulatorTraceATNSim {
fmt.Println("execATNWithFullContext " + s0.String())
Expand All @@ -419,14 +420,12 @@ func (p *ParserATNSimulator) execATNWithFullContext(dfa *DFA, D *DFAState, s0 AT
// ATN states in SLL implies LL will also get nowhere.
// If conflict in states that dip out, choose min since we
// will get error no matter what.
e := p.noViableAlt(input, outerContext, previous, startIndex)
input.Seek(startIndex)
alt := p.getSynValidOrSemInvalidAltThatFinishedDecisionEntryRule(previous, outerContext)
if alt != ATNInvalidAltNumber {
return alt
return alt, nil
}

panic(e)
return alt, p.noViableAlt(input, outerContext, previous, startIndex)
}
altSubSets := PredictionModegetConflictingAltSubsets(reach)
if ParserATNSimulatorDebug {
Expand Down Expand Up @@ -468,7 +467,7 @@ func (p *ParserATNSimulator) execATNWithFullContext(dfa *DFA, D *DFAState, s0 AT
// not SLL.
if reach.GetUniqueAlt() != ATNInvalidAltNumber {
p.ReportContextSensitivity(dfa, predictedAlt, reach, startIndex, input.Index())
return predictedAlt
return predictedAlt, nil
}
// We do not check predicates here because we have checked them
// on-the-fly when doing full context prediction.
Expand Down Expand Up @@ -499,7 +498,7 @@ func (p *ParserATNSimulator) execATNWithFullContext(dfa *DFA, D *DFAState, s0 AT

p.ReportAmbiguity(dfa, D, startIndex, input.Index(), foundExactAmbig, reach.Alts(), reach)

return predictedAlt
return predictedAlt, nil
}

//goland:noinspection GoBoolExpressions
Expand Down Expand Up @@ -1401,7 +1400,7 @@ func (p *ParserATNSimulator) getLookaheadName(input TokenStream) string {
// it out for clarity now that alg. works well. We can leave p
// "dead" code for a bit.
func (p *ParserATNSimulator) dumpDeadEndConfigs(_ *NoViableAltException) {

panic("Not implemented")

// fmt.Println("dead end configs: ")
Expand Down
28 changes: 22 additions & 6 deletions runtime/Go/antlr/v4/recognizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,39 @@ package antlr
import (
"fmt"
"strings"

"strconv"
)

type Recognizer interface {
GetLiteralNames() []string
GetSymbolicNames() []string
GetRuleNames() []string

Sempred(RuleContext, int, int) bool
Precpred(RuleContext, int) bool

GetState() int
SetState(int)
Action(RuleContext, int, int)
AddErrorListener(ErrorListener)
RemoveErrorListeners()
GetATN() *ATN
GetErrorListenerDispatch() ErrorListener
HasError() bool
GetError() RecognitionException
SetError(RecognitionException)
}

type BaseRecognizer struct {
listeners []ErrorListener
state int

RuleNames []string
LiteralNames []string
SymbolicNames []string
GrammarFileName string
SynErr RecognitionException
}

func NewBaseRecognizer() *BaseRecognizer {
Expand All @@ -58,6 +62,18 @@ func (b *BaseRecognizer) checkVersion(toolVersion string) {
}
}

func (b *BaseRecognizer) SetError(err RecognitionException) {
b.SynErr = err
}

func (b *BaseRecognizer) HasError() bool {
return b.SynErr != nil
}

func (b *BaseRecognizer) GetError() RecognitionException {
return b.SynErr
}

func (b *BaseRecognizer) Action(_ RuleContext, _, _ int) {
panic("action not implemented on Recognizer!")
}
Expand Down Expand Up @@ -114,7 +130,7 @@ func (b *BaseRecognizer) SetState(v int) {
//
// TODO: JI This is not yet implemented in the Go runtime. Maybe not needed.
func (b *BaseRecognizer) GetRuleIndexMap() map[string]int {

panic("Method not defined!")
// var ruleNames = b.GetRuleNames()
// if (ruleNames==nil) {
Expand Down Expand Up @@ -204,7 +220,7 @@ func (b *BaseRecognizer) GetTokenErrorDisplay(t Token) string {
s = strings.Replace(s, "\t", "\\t", -1)
s = strings.Replace(s, "\n", "\\n", -1)
s = strings.Replace(s, "\r", "\\r", -1)

return "'" + s + "'"
}

Expand Down
Loading