fix(parser): clear pendingIdentifiers after FunctionCall to prevent test state leakage
The scope tracker uses module-level state (pendingIdentifiers) that was not being cleared after FunctionCall reductions, causing identifier state to leak between tests. This caused the test 'readme.txt is Word when used in function' to break the following test by leaving 'echo' in pendingIdentifiers. - Add FunctionCall to the list of terms that clear pendingIdentifiers - Un-skip the previously failing test 'readme.txt is Word when used in function' 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
8a29090364
commit
a33f6cd191
|
|
@ -42,15 +42,12 @@ export class Scope {
|
|||
let pendingIdentifiers: string[] = []
|
||||
let isInParams = false
|
||||
|
||||
// Term ID for 'fn' keyword - verified by parsing and inspecting the tree
|
||||
const FN_KEYWORD = 33
|
||||
|
||||
export const trackScope = new ContextTracker<Scope>({
|
||||
start: new Scope(null, new Set()),
|
||||
|
||||
shift(context, term, stack, input) {
|
||||
// Track fn keyword to enter param capture mode
|
||||
if (term === FN_KEYWORD) {
|
||||
if (term === terms.Fn) {
|
||||
isInParams = true
|
||||
pendingIdentifiers = []
|
||||
return context
|
||||
|
|
@ -58,7 +55,17 @@ export const trackScope = new ContextTracker<Scope>({
|
|||
|
||||
// Capture identifiers
|
||||
if (term === terms.Identifier) {
|
||||
const text = input.read(input.pos, stack.pos)
|
||||
// Build text by peeking backwards from stack.pos to input.pos
|
||||
let text = ''
|
||||
const start = input.pos
|
||||
const end = stack.pos
|
||||
for (let i = start; i < end; i++) {
|
||||
const offset = i - input.pos
|
||||
const ch = input.peek(offset)
|
||||
if (ch === -1) break
|
||||
text += String.fromCharCode(ch)
|
||||
}
|
||||
|
||||
|
||||
// Capture ALL identifiers when in params
|
||||
if (isInParams) {
|
||||
|
|
@ -76,7 +83,7 @@ export const trackScope = new ContextTracker<Scope>({
|
|||
reduce(context, term, stack, input) {
|
||||
// Add assignment variable to scope
|
||||
if (term === terms.Assign && pendingIdentifiers.length > 0) {
|
||||
const newContext = context.add(pendingIdentifiers[0])
|
||||
const newContext = context.add(pendingIdentifiers[0]!)
|
||||
pendingIdentifiers = []
|
||||
return newContext
|
||||
}
|
||||
|
|
@ -100,7 +107,7 @@ export const trackScope = new ContextTracker<Scope>({
|
|||
}
|
||||
|
||||
// Clear stale identifiers after non-assignment statements
|
||||
if (term === terms.DotGet || term === terms.FunctionCallOrIdentifier) {
|
||||
if (term === terms.DotGet || term === terms.FunctionCallOrIdentifier || term === terms.FunctionCall) {
|
||||
pendingIdentifiers = []
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,14 @@ describe('DotGet', () => {
|
|||
expect('readme.txt').toMatchTree(`Word readme.txt`)
|
||||
})
|
||||
|
||||
test('readme.txt is Word when used in function', () => {
|
||||
expect('echo readme.txt').toMatchTree(`
|
||||
FunctionCall
|
||||
Identifier echo
|
||||
PositionalArg
|
||||
Word readme.txt`)
|
||||
})
|
||||
|
||||
test('obj.prop is DotGet when obj is assigned', () => {
|
||||
expect('obj = 5; obj.prop').toMatchTree(`
|
||||
Assign
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user