Language Expansion: Variables, Statements, Functions
Lesson, slides, and applied problem sets.
View SlidesLesson
Language Expansion: variables, statements, functions, and execution model
This is the first “real language” module: still dynamically typed, but now it has mutable state, branches, calls, and block control.
Why expansion happens in steps
A language that starts with expressions is easy to parse but hard to program. This expansion stage adds:
- declarations,
- assignment,
- control flow,
- functions as top-level declarations,
- runtime truth model.
Each addition is introduced with minimal cross-cutting impact.
Runtime truthiness contract
In this pack:
falseandnilare falsey- everything else is truthy
This rule must be stable across parser and VM for consistent branch semantics.
Variable declarations and mutation
Keywords:
let,var(mutable)const(immutable)
Semantics contract:
- declarations introduce names in current scope
- assignments update existing bindings
- declarations are parsed in statement context
Although const exists here, its enforcement is handled by semantic checks/VM behavior depending on implementation details.
Statements and control
Supported statements:
varDecl,assignStmt,exprStmt,if/else,while,return,block
This turns the parser into a statement dispatcher and introduces structured nesting:
- block pushes a statement list boundary
- nested blocks can change variable resolution (later phases can enforce shadowing rules)
Functions in this stage
Function declarations are top-level shape:
fn name(params) { body }- parameters are local names
- return is explicit via
return
At this stage calls and closures are intentionally limited: functions are declarations with callable bodies and explicit returns.
Design pressure that justifies this stage
Why not jump directly to modules/typing?
- Without
if/while, you cannot test side-effect sequencing. - Without
return, there is no observable function contract. - Without
vars, you cannot meaningfully validate name resolution.
Small-stage evolution keeps each hidden failure surface visible.
Deep practice checkpoints (almost solved)
1) Keyword semantics in declarations
Input: let x = 1; var y = 2; const c = 3;
Expected:
- three declarations, each valid in dynamic semantics phase.
2) Mutability intent
Input: const x = 1; x = 2;
Expected:
- front-end may accept parse; semantic phase should enforce immutability contract.
3) Block semantics
Input: { let x = 1; if (x) { let y = 2; } }
Expected:
- block-scoped shape is produced by parser.
4) If/else branching
Input: if (x) { y = 1; } else { y = 2; }
Expected:
- parser builds branch structure with two block bodies.
5) While semantics shape
Input: while (x) { break; }
Expected:
- while statement with condition and non-empty body.
6) Return placement
Input: return; and return x + 1;
Expected:
- both parse as return forms.
7) Function declaration layout
Input: fn add(a, b) { return a + b; }
Expected:
- parsed as top-level function declaration with param list and body block.
8) Assignment classification
Input: x = x + 1;
Expected:
- assignment statement, not expression statement.
9) Expression statements
Input: add(1, 2);
Expected:
- expression statement containing call expression.
10) Truthiness edge
Input: if (nil) { x = 1; }
Expected:
- branch should be interpreted as falsey.