Iter 3: ADTs + Pattern Matching
- AST: Def::Type mit Ctors; Term::Ctor (Konstruktion) und Term::Match
mit Arm/Pattern. Patterns: Wild, Var, Lit, Ctor { ctor, fields } —
Sub-Patterns im MVP auf Var/Wild beschränkt.
- Typchecker: Type-Registry, ctor_index für O(1)-Resolution, Pattern-
Bindings, Exhaustiveness-Check gegen volle Konstruktormenge plus
Negativ-Tests.
- Codegen: Boxed-Heap-Layout via malloc; Tag in Offset 0, Felder ab
Offset 8 in 8-Byte-Slots. Match lowert zu load tag + switch + Phi
am Join. Default-Block ist unreachable, wenn vom Typchecker geprüft.
- examples/list.ail.json: rekursive Int-Liste mit sum_list via match.
E2E-Test + Exhaustiveness-Tests. 19/19 Tests grün.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+52
-5
@@ -93,6 +93,29 @@ fn main() -> Result<()> {
|
||||
ailang_core::pretty::type_to_string(&c.ty),
|
||||
vec![],
|
||||
),
|
||||
ailang_core::Def::Type(t) => {
|
||||
let s = t
|
||||
.ctors
|
||||
.iter()
|
||||
.map(|c| {
|
||||
if c.fields.is_empty() {
|
||||
c.name.clone()
|
||||
} else {
|
||||
format!(
|
||||
"{}({})",
|
||||
c.name,
|
||||
c.fields
|
||||
.iter()
|
||||
.map(ailang_core::pretty::type_to_string)
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(" | ");
|
||||
("type", s, vec![])
|
||||
}
|
||||
};
|
||||
serde_json::json!({
|
||||
"name": d.name(),
|
||||
@@ -233,11 +256,20 @@ fn main() -> Result<()> {
|
||||
|
||||
fn collect_refs(def: &ailang_core::Def) -> std::collections::BTreeSet<String> {
|
||||
let mut out = std::collections::BTreeSet::new();
|
||||
let body = match def {
|
||||
ailang_core::Def::Fn(f) => &f.body,
|
||||
ailang_core::Def::Const(c) => &c.value,
|
||||
};
|
||||
walk_term(body, &mut out);
|
||||
match def {
|
||||
ailang_core::Def::Fn(f) => walk_term(&f.body, &mut out),
|
||||
ailang_core::Def::Const(c) => walk_term(&c.value, &mut out),
|
||||
ailang_core::Def::Type(td) => {
|
||||
// Eine Typedef referenziert die Typen ihrer Felder.
|
||||
for c in &td.ctors {
|
||||
for ft in &c.fields {
|
||||
if let ailang_core::Type::Con { name } = ft {
|
||||
out.insert(format!("type:{name}"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
@@ -271,5 +303,20 @@ fn walk_term(t: &ailang_core::Term, out: &mut std::collections::BTreeSet<String>
|
||||
walk_term(a, out);
|
||||
}
|
||||
}
|
||||
Term::Ctor { type_name, ctor, args } => {
|
||||
out.insert(format!("ctor:{type_name}/{ctor}"));
|
||||
for a in args {
|
||||
walk_term(a, out);
|
||||
}
|
||||
}
|
||||
Term::Match { scrutinee, arms } => {
|
||||
walk_term(scrutinee, out);
|
||||
for arm in arms {
|
||||
if let ailang_core::ast::Pattern::Ctor { ctor, .. } = &arm.pat {
|
||||
out.insert(format!("ctor:{ctor}"));
|
||||
}
|
||||
walk_term(&arm.body, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,3 +56,10 @@ fn hello_world_str_lit() {
|
||||
let stdout = build_and_run("hello.ail.json");
|
||||
assert_eq!(stdout.trim(), "Hallo, AILang.");
|
||||
}
|
||||
|
||||
/// Schützt ADT-Codegen + Match: rekursive Liste, sum_list via match auf Cons/Nil.
|
||||
#[test]
|
||||
fn list_sum_via_match() {
|
||||
let stdout = build_and_run("list.ail.json");
|
||||
assert_eq!(stdout.trim(), "42");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user