Skip to content

Commit

Permalink
Resolve edge case with error recovery and repetitions
Browse files Browse the repository at this point in the history
Which may cause a stack overflow when the repetition is entered
but never consumed anything.
  • Loading branch information
bd82 committed Jun 21, 2019
1 parent 3cc090e commit 211d410
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 11 deletions.
16 changes: 11 additions & 5 deletions packages/chevrotain/docs/changes/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,38 @@
## X.Y.Z (INSERT_DATE_HERE)

#### Bug Fixes

- [Resolved edge case in repetition error recovery which may cause "Maximum call stack size exceeded".]()

## 4.8.0 (6-14-2019)

#### Minor Changes

- [Custom Token Patterns and "Custom Payloads".](https://github.com/SAP/chevrotain/issues/888).
- [Custom Token Patterns and "Custom Payloads".](https://github.com/SAP/chevrotain/issues/888)

## 4.7.0 (6-8-2019)

#### Minor Changes

- [CST location information.](https://github.com/SAP/chevrotain/issues/932).
- [CST location information.](https://github.com/SAP/chevrotain/issues/932)

## 4.6.0 (6-1-2019)

#### Minor Changes

- [Expose two base Parser classes: CstParser and EmbeddedActionsParser.](https://github.com/SAP/chevrotain/issues/967).
- [Expose two base Parser classes: CstParser and EmbeddedActionsParser.](https://github.com/SAP/chevrotain/issues/967)

## 4.5.0 (5-25-2019)

#### Minor Changes

- [Consider Token Categories in Lookahead Functions Calculation.](https://github.com/SAP/chevrotain/issues/962).
- [Consider Token Categories in Lookahead Functions Calculation.](https://github.com/SAP/chevrotain/issues/962)

## 4.4.0 (5-24-2019)

#### Minor Changes

- [Better handling of infinite loops in repetitions.](https://github.com/SAP/chevrotain/issues/958).
- [Better handling of infinite loops in repetitions.](https://github.com/SAP/chevrotain/issues/958)

## 4.3.3 (4-12-2019)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -620,7 +620,13 @@ export class RecognizerEngine {
<any>lookaheadFunction,
MANY_IDX,
prodOccurrence,
NextTerminalAfterManyWalker
NextTerminalAfterManyWalker,
// The notStuck parameter is only relevant when "attemptInRepetitionRecovery"
// is invoked from manyInternal, in the MANY_SEP case and AT_LEAST_ONE[_SEP]
// An infinite loop cannot occur as:
// - Either the lookahead is guaranteed to consume something (Single Token Separator)
// - AT_LEAST_ONE by definition is guaranteed to consume something (or error out).
notStuck
)
}

Expand Down
20 changes: 15 additions & 5 deletions packages/chevrotain/src/parse/parser/traits/recoverable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,9 +148,16 @@ export class Recoverable {

shouldInRepetitionRecoveryBeTried(
this: MixedInParser,
expectTokAfterLastMatch?: TokenType,
nextTokIdx?: number
expectTokAfterLastMatch: TokenType,
nextTokIdx: number,
notStuck: boolean | undefined
): boolean {
// Edge case of arriving from a MANY repetition which is stuck
// Attempting recovery in this case could cause an infinite loop
if (notStuck === false) {
return false
}

// arguments to try and perform resync into the next iteration of the many are missing
if (expectTokAfterLastMatch === undefined || nextTokIdx === undefined) {
return false
Expand Down Expand Up @@ -383,7 +390,8 @@ export class Recoverable {
lookaheadFunc: () => boolean,
dslMethodIdx: number,
prodOccurrence: number,
nextToksWalker: typeof AbstractNextTerminalAfterProductionWalker
nextToksWalker: typeof AbstractNextTerminalAfterProductionWalker,
notStuck?: boolean
): void {
// by default this is a NO-OP
// The actual implementation is with the function(not method) below
Expand Down Expand Up @@ -425,7 +433,8 @@ export function attemptInRepetitionRecovery(
lookaheadFunc: () => boolean,
dslMethodIdx: number,
prodOccurrence: number,
nextToksWalker: typeof AbstractNextTerminalAfterProductionWalker
nextToksWalker: typeof AbstractNextTerminalAfterProductionWalker,
notStuck?: boolean
) {
let key = this.getKeyForAutomaticLookahead(dslMethodIdx, prodOccurrence)
let firstAfterRepInfo = this.firstAfterRepMap.get(<any>key)
Expand Down Expand Up @@ -458,7 +467,8 @@ export function attemptInRepetitionRecovery(
if (
this.shouldInRepetitionRecoveryBeTried(
expectTokAfterLastMatch,
nextTokIdx
nextTokIdx,
notStuck
)
) {
// TODO: performance optimization: instead of passing the original args here, we modify
Expand Down

0 comments on commit 211d410

Please sign in to comment.