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