use crate::ast::AstNode;
use crate::decision::Verdict;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[repr(u8)]
pub enum Paradigm {
Boolean = 0,
Modal = 1,
Epistemic = 2,
Deontic = 3,
Temporal = 4,
Fuzzy = 5,
Probabilistic = 6,
Paraconsistent = 7,
}
impl Paradigm {
pub const ALL: &'static [Paradigm] = &[
Paradigm::Boolean,
Paradigm::Modal,
Paradigm::Epistemic,
Paradigm::Deontic,
Paradigm::Temporal,
Paradigm::Fuzzy,
Paradigm::Probabilistic,
Paradigm::Paraconsistent,
];
pub fn name(self) -> &'static str {
match self {
Paradigm::Boolean => "boolean",
Paradigm::Modal => "modal",
Paradigm::Epistemic => "epistemic",
Paradigm::Deontic => "deontic",
Paradigm::Temporal => "temporal",
Paradigm::Fuzzy => "fuzzy",
Paradigm::Probabilistic => "probabilistic",
Paradigm::Paraconsistent => "paraconsistent",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EngineId(pub u8);
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EngineError {
UnsupportedNode,
MissingContext(&'static str),
MalformedExpression,
ContradictionDetected,
DepthLimitExceeded,
}
impl EngineError {
pub fn as_str(&self) -> &'static str {
match self {
EngineError::UnsupportedNode => "unsupported_node",
EngineError::MissingContext(_) => "missing_context",
EngineError::MalformedExpression => "malformed_expression",
EngineError::ContradictionDetected => "contradiction_detected",
EngineError::DepthLimitExceeded => "depth_limit_exceeded",
}
}
}
#[cfg(feature = "std")]
impl std::fmt::Display for EngineError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
EngineError::UnsupportedNode => write!(f, "UnsupportedNode"),
EngineError::MissingContext(key) => write!(f, "MissingContext({key})"),
EngineError::MalformedExpression => write!(f, "MalformedExpression"),
EngineError::ContradictionDetected => write!(f, "ContradictionDetected"),
EngineError::DepthLimitExceeded => write!(f, "DepthLimitExceeded"),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for EngineError {}
pub struct EvalContext<'a> {
pub slots: &'a [(&'static str, ContextValue)],
pub logical_time: u64,
pub depth_limit: u8,
}
impl<'a> EvalContext<'a> {
pub fn get(&self, key: &'static str) -> Option<&ContextValue> {
self.slots.iter().find(|(k, _)| *k == key).map(|(_, v)| v)
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum ContextValue {
Bool(bool),
Integer(i64),
Float(f64),
Str(&'static str),
#[cfg(feature = "alloc")]
OwnedStr(alloc::string::String),
}
impl ContextValue {
pub fn as_bool(&self) -> Option<bool> {
if let ContextValue::Bool(b) = self {
Some(*b)
} else {
None
}
}
pub fn as_i64(&self) -> Option<i64> {
if let ContextValue::Integer(n) = self {
Some(*n)
} else {
None
}
}
pub fn as_f64(&self) -> Option<f64> {
if let ContextValue::Float(f) = self {
Some(*f)
} else {
None
}
}
}
pub trait LogicEngine {
fn id(&self) -> EngineId;
fn paradigm(&self) -> Paradigm;
fn name(&self) -> &'static str;
fn can_handle(&self, node: &AstNode) -> bool;
fn evaluate(&self, node: &AstNode, ctx: &EvalContext<'_>) -> Result<Verdict, EngineError>;
}