Skip to content

Commit f0e76a3

Browse files
authored
Add block scoping for conditional statements and expressions (#44)
* add tests for block scoping * Get block scoping working
1 parent 59dca41 commit f0e76a3

File tree

3 files changed

+54
-2
lines changed

3 files changed

+54
-2
lines changed

src/__tests__/__snapshots__/index.ts.snap

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,4 +252,11 @@ Object {
252252
}
253253
`;
254254

255+
exports[`const uses block scoping instead of function scoping 1`] = `
256+
Object {
257+
"status": "finished",
258+
"value": true,
259+
}
260+
`;
261+
255262
exports[`parseError for missing semicolon 1`] = `"Line 1: Missing semicolon at the end of statement"`;

src/__tests__/index.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,26 @@ test(
131131
},
132132
30000
133133
)
134+
135+
// This is bad practice. Don't do this!
136+
test('const uses block scoping instead of function scoping', () => {
137+
const code = `
138+
function test(){
139+
const x = true;
140+
if(true) {
141+
const x = false;
142+
} else {
143+
const x = false;
144+
}
145+
return x;
146+
}
147+
test();
148+
`;
149+
const context = mockContext()
150+
const promise = runInContext(code, context, { scheduler: 'preemptive' })
151+
return promise.then(obj => {
152+
expect(obj).toMatchSnapshot()
153+
expect(obj.status).toBe('finished')
154+
expect((obj as Finished).value).toBe(true)
155+
})
156+
})

src/interpreter.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,20 @@ const createFrame = (
4343
return frame
4444
}
4545

46+
const createBlockFrame = (
47+
context: Context,
48+
vars: es.Identifier[],
49+
args: Value[],
50+
): Frame => {
51+
const frame: Frame = {
52+
name: 'ifStatementBlock',
53+
parent: currentFrame(context),
54+
environment: {},
55+
thisContext: context
56+
}
57+
return frame
58+
}
59+
4660
const handleError = (context: Context, error: SourceError) => {
4761
context.errors.push(error)
4862
if (error.severity === ErrorSeverity.ERROR) {
@@ -369,10 +383,18 @@ export const evaluators: { [nodeType: string]: Evaluator<es.Node> } = {
369383
return undefined
370384
}
371385

386+
// Create a new frame (block scoping)
387+
const frame = createBlockFrame(context, [], [])
388+
pushFrame(context, frame)
389+
372390
if (test) {
373-
return yield* evaluate(node.consequent, context)
391+
const result = yield* evaluate(node.consequent, context)
392+
popFrame(context)
393+
return result
374394
} else if (node.alternate) {
375-
return yield* evaluate(node.alternate, context)
395+
const result = yield* evaluate(node.alternate, context)
396+
popFrame(context)
397+
return result
376398
} else {
377399
return undefined
378400
}

0 commit comments

Comments
 (0)