1use serde::{Deserialize, Serialize};
4use std::collections::{BTreeMap, BTreeSet};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct Invariant {
9 pub name: String,
11
12 pub description: Option<String>,
14
15 pub expression: Expression,
17
18 pub severity: String,
20
21 pub category: String,
23
24 pub is_always_true: bool,
26
27 pub layers: Vec<String>,
30
31 pub phases: Vec<String>,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
38pub enum Expression {
39 Boolean(bool),
41
42 Var(String),
44
45 LayerVar {
47 layer: String,
49 var: String,
51 },
52
53 PhaseQualifiedVar {
56 phase: String,
58 layer: String,
60 var: String,
62 },
63
64 PhaseConstraint {
67 phase: String,
69 constraint: Box<Expression>,
71 },
72
73 CrossPhaseRelation {
77 phase1: String,
79 expr1: Box<Expression>,
81 phase2: String,
83 expr2: Box<Expression>,
85 op: BinaryOp,
87 },
88
89 Int(i128),
91
92 BinaryOp {
94 left: Box<Expression>,
96 op: BinaryOp,
98 right: Box<Expression>,
100 },
101
102 Logical {
104 left: Box<Expression>,
106 op: LogicalOp,
108 right: Box<Expression>,
110 },
111
112 Not(Box<Expression>),
114
115 FunctionCall {
117 name: String,
119 args: Vec<Expression>,
121 },
122
123 Tuple(Vec<Expression>),
125}
126
127impl std::fmt::Display for Expression {
128 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129 match self {
130 Self::Boolean(b) => write!(f, "{}", b),
131 Self::Var(v) => write!(f, "{}", v),
132 Self::LayerVar { layer, var } => write!(f, "{}::{}", layer, var),
133 Self::PhaseQualifiedVar { phase, layer, var } => {
134 write!(f, "{}::{}::{}", phase, layer, var)
135 }
136 Self::PhaseConstraint { phase, constraint } => {
137 write!(f, "({} @ {})", constraint, phase)
138 }
139 Self::CrossPhaseRelation {
140 phase1,
141 expr1,
142 phase2,
143 expr2,
144 op,
145 } => {
146 write!(f, "({}[{}] {} {}[{}])", expr1, phase1, op, expr2, phase2)
147 }
148 Self::Int(i) => write!(f, "{}", i),
149 Self::BinaryOp { left, op, right } => {
150 write!(f, "({} {} {})", left, op, right)
151 }
152 Self::Logical { left, op, right } => {
153 write!(f, "({} {} {})", left, op, right)
154 }
155 Self::Not(e) => write!(f, "!({})", e),
156 Self::FunctionCall { name, args } => {
157 write!(f, "{}(", name)?;
158 for (i, arg) in args.iter().enumerate() {
159 if i > 0 {
160 write!(f, ", ")?;
161 }
162 write!(f, "{}", arg)?;
163 }
164 write!(f, ")")
165 }
166 Self::Tuple(exprs) => {
167 write!(f, "(")?;
168 for (i, e) in exprs.iter().enumerate() {
169 if i > 0 {
170 write!(f, ", ")?;
171 }
172 write!(f, "{}", e)?;
173 }
174 write!(f, ")")
175 }
176 }
177 }
178}
179
180#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
182pub enum BinaryOp {
183 Eq,
185 Neq,
187 Lt,
189 Gt,
191 Lte,
193 Gte,
195}
196
197impl std::fmt::Display for BinaryOp {
198 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
199 match self {
200 Self::Eq => write!(f, "=="),
201 Self::Neq => write!(f, "!="),
202 Self::Lt => write!(f, "<"),
203 Self::Gt => write!(f, ">"),
204 Self::Lte => write!(f, "<="),
205 Self::Gte => write!(f, ">="),
206 }
207 }
208}
209
210#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
212pub enum LogicalOp {
213 And,
215 Or,
217}
218
219impl std::fmt::Display for LogicalOp {
220 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
221 match self {
222 Self::And => write!(f, "&&"),
223 Self::Or => write!(f, "||"),
224 }
225 }
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize)]
230pub struct StateVar {
231 pub name: String,
233
234 pub type_name: String,
236
237 pub is_mutable: bool,
239
240 pub visibility: Option<String>,
242}
243
244#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct FunctionModel {
247 pub name: String,
249
250 pub parameters: Vec<String>,
252
253 pub return_type: Option<String>,
255
256 pub mutates: BTreeSet<String>,
258
259 pub reads: BTreeSet<String>,
261
262 pub is_entry_point: bool,
264
265 pub is_pure: bool,
267}
268
269#[derive(Debug, Clone, Serialize, Deserialize)]
271pub struct ProgramModel {
272 pub name: String,
274
275 pub state_vars: BTreeMap<String, StateVar>,
277
278 pub functions: BTreeMap<String, FunctionModel>,
280
281 pub mutation_graph: BTreeMap<String, BTreeSet<String>>,
283
284 pub chain: String,
286
287 pub source_path: String,
289}
290
291impl ProgramModel {
292 pub fn new(name: String, chain: String, source_path: String) -> Self {
294 Self {
295 name,
296 chain,
297 source_path,
298 state_vars: BTreeMap::new(),
299 functions: BTreeMap::new(),
300 mutation_graph: BTreeMap::new(),
301 }
302 }
303
304 pub fn add_state_var(&mut self, var: StateVar) {
306 self.state_vars.insert(var.name.clone(), var);
307 }
308
309 pub fn add_function(&mut self, func: FunctionModel) {
311 self.mutation_graph
312 .insert(func.name.clone(), func.mutates.clone());
313 self.functions.insert(func.name.clone(), func);
314 }
315}
316
317#[derive(Debug, Clone, Serialize, Deserialize)]
319pub struct GenerationOutput {
320 pub code: String,
322
323 pub assertions: Vec<String>,
325
326 pub tests: Option<String>,
328
329 pub coverage_percent: u8,
331}
332
333#[derive(Debug, Clone, Serialize, Deserialize)]
335pub struct SimulationReport {
336 pub violations: usize,
338
339 pub traces: Vec<String>,
341
342 pub coverage: f64,
344
345 pub seed: u64,
347}