1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
6pub struct Spec {
7 pub name: String,
9 pub quantifiers: Vec<Quantifier>,
10 pub body: SpecExpr,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
15pub struct Quantifier {
16 pub name: String,
17 pub ty: SpecType,
18 #[serde(default, skip_serializing_if = "Option::is_none")]
21 pub constraint: Option<SpecExpr>,
22}
23
24#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
25#[serde(rename_all = "snake_case")]
26pub enum SpecType { Int, Float, Bool, Str }
27
28#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
29#[serde(tag = "node")]
30pub enum SpecExpr {
31 Var { name: String },
32 IntLit { value: i64 },
33 FloatLit { value: f64 },
34 BoolLit { value: bool },
35 StrLit { value: String },
36 Call { func: String, args: Vec<SpecExpr> },
38 Let { name: String, value: Box<SpecExpr>, body: Box<SpecExpr> },
39 BinOp { op: SpecOp, lhs: Box<SpecExpr>, rhs: Box<SpecExpr> },
40 Not { expr: Box<SpecExpr> },
41}
42
43#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
44#[serde(rename_all = "snake_case")]
45pub enum SpecOp {
46 Add, Sub, Mul, Div, Mod,
47 Eq, Neq, Lt, Le, Gt, Ge,
48 And, Or,
49}
50
51impl SpecOp {
52 pub fn as_str(self) -> &'static str {
53 use SpecOp::*;
54 match self {
55 Add => "+", Sub => "-", Mul => "*", Div => "/", Mod => "%",
56 Eq => "==", Neq => "!=", Lt => "<", Le => "<=", Gt => ">", Ge => ">=",
57 And => "and", Or => "or",
58 }
59 }
60 pub fn is_arith(self) -> bool {
61 use SpecOp::*; matches!(self, Add | Sub | Mul | Div | Mod)
62 }
63 pub fn is_compare(self) -> bool {
64 use SpecOp::*; matches!(self, Eq | Neq | Lt | Le | Gt | Ge)
65 }
66 pub fn is_bool(self) -> bool {
67 use SpecOp::*; matches!(self, And | Or)
68 }
69}