feat!(py): expose boolean semantics to Python
This commit is contained in:
parent
c42f892099
commit
e6ef427e2f
8 changed files with 221 additions and 40 deletions
|
|
@ -9,7 +9,7 @@ use pyo3::pyclass::CompareOp;
|
|||
/// expressions supported in Argus (literals, arithmetic, and so on).
|
||||
#[pyclass(name = "NumExpr", subclass, module = "argus")]
|
||||
#[derive(Debug, Clone, derive_more::From)]
|
||||
struct PyNumExpr(Box<NumExpr>);
|
||||
pub struct PyNumExpr(pub Box<NumExpr>);
|
||||
|
||||
#[pymethods]
|
||||
impl PyNumExpr {
|
||||
|
|
@ -55,7 +55,7 @@ impl PyNumExpr {
|
|||
|
||||
/// Create a constant integer expression
|
||||
#[pyclass(extends=PyNumExpr, module = "argus")]
|
||||
struct ConstInt;
|
||||
pub struct ConstInt;
|
||||
|
||||
#[pymethods]
|
||||
impl ConstInt {
|
||||
|
|
@ -72,7 +72,7 @@ impl ConstInt {
|
|||
/// Negating an unsigned integer during evaluation _may_ lead to the evaluation method
|
||||
/// panicking.
|
||||
#[pyclass(extends=PyNumExpr, module = "argus")]
|
||||
struct ConstUInt;
|
||||
pub struct ConstUInt;
|
||||
|
||||
#[pymethods]
|
||||
impl ConstUInt {
|
||||
|
|
@ -84,7 +84,7 @@ impl ConstUInt {
|
|||
|
||||
/// Create a constant floating point number expression.
|
||||
#[pyclass(extends=PyNumExpr, module = "argus")]
|
||||
struct ConstFloat;
|
||||
pub struct ConstFloat;
|
||||
|
||||
#[pymethods]
|
||||
impl ConstFloat {
|
||||
|
|
@ -96,7 +96,7 @@ impl ConstFloat {
|
|||
|
||||
/// Create a integer variable
|
||||
#[pyclass(extends=PyNumExpr, module = "argus")]
|
||||
struct VarInt;
|
||||
pub struct VarInt;
|
||||
|
||||
#[pymethods]
|
||||
impl VarInt {
|
||||
|
|
@ -108,7 +108,7 @@ impl VarInt {
|
|||
|
||||
/// Create an _unsigned_ integer variable
|
||||
#[pyclass(extends=PyNumExpr, module = "argus")]
|
||||
struct VarUInt;
|
||||
pub struct VarUInt;
|
||||
|
||||
#[pymethods]
|
||||
impl VarUInt {
|
||||
|
|
@ -120,7 +120,7 @@ impl VarUInt {
|
|||
|
||||
/// Create a float variable
|
||||
#[pyclass(extends=PyNumExpr, module = "argus")]
|
||||
struct VarFloat;
|
||||
pub struct VarFloat;
|
||||
|
||||
#[pymethods]
|
||||
impl VarFloat {
|
||||
|
|
@ -132,7 +132,7 @@ impl VarFloat {
|
|||
|
||||
/// Create a numeric negation expression
|
||||
#[pyclass(extends=PyNumExpr, module = "argus")]
|
||||
struct Negate;
|
||||
pub struct Negate;
|
||||
|
||||
#[pymethods]
|
||||
impl Negate {
|
||||
|
|
@ -147,7 +147,7 @@ impl Negate {
|
|||
///
|
||||
/// This expression is an `n`-ary expression that takes
|
||||
#[pyclass(extends=PyNumExpr, module = "argus")]
|
||||
struct Add;
|
||||
pub struct Add;
|
||||
|
||||
#[pymethods]
|
||||
impl Add {
|
||||
|
|
@ -159,7 +159,7 @@ impl Add {
|
|||
}
|
||||
|
||||
#[pyclass(extends=PyNumExpr, module = "argus")]
|
||||
struct Sub;
|
||||
pub struct Sub;
|
||||
|
||||
#[pymethods]
|
||||
impl Sub {
|
||||
|
|
@ -172,7 +172,7 @@ impl Sub {
|
|||
}
|
||||
|
||||
#[pyclass(extends=PyNumExpr, module = "argus")]
|
||||
struct Mul;
|
||||
pub struct Mul;
|
||||
|
||||
#[pymethods]
|
||||
impl Mul {
|
||||
|
|
@ -184,7 +184,7 @@ impl Mul {
|
|||
}
|
||||
|
||||
#[pyclass(extends=PyNumExpr, module = "argus")]
|
||||
struct Div;
|
||||
pub struct Div;
|
||||
|
||||
#[pymethods]
|
||||
impl Div {
|
||||
|
|
@ -197,7 +197,7 @@ impl Div {
|
|||
}
|
||||
|
||||
#[pyclass(extends=PyNumExpr, module = "argus")]
|
||||
struct Abs;
|
||||
pub struct Abs;
|
||||
|
||||
#[pymethods]
|
||||
impl Abs {
|
||||
|
|
@ -210,7 +210,7 @@ impl Abs {
|
|||
|
||||
#[pyclass(name = "BoolExpr", subclass, module = "argus")]
|
||||
#[derive(Debug, Clone, derive_more::From)]
|
||||
struct PyBoolExpr(Box<BoolExpr>);
|
||||
pub struct PyBoolExpr(pub Box<BoolExpr>);
|
||||
|
||||
#[pymethods]
|
||||
impl PyBoolExpr {
|
||||
|
|
@ -232,7 +232,7 @@ impl PyBoolExpr {
|
|||
}
|
||||
|
||||
#[pyclass(extends=PyBoolExpr, module = "argus")]
|
||||
struct ConstBool;
|
||||
pub struct ConstBool;
|
||||
|
||||
#[pymethods]
|
||||
impl ConstBool {
|
||||
|
|
@ -243,7 +243,7 @@ impl ConstBool {
|
|||
}
|
||||
|
||||
#[pyclass(extends=PyBoolExpr, module = "argus")]
|
||||
struct VarBool;
|
||||
pub struct VarBool;
|
||||
|
||||
#[pymethods]
|
||||
impl VarBool {
|
||||
|
|
@ -254,11 +254,11 @@ impl VarBool {
|
|||
}
|
||||
|
||||
#[pyclass(extends=PyBoolExpr, module = "argus")]
|
||||
struct Cmp;
|
||||
pub struct Cmp;
|
||||
|
||||
#[pyclass(module = "argus")]
|
||||
#[derive(Debug, Copy, Clone, derive_more::From)]
|
||||
struct PyOrdering(Ordering);
|
||||
pub struct PyOrdering(Ordering);
|
||||
|
||||
impl Cmp {
|
||||
fn new(op: PyOrdering, lhs: PyNumExpr, rhs: PyNumExpr) -> (Self, PyBoolExpr) {
|
||||
|
|
@ -303,7 +303,7 @@ impl Cmp {
|
|||
}
|
||||
|
||||
#[pyclass(extends=PyBoolExpr, module = "argus")]
|
||||
struct Not;
|
||||
pub struct Not;
|
||||
|
||||
#[pymethods]
|
||||
impl Not {
|
||||
|
|
@ -315,7 +315,7 @@ impl Not {
|
|||
}
|
||||
|
||||
#[pyclass(extends=PyBoolExpr, module = "argus")]
|
||||
struct And;
|
||||
pub struct And;
|
||||
|
||||
#[pymethods]
|
||||
impl And {
|
||||
|
|
@ -327,7 +327,7 @@ impl And {
|
|||
}
|
||||
|
||||
#[pyclass(extends=PyBoolExpr, module = "argus")]
|
||||
struct Or;
|
||||
pub struct Or;
|
||||
|
||||
#[pymethods]
|
||||
impl Or {
|
||||
|
|
@ -339,7 +339,7 @@ impl Or {
|
|||
}
|
||||
|
||||
#[pyclass(extends=PyBoolExpr, module = "argus")]
|
||||
struct Next;
|
||||
pub struct Next;
|
||||
|
||||
#[pymethods]
|
||||
impl Next {
|
||||
|
|
@ -351,7 +351,7 @@ impl Next {
|
|||
}
|
||||
|
||||
#[pyclass(extends=PyBoolExpr, module = "argus")]
|
||||
struct Always;
|
||||
pub struct Always;
|
||||
|
||||
#[pymethods]
|
||||
impl Always {
|
||||
|
|
@ -363,7 +363,7 @@ impl Always {
|
|||
}
|
||||
|
||||
#[pyclass(extends=PyBoolExpr, module = "argus")]
|
||||
struct Eventually;
|
||||
pub struct Eventually;
|
||||
|
||||
#[pymethods]
|
||||
impl Eventually {
|
||||
|
|
@ -375,7 +375,7 @@ impl Eventually {
|
|||
}
|
||||
|
||||
#[pyclass(extends=PyBoolExpr, module = "argus")]
|
||||
struct Until;
|
||||
pub struct Until;
|
||||
|
||||
#[pymethods]
|
||||
impl Until {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ impl From<PyArgusError> for PyErr {
|
|||
#[pymodule]
|
||||
#[pyo3(name = "_argus")]
|
||||
fn pyargus(py: Python, m: &PyModule) -> PyResult<()> {
|
||||
pyo3_log::init();
|
||||
|
||||
expr::init(py, m)?;
|
||||
signals::init(py, m)?;
|
||||
semantics::init(py, m)?;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,102 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use argus_core::signals::{AnySignal, Signal};
|
||||
use argus_semantics::{BooleanSemantics, Semantics, Trace};
|
||||
use pyo3::exceptions::PyTypeError;
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::{PyDict, PyString};
|
||||
|
||||
use crate::expr::PyBoolExpr;
|
||||
use crate::signals::{BoolSignal, FloatSignal, IntSignal, Kind, PySignal, UnsignedIntSignal};
|
||||
use crate::PyArgusError;
|
||||
|
||||
#[derive(Debug, Clone, derive_more::From, derive_more::TryInto)]
|
||||
#[try_into(owned, ref, ref_mut)]
|
||||
enum SignalKind {
|
||||
Bool(Signal<bool>),
|
||||
Int(Signal<i64>),
|
||||
UnsignedInt(Signal<u64>),
|
||||
Float(Signal<f64>),
|
||||
}
|
||||
|
||||
#[pyclass(name = "Trace", module = "argus")]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct PyTrace {
|
||||
signals: HashMap<String, SignalKind>,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl PyTrace {
|
||||
#[new]
|
||||
fn new(dict: &PyDict) -> PyResult<Self> {
|
||||
let mut signals = HashMap::with_capacity(dict.len());
|
||||
for (key, val) in dict {
|
||||
let key: &PyString = key
|
||||
.downcast()
|
||||
.map_err(|e| PyTypeError::new_err(format!("expected dictionary with string keys for trace ({})", e)))?;
|
||||
let val: &PyCell<PySignal> = val.downcast().map_err(|e| {
|
||||
PyTypeError::new_err(format!(
|
||||
"expected `argus.Signal` value for key `{}` in trace ({})",
|
||||
key, e
|
||||
))
|
||||
})?;
|
||||
let kind = val.borrow().kind;
|
||||
let signal: SignalKind = match kind {
|
||||
Kind::Bool => val.downcast::<PyCell<BoolSignal>>().unwrap().borrow().0.clone().into(),
|
||||
Kind::Int => val.downcast::<PyCell<IntSignal>>().unwrap().borrow().0.clone().into(),
|
||||
Kind::UnsignedInt => val
|
||||
.downcast::<PyCell<UnsignedIntSignal>>()
|
||||
.unwrap()
|
||||
.borrow()
|
||||
.0
|
||||
.clone()
|
||||
.into(),
|
||||
Kind::Float => val.downcast::<PyCell<FloatSignal>>().unwrap().borrow().0.clone().into(),
|
||||
};
|
||||
|
||||
signals.insert(key.to_string(), signal);
|
||||
}
|
||||
|
||||
Ok(Self { signals })
|
||||
}
|
||||
|
||||
fn __repr__(&self) -> String {
|
||||
format!("{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl Trace for PyTrace {
|
||||
fn signal_names(&self) -> Vec<&str> {
|
||||
self.signals.keys().map(|key| key.as_str()).collect()
|
||||
}
|
||||
|
||||
fn get<T: 'static>(&self, name: &str) -> Option<&Signal<T>> {
|
||||
let kind = self.signals.get(name)?;
|
||||
let signal: &dyn AnySignal = match kind {
|
||||
SignalKind::Bool(sig) => sig,
|
||||
SignalKind::Int(sig) => sig,
|
||||
SignalKind::UnsignedInt(sig) => sig,
|
||||
SignalKind::Float(sig) => sig,
|
||||
};
|
||||
signal.as_any().downcast_ref::<Signal<T>>()
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(name = "BooleanSemantics")]
|
||||
struct PyBooleanSemantics;
|
||||
|
||||
#[pymethods]
|
||||
impl PyBooleanSemantics {
|
||||
#[staticmethod]
|
||||
fn eval(expr: &PyBoolExpr, trace: &PyTrace) -> PyResult<Py<BoolSignal>> {
|
||||
let sig = BooleanSemantics::eval(&expr.0, trace, ()).map_err(PyArgusError::from)?;
|
||||
Python::with_gil(|py| Py::new(py, (BoolSignal::from(sig), BoolSignal::super_type())))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(_py: Python, m: &PyModule) -> PyResult<()> {
|
||||
m.add_class::<PyBooleanSemantics>()?;
|
||||
m.add_class::<PyTrace>()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,32 +6,33 @@ use pyo3::prelude::*;
|
|||
use crate::PyArgusError;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum SignalKind {
|
||||
pub enum Kind {
|
||||
Bool,
|
||||
Int,
|
||||
UnsignedInt,
|
||||
Float,
|
||||
}
|
||||
|
||||
#[pyclass(name = "Signal", subclass)]
|
||||
#[pyclass(name = "Signal", subclass, module = "argus")]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PySignal {
|
||||
pub kind: SignalKind,
|
||||
pub kind: Kind,
|
||||
pub interpolation: InterpolationMethod,
|
||||
}
|
||||
|
||||
macro_rules! impl_signals {
|
||||
($ty_name:ident, $ty:ty) => {
|
||||
paste::paste! {
|
||||
#[pyclass(extends=PySignal)]
|
||||
pub struct [<$ty_name Signal>](Signal<$ty>);
|
||||
#[pyclass(extends=PySignal, module = "argus")]
|
||||
#[derive(Debug, Clone, derive_more::From)]
|
||||
pub struct [<$ty_name Signal>](pub Signal<$ty>);
|
||||
|
||||
impl [<$ty_name Signal>] {
|
||||
#[inline]
|
||||
fn super_type() -> PySignal {
|
||||
pub fn super_type() -> PySignal {
|
||||
PySignal {
|
||||
interpolation: InterpolationMethod::Linear,
|
||||
kind: SignalKind::$ty_name,
|
||||
kind: Kind::$ty_name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -72,13 +73,7 @@ macro_rules! impl_signals {
|
|||
Python::with_gil(|py| {
|
||||
Py::new(
|
||||
py,
|
||||
(
|
||||
Self(ret),
|
||||
PySignal {
|
||||
interpolation: InterpolationMethod::Linear,
|
||||
kind: SignalKind::$ty_name,
|
||||
},
|
||||
),
|
||||
(Self(ret), Self::super_type())
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue