Iter 4a: ail check --json mit strukturierten Diagnostics

Neue Top-Level-API check_module(&Module) -> Vec<Diagnostic> in
ailang-check, plus stabile Codes (unbound-var, type-mismatch,
arity-mismatch, non-exhaustive-match, unknown-ctor-in-pattern,
duplicate-def, …). CLI bekommt --json-Flag für maschinenlesbares
Output, Exit 1 bei Errors. Text-Modus unverändert. E2E-Test
check_json_unbound_var sichert das Format ab.
This commit is contained in:
2026-05-07 11:07:36 +02:00
parent 44243a515e
commit 93fe7237e3
7 changed files with 334 additions and 11 deletions
+42 -5
View File
@@ -42,7 +42,13 @@ enum Cmd {
json: bool,
},
/// Typprüft ein Modul.
Check { path: PathBuf },
Check {
path: PathBuf,
/// Strukturierte Diagnostics als JSON-Array auf stdout.
/// Exit-Code 1, wenn mindestens ein Error gemeldet wird.
#[arg(long)]
json: bool,
},
/// Schreibt LLVM IR (.ll) für das Modul.
EmitIr {
path: PathBuf,
@@ -163,10 +169,41 @@ fn main() -> Result<()> {
print!("{}", ailang_core::pretty::module(&one));
}
}
Cmd::Check { path } => {
let m = ailang_core::load_module(&path)?;
let r = ailang_check::check(&m)?;
println!("ok ({} symbols)", r.symbols.len());
Cmd::Check { path, json } => {
if json {
// JSON-Modus: stdout enthält ausschließlich das Diagnostics-
// Array. Schema-Mismatch wird als strukturiertes Diagnostic
// emittiert (mit Code `schema-mismatch`); echte I/O-Fehler
// propagieren als fatal, weil sie keinen Modul-bezogenen
// Diagnostic-Kontext haben.
let diags = match ailang_core::load_module(&path) {
Ok(m) => ailang_check::check_module(&m),
Err(ailang_core::Error::SchemaMismatch { expected, got }) => {
vec![ailang_check::Diagnostic::error(
"schema-mismatch",
format!(
"schema mismatch: expected {expected:?}, got {got:?}"
),
)
.with_ctx(serde_json::json!({
"expected": expected,
"actual": got,
}))]
}
Err(e) => return Err(anyhow::anyhow!(e)),
};
println!("{}", serde_json::to_string(&diags)?);
if diags
.iter()
.any(|d| matches!(d.severity, ailang_check::Severity::Error))
{
std::process::exit(1);
}
} else {
let m = ailang_core::load_module(&path)?;
let r = ailang_check::check(&m)?;
println!("ok ({} symbols)", r.symbols.len());
}
}
Cmd::EmitIr { path, out } => {
let m = ailang_core::load_module(&path)?;