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,151 @@
|
||||
//! AST-Knoten. Serde-Layout entspricht dem JSON-Schema in `docs/DESIGN.md`.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Module {
|
||||
pub schema: String,
|
||||
pub name: String,
|
||||
#[serde(default)]
|
||||
pub imports: Vec<Import>,
|
||||
pub defs: Vec<Def>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Import {
|
||||
pub module: String,
|
||||
#[serde(rename = "as", default, skip_serializing_if = "Option::is_none")]
|
||||
pub alias: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "kind", rename_all = "lowercase")]
|
||||
pub enum Def {
|
||||
Fn(FnDef),
|
||||
Const(ConstDef),
|
||||
}
|
||||
|
||||
impl Def {
|
||||
pub fn name(&self) -> &str {
|
||||
match self {
|
||||
Def::Fn(f) => &f.name,
|
||||
Def::Const(c) => &c.name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FnDef {
|
||||
pub name: String,
|
||||
#[serde(rename = "type")]
|
||||
pub ty: Type,
|
||||
pub params: Vec<String>,
|
||||
pub body: Term,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub doc: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ConstDef {
|
||||
pub name: String,
|
||||
#[serde(rename = "type")]
|
||||
pub ty: Type,
|
||||
pub value: Term,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub doc: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "t", rename_all = "lowercase")]
|
||||
pub enum Term {
|
||||
Lit { lit: Literal },
|
||||
Var { name: String },
|
||||
App {
|
||||
#[serde(rename = "fn")]
|
||||
callee: Box<Term>,
|
||||
args: Vec<Term>,
|
||||
},
|
||||
Let {
|
||||
name: String,
|
||||
value: Box<Term>,
|
||||
body: Box<Term>,
|
||||
},
|
||||
If {
|
||||
cond: Box<Term>,
|
||||
then: Box<Term>,
|
||||
#[serde(rename = "else")]
|
||||
else_: Box<Term>,
|
||||
},
|
||||
Do {
|
||||
op: String,
|
||||
args: Vec<Term>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "kind", rename_all = "lowercase")]
|
||||
pub enum Literal {
|
||||
Int { value: i64 },
|
||||
Bool { value: bool },
|
||||
Unit,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "k", rename_all = "lowercase")]
|
||||
pub enum Type {
|
||||
Con {
|
||||
name: String,
|
||||
},
|
||||
Fn {
|
||||
params: Vec<Type>,
|
||||
ret: Box<Type>,
|
||||
#[serde(default)]
|
||||
effects: Vec<String>,
|
||||
},
|
||||
Var {
|
||||
name: String,
|
||||
},
|
||||
Forall {
|
||||
vars: Vec<String>,
|
||||
body: Box<Type>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn int() -> Type {
|
||||
Type::Con { name: "Int".into() }
|
||||
}
|
||||
pub fn bool_() -> Type {
|
||||
Type::Con { name: "Bool".into() }
|
||||
}
|
||||
pub fn unit() -> Type {
|
||||
Type::Con { name: "Unit".into() }
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Type {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Type::Con { name: a }, Type::Con { name: b }) => a == b,
|
||||
(
|
||||
Type::Fn { params: ap, ret: ar, effects: ae },
|
||||
Type::Fn { params: bp, ret: br, effects: be },
|
||||
) => {
|
||||
ap == bp && ar == br && {
|
||||
let mut a = ae.clone();
|
||||
let mut b = be.clone();
|
||||
a.sort();
|
||||
b.sort();
|
||||
a == b
|
||||
}
|
||||
}
|
||||
(Type::Var { name: a }, Type::Var { name: b }) => a == b,
|
||||
(
|
||||
Type::Forall { vars: a, body: ab },
|
||||
Type::Forall { vars: b, body: bb },
|
||||
) => a == b && ab == bb,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Eq for Type {}
|
||||
Reference in New Issue
Block a user