From b1169dc92ebcce937c336a24fbebae2bfca0342a Mon Sep 17 00:00:00 2001 From: Mike Lischke Date: Mon, 9 Dec 2024 14:21:13 +0100 Subject: [PATCH] Improved LL1Analyzer construction + add HashMap key enumeration - Each ATN instance now uses an own instance of the LL1Analyzer. That cannot be shared. - Removed a forgotten debug output from the ATNSerializer. - The HashMap now supports enumerating its keys. - The channel value for getHiddenTokensToRight/Left in BufferedTokenStream is now marked as optional (it is already handled like that). Signed-off-by: Mike Lischke --- src/BufferedTokenStream.ts | 5 +++-- src/atn/ATN.ts | 6 ++++-- src/atn/ATNSerializer.ts | 6 ------ src/atn/LL1Analyzer.ts | 8 +++----- src/misc/HashMap.ts | 4 ++++ src/misc/OrderedHashMap.ts | 2 +- 6 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/BufferedTokenStream.ts b/src/BufferedTokenStream.ts index a5bd823..b76580a 100644 --- a/src/BufferedTokenStream.ts +++ b/src/BufferedTokenStream.ts @@ -334,7 +334,7 @@ export class BufferedTokenStream implements TokenStream { * the current token up until we see a token on DEFAULT_TOKEN_CHANNEL or * EOF. If channel is -1, find any non default channel token. */ - public getHiddenTokensToRight(tokenIndex: number, channel: number): Token[] | undefined { + public getHiddenTokensToRight(tokenIndex: number, channel?: number): Token[] | undefined { if (channel === undefined) { channel = -1; } @@ -356,7 +356,7 @@ export class BufferedTokenStream implements TokenStream { * the current token up until we see a token on DEFAULT_TOKEN_CHANNEL. * If channel is -1, find any non default channel token. */ - public getHiddenTokensToLeft(tokenIndex: number, channel: number): Token[] | undefined { + public getHiddenTokensToLeft(tokenIndex: number, channel?: number): Token[] | undefined { if (channel === undefined) { channel = -1; } @@ -388,6 +388,7 @@ export class BufferedTokenStream implements TokenStream { hidden.push(t); } } + if (hidden.length === 0) { return undefined; } diff --git a/src/atn/ATN.ts b/src/atn/ATN.ts index bfa40bf..4ef5c23 100644 --- a/src/atn/ATN.ts +++ b/src/atn/ATN.ts @@ -67,11 +67,13 @@ export class ATN { public readonly modeToStartState: Array = []; - static #analyzer = new LL1Analyzer(); + private analyzer: LL1Analyzer; public constructor(grammarType: number, maxTokenType: number) { this.grammarType = grammarType; this.maxTokenType = maxTokenType; + + this.analyzer = new LL1Analyzer(this); } /** @@ -85,7 +87,7 @@ export class ATN { return atnState.nextTokenWithinRule; } - const next = ATN.#analyzer.look(this, atnState, undefined, ctx); + const next = this.analyzer.look(atnState, undefined, ctx); if (!ctx) { atnState.nextTokenWithinRule = next; } diff --git a/src/atn/ATNSerializer.ts b/src/atn/ATNSerializer.ts index c2df524..1d8f0f0 100644 --- a/src/atn/ATNSerializer.ts +++ b/src/atn/ATNSerializer.ts @@ -219,7 +219,6 @@ export class ATNSerializer { case 0: { let edgeCount = 0; this.data.push(this.atn.states.length); - let i = 0; for (const s of this.atn.states) { if (s === null) { // might be optimized away this.data.push(ATNState.INVALID_TYPE); @@ -231,10 +230,6 @@ export class ATNSerializer { this.nonGreedyStates.push(s.stateNumber); } - if (i === 910) { - console.log("i", i); - } - if (s instanceof RuleStartState && s.isLeftRecursiveRule) { this.precedenceStates.push(s.stateNumber); } @@ -262,7 +257,6 @@ export class ATNSerializer { this.sets.set(st.set, true); } } - ++i; } return edgeCount; diff --git a/src/atn/LL1Analyzer.ts b/src/atn/LL1Analyzer.ts index d97dc63..a45b70f 100644 --- a/src/atn/LL1Analyzer.ts +++ b/src/atn/LL1Analyzer.ts @@ -26,7 +26,7 @@ export class LL1Analyzer { */ private static readonly hitPredicate = Token.INVALID_TYPE; - private atn: ATN; + public constructor(private atn: ATN) { } /** * Calculates the SLL(1) expected lookahead set for each outgoing transition @@ -70,7 +70,6 @@ export class LL1Analyzer { * If `ctx` is not `null` and the end of the outermost rule is * reached, {@link Token//EOF} is added to the result set. * - * @param atn the ATN * @param s the ATN state * @param stopState the ATN state to stop at. This can be a * {@link BlockEndState} to detect epsilon paths through a closure. @@ -80,11 +79,10 @@ export class LL1Analyzer { * @returns The set of tokens that can follow `s` in the ATN in the * specified `ctx`. */ - public look(atn: ATN, s: ATNState, stopState?: ATNState, ctx?: ParserRuleContext): IntervalSet { - this.atn = atn; + public look(s: ATNState, stopState?: ATNState, ctx?: ParserRuleContext): IntervalSet { const r = new IntervalSet(); - const lookContext = ctx ? predictionContextFromRuleContext(atn, ctx) : null; + const lookContext = ctx ? predictionContextFromRuleContext(this.atn, ctx) : null; this.doLook(s, stopState, lookContext, r, new HashSet(), new BitSet(), true, true); return r; diff --git a/src/misc/HashMap.ts b/src/misc/HashMap.ts index ce893e0..e87f893 100644 --- a/src/misc/HashMap.ts +++ b/src/misc/HashMap.ts @@ -88,6 +88,10 @@ export class HashMap { return result; } + public keys(): Iterable { + return this.backingStore.toArray().map((bucket) => { return bucket.key; }); + } + public values(): Iterable { return this.backingStore.toArray().map((bucket) => { return bucket.value!; }); } diff --git a/src/misc/OrderedHashMap.ts b/src/misc/OrderedHashMap.ts index 5bbf272..4f13a12 100644 --- a/src/misc/OrderedHashMap.ts +++ b/src/misc/OrderedHashMap.ts @@ -70,7 +70,7 @@ export class OrderedHashMap extends HashMap { /** * @returns an iterable of the keys in the map, in the order they were inserted. */ - public keys(): IterableIterator { + public override keys(): IterableIterator { return this.#keys[Symbol.iterator](); }