plum

#treesitter#compiler#wasm

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

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


d60eb64 — Peter John 2026-11-01T15:46:48+05:30
docs(plans): pattern if
Files changed (1) hide show
  1. docs/plans/2026-11-01-pattern-if.md +45 -0
docs/plans/2026-11-01-pattern-if.md ADDED
@@ -0,0 +1,45 @@
1
+ # Pattern `if` / `else if` / `while` (user request; runs after the docs refresh)
2
+
3
+ **Status:** in progress.
4
+
5
+ The user wants single-case pattern tests to fit Plum's imperative flow. `match` stays, for exhaustive handling.
6
+
7
+ ## Design
8
+ 1. **Forms.** A condition may be a pattern binding `Pattern := expr`, optionally followed by more conditions `, cond` that see the bindings:
9
+ ```plum
10
+ if Circle(r) := shape
11
+ drawCircle(r)
12
+ else if Rect(w, h) := shape, w > h
13
+ drawWide(w, h)
14
+ else
15
+ drawOther(shape)
16
+
17
+ while Busy(task) := worker.state # loops while the pattern matches
18
+ task.step()
19
+ ```
20
+ - The pattern grammar is exactly `match`'s: constructor patterns with nested positional or named fields, `_`, literals, and bare error names inside an error value. The `.Name` dot-variant form is not part of this task.
21
+ - The existing optional binding `if x := opt` is the special case where the pattern is a plain name over a `T?` (bind when not null). Both keep working, and this task also adds them to `else if`.
22
+ 2. **Semantics.**
23
+ - The bindings are in scope only in that branch's block (and in the conditions after the pattern).
24
+ - A pattern that can't fail on its type (e.g. `Vec2(x, y) := v` on a value enum) is allowed and always takes the branch. Ruling: no warning machinery.
25
+ - There is no exhaustiveness requirement; use `match` for that.
26
+ - Inline form: `if Circle(r) := s then r else 0.0`.
27
+ - `else if` chains may mix plain conditions, optional bindings and pattern bindings.
28
+ 3. **Lowering.** It reuses the match-arm pattern compiler (the subject is evaluated once into a scratch local, then test and bind). It must work for enums, value enums, nested patterns, optionals and error values (`if NotFound := e` inside a `catch e` block).
29
+
30
+ ## Docs (user: "document it nicely as it fits our imperative flow")
31
+ - A README "Pattern if" subsection under Control flow, cross-linked from Enums and Optionals. It covers when to use pattern `if` (one or two cases, early-exit style) versus `match` (every case, exhaustiveness), with side-by-side examples taken from game code (units, shapes, jobs) and a `while` example.
32
+ - Add `plum-examples/pattern_if.plum` with test blocks for each form.
33
+ - Highlighting and format.scm are unchanged unless the grammar needs new nodes. Update the LSP if keyword or snippet completion is affected.
34
+
35
+ ## Tests
36
+ - `if_pattern_enum_variant`;
37
+ - `else_if_pattern_chain` (mixed plain, optional and pattern conditions);
38
+ - `pattern_with_trailing_condition`;
39
+ - `nested_pattern_if`;
40
+ - `inline_pattern_if`;
41
+ - `while_pattern`;
42
+ - `else_if_optional_binding` (fills the gap NL left);
43
+ - `pattern_bindings_scoped_to_branch` (using the binding after the if is an error);
44
+ - `irrefutable_pattern_if_allowed`;
45
+ - `error_name_pattern_in_catch_block`.