plum
git clone https://git.pyrossh.dev/plum
A statically typed, imperative programming language inspired by rust, python
28a3f9f
— Peter John
2026-11-04T19:43:35+05:30
docs: compiler cleanup phase 3a plan
docs/plans/2026-11-04-compiler-cleanup-phase3a.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Compiler cleanup, phase 3a: per-compile state, no fusion globals
|
|
2
|
+
|
|
3
|
+
**Review plan:** docs/plans/2026-11-04-compiler-cleanup.review.md
|
|
4
|
+
**Goal:** The checker's ~23 thread-locals and codegen's 6 become one state value each, created fresh per compile; plum-core's process-global counters restart per compile; the fusion-options thread-local and the CLI's fusion OnceLock are gone. No behaviour change. (Phase 3b: pass-list driver and positioned errors.)
|
|
5
|
+
**Architecture:** Rust workspace (plum-core, plum-checker, plum-wasm-codegen, plum-cli, plum-lsp, plum-host, plum-test-support); plum-game separate.
|
|
6
|
+
**Tech stack:** Rust 2021, cargo, wasmtime 47.
|
|
7
|
+
**Detail:** contracts
|
|
8
|
+
**Target-min:** 20
|
|
9
|
+
|
|
10
|
+
## Global constraints
|
|
11
|
+
- Agents cannot run `cargo test` (hook): `cargo build -p <crate> --tests`, run binaries in `target/debug/deps` (newest by mtime). `touch` edited files first. Use your own scratchpad subdirectory and CARGO_TARGET_DIR if a build is locked.
|
|
12
|
+
- No behaviour change: all 25 examples sha256-identical vs the start sha (`.superlite/progress.md`) via `bash scripts/wasm-hashes.sh <sha> OUT`; `plum test plum-std plum-examples` 678 passed.
|
|
13
|
+
- This is a middle step, not full method-ization: state moves into one struct per crate behind one scoped accessor (`with…State(|s| …)`), reset at the compile/check entry. Don't rewrite function signatures across the file.
|
|
14
|
+
- camelCase fns. Never run `plum format` on real files. Don't commit.
|
|
15
|
+
|
|
16
|
+
## Main diagram
|
|
17
|
+
```mermaid
|
|
18
|
+
flowchart LR
|
|
19
|
+
E["compile / typedSourceWith entry"] --> R["reset: CheckState, GenState, core counters"]
|
|
20
|
+
R --> C["checker reads CheckState"]
|
|
21
|
+
R --> G["codegen reads GenState"]
|
|
22
|
+
O["CompileOptions.fusion"] --> C
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Task graph
|
|
26
|
+
```mermaid
|
|
27
|
+
flowchart LR
|
|
28
|
+
T1[checker state]
|
|
29
|
+
T2[codegen state]
|
|
30
|
+
T3[core counters]
|
|
31
|
+
T4[fusion globals out]
|
|
32
|
+
T5[verify 3a]
|
|
33
|
+
%% taskgraph
|
|
34
|
+
T1 --> T4
|
|
35
|
+
T2 --> T4
|
|
36
|
+
T1 --> T5
|
|
37
|
+
T2 --> T5
|
|
38
|
+
T3 --> T5
|
|
39
|
+
T4 --> T5
|
|
40
|
+
```
|
|
41
|
+
Ruling: sequential - T4 edits checker and codegen lib.rs after T1/T2 - cost: one extra step.
|
|
42
|
+
|
|
43
|
+
## Package A: state
|
|
44
|
+
**Probe entry:** run=bash scripts/wasm-hashes.sh
|
|
45
|
+
|
|
46
|
+
### T1 checker state value · Complexity 5 · Est. context 55k
|
|
47
|
+
**Owns:** plum-checker/src/lib.rs, plum-checker/src/unions.rs, plum-checker/src/traits.rs, plum-checker/src/state.rs
|
|
48
|
+
**Components:** 1
|
|
49
|
+
**LOC owned:** 140
|
|
50
|
+
**Tests:** slow
|
|
51
|
+
**Model:** sonnet
|
|
52
|
+
**Produces:** state::CheckState (all former thread-local fields) · state::withCheck<R>(f: impl FnOnce(&mut CheckState) -> R) -> R · state::resetCheck()
|
|
53
|
+
e.g. resetCheck(); withCheck(|s| s.fresh) -> 0
|
|
54
|
+
e.g. two typedSource calls on the same source -> identical TypedInfo and identical generated names
|
|
55
|
+
**Review Focus:** `reset_complete`: every field the old `checkSourceOnce` reset by hand is reset by `resetCheck`, and every save/restore pair (union plan in adoptPre/recheckKeep) keeps its semantics; `reentrancy`: no `withCheck` borrow is held across a call that re-enters `withCheck` (use short borrows / Cell-like fields; a RefCell double borrow panics — run the full checker suite to prove none).
|
|
56
|
+
**Test code:** a `#[cfg(test)]` test for the two e.g. lines; all checker, plum-core and codegen test binaries pass; hashes identical.
|
|
57
|
+
**Steps:** move lib.rs 17-58 thread-locals, ALLOW_BARE_TOP, unions.rs IN_WRAP/DEPTH/INLINE/NARROW_TOP and traits.rs TRAITS/TRAIT_FIELDS into `CheckState`; keep FUSION_OPTIONS for T4; COVER_WILDCARD is a constant, leave it.
|
|
58
|
+
|
|
59
|
+
### T2 codegen state value · Complexity 4 · Est. context 50k
|
|
60
|
+
**Owns:** plum-wasm-codegen/src/lib.rs
|
|
61
|
+
**Components:** 1
|
|
62
|
+
**LOC owned:** 80
|
|
63
|
+
**Tests:** slow
|
|
64
|
+
**Model:** sonnet
|
|
65
|
+
**Produces:** GenState { gc_types, consts, value_enums, value_block_types, value_helpers, err_info } · withGen<R>(f: impl FnOnce(&mut GenState) -> R) -> R
|
|
66
|
+
e.g. compile twice in one process -> identical bytes
|
|
67
|
+
**Review Focus:** `reentrancy` as in T1; `withGcTypes` indirection folded into `withGen`.
|
|
68
|
+
**Test code:** a `#[cfg(test)]` test compiling one source twice in-process → equal bytes; codegen test binaries pass; hashes identical.
|
|
69
|
+
**Steps:** CURRENT_GC_TYPES, CURRENT_CONSTS, VALUE_ENUMS, VALUE_BLOCK_TYPES, VALUE_HELPERS, ERR_INFO (lib.rs ≈562-776) → one GenState, reset at the start of `compile`.
|
|
70
|
+
|
|
71
|
+
### T3 core counters per compile · Complexity 3 · Est. context 40k
|
|
72
|
+
**Owns:** plum-core/src/forms.rs, plum-core/src/simplify.rs, plum-core/src/unions.rs, plum-core/src/loader.rs, plum-core/src/lower.rs, plum-core/src/session.rs, plum-core/src/lib.rs, plum-core/tests/session_test.rs
|
|
73
|
+
**Components:** 1
|
|
74
|
+
**LOC owned:** 70
|
|
75
|
+
**Tests:** fast
|
|
76
|
+
**Model:** sonnet
|
|
77
|
+
**Produces:** session::begin() (resets forms NEXT_LOOP_ID/COUNTER/REG/LOWERED/ERRORS/USES/SEQ_KINDS, simplify FRESH, unions PLAN/FRESH, loader USER_PRIMS/MERGED_LIT_ERRORS)
|
|
78
|
+
e.g. begin(); load+lower a program twice in one process -> identical ASTs (same generated names)
|
|
79
|
+
**Review Focus:** `begin_called_once`: `lower::frontEnd` calls `session::begin()` first; nothing resets mid-compile (the forms session begin/active/finish protocol keeps working).
|
|
80
|
+
**Test code:** session_test.rs for the e.g. line; plum-core test binaries pass; hashes identical.
|
|
81
|
+
|
|
82
|
+
### T4 fusion globals out · Complexity 3 · Est. context 40k
|
|
83
|
+
**Owns:** plum-checker/src/lib.rs, plum-wasm-codegen/src/lib.rs, plum-cli/src/main.rs, plum-cli/src/game.rs, plum-core/tests/trmc_test.rs, plum-wasm-codegen/tests/fusion_alloc_test.rs, plum-wasm-codegen/tests/e2e_mem/reuse.rs
|
|
84
|
+
**Components:** 2
|
|
85
|
+
**LOC owned:** 70
|
|
86
|
+
**Tests:** slow
|
|
87
|
+
**Model:** sonnet
|
|
88
|
+
**Consumes:** state::withCheck<R>(f: impl FnOnce(&mut CheckState) -> R) -> R (T1) · withGen<R>(f: impl FnOnce(&mut GenState) -> R) -> R (T2)
|
|
89
|
+
**Produces:** none
|
|
90
|
+
**Review Focus:** `cli_flags`: `--no-fusion` / `--explain-fusion` output identical to the start sha's binary (also via `plum game`); `no_globals`: `FUSION_OPTIONS`, `setFusionOptions`, `withFusionOptions`, `fusionOptions` and the CLI `static FUSION` are deleted.
|
|
91
|
+
**Test code:** cli test binaries, trmc_test, fusion_alloc_test, e2e_mem pass; hashes identical.
|
|
92
|
+
**Steps:** tests pass options via `compile(&src, &CompileOptions{fusion, ..})` / `typedSourceWith`; `compileSource`/`typedSource` use `FusionOptions::default()`; the CLI threads options from argv into `compileToWasm(file, lib, opts)` (game.rs too).
|
|
93
|
+
|
|
94
|
+
## Package B: verify
|
|
95
|
+
**Probe entry:** run=bash scripts/wasm-hashes.sh
|
|
96
|
+
|
|
97
|
+
### T5 verify 3a · Complexity 2 · Est. context 30k
|
|
98
|
+
**Owns:** docs/plans/2026-11-04-compiler-cleanup-phase3a.results.md
|
|
99
|
+
**Components:** 1
|
|
100
|
+
**LOC owned:** 40
|
|
101
|
+
**Tests:** slow
|
|
102
|
+
**Model:** sonnet
|
|
103
|
+
**Produces:** none
|
|
104
|
+
**Test code:** all workspace test binaries, plum-game host_test, plum test 678, hashes identical to start sha; `grep -rn "thread_local!" plum-*/src` lists only the new state holders plus forms' session (report each).
|
|
105
|
+
**Steps:** results file: thread-local count before/after per crate, hash diff, test totals.
|
|
106
|
+
|
|
107
|
+
## Review Focus
|
|
108
|
+
- Package A: state, deep — RefCell re-entrancy panics, incomplete resets, save/restore semantics.
|
|
109
|
+
- Package B: file.
|
|
110
|
+
|
|
111
|
+
## Self-review
|
|
112
|
+
Covers the phase 3 state row (Checker/Codegen state, per-compile counters) and two 2b leftovers (fusion thread-local, CLI OnceLock). Pass list and positioned errors are phase 3b.
|