plum

#treesitter#compiler#wasm

git clone https://git.pyrossh.dev/plum

A statically typed, imperative programming language inspired by rust, python


784decf — Peter John 2026-11-04T20:45:59+05:30
docs: run A plan split
docs/plans/2026-11-04-language-simplification-a.md CHANGED
@@ -17,69 +17,112 @@
17
17
  ## Task graph
18
18
  ```mermaid
19
19
  flowchart LR
20
- T1[list literal]
20
+ T1[list literal grammar]
21
+ T8[list literal desugar]
21
22
  T2[std off variadics]
23
+ T9[rust tests off variadics]
22
24
  T3[Seq step struct]
25
+ T10[for over next]
23
26
  T4[std off generators]
24
27
  T5[errors and = inventory]
28
+ T6[remove syntax]
25
- T6[remove from compiler]
29
+ T11[remove checker codegen]
26
30
  T7[verify run A]
27
31
  %% taskgraph
28
- T1 --> T2
32
+ T1 --> T8
33
+ T8 --> T2
34
+ T8 --> T9
29
- T1 --> T3
35
+ T8 --> T3
36
+ T3 --> T10
37
+ T10 --> T4
30
- T3 --> T4
38
+ T2 --> T4
31
- T2 --> T6
32
39
  T4 --> T6
40
+ T9 --> T6
33
41
  T5 --> T6
34
- T6 --> T7
42
+ T6 --> T11
43
+ T11 --> T7
35
44
  ```
36
- Ruling: sequential - std must stop using a feature before the compiler drops it - cost: longer chain.
45
+ Ruling: sequential - std must stop using a feature before the compiler drops it, and List/Map/grammar files are edited in turn - cost: longer chain.
37
46
 
38
47
  ## Package A: new forms
39
48
  **Probe entry:** run=plum test plum-std plum-examples
