From 6d366bc88042fcd99cd47b731dcb9d623a53cb31 Mon Sep 17 00:00:00 2001 From: Trevor Paley <10186337+TheUnlocked@users.noreply.github.com> Date: Fri, 19 Apr 2024 19:30:34 -0700 Subject: [PATCH] Fix some edge cases in incremental parsing --- package.json | 2 +- src/parser/parser.ts | 14 +++++++++++++- tests/grammar/incremental.spec.ts | 11 +++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 2086e4d..8de523f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@necode-org/mike", - "version": "0.3.7", + "version": "0.3.8", "author": { "name": "Trevor Paley", "url": "https://github.com/TheUnlocked" diff --git a/src/parser/parser.ts b/src/parser/parser.ts index 232d2e5..944a34a 100644 --- a/src/parser/parser.ts +++ b/src/parser/parser.ts @@ -162,8 +162,20 @@ export class Parser extends DiagnosticsMixin implements Rules { const { insertedTokens, removedTokens } = this.lexer.mutate(firstTokenIdx, numTokens, fullInsertion); + // Need to also invalidate the previous (non-trivia) token for cases where + // a new token can modify an earlier AST node. For example: + // if true { + // + // } + // els[e] { + // + // } + // Inserting the 'e' changes it from an identifier and a parse error into an else branch of the + // previous if statement. Without invalidating the previous if statement, we couldn't determine that. + const firstRemovedTokenIdx = this.tokens.slice(0, firstTokenIdx).findLastIndex(x => !isTrivia(x)); + // Cache invalidation - for (const token of removedTokens) { + for (const token of this.tokens.slice(firstRemovedTokenIdx, firstTokenIdx).concat(removedTokens)) { let node = this.memoTable.get(token)?.[0]?.node; this.memoTable.delete(token); diff --git a/tests/grammar/incremental.spec.ts b/tests/grammar/incremental.spec.ts index 8eb65dc..f9e20a6 100644 --- a/tests/grammar/incremental.spec.ts +++ b/tests/grammar/incremental.spec.ts @@ -211,6 +211,17 @@ export default () => describe('incremental', () => { } `; + testIncremental('modify identifier to create else keyword')` + on foo() { + if true { + + } + els${['', 'e']} { + + } + } + `; + it('should be a no-op if a mutation is reversed', () => { const p1 = new Parser(); // 0 5 10 15 20 25 30 35 40