feat: field-move Drop (partial/nested/ptr), stmt/pat macros, Windows runtime
ci / build (ubuntu) (push) Has been cancelled
ci / macos smoke (push) Has been cancelled
ci / windows smoke (push) Has been cancelled
selfhost-loop / bootstrap determinism (push) Has been cancelled
ci / unit + fmt (push) Has been cancelled
ci / examples (push) Has been cancelled
ci / goldens + tools (push) Has been cancelled
ci / apps (push) Has been cancelled
ci / selfhost smoke (push) Has been cancelled
ci / CI gate (push) Has been cancelled
ci / build (ubuntu) (push) Has been cancelled
ci / macos smoke (push) Has been cancelled
ci / windows smoke (push) Has been cancelled
selfhost-loop / bootstrap determinism (push) Has been cancelled
ci / unit + fmt (push) Has been cancelled
ci / examples (push) Has been cancelled
ci / goldens + tools (push) Has been cancelled
ci / apps (push) Has been cancelled
ci / selfhost smoke (push) Has been cancelled
ci / CI gate (push) Has been cancelled
Sessions 70–74: partialMovedPaths + ptrAliases in bootstrap/selfhost CBE, remaining drops after field moves, macro stmt/pat fragments, runtime_win.c and MinGW hello CI, examples + drop-move smoke coverage, QUALITY_PLAN update.
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
// Session 72 — macro fragment kinds `stmt` and `pat`
|
||||
import Std::Io::{PrintLine};
|
||||
import Std::String::{String_FromInt};
|
||||
import Std::Test::{Test_AssertTrue, Test_Pass};
|
||||
|
||||
// stmt: splice a full statement (let / assign) into the template
|
||||
macro! with_setup {
|
||||
( $s:stmt, $body:expr ) => {
|
||||
{
|
||||
$s
|
||||
$body
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// stmt from an expression-statement (assign)
|
||||
macro! do_twice {
|
||||
( $s:stmt ) => {
|
||||
{
|
||||
$s
|
||||
$s
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pat: match arm pattern from call-site
|
||||
macro! matches {
|
||||
( $p:pat, $e:expr ) => {
|
||||
match $e {
|
||||
$p => 1,
|
||||
_ => 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Combined: extract payload when pattern matches
|
||||
macro! if_let_like {
|
||||
( $p:pat, $e:expr, $then:expr ) => {
|
||||
match $e {
|
||||
$p => $then,
|
||||
_ => -1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Opt {
|
||||
Some(int),
|
||||
None
|
||||
}
|
||||
|
||||
func Main() -> int {
|
||||
// with_setup: inject `let x = 10` then use x
|
||||
let a: int = with_setup!(let x: int = 10, x + 1);
|
||||
Test_AssertTrue(a == 11);
|
||||
|
||||
// do_twice: run assign twice
|
||||
var n: int = 0;
|
||||
discard do_twice!(n = n + 1);
|
||||
Test_AssertTrue(n == 2);
|
||||
|
||||
// matches: literal / wildcard / enum (bind results — match-as-arg is fragile on buxc2)
|
||||
let m1: int = matches!(1, 1);
|
||||
let m2: int = matches!(2, 1);
|
||||
let m3: int = matches!(_, 99);
|
||||
Test_AssertTrue(m1 == 1);
|
||||
Test_AssertTrue(m2 == 0);
|
||||
Test_AssertTrue(m3 == 1);
|
||||
|
||||
var o1: Opt = Opt { tag: Opt_Some };
|
||||
o1.data.Some_0 = 7;
|
||||
let o2: Opt = Opt { tag: Opt_None };
|
||||
let e1: int = if_let_like!(Opt::Some(v), o1, v);
|
||||
let e2: int = if_let_like!(Opt::Some(v), o2, v);
|
||||
let e3: int = matches!(Opt::None, o2);
|
||||
Test_AssertTrue(e1 == 7);
|
||||
Test_AssertTrue(e2 == -1);
|
||||
Test_AssertTrue(e3 == 1);
|
||||
|
||||
PrintLine(String_FromInt(a));
|
||||
PrintLine(String_FromInt(n));
|
||||
Test_Pass("macro_stmt_pat");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
// Session 73 — nested field path moves (`outer.inner.items`)
|
||||
// Moving a deep droppable field skips root Drop and still drops remaining
|
||||
// fields at every level of the path.
|
||||
import Std::Io::{PrintLine};
|
||||
import Std::Array::{Array, Array_New, Array_Push, Array_Len, Array_Get};
|
||||
import Std::String::{String_FromInt, String_Concat};
|
||||
import Std::Test::{Test_AssertTrue, Test_Pass};
|
||||
|
||||
@[Drop]
|
||||
struct Tracked {
|
||||
id: int,
|
||||
counter: *int
|
||||
}
|
||||
|
||||
func Tracked_Drop(self: *Tracked) {
|
||||
if self.counter != null as *int {
|
||||
*self.counter = *self.counter + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@[Drop]
|
||||
struct Inner {
|
||||
items: Array<int>,
|
||||
note: Tracked
|
||||
}
|
||||
|
||||
func Inner_Drop(self: *Inner) {
|
||||
Array_Drop<int>(&self.items);
|
||||
Tracked_Drop(&self.note);
|
||||
}
|
||||
|
||||
@[Drop]
|
||||
struct Outer {
|
||||
inner: Inner,
|
||||
tag: Tracked
|
||||
}
|
||||
|
||||
func Outer_Drop(self: *Outer) {
|
||||
Inner_Drop(&self.inner);
|
||||
Tracked_Drop(&self.tag);
|
||||
}
|
||||
|
||||
// Move outer.inner.items — must Drop: outer.inner.note + outer.tag
|
||||
// (not Outer_Drop whole, not Array double-free)
|
||||
func TakeNestedItems(counter: *int) -> Array<int> {
|
||||
var items: Array<int> = Array_New<int>(2);
|
||||
Array_Push<int>(&items, 10);
|
||||
Array_Push<int>(&items, 20);
|
||||
let outer: Outer = Outer {
|
||||
inner: Inner {
|
||||
items: items,
|
||||
note: Tracked { id: 1, counter: counter }
|
||||
},
|
||||
tag: Tracked { id: 2, counter: counter }
|
||||
};
|
||||
return outer.inner.items;
|
||||
}
|
||||
|
||||
// let-move nested path
|
||||
func PeekAfterNestedTake(counter: *int) -> int {
|
||||
var items: Array<int> = Array_New<int>(1);
|
||||
Array_Push<int>(&items, 7);
|
||||
let outer: Outer = Outer {
|
||||
inner: Inner {
|
||||
items: items,
|
||||
note: Tracked { id: 3, counter: counter }
|
||||
},
|
||||
tag: Tracked { id: 4, counter: counter }
|
||||
};
|
||||
let moved: Array<int> = outer.inner.items;
|
||||
return Array_Len<int>(&moved) as int;
|
||||
}
|
||||
|
||||
func Main() -> int {
|
||||
var drops: int = 0;
|
||||
|
||||
let taken: Array<int> = TakeNestedItems(&drops);
|
||||
Test_AssertTrue(Array_Len<int>(&taken) == 2);
|
||||
Test_AssertTrue(Array_Get<int>(&taken, 0) == 10);
|
||||
// TakeNestedItems: note(id1) + tag(id2) → 2 Tracked drops
|
||||
Test_AssertTrue(drops == 2);
|
||||
|
||||
let n: int = PeekAfterNestedTake(&drops);
|
||||
Test_AssertTrue(n == 1);
|
||||
// +2 more Tracked drops
|
||||
Test_AssertTrue(drops == 4);
|
||||
|
||||
PrintLine(String_Concat("nested_drops=", String_FromInt(drops as int64)));
|
||||
Test_Pass("move_field_nested");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
// Session 74 — field moves through pointers (`p.field` / `(*p).field`)
|
||||
// When `p = &bag`, moving `p.items` marks the owner `bag` (not the pointer).
|
||||
import Std::Io::{PrintLine};
|
||||
import Std::Array::{Array, Array_New, Array_Push, Array_Len, Array_Get};
|
||||
import Std::String::{String_FromInt, String_Concat};
|
||||
import Std::Test::{Test_AssertTrue, Test_Pass};
|
||||
|
||||
@[Drop]
|
||||
struct Tracked {
|
||||
id: int,
|
||||
counter: *int
|
||||
}
|
||||
|
||||
func Tracked_Drop(self: *Tracked) {
|
||||
if self.counter != null as *int {
|
||||
*self.counter = *self.counter + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@[Drop]
|
||||
struct Bag {
|
||||
items: Array<int>,
|
||||
tag: Tracked
|
||||
}
|
||||
|
||||
func Bag_Drop(self: *Bag) {
|
||||
Array_Drop<int>(&self.items);
|
||||
Tracked_Drop(&self.tag);
|
||||
}
|
||||
|
||||
// p.items via auto-deref of *Bag
|
||||
func TakeViaPtr(counter: *int) -> Array<int> {
|
||||
var items: Array<int> = Array_New<int>(2);
|
||||
Array_Push<int>(&items, 10);
|
||||
Array_Push<int>(&items, 20);
|
||||
let bag: Bag = Bag {
|
||||
items: items,
|
||||
tag: Tracked { id: 1, counter: counter }
|
||||
};
|
||||
let p: *Bag = &bag;
|
||||
return p.items;
|
||||
}
|
||||
|
||||
// Explicit (*p).items
|
||||
func TakeViaDeref(counter: *int) -> Array<int> {
|
||||
var items: Array<int> = Array_New<int>(1);
|
||||
Array_Push<int>(&items, 7);
|
||||
let bag: Bag = Bag {
|
||||
items: items,
|
||||
tag: Tracked { id: 2, counter: counter }
|
||||
};
|
||||
let p: *Bag = &bag;
|
||||
return (*p).items;
|
||||
}
|
||||
|
||||
// let-move through pointer; remaining tag still Drops
|
||||
func PeekAfterPtrTake(counter: *int) -> int {
|
||||
var items: Array<int> = Array_New<int>(1);
|
||||
Array_Push<int>(&items, 3);
|
||||
let bag: Bag = Bag {
|
||||
items: items,
|
||||
tag: Tracked { id: 3, counter: counter }
|
||||
};
|
||||
var p: *Bag = &bag;
|
||||
let moved: Array<int> = p.items;
|
||||
return Array_Len<int>(&moved) as int;
|
||||
}
|
||||
|
||||
// Nested path through pointer: p.inner.items
|
||||
@[Drop]
|
||||
struct Inner {
|
||||
items: Array<int>,
|
||||
note: Tracked
|
||||
}
|
||||
|
||||
func Inner_Drop(self: *Inner) {
|
||||
Array_Drop<int>(&self.items);
|
||||
Tracked_Drop(&self.note);
|
||||
}
|
||||
|
||||
@[Drop]
|
||||
struct Outer {
|
||||
inner: Inner,
|
||||
tag: Tracked
|
||||
}
|
||||
|
||||
func Outer_Drop(self: *Outer) {
|
||||
Inner_Drop(&self.inner);
|
||||
Tracked_Drop(&self.tag);
|
||||
}
|
||||
|
||||
func TakeNestedViaPtr(counter: *int) -> Array<int> {
|
||||
var items: Array<int> = Array_New<int>(1);
|
||||
Array_Push<int>(&items, 99);
|
||||
let outer: Outer = Outer {
|
||||
inner: Inner {
|
||||
items: items,
|
||||
note: Tracked { id: 4, counter: counter }
|
||||
},
|
||||
tag: Tracked { id: 5, counter: counter }
|
||||
};
|
||||
let p: *Outer = &outer;
|
||||
return p.inner.items;
|
||||
}
|
||||
|
||||
func Main() -> int {
|
||||
var drops: int = 0;
|
||||
|
||||
let a: Array<int> = TakeViaPtr(&drops);
|
||||
Test_AssertTrue(Array_Len<int>(&a) == 2);
|
||||
Test_AssertTrue(Array_Get<int>(&a, 0) == 10);
|
||||
// tag Drop once
|
||||
Test_AssertTrue(drops == 1);
|
||||
|
||||
let b: Array<int> = TakeViaDeref(&drops);
|
||||
Test_AssertTrue(Array_Len<int>(&b) == 1);
|
||||
Test_AssertTrue(drops == 2);
|
||||
|
||||
let n: int = PeekAfterPtrTake(&drops);
|
||||
Test_AssertTrue(n == 1);
|
||||
Test_AssertTrue(drops == 3);
|
||||
|
||||
let c: Array<int> = TakeNestedViaPtr(&drops);
|
||||
Test_AssertTrue(Array_Get<int>(&c, 0) == 99);
|
||||
// note + tag → +2
|
||||
Test_AssertTrue(drops == 5);
|
||||
|
||||
PrintLine(String_Concat("ptr_drops=", String_FromInt(drops as int64)));
|
||||
Test_Pass("move_field_ptr");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
// Session 70 — per-field Drop after partial move
|
||||
// Moving one droppable field out of a @[Drop] parent skips Type_Drop of the
|
||||
// parent but still drops the *remaining* droppable fields.
|
||||
import Std::Io::{PrintLine};
|
||||
import Std::Array::{Array, Array_New, Array_Push, Array_Len, Array_Get};
|
||||
import Std::String::{String_FromInt, String_Concat};
|
||||
import Std::Test::{Test_AssertTrue, Test_Pass};
|
||||
|
||||
@[Drop]
|
||||
struct Tracked {
|
||||
n: int,
|
||||
counter: *int
|
||||
}
|
||||
|
||||
func Tracked_Drop(self: *Tracked) {
|
||||
if self.counter != null as *int {
|
||||
*self.counter = *self.counter + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@[Drop]
|
||||
struct PairBag {
|
||||
left: Array<int>,
|
||||
right: Tracked
|
||||
}
|
||||
|
||||
func PairBag_Drop(self: *PairBag) {
|
||||
Array_Drop<int>(&self.left);
|
||||
Tracked_Drop(&self.right);
|
||||
}
|
||||
|
||||
// Move left out via return — right must still Drop (Tracked_Drop)
|
||||
func TakeLeft(counter: *int) -> Array<int> {
|
||||
var left: Array<int> = Array_New<int>(2);
|
||||
Array_Push<int>(&left, 10);
|
||||
Array_Push<int>(&left, 20);
|
||||
let pair: PairBag = PairBag {
|
||||
left: left,
|
||||
right: Tracked { n: 2, counter: counter }
|
||||
};
|
||||
return pair.left;
|
||||
}
|
||||
|
||||
// Move left via let; right still drops at scope end
|
||||
func PeekAfterTake(counter: *int) -> int {
|
||||
var left: Array<int> = Array_New<int>(1);
|
||||
Array_Push<int>(&left, 7);
|
||||
let pair: PairBag = PairBag {
|
||||
left: left,
|
||||
right: Tracked { n: 2, counter: counter }
|
||||
};
|
||||
let moved: Array<int> = pair.left;
|
||||
return Array_Len<int>(&moved) as int;
|
||||
}
|
||||
|
||||
// Whole-struct return: no PairBag_Drop here (caller owns it)
|
||||
func MakePair() -> PairBag {
|
||||
var left: Array<int> = Array_New<int>(1);
|
||||
Array_Push<int>(&left, 1);
|
||||
let pair: PairBag = PairBag {
|
||||
left: left,
|
||||
right: Tracked { n: 9, counter: null as *int }
|
||||
};
|
||||
return pair;
|
||||
}
|
||||
|
||||
func Main() -> int {
|
||||
var drops: int = 0;
|
||||
|
||||
let taken: Array<int> = TakeLeft(&drops);
|
||||
Test_AssertTrue(Array_Len<int>(&taken) == 2);
|
||||
Test_AssertTrue(Array_Get<int>(&taken, 0) == 10);
|
||||
// TakeLeft must have Dropped remaining right field once
|
||||
Test_AssertTrue(drops == 1);
|
||||
|
||||
let n: int = PeekAfterTake(&drops);
|
||||
Test_AssertTrue(n == 1);
|
||||
Test_AssertTrue(drops == 2);
|
||||
|
||||
let p: PairBag = MakePair();
|
||||
Test_AssertTrue(Array_Len<int>(&p.left) == 1);
|
||||
Test_AssertTrue(p.right.n == 9);
|
||||
|
||||
PrintLine(String_Concat("right_drops=", String_FromInt(drops as int64)));
|
||||
Test_Pass("move_field_remaining");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user