iter 22-tidy.6.1: write_class_def + write_instance_def — full Form-B projection
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
Reference in New Issue
Block a user