pub mod utils;
#[derive(Clone, Debug)]
pub struct DTMCAst {
pub modules: Vec<Module>,
pub constants: Vec<(String, ConstDecl)>,
pub renamed_modules: Vec<RenamedModule>,
pub labels: Vec<LabelDecl>,
pub properties: Vec<Property>,
}
#[derive(Clone, Debug)]
pub struct LabelDecl {
pub name: String,
pub expr: Box<Expr>,
}
#[derive(Clone, Debug)]
pub struct ConstDecl {
pub const_type: ConstType,
pub value: Option<Box<Expr>>,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ConstType {
Bool,
Int,
Float,
}
#[derive(Clone, Debug)]
pub struct Module {
pub name: String,
pub local_vars: Vec<VarDecl>,
pub commands: Vec<Command>,
}
#[derive(Clone, Debug)]
pub struct VarDecl {
pub name: String,
pub var_type: VarType,
pub init: Box<Expr>,
}
#[derive(Clone, Debug)]
pub enum VarType {
BoundedInt { lo: Box<Expr>, hi: Box<Expr> },
Bool,
}
#[derive(Clone, Debug)]
pub struct Command {
pub labels: Vec<String>,
pub guard: Box<Expr>,
pub updates: Vec<ProbUpdate>,
}
#[derive(Clone, Debug)]
pub struct ProbUpdate {
pub prob: Box<Expr>,
pub assignments: Vec<Box<Expr>>,
}
#[derive(Clone, Debug)]
pub enum Expr {
BoolLit(bool),
IntLit(i32),
FloatLit(f64),
Ident(String),
PrimedIdent(String),
LabelRef(String),
UnaryOp {
op: UnOp,
operand: Box<Expr>,
},
BinOp {
lhs: Box<Expr>,
op: BinOp,
rhs: Box<Expr>,
},
Ternary {
cond: Box<Expr>,
then_branch: Box<Expr>,
else_branch: Box<Expr>,
},
}
#[derive(Clone, Debug)]
pub enum UnOp {
Not,
Neg,
}
#[derive(Clone, Debug)]
pub enum BinOp {
And,
Or,
Eq,
Neq,
Lt,
Leq,
Gt,
Geq,
Plus,
Minus,
Mul,
Div,
}
#[derive(Clone, Debug)]
pub struct RenamedModule {
pub name: String,
pub base: String,
pub renames: Vec<(String, String)>,
}
#[derive(Clone, Debug)]
pub enum Property {
ProbQuery(PathFormula),
RewardQuery(PathFormula),
}
#[derive(Clone, Debug)]
pub enum PathFormula {
Next(Box<Expr>),
Until {
lhs: Box<Expr>,
rhs: Box<Expr>,
bound: Option<Box<Expr>>,
},
}
impl std::fmt::Display for UnOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
UnOp::Not => write!(f, "!"),
UnOp::Neg => write!(f, "-"),
}
}
}
impl std::fmt::Display for BinOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
BinOp::And => "&",
BinOp::Or => "|",
BinOp::Eq => "=",
BinOp::Neq => "!=",
BinOp::Lt => "<",
BinOp::Leq => "<=",
BinOp::Gt => ">",
BinOp::Geq => ">=",
BinOp::Plus => "+",
BinOp::Minus => "-",
BinOp::Mul => "*",
BinOp::Div => "/",
};
write!(f, "{s}")
}
}
impl std::fmt::Display for Expr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expr::BoolLit(v) => write!(f, "{v}"),
Expr::IntLit(v) => write!(f, "{v}"),
Expr::FloatLit(v) => write!(f, "{v}"),
Expr::Ident(name) => write!(f, "{name}"),
Expr::PrimedIdent(name) => write!(f, "{name}'"),
Expr::LabelRef(name) => write!(f, "\"{name}\""),
Expr::UnaryOp { op, operand } => write!(f, "{}({})", op, operand),
Expr::BinOp { lhs, op, rhs } => write!(f, "({} {} {})", lhs, op, rhs),
Expr::Ternary {
cond,
then_branch,
else_branch,
} => write!(f, "({} ? {} : {})", cond, then_branch, else_branch),
}
}
}
impl std::fmt::Display for PathFormula {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PathFormula::Next(phi) => write!(f, "X {}", phi),
PathFormula::Until { lhs, rhs, bound } => {
if matches!(lhs.as_ref(), Expr::BoolLit(true)) && bound.is_none() {
write!(f, "F {}", rhs)
} else if matches!(lhs.as_ref(), Expr::BoolLit(true)) {
write!(f, "F<={} {}", bound.as_ref().expect("bounded case"), rhs)
} else if let Some(k) = bound {
write!(f, "{} U<={} {}", lhs, k, rhs)
} else {
write!(f, "{} U {}", lhs, rhs)
}
}
}
}
}
impl std::fmt::Display for Property {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Property::ProbQuery(path) => write!(f, "P=? [{}]", path),
Property::RewardQuery(path) => write!(f, "R=? [{}]", path),
}
}
}