Skip to main content

aver/
ast.rs

1#[derive(Debug, Clone, PartialEq)]
2pub enum Literal {
3    Int(i64),
4    Float(f64),
5    Str(String),
6    Bool(bool),
7    Unit,
8}
9
10#[derive(Debug, Clone, PartialEq)]
11pub enum BinOp {
12    Add,
13    Sub,
14    Mul,
15    Div,
16    Eq,
17    Neq,
18    Lt,
19    Gt,
20    Lte,
21    Gte,
22}
23
24#[derive(Debug, Clone, PartialEq)]
25pub struct MatchArm {
26    pub pattern: Pattern,
27    pub body: Box<Expr>,
28}
29
30#[derive(Debug, Clone, PartialEq)]
31pub enum Pattern {
32    Wildcard,
33    Literal(Literal),
34    Ident(String),
35    /// Empty list pattern: `[]`
36    EmptyList,
37    /// Cons-like list pattern: `[head, ..tail]`
38    Cons(String, String),
39    /// Tuple pattern: `(a, b)` / `(_, x)` / nested tuples.
40    Tuple(Vec<Pattern>),
41    /// Constructor pattern: fully-qualified name + list of binding names.
42    /// Built-ins: Result.Ok(x), Result.Err(x), Option.Some(x), Option.None.
43    /// User-defined: Shape.Circle(r), Shape.Rect(w, h), Shape.Point.
44    Constructor(String, Vec<String>),
45}
46
47#[derive(Debug, Clone, PartialEq)]
48pub enum StrPart {
49    Literal(String),
50    Parsed(Box<Expr>),
51}
52
53#[derive(Debug, Clone, PartialEq)]
54pub enum Expr {
55    Literal(Literal),
56    Ident(String),
57    Attr(Box<Expr>, String),
58    FnCall(Box<Expr>, Vec<Expr>),
59    BinOp(BinOp, Box<Expr>, Box<Expr>),
60    Match {
61        subject: Box<Expr>,
62        arms: Vec<MatchArm>,
63        line: usize,
64    },
65    Constructor(String, Option<Box<Expr>>),
66    ErrorProp(Box<Expr>),
67    InterpolatedStr(Vec<StrPart>),
68    List(Vec<Expr>),
69    Tuple(Vec<Expr>),
70    /// Map literal: `{"a" => 1, "b" => 2}`
71    MapLiteral(Vec<(Expr, Expr)>),
72    /// Record creation: `User(name = "Alice", age = 30)`
73    RecordCreate {
74        type_name: String,
75        fields: Vec<(String, Expr)>,
76    },
77    /// Record update: `User.update(base, field = newVal, ...)`
78    RecordUpdate {
79        type_name: String,
80        base: Box<Expr>,
81        updates: Vec<(String, Expr)>,
82    },
83    /// Tail-position call to a function in the same SCC (self or mutual recursion).
84    /// Produced by the TCO transform pass before type-checking.
85    /// Boxed to keep Expr enum at its original size (48 bytes).
86    TailCall(Box<(String, Vec<Expr>)>),
87    /// Compiled variable lookup: `env[last][slot]` — O(1) instead of HashMap scan.
88    /// Produced by the resolver pass for locals inside function bodies.
89    Resolved(u16),
90}
91
92#[derive(Debug, Clone, PartialEq)]
93pub enum Stmt {
94    Binding(String, Option<String>, Expr),
95    Expr(Expr),
96}
97
98#[derive(Debug, Clone, PartialEq)]
99pub enum FnBody {
100    Block(Vec<Stmt>),
101}
102
103impl FnBody {
104    pub fn from_expr(expr: Expr) -> Self {
105        Self::Block(vec![Stmt::Expr(expr)])
106    }
107
108    pub fn stmts(&self) -> &[Stmt] {
109        match self {
110            Self::Block(stmts) => stmts,
111        }
112    }
113
114    pub fn stmts_mut(&mut self) -> &mut Vec<Stmt> {
115        match self {
116            Self::Block(stmts) => stmts,
117        }
118    }
119
120    pub fn tail_expr(&self) -> Option<&Expr> {
121        match self.stmts().last() {
122            Some(Stmt::Expr(expr)) => Some(expr),
123            _ => None,
124        }
125    }
126
127    pub fn tail_expr_mut(&mut self) -> Option<&mut Expr> {
128        match self.stmts_mut().last_mut() {
129            Some(Stmt::Expr(expr)) => Some(expr),
130            _ => None,
131        }
132    }
133}
134
135/// Compile-time resolution metadata for a function body.
136/// Produced by `resolver::resolve_fn` — maps local variable names to slot indices
137/// so the interpreter can use `Vec<Rc<Value>>` instead of `HashMap` lookups.
138#[derive(Debug, Clone, PartialEq)]
139pub struct FnResolution {
140    /// Total number of local slots needed (params + bindings in body).
141    pub local_count: u16,
142    /// Map from local variable name → slot index in the local `Slots` frame.
143    pub local_slots: std::collections::HashMap<String, u16>,
144}
145
146#[derive(Debug, Clone, PartialEq)]
147pub struct FnDef {
148    pub name: String,
149    pub line: usize,
150    pub params: Vec<(String, String)>,
151    pub return_type: String,
152    pub effects: Vec<String>,
153    pub desc: Option<String>,
154    pub body: std::rc::Rc<FnBody>,
155    /// `None` for unresolved (REPL, module sub-interpreters).
156    pub resolution: Option<FnResolution>,
157}
158
159#[derive(Debug, Clone, PartialEq)]
160pub struct Module {
161    pub name: String,
162    pub line: usize,
163    pub depends: Vec<String>,
164    pub exposes: Vec<String>,
165    pub exposes_line: Option<usize>,
166    pub intent: String,
167}
168
169#[derive(Debug, Clone, PartialEq)]
170pub enum VerifyGivenDomain {
171    /// Integer range domain in verify law: `1..50` (inclusive).
172    IntRange { start: i64, end: i64 },
173    /// Explicit domain values in verify law: `[v1, v2, ...]`.
174    Explicit(Vec<Expr>),
175}
176
177#[derive(Debug, Clone, PartialEq)]
178pub struct VerifyGiven {
179    pub name: String,
180    pub type_name: String,
181    pub domain: VerifyGivenDomain,
182}
183
184#[derive(Debug, Clone, PartialEq)]
185pub struct VerifyLaw {
186    pub name: String,
187    pub givens: Vec<VerifyGiven>,
188    /// Optional precondition for the law template, written as `when <bool-expr>`.
189    pub when: Option<Expr>,
190    /// Template assertion from source before given-domain expansion.
191    pub lhs: Expr,
192    pub rhs: Expr,
193    /// Per-sample substituted guards for `when`, aligned with `VerifyBlock.cases`.
194    pub sample_guards: Vec<Expr>,
195}
196
197#[derive(Debug, Clone, PartialEq)]
198pub enum VerifyKind {
199    Cases,
200    Law(Box<VerifyLaw>),
201}
202
203#[derive(Debug, Clone, PartialEq)]
204pub struct VerifyBlock {
205    pub fn_name: String,
206    pub line: usize,
207    pub cases: Vec<(Expr, Expr)>,
208    pub kind: VerifyKind,
209}
210
211#[derive(Debug, Clone, PartialEq)]
212pub struct DecisionBlock {
213    pub name: String,
214    pub line: usize,
215    pub date: String,
216    pub reason: String,
217    pub chosen: DecisionImpact,
218    pub rejected: Vec<DecisionImpact>,
219    pub impacts: Vec<DecisionImpact>,
220    pub author: Option<String>,
221}
222
223#[derive(Debug, Clone, PartialEq, Eq, Hash)]
224pub enum DecisionImpact {
225    Symbol(String),
226    Semantic(String),
227}
228
229impl DecisionImpact {
230    pub fn text(&self) -> &str {
231        match self {
232            DecisionImpact::Symbol(s) | DecisionImpact::Semantic(s) => s,
233        }
234    }
235
236    pub fn as_context_string(&self) -> String {
237        match self {
238            DecisionImpact::Symbol(s) => s.clone(),
239            DecisionImpact::Semantic(s) => format!("\"{}\"", s),
240        }
241    }
242}
243
244/// A variant in a sum type definition.
245/// e.g. `Circle(Float)` → `TypeVariant { name: "Circle", fields: ["Float"] }`
246#[derive(Debug, Clone, PartialEq)]
247pub struct TypeVariant {
248    pub name: String,
249    pub fields: Vec<String>, // type annotations (e.g. "Float", "String")
250}
251
252/// A user-defined type definition.
253#[derive(Debug, Clone, PartialEq)]
254pub enum TypeDef {
255    /// `type Shape` with variants Circle(Float), Rect(Float, Float), Point
256    Sum {
257        name: String,
258        variants: Vec<TypeVariant>,
259        line: usize,
260    },
261    /// `record User` with fields name: String, age: Int
262    Product {
263        name: String,
264        fields: Vec<(String, String)>,
265        line: usize,
266    },
267}
268
269#[derive(Debug, Clone, PartialEq)]
270pub enum TopLevel {
271    Module(Module),
272    FnDef(FnDef),
273    Verify(VerifyBlock),
274    Decision(DecisionBlock),
275    Stmt(Stmt),
276    TypeDef(TypeDef),
277    /// Legacy placeholder for removed `effects X = [...]` syntax.
278    EffectSet {
279        name: String,
280        effects: Vec<String>,
281        line: usize,
282    },
283}