feat: pattern bindings, empty closures, match-as-expr, string interp

Sessions 10–12 from QUALITY_PLAN:

- Pattern payload bindings (Some(value) => value) in bootstrap and selfhost
- Empty-param closures via || (tkPipePipe) with loop/return bodies
- Expression-form match: let x = match …; newline before arms
- f"…" string interpolation desugared to String_Concat + conversions
- Lexer preserves \{ \} for literal braces in f-strings
- Bootstrap fix: f"plain" strips the f prefix after escape processing
- Examples: pattern_matching, closure_control, match_let, string_interp

Selfhost-loop remains binary-identical; all examples and error goldens pass.
This commit is contained in:
2026-07-18 00:58:44 +03:00
parent f619316470
commit db41ba4d84
18 changed files with 1192 additions and 67 deletions
+43
View File
@@ -0,0 +1,43 @@
// Match as expression: let-init, inline arms, combined with operators
import Std::Io::{PrintLine, PrintInt};
import Std::Test::{Test_AssertEqInt, Test_Pass};
enum Option {
Some(int),
None
}
func Main() -> int {
let opt: Option = Option { tag: Option_Some };
opt.data.Some_0 = 21;
let x: int = match opt {
Option::Some(v) => v + v,
Option::None => 0
};
Test_AssertEqInt(x, 42);
let n: int = 3;
let y: int = match n {
0 => 100,
1..5 => 200,
_ => -1
};
Test_AssertEqInt(y, 200);
let z: int = match n { 3 => 1, _ => 0 } + match n { 3 => 2, _ => 0 };
Test_AssertEqInt(z, 3);
let none: Option = Option { tag: Option_None };
// Same binding name as above — one alloca, reassigned per arm
let w: int = match none {
Option::Some(v) => v,
Option::None => -7
};
Test_AssertEqInt(w, -7);
PrintInt(x);
PrintLine("");
Test_Pass("match_let");
return 0;
}