Skip to content

Scope stack infrastructure + while block scoping #246

Description

@frendsick

What to build

Add block scoping infrastructure to the Casa compiler and implement it end-to-end for while/do/done blocks.

Add a scope_stack: List[List[str]] field to both the TypeChecker and BytecodeCompiler. When entering a while block (WhileStart), push a new empty scope frame. When a variable is first assigned inside the block (and doesn't exist in any outer scope), record it in the current scope frame. When exiting the block (WhileEnd), pop the scope frame — variables introduced in that frame are no longer visible.

The typechecker enforces visibility: accessing a variable after its scope has been popped is a compile error. The bytecode compiler maintains a parallel scope stack for correct slot resolution when variable names are reused across sibling scopes (shadowing via = x when no outer x exists).

Key design decisions:

  • = x inside a block mutates outer x if it exists in any enclosing scope; declares a new block-local variable only if x is not already in scope
  • Function::variables stays as a flat List[Variable] (all variables ever declared, for slot allocation) — scope visibility is tracked separately via the scope stack
  • Local variable slots grow monotonically — no slot reuse at block exit
  • for loop variables are automatically covered because for desugars to while at parse time — the loop variable (= x) is assigned inside the while body and will be block-scoped
  • global declarations bypass block scoping entirely
  • Scope starts at WhileStart (condition area is inside the scope), so for-desugared hidden variables like __for_opt_N assigned in the condition area are accessible in the body

Acceptance criteria

  • TypeChecker has a scope stack that pushes/pops at WhileStart/WhileEnd
  • BytecodeCompiler has a parallel scope stack with scope-aware variable resolution
  • Variable first assigned inside while body is not accessible after done (compile error)
  • = x inside while mutates outer x if it exists in enclosing scope
  • for loop iteration variable is not accessible after done
  • for-desugared hidden variables (__for_iter_N, __for_opt_N) work correctly (assigned before/inside while respectively)
  • global declarations inside while are unaffected
  • Existing compiler code compiles without errors (no while-leaking patterns broken)
  • Tests cover: while scoping, for scoping, mutation of outer variable, out-of-scope error, global bypass

Blocked by

None — can start immediately.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ready-for-agentFully specified, ready for an AFK agent

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions