The rest of the grammar
After today, every Chiya program has a syntax tree, and the parser never needs to change again until you add new syntax yourself.
Chiya still can't express functions or lists. Today you finish the parser: function literals fn(a, b) { … }, calls f(1, 2), array literals [1, 2, 3] and indexing xs[0]. Calls and indexing look like infix operators — they come after a value — so they slot into the Pratt loop with the highest binding power, 6.
let add = fn(a, b) { a + b };
let xs = [add(1, 2), 4];
xs[0] * 10Calls and indexing in the loop
Give ( and [ binding power 6 in the table. When the loop meets ( after a value, the value is being called: parse a comma-separated list of arguments up to ). When it meets [, parse one expression and expect ]. Because they bind tightest, a + f(x)[0] becomes (a + (f(x)[0])).
while ((PRECEDENCE[peek().type] ?? 0) > min) {
const op = next();
if (op.type === "(") left = { type: "Call", callee: left, args: list(")") };
else if (op.type === "[") {
const index = expression(0);
expect("]");
left = { type: "Index", target: left, index };
} else left = { type: "Infix", op: op.type, left, right: expression(PRECEDENCE[op.type]) };
}One list(close) helper parses expr, expr, … up to a closing token. Calls use it with ) and array literals with ].