plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
7873c08
— Peter John
2026-11-04T20:41:58+05:30
docs: language simplification run A plan
docs/plans/2026-11-04-language-simplification-a.md
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Language simplification, run A: value enums, variadics, generators, error forms, `=`
|
|
2
|
+
|
|
3
|
+
**Review plan:** docs/plans/2026-11-04-language-simplification.review.md
|
|
4
|
+
**Goal:** Remove value enums, variadics (replaced by a `[a, b]` list literal), generators (Seq becomes a step-function struct), the extra error forms, and declare-on-first-use `=`. Std, examples and tests are rewritten first, then the compiler support is deleted.
|
|
5
|
+
**Architecture:** tree-sitter grammar (plum-tooling/tree-sitter-plum), plum-core parser/passes, plum-checker, plum-wasm-codegen, plum-std, plum-examples.
|
|
6
|
+
**Tech stack:** Rust 2021, tree-sitter, Plum.
|
|
7
|
+
**Detail:** contracts
|
|
8
|
+
**Target-min:** 40
|
|
9
|
+
|
|
10
|
+
## Global constraints
|
|
11
|
+
- Agents cannot run `cargo test` (hook): `cargo build --workspace --tests`, run binaries in `target/debug/deps` (newest by mtime). `touch` edited files. Own scratchpad subdir + CARGO_TARGET_DIR if the shared one is locked.
|
|
12
|
+
- Grammar edits: regenerate with `tree-sitter generate --disable-optimizations` (the default optimizer silently breaks unrelated parses); update corpus fixtures.
|
|
13
|
+
- Gate for every task: workspace test binaries pass and `plum test plum-std plum-examples` passes (678 today; the count may change only by tests this plan deletes or adds, each listed). Wasm bytes may change.
|
|
14
|
+
- Never run `plum format` on real files. Don't commit.
|
|
15
|
+
- Rulings from the user (2026-11-04): list literal syntax `[a, b, c]` (brackets at expression start; `[]` stays generics after a type name), a pure parser desugaring to `List.empty().append(a).append(b).append(c)` — no `init` method on List or Map (both `init`s are deleted); `[]` is `List.empty()` (element type from the annotation or use); a Map literal `["a" => 1, "b" => 2]` desugars to `Map.empty().set("a", 1).set("b", 2)` (coordinator default, user may change); `Seq` becomes a struct holding a `next` step closure returning `T?`, and `for x := s` loops over anything with `next(self) -> T?`.
|
|
16
|
+
|
|
17
|
+
## Task graph
|
|
18
|
+
```mermaid
|
|
19
|
+
flowchart LR
|
|
20
|
+
T1[list literal]
|
|
21
|
+
T2[std off variadics]
|
|
22
|
+
T3[Seq step struct]
|
|
23
|
+
T4[std off generators]
|
|
24
|
+
T5[errors and = inventory]
|
|
25
|
+
T6[remove from compiler]
|
|
26
|
+
T7[verify run A]
|
|
27
|
+
%% taskgraph
|
|
28
|
+
T1 --> T2
|
|
29
|
+
T1 --> T3
|
|
30
|
+
T3 --> T4
|
|
31
|
+
T2 --> T6
|
|
32
|
+
T4 --> T6
|
|
33
|
+
T5 --> T6
|
|
34
|
+
T6 --> T7
|
|
35
|
+
```
|
|
36
|
+
Ruling: sequential - std must stop using a feature before the compiler drops it - cost: longer chain.
|
|
37
|
+
|
|
38
|
+
## Package A: new forms
|
|
39
|
+
**Probe entry:** run=plum test plum-std plum-examples
|
|
40
|
+
|
|
41
|
+
### T1 list literal · Complexity 5 · Est. context 50k
|
|
42
|
+
**Owns:** plum-tooling/tree-sitter-plum/grammar.js, plum-tooling/tree-sitter-plum/src/**, plum-tooling/tree-sitter-plum/test/corpus/**, plum-core/src/parser.rs, plum-core/src/ast.rs, plum-std/List.plum, plum-std/Map.plum, plum-core/tests/list_literal_test.rs, plum-examples/list_literal_probe.plum
|
|
43
|
+
**Components:** 2
|
|
44
|
+
**LOC owned:** 140
|
|
45
|
+
**Tests:** slow
|
|
46
|
+
**Model:** opus
|
|
47
|
+
**Produces:** parser desugaring of `[..]` into method chains (no new AST variant needed; a `ListLit` variant only if the parser needs it transiently)
|
|
48
|
+
e.g. `xs := [1, 2, 3]` -> parses as `List.empty().append(1).append(2).append(3)`, a List[Int] of 3
|
|
49
|
+
e.g. `xs: List[Int] := []` -> `List.empty()`
|
|
50
|
+
e.g. `["a" => 1, "b" => 2]` -> `Map.empty().set("a", 1).set("b", 2)`
|
|
51
|
+
**Test code:** parser tests asserting the desugared AST for the three e.g. lines; a `.plum` test block in the probe file checking length/get of each; grammar corpus green. List and Map get `empty()` / `append` / `set` if missing (in plum-std/List.plum and Map.plum — ruling: T1 may add those methods only).
|
|
52
|
+
|
|
53
|
+
## Package B: std and examples
|
|
54
|
+
**Probe entry:** run=plum test plum-std plum-examples
|
|
55
|
+
|
|
56
|
+
### T2 std off variadics · Complexity 4 · Est. context 45k
|
|
57
|
+
**Owns:** plum-std/List.plum, plum-std/Map.plum, plum-std/Json.plum, plum-std/Slice.plum, plum-examples/basics.plum, plum-examples/structs_records.plum, plum-wasm-codegen/tests/**, plum-checker/tests/**, plum-core/tests/** except list_literal_test.rs
|
|
58
|
+
**Components:** 1
|
|
59
|
+
**LOC owned:** 120
|
|
60
|
+
**Tests:** slow
|
|
61
|
+
**Consumes:** ast::Expr::ListLit(Vec<Expr>) (T1)
|
|
62
|
+
**Produces:** none
|
|
63
|
+
**Test code:** every `...T` parameter is removed (`List.init`/`Map.init` deleted; other variadic fns take a `List[T]`); every `List(1, 2, 3)` / `Map("a" => 1)` call becomes `[1, 2, 3]` / `["a" => 1]` in std, examples and embedded test sources; all gates pass.
|
|
64
|
+
|
|
65
|
+
### T3 Seq as a step struct · Complexity 5 · Est. context 50k
|
|
66
|
+
**Owns:** plum-std/Seq.plum, plum-core/src/forms.rs, plum-checker/src/lib.rs, plum-wasm-codegen/src/lib.rs
|
|
67
|
+
**Components:** 2
|
|
68
|
+
**LOC owned:** 160
|
|
69
|
+
**Tests:** slow
|
|
70
|
+
**Consumes:** ast::Expr::ListLit(Vec<Expr>) (T1)
|
|
71
|
+
**Produces:** std Seq[T] { next: fn() -> T? } with map/filter/take/fold as plain fns · `for x := s` over a value with `next(self) -> T?`
|
|
72
|
+
e.g. `for x := Seq.range(0, 3)` binds 0, 1, 2
|
|
73
|
+
e.g. `Seq.range(0, 10).filter(|n| n % 2 == 0).take(2)` -> 0, 2
|
|
74
|
+
**Review Focus:** fusion: `fusion_alloc_test` and the List-chain fusion still pass; report any lost fusion with numbers.
|
|
75
|
+
**Test code:** Seq.plum test blocks for the e.g. lines and every old Seq test rewritten.
|
|
76
|
+
|
|
77
|
+
### T4 std and examples off generators · Complexity 4 · Est. context 45k
|
|
78
|
+
**Owns:** plum-std/Map.plum, plum-std/Int.plum, plum-std/List.plum, plum-examples/functional.plum, plum-examples/sequences.plum
|
|
79
|
+
**Components:** 1
|
|
80
|
+
**LOC owned:** 100
|
|
81
|
+
**Tests:** slow
|
|
82
|
+
**Consumes:** std Seq[T] { next: fn() -> T? } with map/filter/take/fold as plain fns (T3)
|
|
83
|
+
**Produces:** none
|
|
84
|
+
**Test code:** no `fun*`/`yield` left in plum-std or plum-examples; all gates pass.
|
|
85
|
+
|
|
86
|
+
### T5 error forms and `=` inventory · Complexity 4 · Est. context 45k
|
|
87
|
+
**Owns:** plum-examples/errors.plum, docs/plans/2026-11-04-language-simplification-a.inventory.md
|
|
88
|
+
**Components:** 1
|
|
89
|
+
**LOC owned:** 60
|
|
90
|
+
**Tests:** slow
|
|
91
|
+
**Produces:** inventory file listing (a) every error form the checker/codegen still accept beyond `T!E` and `T?` with file:line, (b) every `=` that declares on first use in plum-std/plum-examples (found by a temporary local checker build that errors on it — do not commit that build)
|
|
92
|
+
**Test code:** errors.plum rewritten without `?.`; gates pass.
|
|
93
|
+
|
|
94
|
+
## Package C: remove and verify
|
|
95
|
+
**Probe entry:** run=plum test plum-std plum-examples
|
|
96
|
+
|
|
97
|
+
### T6 remove from the compiler · Complexity 5 · Est. context 55k
|
|
98
|
+
**Owns:** plum-tooling/tree-sitter-plum/**, plum-core/src/*.rs, plum-checker/src/*.rs, plum-wasm-codegen/src/lib.rs, plum-lsp/src/*.rs, plum-std/**, plum-examples/**, plum-*/tests/**
|
|
99
|
+
**Components:** 3
|
|
100
|
+
**LOC owned:** 120
|
|
101
|
+
**Tests:** slow
|
|
102
|
+
**Produces:** none
|
|
103
|
+
**Review Focus:** each removed form gives a clear compile error naming its replacement (`...T` → `Slice[T]` + `[..]`; `fun*` → Seq; value enum → plain enum; `?.` and other forms → `T!E`/`T?`; first-use `=` → `:=`).
|
|
104
|
+
**Test code:** checker tests for each error message; all gates pass; grep finds none of the removed syntax in std/examples/grammar.
|
|
105
|
+
**Steps:** fix every `=` site from T5's inventory with `:=`; delete grammar rules, AST variants, checker intrinsics (variadic length/at, generator typing, value-enum checks, the `?.`→andThen path, forms already listed in T5), codegen value-enum helpers.
|
|
106
|
+
|
|
107
|
+
### T7 verify run A · Complexity 2 · Est. context 30k
|
|
108
|
+
**Owns:** docs/plans/2026-11-04-language-simplification-a.results.md
|
|
109
|
+
**Components:** 1
|
|
110
|
+
**LOC owned:** 40
|
|
111
|
+
**Tests:** slow
|
|
112
|
+
**Produces:** none
|
|
113
|
+
**Test code:** workspace binaries, plum test, plum-game host_test, browser game check if available; Rust LOC removed per crate vs the start sha.
|
|
114
|
+
|
|
115
|
+
## Review Focus
|
|
116
|
+
- Packages A/C (compiler): deep, protocol — grammar conflicts from `[` at expression start; error messages.
|
|
117
|
+
- Package B (std): numeric, state — Seq laziness, fusion.
|
|
118
|
+
|
|
119
|
+
## Self-review
|
|
120
|
+
Covers run A of the review plan: value enums, variadics, generators, error model, `=`.
|