use syn::{Attribute, Expr, ItemFn};
#[derive(Debug, Clone)]
pub struct Contract {
pub contract_type: ContractType,
pub condition: Expr,
pub comment: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ContractType {
Requires,
Ensures,
Axiom,
}
pub fn extract_contracts(func: &ItemFn) -> Vec<Contract> {
let mut contracts = Vec::new();
for attr in &func.attrs {
if let Some(contract) = parse_contract_attribute(attr) {
contracts.push(contract);
}
}
contracts
}
fn parse_contract_attribute(attr: &Attribute) -> Option<Contract> {
let path = attr.path();
let is_requires = path.is_ident("requires")
|| (path.segments.len() == 2
&& path.segments[0].ident == "blvm_spec_lock"
&& path.segments[1].ident == "requires");
let is_ensures = path.is_ident("ensures")
|| (path.segments.len() == 2
&& path.segments[0].ident == "blvm_spec_lock"
&& path.segments[1].ident == "ensures");
let is_axiom = path.is_ident("axiom")
|| (path.segments.len() == 2
&& path.segments[0].ident == "blvm_spec_lock"
&& path.segments[1].ident == "axiom");
if is_requires {
if let Ok(expr) = attr.parse_args::<Expr>() {
return Some(Contract {
contract_type: ContractType::Requires,
condition: expr,
comment: extract_comment(attr),
});
}
} else if is_ensures {
if let Ok(expr) = attr.parse_args::<Expr>() {
return Some(Contract {
contract_type: ContractType::Ensures,
condition: expr,
comment: extract_comment(attr),
});
}
} else if is_axiom {
if let Ok(expr) = attr.parse_args::<Expr>() {
return Some(Contract {
contract_type: ContractType::Axiom,
condition: expr,
comment: extract_comment(attr),
});
}
}
None
}
fn extract_comment(_attr: &Attribute) -> Option<String> {
None
}