MVP: AILang-Sprache mit JSON-AST, Typchecker, LLVM-IR-Backend
Erste lauffähige Iteration. examples/sum.ail.json wird zu nativem Binary kompiliert und druckt 55 (Summe 1..10) als End-to-End-Test. Architektur: - ailang-core: hashbares JSON-AST + canonical-form + pretty-printer - ailang-check: monomorpher HM-Subset + Effekt-Set-Tracking - ailang-codegen: LLVM-IR-Text-Emitter (kein libllvm-link) - ail: CLI mit check/manifest/render/describe/emit-ir/build/builtins Designentscheidungen sind in docs/DESIGN.md dokumentiert; der Verlauf in docs/JOURNAL.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
//! Content-addressed Hashing für Definitionen.
|
||||
//!
|
||||
//! Hash = BLAKE3 über die kanonische JSON-Form (siehe `canonical`).
|
||||
//! Das `hash`-Feld in der Eingabe wird vor dem Hashen entfernt.
|
||||
|
||||
use crate::ast::Def;
|
||||
use crate::canonical;
|
||||
|
||||
/// 16-Hex-Zeichen (64 bit) Prefix des BLAKE3-Hashes.
|
||||
/// Reicht für Eindeutigkeit innerhalb realistischer Codebases und ist
|
||||
/// kompakt genug für visuelle Inspektion.
|
||||
pub fn def_hash(def: &Def) -> String {
|
||||
let bytes = canonical::to_bytes(def);
|
||||
let h = blake3::hash(&bytes);
|
||||
let hex = h.to_hex();
|
||||
hex.as_str()[..16].to_string()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::ast::*;
|
||||
|
||||
fn sample_fn() -> Def {
|
||||
Def::Fn(FnDef {
|
||||
name: "add".into(),
|
||||
ty: Type::Fn {
|
||||
params: vec![Type::int(), Type::int()],
|
||||
ret: Box::new(Type::int()),
|
||||
effects: vec![],
|
||||
},
|
||||
params: vec!["a".into(), "b".into()],
|
||||
body: Term::App {
|
||||
callee: Box::new(Term::Var { name: "+".into() }),
|
||||
args: vec![
|
||||
Term::Var { name: "a".into() },
|
||||
Term::Var { name: "b".into() },
|
||||
],
|
||||
},
|
||||
doc: None,
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_is_stable() {
|
||||
let h1 = def_hash(&sample_fn());
|
||||
let h2 = def_hash(&sample_fn());
|
||||
assert_eq!(h1, h2);
|
||||
assert_eq!(h1.len(), 16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_changes_with_content() {
|
||||
let mut def = sample_fn();
|
||||
let h1 = def_hash(&def);
|
||||
if let Def::Fn(ref mut f) = def {
|
||||
f.name = "mul".into();
|
||||
}
|
||||
let h2 = def_hash(&def);
|
||||
assert_ne!(h1, h2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user