Lowering to Bytecode

Why lower?

  • AST is ideal for analysis; bytecode is ideal for execution
  • linear IR reduces execution complexity
  • deterministic output improves debugging and testing

Core contract

  • node-kind -> deterministic instruction sequence
  • preserve evaluation order
  • preserve side effects
  • preserve errors where possible

Stack-bytecode pattern

  • emit operands before operators (postfix/RPN)
  • unary: [operand] OpNot/OpNeg
  • binary: [left] [right] OpAdd/OpSub/...
  • identifiers become LOAD, not special-cased pushes

Calls and scope

  • lower arguments in source order
  • CALL name arity
  • blocks with locals: ENTER_SCOPE then body then EXIT_SCOPE

Determinism goals

  • same AST always emits same instructions
  • roundtrip checks: AST -> BC -> BC1 -> AST behavior
  • clear failure on unknown node kinds

Why this matters

  • wrong order often returns “valid” but wrong answers
  • wrong scoping leaks locals
  • stable lowering allows you to evolve to register IR later

Quick checks

  • 1 + 2 * 3 becomes postfix emit order
  • (a + b) / c emits ADD before DIV
  • f(1, x, 2) emits three arg loads, then call
  • block enters/exits scope explicitly
1 / 1
Use arrow keys or click edges to navigate. Press H to toggle help, F for fullscreen.