v3 Parsing: Postfix, Maps, and Arrays
Work through examples, try the reasoning yourself, then put it into practice.
View SlidesBefore you start
- Parse v2 statements and understand v3 callable/container values.
What you will practice
- Build repeated postfix wrappers in left-to-right order.
- Separate assignable syntax from runtime index validity.
- Distinguish map expressions from statement blocks by context.
In this lesson
Lesson
3 min readv3 Parsing: Postfix, Maps, and Arrays
v3 changes both statement placement and expression shape. fn is now a
statement, so nested declarations parse inside blocks. A call stores its callee
expression in ExprCall.Left, not a name in Value. Assignment stores an
identifier or index expression in Stmt.Target.
Worked reconstruction
Start with primary factory in factory(2)[0](5):
| Consumed suffix | New root | Prior expression retained as |
|---|---|---|
(2) |
Call | callee Left = Ident(factory) |
[0] |
Index | target Left = previous Call |
(5) |
Call | callee Left = previous Index |
A postfix loop keeps wrapping the accumulated expression until the next token
is not ( or [. All suffixes bind more tightly than unary and binary
operators. Thus -a[0] is Neg(Index(a,0)), not Index(Neg(a),0).
Assignment is a second decision
Parse an expression first. If the next token is =, require its root to be an
identifier or index, parse the RHS, and form a statement. a[0]=7; has an index
target. a+b=7; and f()=7; are parser errors. Conversely 3[0]=7; has an
index-shaped target and can parse; runtime will reject the non-container base.
Shape validation does not prove the target is operationally valid.
Delimiter context
At statement entry, { opens a block. In expression context, such as after
let m=, { opens a map literal whose pairs need colons. Arrays and maps can
be empty, and pair/element expressions reuse the full expression parser.
let m={"x":[2,3]}; nests map, array, and declaration terminators; each parser
owns its delimiter and returns at the first following token. This grammar does
not accept a trailing comma before ] or }.
A bare map at statement start is ambiguous with a block under these dispatch
rules. Parenthesizing it, as ({"x":2});, explicitly enters expression context.
The language remains dynamically typed; do not infer key or element types in
this parser.
Debugging lab
A parser accepts factory(2) then returns before [0](5), and represents a call by putting factory’s text in Value. Identify the two v2 assumptions that no longer hold.
Compare your diagnosis after attempting the lab
Postfix syntax must loop through every suffix. The callee is now an arbitrary expression retained in Left; extracting only its name loses nested call/index structure.
Transfer task
Draw the tree for build()[pick(1)] = source()[0];, labeling target, index, and RHS. Change only the target root to make it syntactically invalid, then create a different target that parses but is invalid at runtime.
Carry forward
Carry the postfix tree and explicit assignment target into v3 analysis. Store one chain with three suffixes as a regression against accidental one-suffix parsing.
Build program-parser-v3. Keep a before/after trace of one failing test. Use the checkpoint to diagnose specific skills; passing it does not replace implementing and testing the artifact.
Practice sequence
Use the order below for a guided path, or choose an item to revisit. A pass records a successful attempt; try a fresh example later to check what you can reconstruct.