v4 Semantics: loop rules and scope
Lesson, slides, and applied problem sets.
View SlidesLesson
v4 Semantics: loop rules and scope
Why v4 semantics is not “just the same checks with new keywords”
Control-flow introduces branch legality requirements:
breakandcontinueare now context-sensitiveforbinds loop-local names and scopes them correctly- logical operators must still be fully analyzed despite runtime short-circuit
This module enforces these semantics before compile.
1) Loop legality invariant
Track loopDepth and enforce:
loopDepth == 0outside any loopbreakandcontinuevalid only whenloopDepth > 0- diagnostic forms:
break outside loopcontinue outside loop
Nested loops work because loopDepth is incremented/decremented with lexical entry/exit of each loop body.
2) for-loop scope and analysis order
For for (init; cond; post) { body }:
- open loop scope once for the whole loop construct
- analyze
initin that scope - analyze
condin that scope - analyze
postin that scope - analyze
bodywhileloopDepth > 0 - close loop scope at loop end
This gives correct behavior for:
let i = 0;visible in condition and postletin loop body not visible outside loop
while in this pack does not create a new declaration scope, but still uses loopDepth for control-break legality.
3) Post-expression visibility edge case
for (; ; i = i + 1) {}
If i was not declared in an accessible scope, analyzer should report undefined name in the post expression even though execution might never run.
Static analysis is about syntax+scope correctness, not runtime reachability.
4) Return / function context unchanged, now concurrent with loops
v4 keeps earlier return semantics:
returnonly valid when in function depth > 0
The analyzer must track both:
- function depth
- loop depth
So control transfer checks do not interfere with each other and each has independent error messages.
5) Short-circuit operators as complete semantic nodes
Even if runtime skips RHS in some cases, semantic analysis still visits both sides:
true || unknownfalse && unknown
Both should still surface static errors on unknown in this pack.
This avoids accidental dependence on evaluator path when producing diagnostics.
6) Carry-over invariants from prior versions
All previous checks remain enabled:
- undefined name
- redeclare in same scope
- const initialization / assignment rules
- call arity checks
- function binding validity
Adding loops must not relax earlier safety guarantees.
7) Practice checkpoints (almost solved)
1) Nested depth + for (let i = 0; ; i = i + 1) { while (true) { continue; } }
Both continue usages are valid at their respective loop levels.
2) Invalid control transfer + if (true) { break; }
Expected: break outside loop.
3) For-scope visibility + for (let i = 0; ; ) { i; }
Expected: i resolved in body.
4) Scope leak + for (let j = 0; ; ) {} let j = 1;
Expected: second declaration in outer scope should be allowed.
5) Post expression error + for (; ; i = i + 1) {}
Expected: undefined name: i from post.
6) Logical full-scan + true || unknown
Expected: undefined-name error despite short-circuit result at runtime.
This module keeps control-flow strict and deterministic before lowering.
Module Items
Semantic Analysis v4