Skip to main content

intent_ir/
types.rs

1//! Core IR type definitions for IntentLang.
2//!
3//! The IR is a typed, formally verifiable representation generated from
4//! intent specs. Every IR node carries a `SourceTrace` linking it back
5//! to the originating spec element (for Phase 3 Audit Bridge).
6
7use intent_parser::ast::Span;
8use serde::{Deserialize, Serialize};
9
10// ── Source tracing ──────────────────────────────────────────
11
12/// Links an IR node back to its originating spec element.
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct SourceTrace {
15    /// Module name from the intent file.
16    pub module: String,
17    /// Which spec item produced this IR node (e.g., "Transfer", "NoNegativeBalances").
18    pub item: String,
19    /// Which part of the spec item (e.g., "requires", "ensures", "field:balance").
20    pub part: String,
21    /// Byte span in the original source.
22    pub span: Span,
23}
24
25// ── Module ──────────────────────────────────────────────────
26
27/// A compiled IR module — the output of lowering a single `.intent` file.
28#[derive(Debug, Clone, Serialize)]
29pub struct Module {
30    pub name: String,
31    pub structs: Vec<Struct>,
32    pub functions: Vec<Function>,
33    pub invariants: Vec<Invariant>,
34    pub edge_guards: Vec<EdgeGuard>,
35}
36
37// ── Types ───────────────────────────────────────────────────
38
39/// An IR type — resolved from the intent language's type expressions.
40#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
41pub enum IrType {
42    /// Named primitive or domain type (UUID, String, Int, Bool, etc.)
43    Named(String),
44    /// Reference to a struct defined in this module.
45    Struct(String),
46    /// `List<T>`
47    List(Box<IrType>),
48    /// `Set<T>`
49    Set(Box<IrType>),
50    /// `Map<K, V>`
51    Map(Box<IrType>, Box<IrType>),
52    /// Optional wrapper: `T?`
53    Optional(Box<IrType>),
54    /// Union of variants (enum-like): `Active | Frozen | Closed`
55    Union(Vec<String>),
56    /// Decimal with precision: `Decimal(2)`
57    Decimal(u32),
58}
59
60// ── Struct (from entity) ────────────────────────────────────
61
62/// A struct type — lowered from an `entity` declaration.
63#[derive(Debug, Clone, Serialize)]
64pub struct Struct {
65    pub name: String,
66    pub fields: Vec<Field>,
67    pub trace: SourceTrace,
68}
69
70/// A typed field within a struct.
71#[derive(Debug, Clone, Serialize)]
72pub struct Field {
73    pub name: String,
74    pub ty: IrType,
75    pub trace: SourceTrace,
76}
77
78// ── Function (from action) ──────────────────────────────────
79
80/// A function — lowered from an `action` declaration.
81/// Contains typed parameters, pre/postconditions, and effect/property annotations.
82#[derive(Debug, Clone, Serialize)]
83pub struct Function {
84    pub name: String,
85    pub params: Vec<Param>,
86    pub preconditions: Vec<Condition>,
87    pub postconditions: Vec<Postcondition>,
88    pub properties: Vec<Property>,
89    pub trace: SourceTrace,
90}
91
92/// A typed function parameter.
93#[derive(Debug, Clone, Serialize)]
94pub struct Param {
95    pub name: String,
96    pub ty: IrType,
97    pub trace: SourceTrace,
98}
99
100/// A precondition (from `requires`).
101#[derive(Debug, Clone, Serialize)]
102pub struct Condition {
103    pub expr: IrExpr,
104    pub trace: SourceTrace,
105}
106
107/// A postcondition (from `ensures`) — may be unconditional or guarded by `when`.
108#[derive(Debug, Clone, Serialize)]
109pub enum Postcondition {
110    /// Always holds after execution.
111    Always { expr: IrExpr, trace: SourceTrace },
112    /// Holds only when `guard` is true.
113    When {
114        guard: IrExpr,
115        expr: IrExpr,
116        trace: SourceTrace,
117    },
118}
119
120/// A declarative property annotation (idempotent, atomic, etc.)
121#[derive(Debug, Clone, Serialize)]
122pub struct Property {
123    pub key: String,
124    pub value: PropertyValue,
125    pub trace: SourceTrace,
126}
127
128/// Property value — mirrors the AST's PropValue but in IR form.
129#[derive(Debug, Clone, Serialize)]
130pub enum PropertyValue {
131    Bool(bool),
132    Int(i64),
133    String(String),
134    Ident(String),
135}
136
137// ── Invariant ───────────────────────────────────────────────
138
139/// A module-level invariant — a proof obligation that must always hold.
140#[derive(Debug, Clone, Serialize)]
141pub struct Invariant {
142    pub name: String,
143    pub expr: IrExpr,
144    pub trace: SourceTrace,
145}
146
147// ── Edge guards ─────────────────────────────────────────────
148
149/// An edge-case guard — lowered from `edge_cases { when cond => action }`.
150#[derive(Debug, Clone, Serialize)]
151pub struct EdgeGuard {
152    pub condition: IrExpr,
153    pub action: String,
154    pub args: Vec<(String, IrExpr)>,
155    pub trace: SourceTrace,
156}
157
158// ── IR Expressions ──────────────────────────────────────────
159
160/// An IR expression — a simplified, typed expression tree.
161#[derive(Debug, Clone, Serialize)]
162pub enum IrExpr {
163    /// Variable reference (parameter name or quantifier binding).
164    Var(String),
165    /// Literal value.
166    Literal(IrLiteral),
167    /// Field access: `obj.field`
168    FieldAccess { root: Box<IrExpr>, field: String },
169    /// Binary comparison.
170    Compare {
171        left: Box<IrExpr>,
172        op: CmpOp,
173        right: Box<IrExpr>,
174    },
175    /// Arithmetic operation.
176    Arithmetic {
177        left: Box<IrExpr>,
178        op: ArithOp,
179        right: Box<IrExpr>,
180    },
181    /// Logical AND.
182    And(Box<IrExpr>, Box<IrExpr>),
183    /// Logical OR.
184    Or(Box<IrExpr>, Box<IrExpr>),
185    /// Logical NOT.
186    Not(Box<IrExpr>),
187    /// Logical implication: `a => b` ≡ `!a || b`.
188    Implies(Box<IrExpr>, Box<IrExpr>),
189    /// Pre-state reference: `old(expr)`.
190    Old(Box<IrExpr>),
191    /// Universal quantifier: `forall x: T => body`.
192    Forall {
193        binding: String,
194        ty: String,
195        body: Box<IrExpr>,
196    },
197    /// Existential quantifier: `exists x: T => body`.
198    Exists {
199        binding: String,
200        ty: String,
201        body: Box<IrExpr>,
202    },
203    /// Function call.
204    Call { name: String, args: Vec<IrExpr> },
205    /// List literal: `[a, b, c]`.
206    List(Vec<IrExpr>),
207}
208
209/// Comparison operators (shared with AST but owned by IR).
210#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
211pub enum CmpOp {
212    Eq,
213    Ne,
214    Lt,
215    Gt,
216    Le,
217    Ge,
218}
219
220/// Arithmetic operators.
221#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
222pub enum ArithOp {
223    Add,
224    Sub,
225}
226
227/// IR literal values.
228#[derive(Debug, Clone, PartialEq, Serialize)]
229pub enum IrLiteral {
230    Null,
231    Bool(bool),
232    Int(i64),
233    Decimal(String),
234    String(String),
235}