v4 Semantics: loop rules and scope

Lesson, slides, and applied problem sets.

View Slides

Lesson

v4 Semantics: loop rules and scope

Why v4 semantics is not “just the same checks with new keywords”

Control-flow introduces branch legality requirements:

  • break and continue are now context-sensitive
  • for binds 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 == 0 outside any loop
  • break and continue valid only when loopDepth > 0
  • diagnostic forms:
    • break outside loop
    • continue 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 init in that scope
  • analyze cond in that scope
  • analyze post in that scope
  • analyze body while loopDepth > 0
  • close loop scope at loop end

This gives correct behavior for:

  • let i = 0; visible in condition and post
  • let in 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:

  • return only 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 || unknown
  • false && 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

    Validate v4 programs with loop rules and scope handling.

    hard Upgrade to Pro to access hard problems
Join Discord