feat: implement M3 aggregate types and iteration

This commit is contained in:
2026-08-16 08:49:50 +09:00
parent 57b47a574a
commit 8e6a409637
32 changed files with 1729 additions and 94 deletions
+9
View File
@@ -0,0 +1,9 @@
unit m3_array;
fn main() -> i32 {
let a: [3]i32 = [1, 2, 3];
let s: []i32 = a[..];
let t: []i32 = s[1..3];
if a[0] + s[1] + t[0] == 5 and s.n == 3 { return 0; }
return 1;
}
+7
View File
@@ -0,0 +1,7 @@
unit m3_arrayctx;
fn main() -> i32 {
let bytes: [3]u8 = [1, 2, 3];
if bytes[0] == 1 and bytes[2] == 3 { return 0; }
return 1;
}
+5
View File
@@ -0,0 +1,5 @@
unit fail_m3_array;
fn main() -> i32 {
let a: [2]i32 = [1, true, 3];
return a[0];
}
+6
View File
@@ -0,0 +1,6 @@
unit fail_m3_char;
fn main() -> i32 {
let u: u8 = 'A';
return u;
}
+6
View File
@@ -0,0 +1,6 @@
unit fail_m3_cycle;
struct A { b: B, }
struct B { a: A, }
fn main() -> i32 { return 0; }
+8
View File
@@ -0,0 +1,8 @@
unit fail_m3_let_field;
struct Point { x: i32, y: i32, }
fn main() -> i32 {
let p: Point = Point{ x: 1, y: 2 };
p.x = 3;
return p.x;
}
+6
View File
@@ -0,0 +1,6 @@
unit fail_m3_fields;
struct Point { x: i32, y: i32, }
fn main() -> i32 {
let p: Point = Point{ x: 1 };
return p.z;
}
+7
View File
@@ -0,0 +1,7 @@
unit fail_m3_let_index;
fn main() -> i32 {
let a: [2]i32 = [1, 2];
a[0] = 3;
return a[0];
}
+6
View File
@@ -0,0 +1,6 @@
unit fail_m3_match;
enum Shape { Empty, Circle(i32), }
fn main() -> i32 {
match Shape.Empty { Empty => 0; }
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
unit fail_m3_str;
fn main() -> i32 {
var text: str = "abc";
text[0] = 'z';
return 0;
}
+6
View File
@@ -0,0 +1,6 @@
unit m3_bounds;
fn main() -> i32 {
let a: [2]i32 = [1, 2];
return a[2];
}
+9
View File
@@ -0,0 +1,9 @@
unit m3_char;
fn main() -> i32 {
let c: char = '\u0041';
let u: u8 = c as u8;
let d: char = u as char;
if c == d and u == ('A' as u8) { return 0; }
return 1;
}
+16
View File
@@ -0,0 +1,16 @@
unit m3_enum;
enum Shape { Empty, Circle(i32), Rect { w: i32, h: i32, }, }
fn score(s: Shape) -> i32 {
match s {
Empty => { return 0; }
Circle(value) => { return value; }
Rect { w, h } => { return w * h; }
}
}
fn main() -> i32 {
if score(Shape.Circle(5)) == 5 and score(Shape.Rect{ w: 2, h: 3 }) == 6 { return 0; }
return 1;
}
+18
View File
@@ -0,0 +1,18 @@
unit m3_for;
fn main() -> i32 {
var total: i32 = 0;
let a: [3]i32 = [1, 2, 3];
let s: []i32 = a[..];
var m: [1]i32 = [1];
let ready: bool = true;
if ready { total += 0; }
while false { total += 100; }
for x in a { total += x.^; }
for i, x in a { if i == 1 and x.^ == 2 { total += 1; } }
for x in "ab" { if x.^ == ('a' as u8) { total += 1; } }
for x in s { if x.^ == 3 { total += 1; } }
for x in m { x.^ = 2; }
if total == 9 and m[0] == 2 { return 0; }
return 1;
}
+10
View File
@@ -0,0 +1,10 @@
unit m3_nested;
struct Outer { inner: Inner, }
struct Inner { value: i32, }
fn main() -> i32 {
let x: Outer = Outer{ inner: Inner{ value: 7 } };
if x.inner.value == 7 { return 0; }
return 1;
}
+7
View File
@@ -0,0 +1,7 @@
unit m3_str;
fn main() -> i32 {
let text: str = "abc";
if text[1] == ('b' as u8) and text.n == 3 { return 0; }
return 1;
}
+14
View File
@@ -0,0 +1,14 @@
unit m3_struct;
struct Point { x: i32, y: i32, }
packed struct PackedPoint { x: u8, y: i32, }
struct Natural { a: u8, b: i32, }
fn main() -> i32 {
let p: Point = Point{ x: 3, y: 4 };
let q: PackedPoint = PackedPoint{ x: 1, y: 6 };
let n: Natural = Natural{ a: 1, b: 2 };
if p.x + p.y == 7 and q.y == 6 and n.b == 2 and
(Point{ x: 1, y: 2 }.x == 1) and @size_of(Natural) == 8 { return 0; }
return 1;
}
+21
View File
@@ -40,3 +40,24 @@ for f in bad-condition bad-cast bad-assign bad-unknown bad-arity bad-types bad-r
fi
done
echo "M2 tests: integer control-flow smoke passed"
m3tmp=$(mktemp -d)
trap 'rm -rf "$m2tmp" "$m3tmp"' EXIT HUP INT TERM
for f in struct enum array arrayctx str for nested char; do
"$root"/fec --target=bits32 --emit-c "$root"/tests/m3/$f.fe -o "$m3tmp/$f.c"
${CC:-cc} -std=c89 -pedantic "$m3tmp/$f.c" -o "$m3tmp/$f"
"$m3tmp/$f"
done
"$root"/fec --target=bits32 --emit-c "$root"/tests/m3/bounds.fe -o "$m3tmp/bounds.c"
${CC:-cc} -std=c89 -pedantic "$m3tmp/bounds.c" -o "$m3tmp/bounds"
if "$m3tmp/bounds"; then
echo "FAIL (bounds trap did not fire): tests/m3/bounds.fe"
exit 1
fi
for f in badfld badmat badarr badcycle badstr badchar badfield badindex; do
if "$root"/fec --target=bits32 --emit-c "$root"/tests/m3/$f.fe -o "$m3tmp/$f.c" >/dev/null 2>/dev/null; then
echo "FAIL (accepted M3 semantic error): $f.fe"
exit 1
fi
done
echo "M3 tests: structs, enums, arrays, slices, str, match, and bounds passed"