Skip to content

Commit

Permalink
Improve repetition re-sync recovery.
Browse files Browse the repository at this point in the history
fixes #133
  • Loading branch information
Shahar Soel committed Mar 6, 2016
1 parent 62dd10e commit 71c3516
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 10 deletions.
2 changes: 1 addition & 1 deletion docs/tutorial/step4_fault_tolerance.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Repetition re-sync recovery happens when:
* The next token X is invalid right after the repetition ended.
In such a situation the parser will attempt to skip tokens until it detects the beginning of a another iteration of
the repetition.
the repetition **or** the token it originally expected after the last iteration.
There are a couple of edge cases in which **other** recovery methods will be preferred:
* If single token insertion/deletion can be performed, it is always preferred as it skips fewer tokens.
Expand Down
23 changes: 16 additions & 7 deletions src/parse/parser_public.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1114,16 +1114,25 @@ export class Parser {
let nextTokenWithoutResync = this.NEXT_TOKEN()
let currToken = this.NEXT_TOKEN()
let passedResyncPoint = false

let generateErrorMessage = () => {
// we are preemptively re-syncing before an error has been detected, therefor we must reproduce
// the error that would have been thrown
let expectedTokName = tokenName(expectedTokType)
let msg = "Expecting token of type -->" + expectedTokName +
"<-- but found -->'" + nextTokenWithoutResync.image + "'<--"
this.SAVE_ERROR(new exceptions.MismatchedTokenException(msg, nextTokenWithoutResync))
}

while (!passedResyncPoint) {
// re-synced to a point where we can safely exit the repetition/
if (currToken instanceof expectedTokType) {
generateErrorMessage()
return // must return here to avoid reverting the inputIdx
}
// we skipped enough tokens so we can resync right back into another iteration of the repetition grammar rule
if (lookAheadFunc.call(this)) {
// we are preemptively re-syncing before an error has been detected, therefor we must reproduce
// the error that would have been thrown
let expectedTokName = tokenName(expectedTokType)
let msg = "Expecting token of type -->" + expectedTokName +
"<-- but found -->'" + nextTokenWithoutResync.image + "'<--"
this.SAVE_ERROR(new exceptions.MismatchedTokenException(msg, nextTokenWithoutResync))

generateErrorMessage()
// recursive invocation in other to support multiple re-syncs in the same top level repetition grammar rule
grammarRule.apply(this, grammarRuleArgs)
return // must return here to avoid reverting the inputIdx
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ describe("Error Recovery switch-case Example", () => {
})
})

it("can also sometimes fail in automatic error recovery :)", () => {
it("can perform re-sync recovery to the right curly after the case statements repetition", () => {
let input = [
// switch (name) {
new SwitchTok(1, 1), new LParenTok(1, 1), new IdentTok("name", 0, 1, 1), new RParenTok(1, 1), new LCurlyTok(1, 1),
Expand All @@ -138,7 +138,11 @@ describe("Error Recovery switch-case Example", () => {
let parseResult = parser.switchStmt()
expect(parser.errors.length).to.equal(1)
expect(parser.isAtEndOfInput()).to.equal(true)
expect(parseResult).to.deep.equal({})
expect(parseResult).to.deep.equal({
"Terry": 2,
"Robert": 4,
"Brandon": 6
})
})

it("can perform single token deletion recovery", () => {
Expand Down

0 comments on commit 71c3516

Please sign in to comment.