plum
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
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`.
|