40
49
 
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
50
+ ### T1 list literal grammar · Complexity 4 · Est. context 40k
51
+ **Owns:** plum-tooling/tree-sitter-plum/grammar.js, plum-tooling/tree-sitter-plum/src/**, plum-tooling/tree-sitter-plum/test/corpus/**
52
+ **Components:** 1
53
+ **LOC owned:** 40
54
+ **Tests:** fast
55
+ **Model:** sonnet
56
+ **Produces:** grammar node `list_literal` = `[` commaSep(expression) `]` at expression start (pairs `k => v` allowed as elements)
57
+ e.g. `xs := [1, 2, 3]` -> (list_literal (int) (int) (int))
58
+ e.g. `["a" => 1]` -> (list_literal (pair_arg ...))
59
+ **Test code:** corpus cases for the e.g. lines and `[]`; existing corpus green (generics `List[Int]` unaffected).
60
+
61
+ ### T8 list literal desugar · Complexity 4 · Est. context 45k
62
+ **Owns:** plum-core/src/parser.rs, plum-std/List.plum, plum-std/Map.plum, plum-core/tests/list_literal_test.rs, plum-examples/list_literal_probe.plum
63
+ **Components:** 1
64
+ **LOC owned:** 90
45
65
  **Tests:** slow
46
- **Model:** opus
66
+ **Model:** sonnet
47
- **Produces:** parser desugaring of `[..]` into method chains (no new AST variant needed; a `ListLit` variant only if the parser needs it transiently)
67
+ **Consumes:** grammar node `list_literal` = `[` commaSep(expression) `]` at expression start (pairs `k => v` allowed as elements) (T1)
48
- e.g. `xs := [1, 2, 3]` -> parses as `List.empty().append(1).append(2).append(3)`, a List[Int] of 3
68
+ **Produces:** `[a, b]` parses as `List.empty().append(a).append(b)`; `[k => v]` as `Map.empty().set(k, v)`
69
+ e.g. `xs := [1, 2, 3]` -> List[Int] of 3
49
70
  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).
71
+ **Test code:** parser tests asserting the desugared AST; probe `.plum` test blocks checking length/get; List/Map gain `empty`/`append`/`set` if missing.
52
72
 
53
73
  ## Package B: std and examples
54
74
  **Probe entry:** run=plum test plum-std plum-examples
55
75
 
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
76
+ ### T2 std off variadics · Complexity 3 · Est. context 40k
77
+ **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
58
78
  **Components:** 1
59
- **LOC owned:** 120
79
+ **LOC owned:** 60
60
80
  **Tests:** slow
81
+ **Model:** sonnet
61
- **Consumes:** ast::Expr::ListLit(Vec<Expr>) (T1)
82
+ **Consumes:** `[a, b]` parses as `List.empty().append(a).append(b)`; `[k => v]` as `Map.empty().set(k, v)` (T8)
62
83
  **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.
84
+ **Test code:** `List.init`/`Map.init` deleted; other `...T` params take `List[T]`; `List(1, 2, 3)`/`Map("a" => 1)` become `[1, 2, 3]`/`["a" => 1]`; gates pass.
64
85
 
86
+ ### T9 rust tests off variadics · Complexity 3 · Est. context 40k
87
+ **Owns:** plum-wasm-codegen/tests/**, plum-checker/tests/**, plum-core/tests/** except list_literal_test.rs
88
+ **Components:** 1
89
+ **LOC owned:** 60
90
+ **Tests:** slow
91
+ **Model:** sonnet
92
+ **Consumes:** `[a, b]` parses as `List.empty().append(a).append(b)`; `[k => v]` as `Map.empty().set(k, v)` (T8)
93
+ **Produces:** none
94
+ **Test code:** embedded Plum sources in Rust tests use `[..]` instead of `List(..)`/`Map(..)` and no `...T`; same test counts.
95
+
65
- ### T3 Seq as a step struct · Complexity 5 · Est. context 50k
96
+ ### T3 Seq as a step struct · Complexity 4 · Est. context 45k
66
- **Owns:** plum-std/Seq.plum, plum-core/src/forms.rs, plum-checker/src/lib.rs, plum-wasm-codegen/src/lib.rs
97
+ **Owns:** plum-std/Seq.plum
67
- **Components:** 2
98
+ **Components:** 1
99
+ **LOC owned:** 95
100
+ **Tests:** slow
101
+ **Model:** sonnet
102
+ **Consumes:** `[a, b]` parses as `List.empty().append(a).append(b)`; `[k => v]` as `Map.empty().set(k, v)` (T8)
103
+ **Produces:** std Seq[T] { next: fn() -> T? } with range/map/filter/take/fold as plain fns
104
+ e.g. `Seq.range(0, 10).filter(|n| n % 2 == 0).take(2).fold(0, |a, n| a + n)` -> 2
105
+ **Test code:** Seq.plum test blocks for the e.g. line and every old Seq test rewritten with explicit `next()` loops (no `for x := s` yet).
106
+
107
+ ### T10 for over next · Complexity 4 · Est. context 45k
108
+ **Owns:** plum-core/src/forms.rs, plum-checker/src/lib.rs, plum-wasm-codegen/src/lib.rs, plum-core/tests/for_next_test.rs
109
+ **Components:** 1
68
- **LOC owned:** 160
110
+ **LOC owned:** 80
69
111
  **Tests:** slow
70
- **Consumes:** ast::Expr::ListLit(Vec<Expr>) (T1)
112
+ **Model:** sonnet
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?`
113
+ **Consumes:** std Seq[T] { next: fn() -> T? } with range/map/filter/take/fold as plain fns (T3)
114
+ **Produces:** `for x := s` over any value with `next(self) -> T?`
72
115
  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.
116
+ **Review Focus:** fusion: `fusion_alloc_test` and 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.
117
+ **Test code:** for_next_test for the e.g. line; gates pass.
76
118
 
77
119
  ### T4 std and examples off generators · Complexity 4 · Est. context 45k
78
120
  **Owns:** plum-std/Map.plum, plum-std/Int.plum, plum-std/List.plum, plum-examples/functional.plum, plum-examples/sequences.plum
79
121
  **Components:** 1
80
122
  **LOC owned:** 100
81
123
  **Tests:** slow
124
+ **Model:** sonnet
82
- **Consumes:** std Seq[T] { next: fn() -> T? } with map/filter/take/fold as plain fns (T3)
125
+ **Consumes:** `for x := s` over any value with `next(self) -> T?` (T10)
83
126
  **Produces:** none
84
127
  **Test code:** no `fun*`/`yield` left in plum-std or plum-examples; all gates pass.
85
128
 
@@ -94,21 +137,32 @@ e.g. `Seq.range(0, 10).filter(|n| n % 2 == 0).take(2)` -> 0, 2
94
137
  ## Package C: remove and verify
95
138
  **Probe entry:** run=plum test plum-std plum-examples
96
139
 
97
- ### T6 remove from the compiler · Complexity 5 · Est. context 55k
140
+ ### T6 remove syntax · Complexity 4 · Est. context 45k
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/**
141
+ **Owns:** plum-tooling/tree-sitter-plum/**, plum-core/src/parser.rs, plum-core/src/ast.rs, plum-std/**, plum-examples/**
99
- **Components:** 3
142
+ **Components:** 2
100
- **LOC owned:** 120
143
+ **LOC owned:** 80
144
+ **Tests:** slow
145
+ **Model:** sonnet
146
+ **Produces:** none
147
+ **Review Focus:** each removed form gives a clear parse/check error naming its replacement (`...T` → `List[T]` + `[..]`; `fun*` → Seq; value enum → plain enum; first-use `=` → `:=`).
148
+ **Test code:** parser tests for each error; gates pass; grep finds none of the removed syntax in std/examples/grammar.
149
+ **Steps:** fix every `=` site from T5's inventory with `:=`; delete grammar rules and AST variants for variadics, `fun*`/`yield`, value-enum discriminants, and the error forms T5 listed.
150
+
151
+ ### T11 remove checker and codegen support · Complexity 4 · Est. context 45k
152
+ **Owns:** plum-core/src/*.rs except parser.rs and ast.rs, plum-checker/src/*.rs, plum-wasm-codegen/src/lib.rs, plum-lsp/src/*.rs, plum-*/tests/**
153
+ **Components:** 2
154
+ **LOC owned:** 60
101
155
  **Tests:** slow
156
+ **Model:** sonnet
102
157
  **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.
158
+ **Test code:** variadic length/at intrinsics, generator typing and lowering, value-enum checks, the `?.`→andThen path, first-use declaration and codegen value-enum helpers are deleted; checker test for the `=` error message; gates pass.
106
159
 
107
160
  ### T7 verify run A · Complexity 2 · Est. context 30k
108
161
  **Owns:** docs/plans/2026-11-04-language-simplification-a.results.md
109
162
  **Components:** 1
110
163
  **LOC owned:** 40
111
164
  **Tests:** slow
165
+ **Model:** sonnet
112
166
  **Produces:** none
113
167
  **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
168