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:
@@ -0,0 +1,63 @@
|
||||
// Closures with control flow: empty `||` params, while/break, early return
|
||||
import Std::Io::{PrintLine, PrintInt};
|
||||
import Std::Test::{Test_AssertEqInt, Test_Pass};
|
||||
|
||||
// Zero-param capturing closure written as `||` (not `| |`)
|
||||
func MakeCounter(limit: int) -> func() -> int {
|
||||
return || -> int {
|
||||
var sum: int = 0;
|
||||
var i: int = 0;
|
||||
while i < limit {
|
||||
sum = sum + i;
|
||||
i = i + 1;
|
||||
if i == 3 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
};
|
||||
}
|
||||
|
||||
func MakeClamp(n: int) -> func(int) -> int {
|
||||
return |x: int| -> int {
|
||||
if x < 0 {
|
||||
return 0;
|
||||
}
|
||||
if x > n {
|
||||
return n;
|
||||
}
|
||||
return x;
|
||||
};
|
||||
}
|
||||
|
||||
// return from inside a loop inside a closure
|
||||
func MakeLoopReturn(n: int) -> func() -> int {
|
||||
return || -> int {
|
||||
var i: int = 0;
|
||||
while i < n {
|
||||
if i == 2 {
|
||||
return 99;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
return i;
|
||||
};
|
||||
}
|
||||
|
||||
func Main() -> int {
|
||||
let c: func() -> int = MakeCounter(10);
|
||||
Test_AssertEqInt(c(), 3); // 0+1+2
|
||||
|
||||
let f: func(int) -> int = MakeClamp(5);
|
||||
Test_AssertEqInt(f(-1), 0);
|
||||
Test_AssertEqInt(f(3), 3);
|
||||
Test_AssertEqInt(f(100), 5);
|
||||
|
||||
let g: func() -> int = MakeLoopReturn(10);
|
||||
Test_AssertEqInt(g(), 99);
|
||||
|
||||
PrintInt(c());
|
||||
PrintLine("");
|
||||
Test_Pass("closure_control");
|
||||
return 0;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,19 +1,41 @@
|
||||
// Pattern Matching — enum tags, literals, ranges, wildcard
|
||||
// Pattern Matching — enum tags, payload bindings, literals, ranges, wildcard
|
||||
import Std::Io::{PrintLine, PrintInt};
|
||||
|
||||
import Std::Test::{Test_AssertEqInt, Test_Pass};
|
||||
|
||||
enum Option {
|
||||
Some(int),
|
||||
None
|
||||
}
|
||||
|
||||
enum Msg {
|
||||
Quit,
|
||||
Move(int),
|
||||
Write(String)
|
||||
}
|
||||
|
||||
func GetValue(opt: Option) -> int {
|
||||
// Pattern binding: value is bound from Option::Some payload
|
||||
match opt {
|
||||
Option::Some(value) => opt.data.Some_0,
|
||||
Option::Some(value) => value,
|
||||
Option::None => 0
|
||||
}
|
||||
}
|
||||
|
||||
func DoubleSome(opt: Option) -> int {
|
||||
match opt {
|
||||
Option::Some(n) => n + n,
|
||||
Option::None => -1
|
||||
}
|
||||
}
|
||||
|
||||
func MsgCode(m: Msg) -> int {
|
||||
match m {
|
||||
Msg::Quit => 0,
|
||||
Msg::Move(x) => x,
|
||||
Msg::Write(s) => 1
|
||||
}
|
||||
}
|
||||
|
||||
func Classify(n: int) -> int {
|
||||
// literal arms + exclusive range + inclusive range + wildcard
|
||||
match n {
|
||||
@@ -40,6 +62,15 @@ func Main() -> int {
|
||||
|
||||
let opt2: Option = Option { tag: Option_None };
|
||||
|
||||
Test_AssertEqInt(GetValue(opt1), 42);
|
||||
Test_AssertEqInt(GetValue(opt2), 0);
|
||||
Test_AssertEqInt(DoubleSome(opt1), 84);
|
||||
Test_AssertEqInt(DoubleSome(opt2), -1);
|
||||
|
||||
let m: Msg = Msg { tag: Msg_Move };
|
||||
m.data.Move_0 = 7;
|
||||
Test_AssertEqInt(MsgCode(m), 7);
|
||||
|
||||
PrintLine("opt1 value: ");
|
||||
PrintInt(GetValue(opt1));
|
||||
PrintLine("");
|
||||
@@ -61,5 +92,6 @@ func Main() -> int {
|
||||
PrintLine("color:");
|
||||
PrintLine(ColorName(2));
|
||||
|
||||
Test_Pass("pattern_matching");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import Std::Io::{PrintLine};
|
||||
import Std::Test::{Test_AssertEqString, Test_Pass};
|
||||
|
||||
func Main() -> int {
|
||||
let name: String = "Bux";
|
||||
let n: int = 42;
|
||||
let msg: String = f"Hello, {name}! count={n}";
|
||||
PrintLine(msg);
|
||||
Test_AssertEqString(msg, "Hello, Bux! count=42");
|
||||
|
||||
let flag: bool = true;
|
||||
let bmsg: String = f"flag={flag}";
|
||||
Test_AssertEqString(bmsg, "flag=true");
|
||||
|
||||
let empty: String = f"plain";
|
||||
Test_AssertEqString(empty, "plain");
|
||||
|
||||
let raw: String = f"use \{braces\} literally";
|
||||
Test_AssertEqString(raw, "use {braces} literally");
|
||||
|
||||
Test_Pass("string_interp");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user