iter 22-tidy.6.1: write_class_def + write_instance_def — full Form-B projection

This commit is contained in:
2026-05-10 04:47:50 +02:00
parent e7af79183d
commit d1c992d49a
3 changed files with 120 additions and 24 deletions
+99 -24
View File
@@ -25,8 +25,8 @@
//! never fails on a well-formed AST.
use ailang_core::ast::{
ConstDef, Ctor, Def, FnDef, Import, Literal, Module, ParamMode, Pattern, Suppress, Term, Type,
TypeDef,
ClassDef, ClassMethod, ConstDef, Ctor, Def, FnDef, Import, InstanceDef, InstanceMethod,
Literal, Module, ParamMode, Pattern, Suppress, Term, Type, TypeDef,
};
/// Render a [`Module`] as human-readable prose.
@@ -77,28 +77,8 @@ fn write_def(out: &mut String, def: &Def, level: usize) {
Def::Type(td) => write_type_def(out, td, level),
Def::Fn(fd) => write_fn_def(out, fd, level),
Def::Const(cd) => write_const_def(out, cd, level),
// ClassDef / InstanceDef render as a single-line placeholder
// so prose round-trip survives a module that contains them.
// The full Form-B projection (mirror of the Form-A schema,
// with method bodies re-indented and superclass / default
// markers spelled out) is queued post-22 — `crates/ailang-prose`
// is one-way (no parser by design), so the placeholder is
// informational only and the round-trip mediator does not
// read these back.
Def::Class(c) => {
indent(out, level);
out.push_str("// (class ");
out.push_str(&c.name);
out.push(' ');
out.push_str(&c.param);
out.push_str(") -- full Form-B projection deferred (post-22)\n");
}
Def::Instance(i) => {
indent(out, level);
out.push_str("// (instance ");
out.push_str(&i.class);
out.push_str(") -- full Form-B projection deferred (post-22)\n");
}
Def::Class(c) => write_class_def(out, c, level),
Def::Instance(i) => write_instance_def(out, i, level),
}
}
@@ -341,6 +321,101 @@ fn write_const_def(out: &mut String, cd: &ConstDef, level: usize) {
write_term(out, &cd.value, level);
}
fn write_class_def(out: &mut String, c: &ClassDef, level: usize) {
write_doc(out, &c.doc, level);
indent(out, level);
out.push_str("class ");
out.push_str(&c.name);
out.push(' ');
out.push_str(&c.param);
if let Some(sc) = &c.superclass {
out.push_str(" extends ");
out.push_str(&sc.class);
}
out.push_str(" {\n");
for m in &c.methods {
write_class_method(out, m, level + 1);
}
indent(out, level);
out.push('}');
}
fn write_class_method(out: &mut String, m: &ClassMethod, level: usize) {
indent(out, level);
out.push_str("fn ");
out.push_str(&m.name);
out.push('(');
if let Type::Fn { params, param_modes, ret, ret_mode, effects } = &m.ty {
for (i, p) in params.iter().enumerate() {
if i > 0 {
out.push_str(", ");
}
// Class methods carry types but no parameter names — name slots
// as `x`, `x1`, `x2`, … to keep the projection unambiguous
// without inventing names that could collide with the body.
if i == 0 {
out.push_str("x");
} else {
out.push_str(&format!("x{i}"));
}
out.push_str(": ");
let mode = param_modes.get(i).copied().unwrap_or(ParamMode::Implicit);
write_mode_type(out, p, mode);
}
out.push_str(") -> ");
write_mode_type(out, ret, *ret_mode);
if !effects.is_empty() {
out.push_str(" with ");
for (i, e) in effects.iter().enumerate() {
if i > 0 {
out.push_str(", ");
}
out.push_str(e);
}
}
} else {
out.push_str(") -> ");
write_type(out, &m.ty);
}
if let Some(body) = &m.default {
out.push_str(" default {\n");
indent(out, level + 1);
write_term(out, body, level + 1);
out.push('\n');
indent(out, level);
out.push_str("}\n");
} else {
out.push('\n');
}
}
fn write_instance_def(out: &mut String, i: &InstanceDef, level: usize) {
write_doc(out, &i.doc, level);
indent(out, level);
out.push_str("instance ");
out.push_str(&i.class);
out.push(' ');
write_type(out, &i.type_);
out.push_str(" {\n");
for m in &i.methods {
write_instance_method(out, m, level + 1);
}
indent(out, level);
out.push('}');
}
fn write_instance_method(out: &mut String, m: &InstanceMethod, level: usize) {
indent(out, level);
out.push_str("fn ");
out.push_str(&m.name);
out.push_str(" {\n");
indent(out, level + 1);
write_term(out, &m.body, level + 1);
out.push('\n');
indent(out, level);
out.push_str("}\n");
}
// ---- types ----------------------------------------------------------------
fn write_mode_type(out: &mut String, t: &Type, mode: ParamMode) {
+5
View File
@@ -71,3 +71,8 @@ fn snapshot_rc_app_let_partial_drop_leak() {
fn snapshot_bench_list_sum() {
check_snapshot("bench_list_sum");
}
#[test]
fn snapshot_test_22b3_default_e2e() {
check_snapshot("test_22b3_default_e2e");
}
+16
View File
@@ -0,0 +1,16 @@
// module test_22b3_default_e2e
class D a {
fn dval(x: a) -> Int default {
|x: a| -> Int {
99
}
}
}
instance D Int {
}
fn main() -> Unit with IO {
do io/print_int(dval(0))
}