Skip to content
Ridgun
English

Ridgun

The language itself: a compiler that compiles itself, the stable project tool, the specification and the book

FR-COMP-003-unified-equals-grammar-guards-parallel-pipes-and-mut.md141 lines · 8.5 KBRaw
1---
2id: FR-COMP-003
3title: Unified `=` Block Grammar (`(none)`, `|`, `||` without `where`) and Explicit `mut` Variable Bindings
4status: implemented
5priority: must
6created: 2026-10-20
7updated: 2026-10-20
8depends_on:
9 - FR-COMP-002
10verified_by: []
11---
12# FR-COMP-003 — Unified `=` Block Grammar (`(none)`, `|`, `||` without `where`) and Explicit `mut` Variable Bindings
13
14## Statement
15The Ridgun language and `ridgunc` compiler SHALL unify block, conditional, parallel, and variable-binding syntax under four rules:
161. **Universal `=` Right-Hand Side (`(none)` / `|` / `||`)**: Every function clause (`fn ::`), operator clause (`op ::`), local variable binding (`x =` / `mut x =`), and guard branch (`| cond =` / `| otherwise =`) SHALL require `=` and SHALL accept any of the following right-hand-side forms:
17 - Inline expression (optionally followed on subsequent lines by `|| expr -> var` parallel bindings),
18 - Sequential block (indented lines with no prefix),
19 - Conditional guard block (`| cond = ...` and `| otherwise = ...`),
20 - Parallel DAG block (`|| expr -> var` or `|| expr`).
212. **Guard Blocks (`|`) Behind `=` & Nested Block Closers (`|.` / `||.`)**:
22 - Guarded function and operator clauses SHALL include `=` after their pattern list (`name pats =` followed by `| cond = ...`).
23 - Local variable bindings SHALL support conditional guard blocks (`x =` followed by `| cond = ...`).
24 - Guard branches (`| cond =` and `| otherwise =`) SHALL support nested `|` guard blocks to form arbitrary decision trees (3–4+ levels deep).
25 - When a nested `|` or `||` block finishes and execution continues at an outer/parent level below it, the nested block MAY be explicitly closed with **`|.`** (for `|`) or **`||.`** (for `||`), either **inline at the end of the last line** (`| otherwise = expr |.`, the canonical compact form) or on the following line (`|.`). At the end of a function or outer block where no ambiguity exists, `|.` and `||.` are omitted.
263. **Elimination of `where` in Favor of `||`**:
27 - The `where` keyword SHALL be removed from the language grammar.
28 - Named parallel sub-computations feeding an expression SHALL be written directly as `|| expr -> var` (or `|| expr -> target[i, j]`) beneath the expression.
294. **Immutable-by-Default (`x = ...`), Explicit Mutable Variables (`mut x = ...`), and Lowercase Logical Operators (`and`, `or`, `xor`, `not`)**:
30 - A binding `x = expr` without `mut` SHALL declare an immutable local variable; reassigning an immutable variable in the same scope SHALL be rejected at compile time, unless `x` was previously declared with `mut x = expr` in that scope.
31 - Reassigning a `mut` variable (`x = new_expr`) SHALL integrate with `RMM2` (`FR-COMP-002`) by incrementing (`+1`) the new structure before decrementing (`-1`, and destroying on `0` with child cascade) the previous structure held by `x`.
32 - Word-based logical operators SHALL be lowercase (`and`, `or`, `xor`, `not`), while also remaining usable as contextual words inside natural-language operator declarations (`op ::`).
33
34## Rationale
35- Placing `|` behind `=` eliminates the only syntactic exception where function clauses omitted `=`, aligns `=` vertically under `=>` across 100% of declarations, enables inline conditional variable assignments (`x =` followed by `|`), and allows recursive decision trees (`| otherwise =` followed by nested `|`).
36- Replacing `where` with `|| expr -> var` removes a redundant keyword and unifies Ridgun's block prefixes into a clean triad: **nothing** (sequential), **`|`** (conditional OR choice), and **`||`** (parallel AND execution).
37- Immutable-by-default (`x = ...`) keeps mathematical expressions clean while `mut x = ...` (at declaration, followed by `x = ...` on update) makes mutability explicit to both human readers and the `RMM2` memory manager.
38
39## Functional Specification
40
41### 1. Case 1 — Guarded Function & Operator Clauses (`=` Before `|`)
42```ridgun
43op :: clamp Int between Int and Int => Int
44 clamp x between lo and hi =
45 | x < lo = lo
46 | x > hi = hi
47 | otherwise = x
48```
49
50### 2. Case 2 — Conditional Local Variable Assignment (`x =` Followed by `|`)
51```ridgun
52fn :: compute_invoice Int Bool => Int
53 compute_invoice base is_vip =
54 discount =
55 | is_vip = 20
56 | base > 50 = 10
57 | otherwise = 0
58 base - discount
59```
60
61### 3. Case 3 — Deeply Nested Decision Trees (`|` Inside `| cond =` / `| otherwise =`) & Compact `|.` / `||.` Closers
62When a nested `|` or `||` sub-tree finishes and the outer level continues below it, **`|.`** (or **`||.`**) closes the inner block and returns to the parent level. Both inline placement at the end of the last branch (`| otherwise = val |.`, canonical compact style) and next-line placement (`|.`) are valid; at the final branch of a function, no closer is needed:
63
64```ridgun
65fn :: evaluate_payment Account Customer Payment => String
66 evaluate_payment account customer payment =
67 | is_locked account = "REJECTED_ACCOUNT_LOCKED"
68 | amount payment <= 0 = "ERROR_INVALID_AMOUNT"
69 | otherwise =
70 | tier customer == "ENTERPRISE" =
71 | amount payment > 50000 =
72 | has_dual_signature payment = "APPROVED_ENTERPRISE_DUAL_SIG"
73 | tenure customer > 10 = "RISK_COMMITTEE_REVIEW"
74 | otherwise = "REJECTED_ENTERPRISE_LIMIT" |.
75 | country payment != "US" =
76 | is_whitelisted (country payment) = "APPROVED_ENTERPRISE_INTL"
77 | otherwise = "HELD_COMPLIANCE_INTL" |.
78 | otherwise = "APPROVED_ENTERPRISE_STANDARD" |.
79 | tier customer == "VIP" =
80 | amount payment > 10000 =
81 | has_2fa payment = "APPROVED_VIP_2FA"
82 | otherwise = "REQUEST_VIP_SMS" |.
83 | otherwise = "APPROVED_VIP_DIRECT" |.
84 | otherwise =
85 | amount payment > 1000 =
86 | has_2fa payment and risk payment < 30 = "APPROVED_RETAIL_2FA"
87 | otherwise = "REJECTED_RETAIL_RISK" |.
88 | otherwise = "APPROVED_RETAIL_LOW_AMOUNT"
89```
90
91Similarly, when a parallel `||` block or a conditional `|` assignment sits in the middle of a sequential block and execution continues with subsequent statements, `||.` / `|.` marks the return to the sequential level:
92
93```ridgun
94fn :: charge_order Payment => Int
95 charge_order payment =
96 || fetch_base_fee payment -> base_fee
97 || compute_risk_score payment -> risk_score ||.
98 surcharge =
99 | risk_score > 80 = 50
100 | otherwise = 0 |.
101 base_fee + surcharge
102```
103
104### 4. Case 4 — Parallel `||` DAG Blocks (Replacing `where`)
105- **Named parallel DAG feeding a header expression (`|| expr -> var`)**:
106 ```ridgun
107 fn :: parallel_dag_calc => Int
108 parallel_dag_calc = a + b
109 || fib 10 -> a
110 || fact 6 -> b
111 ```
112- **Anonymous parallel tuple branches (`|| expr`)**:
113 ```ridgun
114 fn :: both_metrics Int => (Int, Int)
115 both_metrics x =
116 || fib x
117 || fact x
118 ```
119- **Indexed parallel slot assignment (`|| expr -> target[i, j]`)**:
120 ```ridgun
121 fn :: fill_row => Tensor
122 fill_row = m
123 || 10.0 -> m[0, 0]
124 || 20.0 -> m[0, 1]
125 ```
126
127### 5. Case 5 — Immutable (`x = ...`) vs Mutable (`mut x = ...`) Variables & `RMM2` Lifecycle
128- **Immutable binding (`x = expr`)**:
129 - `x` is bound once (`+1` on structure assignment). Any subsequent `x = ...` in the same scope without a prior `mut x = ...` raises a compile-time error (`ErrImmutableReassign`).
130- **Mutable declaration & reassignment (`mut x = expr`, then `x = new_expr`)**:
131 - First declaration `mut x = e1`: marks `x` as mutable in the current scope and assigns `e1` (`+1`).
132 - Subsequent update `x = e2`:
133 1. Evaluates `e2` and increments its reference count (`+1`).
134 2. Decrements (`-1`) the old value stored in `x` (destroying it and cascading `-1` to its children if its count reaches `0`).
135 3. Stores `e2` into `x`.
136 *(Incrementing `e2` before decrementing the old `x` guarantees safety on self-referential updates such as `x = choose_list cond x other` or `x = x[0]`).*
137
138## Acceptance Criteria
139- AC1: `=` precedes `|` in function/operator clauses, local variable bindings, and nested `|` decision trees.
140- AC2: `|| expr -> var` replaces `where` for parallel DAG bindings, and `where` is no longer a reserved keyword.
141- AC3: `mut x = ...` enables subsequent `x = ...` reassignments in the same scope under `RMM2`, while reassigning a non-`mut` variable fails typechecking.