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<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::rc::Rc<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_opaque: Vec<String>,
166    pub exposes_line: Option<usize>,
167    pub intent: String,
168}
169
170#[derive(Debug, Clone, PartialEq)]
171pub enum VerifyGivenDomain {
172    /// Integer range domain in verify law: `1..50` (inclusive).
173    IntRange { start: i64, end: i64 },
174    /// Explicit domain values in verify law: `[v1, v2, ...]`.
175    Explicit(Vec<Expr>),
176}
177
178#[derive(Debug, Clone, PartialEq)]
179pub struct VerifyGiven {
180    pub name: String,
181    pub type_name: String,
182    pub domain: VerifyGivenDomain,
183}
184
185#[derive(Debug, Clone, PartialEq)]
186pub struct VerifyLaw {
187    pub name: String,
188    pub givens: Vec<VerifyGiven>,
189    /// Optional precondition for the law template, written as `when <bool-expr>`.
190    pub when: Option<Expr>,
191    /// Template assertion from source before given-domain expansion.
192    pub lhs: Expr,
193    pub rhs: Expr,
194    /// Per-sample substituted guards for `when`, aligned with `VerifyBlock.cases`.
195    pub sample_guards: Vec<Expr>,
196}
197
198#[derive(Debug, Clone, PartialEq)]
199pub enum VerifyKind {
200    Cases,
201    Law(Box<VerifyLaw>),
202}
203
204#[derive(Debug, Clone, PartialEq)]
205pub struct VerifyBlock {
206    pub fn_name: String,
207    pub line: usize,
208    pub cases: Vec<(Expr, Expr)>,
209    pub kind: VerifyKind,
210}
211
212#[derive(Debug, Clone, PartialEq)]
213pub struct DecisionBlock {
214    pub name: String,
215    pub line: usize,
216    pub date: String,
217    pub reason: String,
218    pub chosen: DecisionImpact,
219    pub rejected: Vec<DecisionImpact>,
220    pub impacts: Vec<DecisionImpact>,
221    pub author: Option<String>,
222}
223
224#[derive(Debug, Clone, PartialEq, Eq, Hash)]
225pub enum DecisionImpact {
226    Symbol(String),
227    Semantic(String),
228}
229
230impl DecisionImpact {
231    pub fn text(&self) -> &str {
232        match self {
233            DecisionImpact::Symbol(s) | DecisionImpact::Semantic(s) => s,
234        }
235    }
236
237    pub fn as_context_string(&self) -> String {
238        match self {
239            DecisionImpact::Symbol(s) => s.clone(),
240            DecisionImpact::Semantic(s) => format!("\"{}\"", s),
241        }
242    }
243}
244
245/// A variant in a sum type definition.
246/// e.g. `Circle(Float)` → `TypeVariant { name: "Circle", fields: ["Float"] }`
247#[derive(Debug, Clone, PartialEq)]
248pub struct TypeVariant {
249    pub name: String,
250    pub fields: Vec<String>, // type annotations (e.g. "Float", "String")
251}
252
253/// A user-defined type definition.
254#[derive(Debug, Clone, PartialEq)]
255pub enum TypeDef {
256    /// `type Shape` with variants Circle(Float), Rect(Float, Float), Point
257    Sum {
258        name: String,
259        variants: Vec<TypeVariant>,
260        line: usize,
261    },
262    /// `record User` with fields name: String, age: Int
263    Product {
264        name: String,
265        fields: Vec<(String, String)>,
266        line: usize,
267    },
268}
269
270#[derive(Debug, Clone, PartialEq)]
271pub enum TopLevel {
272    Module(Module),
273    FnDef(FnDef),
274    Verify(VerifyBlock),
275    Decision(DecisionBlock),
276    Stmt(Stmt),
277    TypeDef(TypeDef),
278    /// Legacy placeholder for removed `effects X = [...]` syntax.
279    EffectSet {
280        name: String,
281        effects: Vec<String>,
282        line: usize,
283    },
284}