From 4e0ff0ac609eb016d14a56e6689d718999e7dd92 Mon Sep 17 00:00:00 2001 From: Robin Jadoul Date: Fri, 6 Feb 2026 13:51:35 +0100 Subject: [PATCH] spec: Introduce array expressions Closes #135 --- spec/chip.typ | 4 ++-- spec/expr.typ | 3 +++ spec/src/branch.toml | 2 +- spec/src/shift.toml | 6 +++--- spec/tooling/chip.py | 3 +++ 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/spec/chip.typ b/spec/chip.typ index 4749b886e..f3ac28a74 100644 --- a/spec/chip.typ +++ b/spec/chip.typ @@ -52,9 +52,9 @@ #let render_chip_padding_table(chip, config) = { // Whether `var` is a preprocessed variable. let is_preprocessed(var) = { - config.variables.types + let type = config.variables.types .filter(t => t.label == var.type) - .all(t => t.at("preprocessed", default: false)) + type.len() > 0 and type.all(t => t.at("preprocessed", default: false)) } let instantiated_vars = config.variables.categories.instantiated.map(c => chip.variables.at(c, default: ())).flatten() diff --git a/spec/expr.typ b/spec/expr.typ index 1c6c7942e..c4f84eb59 100644 --- a/spec/expr.typ +++ b/spec/expr.typ @@ -28,6 +28,7 @@ // ::= () ; "" // | var ; str(var) // | int ; int +// | ["arr", expr, ...] ; [expr, ...] // | ["idx", expr1, expr2] ; expr1[expr2] // | ["not", expr] ; !expr // | ["+", expr1, expr2, ...] ; expr1 + expr2 + ... @@ -91,6 +92,7 @@ // Typeset an expression as code #let expr_to_code = make_expr_formatter( ( + "arr": (pp, rec, e) => `[` + e.slice(1).map(rec.with(PREC.MAX)).join(`, `) + `]`, "idx": (pp, rec, e) => rec(PREC.MIN, e.at(1)) + `[` + rec(PREC.MAX, e.at(2)) + `]`, "not": (pp, rec, e) => cwrap(rec(PREC.not, 1) + ` - ` + rec(PREC.not, e.at(1)), pp < PREC.not), "+": (pp, rec, e) => cwrap(e.slice(1).map(rec.with(PREC.add)).join(` + `), pp < PREC.add), @@ -149,6 +151,7 @@ // Typeset an expression as math #let expr_to_math = make_expr_formatter( ( + "arr": (pp, rec, e) => $[#e.slice(1).map(rec.with(PREC.MAX)).join($, $)]$, "idx": (pp, rec, e) => { let (val, idxs) = flat_idxs(e) $#rec(PREC.idx, val)_(#idxs.map(idx => rec(PREC.idx, idx)).join($, $))$ diff --git a/spec/src/branch.toml b/spec/src/branch.toml index beb3c1922..34bcdf8cb 100644 --- a/spec/src/branch.toml +++ b/spec/src/branch.toml @@ -34,7 +34,7 @@ pad = 0 name = "next_pc_high" type = ["Half", 3] desc = "The upper part of the next pc" -pad = 0 # TODO(#128): improve handling for arrays +pad = ["arr", 0, 0, 0] [[variables.output]] name = "next_pc_low" diff --git a/spec/src/shift.toml b/spec/src/shift.toml index bd6c471a6..5faed54c7 100644 --- a/spec/src/shift.toml +++ b/spec/src/shift.toml @@ -65,19 +65,19 @@ pad = 1 name = "X" type = ["Half", 5] desc = "scratch variable." -pad = 0 # TODO: array +pad = ["arr", 0, 0, 0, 0, 0] [[variables.auxiliary]] name = "Y" type = ["Half", 4] desc = "scratch variable." -pad = 0 # TODO: array +pad = ["arr", 0, 0, 0, 0] [[variables.auxiliary]] name = "limb_shift" type = ["Bit", 4] desc = "One-hot vector indicating whether $floor.l #`shift` / 16 floor.r equiv i mod s$, where $s = 2$ when $#`word_instr` = 1$ and $4$ otherwise." -pad = 0 # TODO: array +pad = ["arr", 0, 0, 0, 0] # Virtual diff --git a/spec/tooling/chip.py b/spec/tooling/chip.py index 8a15ae338..6a78dc091 100644 --- a/spec/tooling/chip.py +++ b/spec/tooling/chip.py @@ -62,6 +62,7 @@ def get_const(self) -> int: type Expr = ( LitExpr | VarExpr + | ArrExpr | IdxExpr | CastExpr | MulExpr @@ -303,6 +304,8 @@ def build_expr(config: Optional["Config"], data: object) -> Expr: x.isidentifier(), f"Invalid identifier name for variable {x!r}" ) return VarExpr(x) + case ["arr", *elems]: + return ArrExpr([build_expr(config, e) for e in elems]) case ["idx", x, y]: return IdxExpr(build_expr(config, x), build_expr(config, y)) case ["cast", x, t]: