diff --git a/Cargo.lock b/Cargo.lock
index 96bd64d..89ec3f0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -27,6 +27,12 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+[[package]]
+name = "bitflags"
+version = "2.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
+
[[package]]
name = "byteorder"
version = "1.5.0"
@@ -66,6 +72,38 @@ dependencies = [
"thiserror",
]
+[[package]]
+name = "clarirs_py"
+version = "0.1.0"
+dependencies = [
+ "clarirs_core",
+ "dashmap",
+ "log",
+ "num-bigint",
+ "pyo3",
+ "thiserror",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+
+[[package]]
+name = "dashmap"
+version = "6.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+ "hashbrown 0.14.5",
+ "lock_api",
+ "once_cell",
+ "parking_lot_core",
+]
+
[[package]]
name = "equivalent"
version = "1.0.1"
@@ -89,12 +127,24 @@ dependencies = [
"wasi",
]
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+
[[package]]
name = "hashbrown"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
[[package]]
name = "indexmap"
version = "2.6.0"
@@ -102,15 +152,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
dependencies = [
"equivalent",
- "hashbrown",
+ "hashbrown 0.15.0",
]
+[[package]]
+name = "indoc"
+version = "2.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5"
+
[[package]]
name = "libc"
version = "0.2.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
+[[package]]
+name = "lock_api"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+
+[[package]]
+name = "memoffset"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+dependencies = [
+ "autocfg",
+]
+
[[package]]
name = "num-bigint"
version = "0.4.6"
@@ -146,6 +227,19 @@ version = "1.20.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
+[[package]]
+name = "parking_lot_core"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets",
+]
+
[[package]]
name = "paste"
version = "1.0.15"
@@ -162,6 +256,12 @@ dependencies = [
"indexmap",
]
+[[package]]
+name = "portable-atomic"
+version = "1.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2"
+
[[package]]
name = "ppv-lite86"
version = "0.2.20"
@@ -180,6 +280,70 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "pyo3"
+version = "0.22.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d922163ba1f79c04bc49073ba7b32fd5a8d3b76a87c955921234b8e77333c51"
+dependencies = [
+ "cfg-if",
+ "indoc",
+ "libc",
+ "memoffset",
+ "num-bigint",
+ "once_cell",
+ "portable-atomic",
+ "pyo3-build-config",
+ "pyo3-ffi",
+ "pyo3-macros",
+ "unindent",
+]
+
+[[package]]
+name = "pyo3-build-config"
+version = "0.22.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc38c5feeb496c8321091edf3d63e9a6829eab4b863b4a6a65f26f3e9cc6b179"
+dependencies = [
+ "once_cell",
+ "target-lexicon",
+]
+
+[[package]]
+name = "pyo3-ffi"
+version = "0.22.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94845622d88ae274d2729fcefc850e63d7a3ddff5e3ce11bd88486db9f1d357d"
+dependencies = [
+ "libc",
+ "pyo3-build-config",
+]
+
+[[package]]
+name = "pyo3-macros"
+version = "0.22.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e655aad15e09b94ffdb3ce3d217acf652e26bbc37697ef012f5e5e348c716e5e"
+dependencies = [
+ "proc-macro2",
+ "pyo3-macros-backend",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pyo3-macros-backend"
+version = "0.22.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae1e3f09eecd94618f60a455a23def79f79eba4dc561a97324bf9ac8c6df30ce"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "pyo3-build-config",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "quote"
version = "1.0.37"
@@ -219,6 +383,21 @@ dependencies = [
"getrandom",
]
+[[package]]
+name = "redox_syscall"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
[[package]]
name = "serde"
version = "1.0.209"
@@ -259,6 +438,12 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "target-lexicon"
+version = "0.12.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
+
[[package]]
name = "thiserror"
version = "1.0.63"
@@ -285,6 +470,12 @@ version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+[[package]]
+name = "unindent"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7de7d73e1754487cb58364ee906a499937a0dfabd86bcb980fa99ec8c8fa2ce"
+
[[package]]
name = "version_check"
version = "0.9.5"
@@ -297,6 +488,70 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
[[package]]
name = "zerocopy"
version = "0.7.35"
diff --git a/Cargo.toml b/Cargo.toml
index 60a7fad..b9234d4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -2,6 +2,7 @@
members = [
"crates/clarirs_num",
"crates/clarirs_core",
+ "crates/clarirs_py",
]
resolver = "2"
@@ -14,4 +15,4 @@ repository = "https://github.com/twizmwazin/clarirs.git"
[workspace.lints.clippy]
all = "warn"
-cargo = "deny"
+cargo = "warn"
diff --git a/crates/claripy/src/ast/base.rs b/crates/claripy/src/ast/base.rs
deleted file mode 100644
index f3ff9b9..0000000
--- a/crates/claripy/src/ast/base.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-use crate::prelude::*;
-
-#[pyclass(subclass, frozen, weakref, module = "claripy.ast.base")]
-#[derive(Clone)]
-pub struct Base {
- pub ast: AstRef<'static>,
-}
-
-#[pymethods]
-impl Base {}
-
-impl Base {
- pub fn new(ast: &AstRef<'static>) -> Self {
- Base { ast: ast.clone() }
- }
-}
-
-impl From for AstRef<'static> {
- fn from(base: Base) -> Self {
- base.ast
- }
-}
-
-impl PyAst for Base {
- fn new_from_astref(ast_ref: &AstRef<'static>) -> PyClassInitializer {
- PyClassInitializer::from(Base::new(ast_ref))
- }
-
- fn as_base(self_: PyRef) -> PyRef {
- self_
- }
-}
-
-pub(crate) fn import(_: Python, m: &Bound) -> PyResult<()> {
- m.add_class::()?;
- Ok(())
-}
diff --git a/crates/claripy/src/ast/bits.rs b/crates/claripy/src/ast/bits.rs
deleted file mode 100644
index ff3ec82..0000000
--- a/crates/claripy/src/ast/bits.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-use crate::prelude::*;
-
-#[pyclass(extends=Base, subclass, frozen, weakref, module="claripy.ast.bits")]
-#[derive(Default)]
-pub struct Bits;
-
-impl Bits {
- pub fn new() -> Self {
- Bits {}
- }
-}
-
-impl PyAst for Bits {
- fn new_from_astref(ast_ref: &AstRef<'static>) -> PyClassInitializer {
- Base::new_from_astref(ast_ref).add_subclass(Bits::new())
- }
-
- fn as_base(self_: PyRef) -> PyRef {
- self_.into_super()
- }
-}
-
-pub(crate) fn import(_: Python, m: &Bound) -> PyResult<()> {
- m.add_class::()?;
- Ok(())
-}
diff --git a/crates/claripy/src/ast/bool.rs b/crates/claripy/src/ast/bool.rs
deleted file mode 100644
index 8aceed1..0000000
--- a/crates/claripy/src/ast/bool.rs
+++ /dev/null
@@ -1,65 +0,0 @@
-#![allow(non_snake_case)]
-
-use pyo3::prelude::*;
-
-use crate::prelude::*;
-use crate::{ast::py_factory::GLOBAL_CONTEXT, error::ClaripyError};
-
-use super::shared_ops;
-use super::{base::Base, py_factory::py_ast_from_astref, PyAst};
-
-#[pyclass(extends=Base, subclass, frozen, weakref, module="claripy.ast.bool")]
-pub struct Bool;
-
-#[pymethods]
-impl Bool {
- fn is_true(self_: PyRef) -> bool {
- self_.as_super().ast.is_true()
- }
-
- fn is_false(self_: PyRef) -> bool {
- self_.as_super().ast.is_false()
- }
-}
-
-impl PyAst for Bool {
- fn new_from_astref(ast_ref: &AstRef<'static>) -> PyClassInitializer {
- Base::new_from_astref(ast_ref).add_subclass(Bool {})
- }
-
- fn as_base(self_: PyRef) -> PyRef {
- self_.into_super()
- }
-}
-
-pyop!(BoolS, bools, Bool, name: String);
-pyop!(BoolV, boolv, Bool, value: bool);
-
-#[pyfunction(name = "true")]
-pub fn true_op(py: Python) -> Result, ClaripyError> {
- py_ast_from_astref(py, GLOBAL_CONTEXT.true_()?)
-}
-#[pyfunction(name = "false")]
-pub fn false_op(py: Python) -> Result, ClaripyError> {
- py_ast_from_astref(py, GLOBAL_CONTEXT.false_()?)
-}
-
-pub(crate) fn import(_: Python, m: &Bound) -> PyResult<()> {
- m.add_class::()?;
-
- add_pyfunctions!(
- m,
- BoolS,
- BoolV,
- shared_ops::Not,
- shared_ops::And,
- shared_ops::Or,
- shared_ops::Xor,
- shared_ops::Eq_,
- shared_ops::If,
- true_op,
- false_op,
- );
-
- Ok(())
-}
diff --git a/crates/claripy/src/ast/bv.rs b/crates/claripy/src/ast/bv.rs
deleted file mode 100644
index 35617b6..0000000
--- a/crates/claripy/src/ast/bv.rs
+++ /dev/null
@@ -1,137 +0,0 @@
-#![allow(non_snake_case)]
-
-use num_bigint::BigUint;
-use pyo3::exceptions::{PyTypeError, PyValueError};
-
-use super::shared_ops;
-use super::{bits::Bits, bool::Bool};
-use crate::prelude::*;
-
-#[pyclass(extends=Bits, subclass, frozen, weakref, module="claripy.ast.bv")]
-pub struct BV;
-
-impl PyAst for BV {
- fn new_from_astref(ast_ref: &AstRef<'static>) -> PyClassInitializer {
- Bits::new_from_astref(ast_ref).add_subclass(BV {})
- }
-
- fn as_base(self_: PyRef) -> PyRef {
- self_.into_super().into_super()
- }
-}
-
-#[pymethods]
-impl BV {}
-
-pyop!(BVS, bvs, BV, name: String, size: u32);
-
-#[allow(non_snake_case)]
-#[pyfunction(signature = (value, size = None))]
-pub fn BVV(py: Python, value: Bound, size: Option) -> Result, PyErr> {
- if let Ok(int_val) = value.extract::() {
- if let Some(size) = size {
- return Ok(py_ast_from_astref(
- py,
- GLOBAL_CONTEXT
- .bvv_from_biguint_with_size(&int_val, size)
- .map_err(ClaripyError::from)?,
- )?);
- } else {
- return Err(PyErr::new::("size must be specified"));
- }
- }
- // TODO: deduplicate bytes/str
- if let Ok(bytes_val) = value.extract::>() {
- let int_val = BigUint::from_bytes_le(&bytes_val);
- log::warn!("bytes value passed to BVV, assuming little-endian");
- if size.is_some() {
- log::warn!("BVV size specified with bytes, value will be ignored");
- }
- return Ok(py_ast_from_astref(
- py,
- GLOBAL_CONTEXT
- .bvv_from_biguint_with_size(&int_val, bytes_val.len() as u32 * 8)
- .map_err(ClaripyError::from)?,
- )?);
- }
- if let Ok(str_val) = value.extract::() {
- log::warn!("string value passed to BVV, assuming utf-8");
- let bytes_val = str_val.as_bytes();
- let int_val = BigUint::from_bytes_le(bytes_val);
- log::warn!("bytes value passed to BVV, assuming little-endian");
- if size.is_some() {
- log::warn!("BVV size specified with bytes, value will be ignored");
- }
- return Ok(py_ast_from_astref(
- py,
- GLOBAL_CONTEXT
- .bvv_from_biguint_with_size(&int_val, bytes_val.len() as u32 * 8)
- .map_err(ClaripyError::from)?,
- )?);
- }
- Err(PyErr::new::(
- "BVV value must be a int, bytes, or str",
- ))
-}
-
-pyop!(Add, add, BV, BV, BV);
-pyop!(Sub, sub, BV, BV, BV);
-pyop!(Mul, mul, BV, BV, BV);
-pyop!(UDiv, udiv, BV, BV, BV);
-pyop!(SDiv, sdiv, BV, BV, BV);
-pyop!(UMod, urem, BV, BV, BV);
-pyop!(SMod, srem, BV, BV, BV);
-pyop!(Pow, pow, BV, BV, BV);
-pyop!(LShL, lshl, BV, BV, BV);
-pyop!(LShR, lshr, BV, BV, BV);
-pyop!(AShR, ashr, BV, BV, BV);
-pyop!(AShL, ashl, BV, BV, BV);
-pyop!(Concat, concat, BV, BV, BV);
-pyop!(Extract, extract, BV, BV, start: u32, end: u32);
-
-pyop!(ULT, ult, Bool, BV, BV);
-pyop!(ULE, ule, Bool, BV, BV);
-pyop!(UGT, ugt, Bool, BV, BV);
-pyop!(UGE, uge, Bool, BV, BV);
-pyop!(SLT, slt, Bool, BV, BV);
-pyop!(SLE, sle, Bool, BV, BV);
-pyop!(SGT, sgt, Bool, BV, BV);
-pyop!(SGE, sge, Bool, BV, BV);
-
-pub(crate) fn import(_: Python, m: &Bound) -> PyResult<()> {
- m.add_class::()?;
-
- add_pyfunctions!(
- m,
- BVS,
- BVV,
- shared_ops::Not,
- shared_ops::And,
- Add,
- Sub,
- Mul,
- UDiv,
- SDiv,
- UMod,
- SMod,
- Pow,
- LShL,
- LShR,
- AShR,
- AShL,
- Concat,
- Extract,
- ULT,
- ULE,
- UGT,
- UGE,
- SLT,
- SLE,
- SGT,
- SGE,
- shared_ops::Eq_,
- shared_ops::If,
- );
-
- Ok(())
-}
diff --git a/crates/claripy/src/ast/mod.rs b/crates/claripy/src/ast/mod.rs
deleted file mode 100644
index 8d5d935..0000000
--- a/crates/claripy/src/ast/mod.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-pub mod base;
-pub mod bits;
-pub mod bool;
-pub mod bv;
-pub mod fp;
-pub mod py_factory;
-pub mod shared_ops;
-pub mod string;
-
-use pyo3::{prelude::*, PyClass};
-
-use clarirs_core::ast::AstRef;
-
-use super::import_submodule;
-
-pub trait PyAst: PyClass {
- fn new_from_astref(ast_ref: &AstRef<'static>) -> PyClassInitializer;
- fn as_base(self_: PyRef) -> PyRef;
-}
-
-pub fn get_astref(self_: PyRef) -> AstRef<'static>
-where
- T: PyAst,
-{
- T::as_base(self_).ast.clone()
-}
-
-pub(crate) fn import(py: Python, m: &Bound) -> PyResult<()> {
- import_submodule(py, m, "claripy.ast", "base", base::import)?;
- import_submodule(py, m, "claripy.ast", "bits", bits::import)?;
- import_submodule(py, m, "claripy.ast", "bool", bool::import)?;
- import_submodule(py, m, "claripy.ast", "bv", bv::import)?;
- import_submodule(py, m, "claripy.ast", "fp", fp::import)?;
- import_submodule(py, m, "claripy.ast", "strings", string::import)?;
-
- m.add_class::()?;
- m.add_class::()?;
- m.add_class::()?;
- m.add_class::()?;
- m.add_class::()?;
- m.add_class::()?;
- Ok(())
-}
diff --git a/crates/claripy/src/ast/py_factory.rs b/crates/claripy/src/ast/py_factory.rs
deleted file mode 100644
index 28a026b..0000000
--- a/crates/claripy/src/ast/py_factory.rs
+++ /dev/null
@@ -1,54 +0,0 @@
-use std::{
- collections::HashMap,
- sync::{LazyLock, RwLock},
-};
-
-use pyo3::pyclass_init::PyObjectInit;
-
-use crate::prelude::*;
-
-pub static GLOBAL_CONTEXT: LazyLock> = LazyLock::new(Context::new);
-pub static PY_OBJECT_CACHE: LazyLock>> =
- LazyLock::new(|| RwLock::new(HashMap::new()));
-
-pub fn extract_arg<'py, T>(
- py: Python<'py>,
- args: &[PyObject],
- index: usize,
-) -> Result
-where
- T: FromPyObject<'py>,
-{
- args.get(index)
- .ok_or(ClaripyError::MissingArgIndex(index))
- .and_then(|arg| {
- arg.extract::(py)
- .map_err(|_| ClaripyError::FailedToExtractArg(arg.clone_ref(py)))
- })
-}
-
-pub fn py_ast_from_astref(py: Python, native_ast: AstRef<'static>) -> Result, ClaripyError>
-where
- T: PyAst,
-{
- let cached_obj = PY_OBJECT_CACHE
- .read()
- .unwrap()
- .get(&native_ast.hash())
- .and_then(|weak_ptr| weak_ptr.upgrade(py));
- match cached_obj {
- Some(py_obj) => Ok(py_obj),
- None => {
- let py_init = T::new_from_astref(&native_ast);
- let py_obj = unsafe {
- Py::from_owned_ptr(py, py_init.into_new_object(py, T::type_object_raw(py))?)
- };
- let weakref = WeakRef::from(&py_obj);
- PY_OBJECT_CACHE
- .write()
- .unwrap()
- .insert(native_ast.hash(), weakref);
- Ok(py_obj)
- }
- }
-}
diff --git a/crates/claripy/src/ast/shared_ops.rs b/crates/claripy/src/ast/shared_ops.rs
deleted file mode 100644
index b91506d..0000000
--- a/crates/claripy/src/ast/shared_ops.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-#![allow(non_snake_case)]
-
-use crate::ast::{base::Base, bool::Bool};
-use crate::prelude::*;
-
-#[pyfunction]
-pub fn Not(py: Python, b: PyRef) -> Result, ClaripyError> {
- py_ast_from_astref(py, GLOBAL_CONTEXT.not(&get_astref(b))?)
-}
-
-#[pyfunction]
-pub fn And(py: Python, lhs: PyRef, rhs: PyRef) -> Result, ClaripyError> {
- py_ast_from_astref(py, GLOBAL_CONTEXT.and(&get_astref(lhs), &get_astref(rhs))?)
-}
-
-#[pyfunction]
-pub fn Or(py: Python, lhs: PyRef, rhs: PyRef) -> Result, ClaripyError> {
- py_ast_from_astref(py, GLOBAL_CONTEXT.or(&get_astref(lhs), &get_astref(rhs))?)
-}
-
-#[pyfunction]
-pub fn Xor(py: Python, lhs: PyRef, rhs: PyRef) -> Result, ClaripyError> {
- py_ast_from_astref(py, GLOBAL_CONTEXT.xor(&get_astref(lhs), &get_astref(rhs))?)
-}
-
-#[allow(non_snake_case)]
-#[pyfunction(name = "Eq")]
-pub fn Eq_(py: Python, lhs: PyRef, rhs: PyRef) -> Result, ClaripyError> {
- py_ast_from_astref(
- py,
- crate::ast::py_factory::GLOBAL_CONTEXT
- .eq_(&crate::ast::get_astref(lhs), &crate::ast::get_astref(rhs))?,
- )
-}
-
-#[pyfunction]
-pub fn If(
- py: Python,
- cond: PyRef,
- then_: PyRef,
- else_: PyRef,
-) -> Result, ClaripyError> {
- py_ast_from_astref(
- py,
- GLOBAL_CONTEXT.if_(&get_astref(cond), &get_astref(then_), &get_astref(else_))?,
- )
-}
diff --git a/crates/claripy/src/ast/string.rs b/crates/claripy/src/ast/string.rs
deleted file mode 100644
index f1d43bc..0000000
--- a/crates/claripy/src/ast/string.rs
+++ /dev/null
@@ -1,115 +0,0 @@
-#![allow(non_snake_case)]
-
-use ast::bv::BV;
-
-use crate::ast::bits::Bits;
-use crate::prelude::*;
-
-#[pyclass(name="String", extends=Bits, subclass, frozen, module="claripy.ast.string")]
-pub struct AstString;
-
-impl PyAst for AstString {
- fn new_from_astref(ast_ref: &AstRef<'static>) -> PyClassInitializer {
- Bits::new_from_astref(ast_ref).add_subclass(AstString {})
- }
-
- fn as_base(self_: PyRef) -> PyRef {
- self_.into_super().into_super()
- }
-}
-
-pyop!(StringS, strings, AstString, name: String, size: u32);
-pyop!(StringV, stringv, AstString, value: String);
-pyop!(StrLen, strlen, AstString, AstString);
-pyop!(StrConcat, strconcat, AstString, AstString, AstString);
-
-#[pyfunction]
-pub fn StrSubstr(
- py: Python,
- base: PyRef,
- start: PyRef,
- end: PyRef,
-) -> Result, ClaripyError> {
- py_ast_from_astref(
- py,
- GLOBAL_CONTEXT.strsubstr(&get_astref(base), &get_astref(start), &get_astref(end))?,
- )
-}
-
-pyop!(StrContains, strcontains, AstString, AstString, AstString);
-
-#[pyfunction]
-pub fn StrIndexOf(
- py: Python,
- haystack: PyRef,
- needle: PyRef,
- start: PyRef,
-) -> Result, ClaripyError> {
- py_ast_from_astref(
- py,
- GLOBAL_CONTEXT.strindexof(
- &get_astref(haystack),
- &get_astref(needle),
- &get_astref(start),
- )?,
- )
-}
-
-#[pyfunction]
-pub fn StrReplace(
- py: Python,
- haystack: PyRef,
- needle: PyRef,
- replacement: PyRef,
-) -> Result, ClaripyError> {
- py_ast_from_astref(
- py,
- GLOBAL_CONTEXT.strreplace(
- &get_astref(haystack),
- &get_astref(needle),
- &get_astref(replacement),
- )?,
- )
-}
-
-pyop!(StrPrefixOf, strprefixof, AstString, AstString, AstString);
-pyop!(StrSuffixOf, strsuffixof, AstString, AstString, AstString);
-
-#[pyfunction]
-pub fn StrToBV(py: Python, s: PyRef) -> Result, ClaripyError> {
- py_ast_from_astref(py, GLOBAL_CONTEXT.strtobv(&get_astref(s))?)
-}
-
-#[pyfunction]
-pub fn BVToStr(py: Python, bv: PyRef) -> Result, ClaripyError> {
- py_ast_from_astref(py, GLOBAL_CONTEXT.bvtostr(&get_astref(bv))?)
-}
-
-pyop!(StrIsDigit, strisdigit, AstString, AstString);
-pyop!(StrEq, streq, AstString, AstString, AstString);
-pyop!(StrNeq, strneq, AstString, AstString, AstString);
-
-pub(crate) fn import(_: Python, m: &Bound) -> PyResult<()> {
- m.add_class::()?;
-
- add_pyfunctions!(
- m,
- StringS,
- StringV,
- StrLen,
- StrConcat,
- StrSubstr,
- StrContains,
- StrIndexOf,
- StrReplace,
- StrPrefixOf,
- StrSuffixOf,
- StrToBV,
- BVToStr,
- StrIsDigit,
- StrEq,
- StrNeq,
- );
-
- Ok(())
-}
diff --git a/crates/claripy/src/macros.rs b/crates/claripy/src/macros.rs
deleted file mode 100644
index 20736bf..0000000
--- a/crates/claripy/src/macros.rs
+++ /dev/null
@@ -1,108 +0,0 @@
-#[macro_export]
-macro_rules! add_pyfunctions {
- ($m:ident, $($fn_name:path),*,) => {
- $(
- $m.add_function(wrap_pyfunction!($fn_name, $m)?)?;
- )*
- };
-}
-
-#[macro_export]
-macro_rules! pyop {
- // Match one argument
- ($fn_name:ident, $context_method:ident, $return_type:ty, $at:tt) => {
- #[allow(non_snake_case)]
- #[pyfunction]
- pub fn $fn_name(py: Python, ast: pyop!(@py? $at)) -> Result, ClaripyError> {
- py_ast_from_astref(py, $crate::ast::py_factory::GLOBAL_CONTEXT.$context_method(&$crate::ast::get_astref(ast))?)
- }
- };
-
- // Match two arguments
- ($fn_name:ident, $context_method:ident, $return_type:ty, $at1:tt, $at2:tt) => {
- #[allow(non_snake_case)]
- #[pyfunction]
- pub fn $fn_name(py: Python, lhs: pyop!(@py? $at1), rhs: pyop!(@py? $at2)) -> Result, ClaripyError> {
- py_ast_from_astref(py, $crate::ast::py_factory::GLOBAL_CONTEXT.$context_method(&$crate::ast::get_astref(lhs), &$crate::ast::get_astref(rhs))?)
- }
- };
-
- // Extract-shaped
- // TODO: Why can't the named arguments pattern cover this?
- ($fn_name:ident, $context_method:ident, $return_type:ty, $at:ty, $a1:ident: $a1_t:tt, $a2:ident: $a2_t:tt) => {
- #[allow(non_snake_case)]
- #[pyfunction]
- pub fn $fn_name(py: Python, ast: PyRef<$at>, $a1: $a1_t, $a2: $a2_t) -> Result, ClaripyError> {
- py_ast_from_astref(py, GLOBAL_CONTEXT.$context_method(&get_astref(ast), $a1, $a2)?)
- }
- };
-
- // If-shaped
- // TODO: Why can't the named arguments pattern cover this?
- ($fn_name:ident, $context_method:ident, $return_type:ty, $a1:ident: $a1_t:tt, $a2:ident: $a2_t:tt, $a3:ident, $a3_t:tt) => {
- #[allow(non_snake_case)]
- #[pyfunction]
- pub fn $fn_name(py: Python, ast: PyRef<$at>, $a1: pyop!(@py? $a1_t), $a2: pyop!(@py? $a2_t), $a3: pyop!(@py? $a3_t)) -> Result, ClaripyError> {
- py_ast_from_astref(py, GLOBAL_CONTEXT.$context_method(&get_astref($a1), &get_astref($a2), &get_astref($a3))?)
- }
- };
-
- // Named arguments
- ($fn_name:ident, $context_method:ident, $return_type:ty, $($arg_name:ident: $arg_type:tt),*) => {
- #[pyfunction]
- #[allow(non_snake_case)]
- pub fn $fn_name(py: Python, $($arg_name: pyop!(@py? $arg_type)),*) -> Result, ClaripyError> {
- // $(let $arg_name = define_pyop!(@convert_arg $arg_name, $arg_type);)*
- py_ast_from_astref(py, $crate::ast::py_factory::GLOBAL_CONTEXT.$context_method($(pyop!(@astref? $arg_name, $arg_type)),*)?)
- }
- };
-
- // Helper to convert PyRef arguments to AstRef using get_astref
- (@astref? $arg_name:ident, PyRef<$inner_type:tt>) => {
- &$crate::ast::py_factory::get_astref($arg_name),
- };
-
- (@astref? $arg_name:ident, String) => {
- $arg_name
- };
-
- (@astref? $arg_name:ident, BigUint) => {
- &$arg_name
- };
-
- (@astref? $arg_name:ident, u32) => {
- $arg_name
- };
-
- (@astref? $arg_name:ident, $arg_type:ty) => {
- $arg_name
- };
-
- (@py? Bool) => {
- PyRef
- };
-
- (@py? BV) => {
- PyRef
- };
-
- (@py? FP) => {
- PyRef
- };
-
- (@py? AstString) => {
- PyRef
- };
-
- (@py? FSort) => {
- PyRef
- };
-
- (@py? PyRef<$arg_type:tt>) => {
- PyRef<$arg_type>
- };
-
- (@py? $arg_type:ty) => {
- $arg_type
- };
-}
diff --git a/crates/claripy/src/prelude.rs b/crates/claripy/src/prelude.rs
deleted file mode 100644
index 7755a5a..0000000
--- a/crates/claripy/src/prelude.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-pub use crate::ast;
-pub use crate::ast::{
- base::Base, get_astref, py_factory::extract_arg, py_factory::py_ast_from_astref,
- py_factory::GLOBAL_CONTEXT, PyAst,
-};
-pub use crate::error::ClaripyError;
-pub use crate::weakref::WeakRef;
-pub use clarirs_core::prelude::*;
-pub use pyo3::prelude::*;
diff --git a/crates/claripy/src/solver.rs b/crates/claripy/src/solver.rs
deleted file mode 100644
index 659d522..0000000
--- a/crates/claripy/src/solver.rs
+++ /dev/null
@@ -1,71 +0,0 @@
-use crate::prelude::*;
-
-macro_rules! pysolver {
- ($m:ident, $pystruct:ident, $struct_:ident, $pyname:literal) => {
- #[pyclass(name = $pyname, module = "claripy.solver")]
- pub struct $pystruct {
- solver: $struct_<'static>,
- }
-
- #[pymethods]
- impl $pystruct {
- #[new]
- fn new() -> Result, ClaripyError> {
- Ok(PyClassInitializer::from(Self {
- solver: $struct_::new(&GLOBAL_CONTEXT)?,
- }))
- }
-
- fn add(&mut self, expr: Bound) -> Result<(), ClaripyError> {
- Ok(self.solver.add(&expr.get().ast.clone())?)
- }
-
- fn eval(&mut self, py: Python, expr: Bound) -> Result, ClaripyError> {
- py_ast_from_astref(py, self.solver.eval(&expr.get().ast)?)
- }
-
- fn batch_eval(
- &mut self,
- py: Python,
- exprs: Vec>,
- max_solutions: u32,
- ) -> Result>, ClaripyError> {
- self.solver
- .batch_eval(exprs.iter().map(|e| e.get().ast.clone()), max_solutions)?
- .into_iter()
- .map(|ast| py_ast_from_astref::(py, ast))
- .collect::>, ClaripyError>>()
- }
-
- fn is_solution(
- &mut self,
- expr: Bound,
- value: Bound,
- ) -> Result {
- Ok(self.solver.is_solution(&expr.get().ast, &value.get().ast)?)
- }
-
- fn is_true(&mut self, expr: Bound) -> Result {
- Ok(self.solver.is_true(&expr.get().ast).unwrap())
- }
-
- fn is_false(&mut self, expr: Bound) -> Result {
- Ok(self.solver.is_false(&expr.get().ast).unwrap())
- }
-
- fn min(&mut self, py: Python, expr: Bound) -> Result, ClaripyError> {
- py_ast_from_astref(py, self.solver.min(expr.get().ast.clone()).unwrap())
- }
-
- fn max(&mut self, py: Python, expr: Bound) -> Result, ClaripyError> {
- py_ast_from_astref(py, self.solver.max(expr.get().ast.clone()).unwrap())
- }
- }
- $m.add_class::()?;
- };
-}
-
-pub(crate) fn import(_: Python, m: &Bound) -> PyResult<()> {
- pysolver!(m, PyConcreteSolver, ConcreteSolver, "ConcreteSolver");
- Ok(())
-}
diff --git a/crates/claripy/src/weakref.rs b/crates/claripy/src/weakref.rs
deleted file mode 100644
index 5afbcbe..0000000
--- a/crates/claripy/src/weakref.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-use pyo3::{
- ffi::{self},
- Py, Python,
-};
-
-pub struct WeakRef(*mut ffi::PyObject);
-
-unsafe impl Send for WeakRef {}
-unsafe impl Sync for WeakRef {}
-
-impl WeakRef {
- pub fn is_valid(&self) -> bool {
- unsafe { ffi::PyWeakref_CheckRef(self.0) != 0 }
- }
-
- pub fn upgrade(&self, py: Python<'_>) -> Option> {
- if self.is_valid() {
- Some(unsafe { Py::from_borrowed_ptr(py, ffi::PyWeakref_GetObject(self.0)) })
- } else {
- None
- }
- }
-}
-
-impl From<&Py> for WeakRef {
- fn from(obj: &Py) -> Self {
- WeakRef(unsafe { ffi::PyWeakref_NewRef(obj.as_ptr(), std::ptr::null_mut()) })
- }
-}
diff --git a/crates/clarirs_core/src/algorithms/simplify.rs b/crates/clarirs_core/src/algorithms/simplify.rs
index d4acace..a6d65ef 100644
--- a/crates/clarirs_core/src/algorithms/simplify.rs
+++ b/crates/clarirs_core/src/algorithms/simplify.rs
@@ -24,6 +24,8 @@ impl<'c> Simplify<'c> for BoolAst<'c> {
BooleanOp::And(arc, arc1) => todo!(),
BooleanOp::Or(arc, arc1) => todo!(),
BooleanOp::Xor(arc, arc1) => todo!(),
+ BooleanOp::BoolEq(arc, arc1) => todo!(),
+ BooleanOp::BoolNeq(arc, arc1) => todo!(),
BooleanOp::Eq(arc, arc1) => todo!(),
BooleanOp::Neq(arc, arc1) => todo!(),
BooleanOp::ULT(arc, arc1) => todo!(),
diff --git a/crates/clarirs_core/src/ast/bool.rs b/crates/clarirs_core/src/ast/bool.rs
index e30fa04..c3f859e 100644
--- a/crates/clarirs_core/src/ast/bool.rs
+++ b/crates/clarirs_core/src/ast/bool.rs
@@ -13,6 +13,8 @@ pub enum BooleanOp<'c> {
And(BoolAst<'c>, BoolAst<'c>),
Or(BoolAst<'c>, BoolAst<'c>),
Xor(BoolAst<'c>, BoolAst<'c>),
+ BoolEq(BoolAst<'c>, BoolAst<'c>),
+ BoolNeq(BoolAst<'c>, BoolAst<'c>),
Eq(BitVecAst<'c>, BitVecAst<'c>),
Neq(BitVecAst<'c>, BitVecAst<'c>),
ULT(BitVecAst<'c>, BitVecAst<'c>),
@@ -56,7 +58,11 @@ impl<'c> Op<'c> for BooleanOp<'c> {
BooleanOp::StrIsDigit(a) => vec![a.into()],
// Cases with two children
- BooleanOp::And(a, b) | BooleanOp::Or(a, b) | BooleanOp::Xor(a, b) => {
+ BooleanOp::And(a, b)
+ | BooleanOp::Or(a, b)
+ | BooleanOp::Xor(a, b)
+ | BooleanOp::BoolEq(a, b)
+ | BooleanOp::BoolNeq(a, b) => {
vec![a.into(), b.into()]
}
BooleanOp::Eq(a, b)
diff --git a/crates/clarirs_core/src/ast/factory.rs b/crates/clarirs_core/src/ast/factory.rs
index 15514e0..0f3670b 100644
--- a/crates/clarirs_core/src/ast/factory.rs
+++ b/crates/clarirs_core/src/ast/factory.rs
@@ -84,6 +84,22 @@ pub trait AstFactory<'c>: Sized {
Op::xor(self, lhs, rhs)
}
+ fn eq_>(
+ &'c self,
+ lhs: &AstRef<'c, Op>,
+ rhs: &AstRef<'c, Op>,
+ ) -> Result, ClarirsError> {
+ Op::eq_(self, lhs, rhs)
+ }
+
+ fn neq>(
+ &'c self,
+ lhs: &AstRef<'c, Op>,
+ rhs: &AstRef<'c, Op>,
+ ) -> Result, ClarirsError> {
+ Op::neq(self, lhs, rhs)
+ }
+
fn add>(
&'c self,
lhs: &AstRef<'c, Op>,
@@ -217,22 +233,6 @@ pub trait AstFactory<'c>: Sized {
self.make_bitvec(BitVecOp::Reverse(lhs.clone()))
}
- fn eq_(
- &'c self,
- lhs: &BitVecAst<'c>,
- rhs: &BitVecAst<'c>,
- ) -> Result, ClarirsError> {
- self.make_bool(BooleanOp::Eq(lhs.clone(), rhs.clone()))
- }
-
- fn neq(
- &'c self,
- lhs: &BitVecAst<'c>,
- rhs: &BitVecAst<'c>,
- ) -> Result, ClarirsError> {
- self.make_bool(BooleanOp::Neq(lhs.clone(), rhs.clone()))
- }
-
fn ult(
&'c self,
lhs: &BitVecAst<'c>,
diff --git a/crates/clarirs_core/src/ast/factory_support.rs b/crates/clarirs_core/src/ast/factory_support.rs
index 17a0ca5..d0ebf9a 100644
--- a/crates/clarirs_core/src/ast/factory_support.rs
+++ b/crates/clarirs_core/src/ast/factory_support.rs
@@ -3,7 +3,7 @@ use crate::prelude::*;
macro_rules! uniop_support_trait {
($name:ident, $($impler:ty, $factory_func:ident),*) => {
paste::paste! {
- pub(crate) trait []<'c>: Op<'c> + Sized {
+ pub trait []<'c>: Op<'c> + Sized {
fn [< $name:lower >](factory: &'c impl AstFactory<'c>, ast: &AstRef<'c, Self>) -> Result, ClarirsError>;
}
}
@@ -99,3 +99,99 @@ impl_supports_if_and_annotated!(
StringOp<'c>,
make_string
);
+
+pub trait SupportsEq<'c>: Op<'c> + Sized {
+ fn eq_(
+ factory: &'c impl AstFactory<'c>,
+ lhs: &AstRef<'c, Self>,
+ rhs: &AstRef<'c, Self>,
+ ) -> Result, ClarirsError>;
+}
+
+impl<'c> SupportsEq<'c> for BooleanOp<'c> {
+ fn eq_(
+ factory: &'c impl AstFactory<'c>,
+ lhs: &AstRef<'c, Self>,
+ rhs: &AstRef<'c, Self>,
+ ) -> Result, ClarirsError> {
+ factory.make_bool(BooleanOp::BoolEq(lhs.clone(), rhs.clone()))
+ }
+}
+
+impl<'c> SupportsEq<'c> for BitVecOp<'c> {
+ fn eq_(
+ factory: &'c impl AstFactory<'c>,
+ lhs: &AstRef<'c, Self>,
+ rhs: &AstRef<'c, Self>,
+ ) -> Result, ClarirsError> {
+ factory.make_bool(BooleanOp::Eq(lhs.clone(), rhs.clone()))
+ }
+}
+
+impl<'c> SupportsEq<'c> for FloatOp<'c> {
+ fn eq_(
+ factory: &'c impl AstFactory<'c>,
+ lhs: &AstRef<'c, Self>,
+ rhs: &AstRef<'c, Self>,
+ ) -> Result, ClarirsError> {
+ factory.make_bool(BooleanOp::FpEq(lhs.clone(), rhs.clone()))
+ }
+}
+
+impl<'c> SupportsEq<'c> for StringOp<'c> {
+ fn eq_(
+ factory: &'c impl AstFactory<'c>,
+ lhs: &AstRef<'c, Self>,
+ rhs: &AstRef<'c, Self>,
+ ) -> Result, ClarirsError> {
+ factory.make_bool(BooleanOp::StrEq(lhs.clone(), rhs.clone()))
+ }
+}
+
+pub trait SupportsNeq<'c>: Op<'c> + Sized {
+ fn neq(
+ factory: &'c impl AstFactory<'c>,
+ lhs: &AstRef<'c, Self>,
+ rhs: &AstRef<'c, Self>,
+ ) -> Result, ClarirsError>;
+}
+
+impl<'c> SupportsNeq<'c> for BooleanOp<'c> {
+ fn neq(
+ factory: &'c impl AstFactory<'c>,
+ lhs: &AstRef<'c, Self>,
+ rhs: &AstRef<'c, Self>,
+ ) -> Result, ClarirsError> {
+ factory.make_bool(BooleanOp::BoolNeq(lhs.clone(), rhs.clone()))
+ }
+}
+
+impl<'c> SupportsNeq<'c> for BitVecOp<'c> {
+ fn neq(
+ factory: &'c impl AstFactory<'c>,
+ lhs: &AstRef<'c, Self>,
+ rhs: &AstRef<'c, Self>,
+ ) -> Result, ClarirsError> {
+ factory.make_bool(BooleanOp::Neq(lhs.clone(), rhs.clone()))
+ }
+}
+
+impl<'c> SupportsNeq<'c> for FloatOp<'c> {
+ fn neq(
+ factory: &'c impl AstFactory<'c>,
+ lhs: &AstRef<'c, Self>,
+ rhs: &AstRef<'c, Self>,
+ ) -> Result, ClarirsError> {
+ factory.make_bool(BooleanOp::FpNeq(lhs.clone(), rhs.clone()))
+ }
+}
+
+impl<'c> SupportsNeq<'c> for StringOp<'c> {
+ fn neq(
+ factory: &'c impl AstFactory<'c>,
+ lhs: &AstRef<'c, Self>,
+ rhs: &AstRef<'c, Self>,
+ ) -> Result, ClarirsError> {
+ factory.make_bool(BooleanOp::StrNeq(lhs.clone(), rhs.clone()))
+ }
+}
diff --git a/crates/clarirs_core/src/solver/solver.rs b/crates/clarirs_core/src/solver/solver.rs
index 5049615..a93b6d5 100644
--- a/crates/clarirs_core/src/solver/solver.rs
+++ b/crates/clarirs_core/src/solver/solver.rs
@@ -26,13 +26,13 @@ pub trait Model<'c> {
/// Get the minimum value of an expression in the current model. If the constraints are
/// unsatisfiable, an error is returned.
- fn min(&self, expr: BitVecAst<'c>) -> Result, ClarirsError> {
+ fn min(&self, expr: &BitVecAst<'c>) -> Result, ClarirsError> {
todo!()
}
/// Get the maximum value of an expression in the current model. If the constraints are
/// unsatisfiable, an error is returned.
- fn max(&self, expr: BitVecAst<'c>) -> Result, ClarirsError> {
+ fn max(&self, expr: &BitVecAst<'c>) -> Result, ClarirsError> {
todo!()
}
}
@@ -104,13 +104,13 @@ pub trait Solver<'c>: Clone + HasContext<'c> {
/// Get the minimum value of an expression in the current model. If the constraints are
/// unsatisfiable, an error is returned.
- fn min(&mut self, expr: BitVecAst<'c>) -> Result, ClarirsError> {
+ fn min(&mut self, expr: &BitVecAst<'c>) -> Result, ClarirsError> {
self.model()?.min(expr)
}
/// Get the maximum value of an expression in the current model. If the constraints are
/// unsatisfiable, an error is returned.
- fn max(&mut self, expr: BitVecAst<'c>) -> Result, ClarirsError> {
+ fn max(&mut self, expr: &BitVecAst<'c>) -> Result, ClarirsError> {
self.model()?.max(expr)
}
}
diff --git a/crates/claripy/Cargo.toml b/crates/clarirs_py/Cargo.toml
similarity index 56%
rename from crates/claripy/Cargo.toml
rename to crates/clarirs_py/Cargo.toml
index 9a48a69..8de3bd5 100644
--- a/crates/claripy/Cargo.toml
+++ b/crates/clarirs_py/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "claripy"
+name = "clarirs_py"
version = "0.1.0"
edition = "2021"
description = "Python bindings for clarirs"
@@ -10,14 +10,19 @@ categories = { workspace = true }
repository = { workspace = true }
[dependencies]
-# pyo3 0.22.2 has an issue with raising exceptions on Python 3.12, so we use the
-# latest version from the master branch until a new release is made.
-# See https://github.com/PyO3/pyo3/pull/3306
-pyo3 = { git = "https://github.com/PyO3/pyo3.git", features = ["extension-module", "py-clone", "num-bigint"] }
+pyo3 = { version = "0.22.5", features = [
+ "extension-module",
+ "py-clone",
+ "num-bigint",
+] }
clarirs_core = { path = "../clarirs_core", features = ["runtime-checks"] }
thiserror = "1.0.63"
num-bigint = "0.4.6"
log = "0.4.22"
+dashmap = "6.1.0"
+
+[lib]
+name = "clarirs"
[lints]
workspace = true
diff --git a/crates/claripy/benchmarks/perf_ast.py b/crates/clarirs_py/benchmarks/perf_ast.py
similarity index 59%
rename from crates/claripy/benchmarks/perf_ast.py
rename to crates/clarirs_py/benchmarks/perf_ast.py
index 6dfd9b4..34819cb 100644
--- a/crates/claripy/benchmarks/perf_ast.py
+++ b/crates/clarirs_py/benchmarks/perf_ast.py
@@ -1,10 +1,10 @@
from __future__ import annotations
-import claripy
-from claripy.ast.base import Base
+import clarirs
+from clarirs.ast.base import Base
-class MyAnnotation(claripy.Annotation):
+class MyAnnotation(clarirs.Annotation):
def __init__(self, value):
self.value = value
@@ -16,23 +16,22 @@ def make_asts() -> list[Base]:
results: list[Base] = []
# Make a lot of BVS
- results.extend([claripy.BVS(str(i), 32) for i in range(1000)])
+ results.extend([clarirs.BVS(str(i), 32) for i in range(1000)])
# Make a lot of BVV
- results.extend([claripy.BVV(i, 32) for i in range(1000)])
+ results.extend([clarirs.BVV(i, 32) for i in range(1000)])
# Make a lot of And
- results.extend([claripy.And(claripy.BVS(str(i), 32), claripy.BVV(i, 32)) for i in range(1000)])
- # results.extend(res)
+ results.extend([clarirs.And(clarirs.BVS(str(i), 32), clarirs.BVV(i, 32)) for i in range(1000)])
# Make a lot of Or
- results.extend([claripy.Or(claripy.BVS(str(i), 32), claripy.BVV(i, 32)) for i in range(1000)])
+ results.extend([clarirs.Or(clarirs.BVS(str(i), 32), clarirs.BVV(i, 32)) for i in range(1000)])
# Make a lot of FPS
- results.extend([claripy.FPS(str(i), claripy.FSORT_DOUBLE) for i in range(1000)])
+ results.extend([clarirs.FPS(str(i), clarirs.FSORT_DOUBLE) for i in range(1000)])
# Make a lot of FPV
- results.extend([claripy.FPV(i, claripy.FSORT_DOUBLE) for i in range(1000)])
+ results.extend([clarirs.FPV(i, clarirs.FSORT_DOUBLE) for i in range(1000)])
# Annotate!
# for i in range(100):
diff --git a/crates/claripy/src/annotation.rs b/crates/clarirs_py/src/annotation.rs
similarity index 66%
rename from crates/claripy/src/annotation.rs
rename to crates/clarirs_py/src/annotation.rs
index a3e8087..44df10a 100644
--- a/crates/claripy/src/annotation.rs
+++ b/crates/clarirs_py/src/annotation.rs
@@ -1,12 +1,12 @@
use crate::prelude::*;
-#[pyclass(name = "Annotation", module = "claripy.annotation", subclass)]
+#[pyclass(name = "Annotation", module = "clarirs.annotation", subclass)]
pub struct PyAnnotation {}
-#[pyclass(extends = PyAnnotation, module = "claripy.annotation", subclass)]
+#[pyclass(extends = PyAnnotation, module = "clarirs.annotation", subclass)]
pub struct SimplificationAvoidanceAnnotation {}
-#[pyclass(extends = PyAnnotation, module = "claripy.annotation", subclass)]
+#[pyclass(extends = PyAnnotation, module = "clarirs.annotation", subclass)]
pub struct RegionAnnotation {}
pub(crate) fn import(_: Python, m: &Bound) -> PyResult<()> {
diff --git a/crates/clarirs_py/src/ast/base.rs b/crates/clarirs_py/src/ast/base.rs
new file mode 100644
index 0000000..f55b103
--- /dev/null
+++ b/crates/clarirs_py/src/ast/base.rs
@@ -0,0 +1,19 @@
+use crate::prelude::*;
+
+#[pyclass(subclass, frozen, weakref, module = "clarirs.ast.base")]
+#[derive(Clone, Default)]
+pub struct Base {}
+
+#[pymethods]
+impl Base {}
+
+impl Base {
+ pub fn new() -> Self {
+ Base {}
+ }
+}
+
+pub(crate) fn import(_: Python, m: &Bound) -> PyResult<()> {
+ m.add_class::()?;
+ Ok(())
+}
diff --git a/crates/clarirs_py/src/ast/bits.rs b/crates/clarirs_py/src/ast/bits.rs
new file mode 100644
index 0000000..80e8ff0
--- /dev/null
+++ b/crates/clarirs_py/src/ast/bits.rs
@@ -0,0 +1,16 @@
+use crate::prelude::*;
+
+#[pyclass(extends=Base, subclass, frozen, weakref, module="clarirs.ast.bits")]
+#[derive(Clone, Default)]
+pub struct Bits;
+
+impl Bits {
+ pub fn new() -> Self {
+ Bits {}
+ }
+}
+
+pub(crate) fn import(_: Python, m: &Bound) -> PyResult<()> {
+ m.add_class::()?;
+ Ok(())
+}
diff --git a/crates/clarirs_py/src/ast/bool.rs b/crates/clarirs_py/src/ast/bool.rs
new file mode 100644
index 0000000..03fc15e
--- /dev/null
+++ b/crates/clarirs_py/src/ast/bool.rs
@@ -0,0 +1,101 @@
+#![allow(non_snake_case)]
+
+use std::sync::LazyLock;
+
+use dashmap::DashMap;
+use pyo3::types::PyWeakrefMethods;
+use pyo3::types::PyWeakrefReference;
+
+use crate::ast::{And, Not, Or, Xor};
+use crate::prelude::*;
+
+static PY_BOOL_CACHE: LazyLock>> = LazyLock::new(DashMap::new);
+
+#[pyclass(extends=Base, subclass, frozen, weakref, module="clarirs.ast.bool")]
+pub struct Bool {
+ pub(crate) inner: BoolAst<'static>,
+}
+
+impl Bool {
+ pub fn new(py: Python, inner: BoolAst<'static>) -> Result, ClaripyError> {
+ if let Some(cache_hit) = PY_BOOL_CACHE.get(&inner.hash()).and_then(|cache_hit| {
+ cache_hit
+ .bind(py)
+ .upgrade_as::()
+ .expect("bool cache poisoned")
+ }) {
+ Ok(cache_hit.unbind())
+ } else {
+ let this = Py::new(
+ py,
+ PyClassInitializer::from(Base::new()).add_subclass(Bool {
+ inner: inner.clone(),
+ }),
+ )?;
+ let weakref = PyWeakrefReference::new_bound(this.bind(py))?;
+ PY_BOOL_CACHE.insert(inner.hash(), weakref.unbind());
+
+ Ok(this)
+ }
+ }
+}
+
+#[pymethods]
+impl Bool {
+ fn is_true(self_: PyRef) -> bool {
+ self_.inner.is_true()
+ }
+
+ fn is_false(self_: PyRef) -> bool {
+ self_.inner.is_false()
+ }
+}
+
+#[pyfunction]
+pub fn BoolS(py: Python, name: &str) -> Result, ClaripyError> {
+ Bool::new(py, GLOBAL_CONTEXT.bools(name)?)
+}
+#[pyfunction]
+pub fn BoolV(py: Python, value: bool) -> Result, ClaripyError> {
+ Bool::new(py, GLOBAL_CONTEXT.boolv(value)?)
+}
+
+#[pyfunction]
+pub fn Eq_(py: Python, a: Bound, b: Bound) -> Result, ClaripyError> {
+ Bool::new(py, GLOBAL_CONTEXT.eq_(&a.get().inner, &b.get().inner)?)
+}
+
+#[pyfunction]
+pub fn Neq(py: Python, a: Bound, b: Bound) -> Result, ClaripyError> {
+ Bool::new(py, GLOBAL_CONTEXT.neq(&a.get().inner, &b.get().inner)?)
+}
+
+#[pyfunction]
+pub fn If(
+ py: Python,
+ cond: Bound,
+ then_: Bound,
+ else_: Bound,
+) -> Result, ClaripyError> {
+ Bool::new(
+ py,
+ GLOBAL_CONTEXT.if_(&cond.get().inner, &then_.get().inner, &else_.get().inner)?,
+ )
+}
+
+#[pyfunction(name = "true")]
+pub fn true_op(py: Python) -> Result, ClaripyError> {
+ Bool::new(py, GLOBAL_CONTEXT.true_()?)
+}
+#[pyfunction(name = "false")]
+pub fn false_op(py: Python) -> Result, ClaripyError> {
+ Bool::new(py, GLOBAL_CONTEXT.false_()?)
+}
+
+pub(crate) fn import(_: Python, m: &Bound) -> PyResult<()> {
+ m.add_class::()?;
+
+ add_pyfunctions!(m, BoolS, BoolV, Not, And, Or, Xor, Eq_, If, true_op, false_op,);
+
+ Ok(())
+}
diff --git a/crates/clarirs_py/src/ast/bv.rs b/crates/clarirs_py/src/ast/bv.rs
new file mode 100644
index 0000000..a3ebc7f
--- /dev/null
+++ b/crates/clarirs_py/src/ast/bv.rs
@@ -0,0 +1,168 @@
+#![allow(non_snake_case)]
+
+use std::sync::LazyLock;
+
+use dashmap::DashMap;
+use num_bigint::BigUint;
+use pyo3::exceptions::{PyTypeError, PyValueError};
+use pyo3::types::PyWeakrefReference;
+
+use crate::ast::{And, Not, Or, Xor};
+use crate::prelude::*;
+
+static PY_BV_CACHE: LazyLock>> = LazyLock::new(DashMap::new);
+
+#[pyclass(extends=Bits, subclass, frozen, weakref, module="clarirs.ast.bv")]
+pub struct BV {
+ pub(crate) inner: BitVecAst<'static>,
+}
+
+impl BV {
+ pub fn new(py: Python, inner: BitVecAst<'static>) -> Result, ClaripyError> {
+ if let Some(cache_hit) = PY_BV_CACHE.get(&inner.hash()).and_then(|cache_hit| {
+ cache_hit
+ .bind(py)
+ .upgrade_as::()
+ .expect("bool cache poisoned")
+ }) {
+ Ok(cache_hit.unbind())
+ } else {
+ let this = Py::new(
+ py,
+ PyClassInitializer::from(Base::new())
+ .add_subclass(Bits::new())
+ .add_subclass(BV {
+ inner: inner.clone(),
+ }),
+ )?;
+ let weakref = PyWeakrefReference::new_bound(this.bind(py))?;
+ PY_BV_CACHE.insert(inner.hash(), weakref.unbind());
+
+ Ok(this)
+ }
+ }
+}
+
+#[pymethods]
+impl BV {}
+
+#[pyfunction]
+pub fn BVS(py: Python, name: String, size: u32) -> Result, ClaripyError> {
+ BV::new(py, GLOBAL_CONTEXT.bvs(&name, size)?)
+}
+
+#[allow(non_snake_case)]
+#[pyfunction(signature = (value, size = None))]
+pub fn BVV(py: Python, value: Bound, size: Option) -> Result, PyErr> {
+ if let Ok(int_val) = value.extract::() {
+ if let Some(size) = size {
+ let a = GLOBAL_CONTEXT
+ .bvv_from_biguint_with_size(&int_val, size)
+ .map_err(ClaripyError::from)?;
+ return Ok(BV::new(py, a)?);
+ } else {
+ return Err(PyErr::new::("size must be specified"));
+ }
+ }
+ // TODO: deduplicate bytes/str
+ if let Ok(bytes_val) = value.extract::>() {
+ let int_val = BigUint::from_bytes_le(&bytes_val);
+ log::warn!("bytes value passed to BVV, assuming little-endian");
+ if size.is_some() {
+ log::warn!("BVV size specified with bytes, value will be ignored");
+ }
+ return Ok(BV::new(
+ py,
+ GLOBAL_CONTEXT
+ .bvv_from_biguint_with_size(&int_val, bytes_val.len() as u32 * 8)
+ .map_err(ClaripyError::from)?,
+ )?);
+ }
+ if let Ok(str_val) = value.extract::() {
+ log::warn!("string value passed to BVV, assuming utf-8");
+ let bytes_val = str_val.as_bytes();
+ let int_val = BigUint::from_bytes_le(bytes_val);
+ log::warn!("bytes value passed to BVV, assuming little-endian");
+ if size.is_some() {
+ log::warn!("BVV size specified with bytes, value will be ignored");
+ }
+ return Ok(BV::new(
+ py,
+ GLOBAL_CONTEXT
+ .bvv_from_biguint_with_size(&int_val, bytes_val.len() as u32 * 8)
+ .map_err(ClaripyError::from)?,
+ )?);
+ }
+ Err(PyErr::new::(
+ "BVV value must be a int, bytes, or str",
+ ))
+}
+
+macro_rules! binop {
+ ($name:ident, $context_method:ident, $return_type:ty, $lhs:ty, $rhs:ty) => {
+ #[pyfunction]
+ pub fn $name(
+ py: Python,
+ lhs: Bound<$lhs>,
+ rhs: Bound<$rhs>,
+ ) -> Result, ClaripyError> {
+ <$return_type>::new(
+ py,
+ GLOBAL_CONTEXT.$context_method(&lhs.get().inner, &rhs.get().inner)?,
+ )
+ }
+ };
+}
+
+binop!(Add, add, BV, BV, BV);
+binop!(Sub, sub, BV, BV, BV);
+binop!(Mul, mul, BV, BV, BV);
+binop!(UDiv, udiv, BV, BV, BV);
+binop!(SDiv, sdiv, BV, BV, BV);
+binop!(UMod, urem, BV, BV, BV);
+binop!(SMod, srem, BV, BV, BV);
+binop!(Pow, pow, BV, BV, BV);
+binop!(ShL, ashl, BV, BV, BV);
+binop!(LShR, lshr, BV, BV, BV);
+binop!(AShR, ashr, BV, BV, BV);
+binop!(Concat, concat, BV, BV, BV);
+
+binop!(ULT, ult, Bool, BV, BV);
+binop!(ULE, ule, Bool, BV, BV);
+binop!(UGT, ugt, Bool, BV, BV);
+binop!(UGE, uge, Bool, BV, BV);
+binop!(SLT, slt, Bool, BV, BV);
+binop!(SLE, sle, Bool, BV, BV);
+binop!(SGT, sgt, Bool, BV, BV);
+binop!(SGE, sge, Bool, BV, BV);
+binop!(Eq_, eq_, Bool, BV, BV);
+binop!(Neq, neq, Bool, BV, BV);
+
+#[pyfunction]
+pub fn Extract(py: Python, base: Bound, start: u32, end: u32) -> Result, ClaripyError> {
+ BV::new(py, GLOBAL_CONTEXT.extract(&base.get().inner, start, end)?)
+}
+
+#[pyfunction]
+pub fn If(
+ py: Python,
+ cond: Bound,
+ then_: Bound,
+ else_: Bound,
+) -> Result, ClaripyError> {
+ BV::new(
+ py,
+ GLOBAL_CONTEXT.if_(&cond.get().inner, &then_.get().inner, &else_.get().inner)?,
+ )
+}
+
+pub(crate) fn import(_: Python, m: &Bound) -> PyResult<()> {
+ m.add_class::()?;
+
+ add_pyfunctions!(
+ m, BVS, BVV, Not, And, Or, Xor, Add, Sub, Mul, UDiv, SDiv, UMod, SMod, Pow, ShL, LShR,
+ AShR, Concat, Extract, ULT, ULE, UGT, UGE, SLT, SLE, SGT, SGE, Eq_, If,
+ );
+
+ Ok(())
+}
diff --git a/crates/claripy/src/ast/fp.rs b/crates/clarirs_py/src/ast/fp.rs
similarity index 50%
rename from crates/claripy/src/ast/fp.rs
rename to crates/clarirs_py/src/ast/fp.rs
index 939cb52..e82ddc8 100644
--- a/crates/claripy/src/ast/fp.rs
+++ b/crates/clarirs_py/src/ast/fp.rs
@@ -1,11 +1,15 @@
#![allow(non_snake_case)]
-use ast::bv::BV;
+use std::sync::LazyLock;
+
+use dashmap::DashMap;
+use pyo3::types::PyWeakrefReference;
-use crate::ast::bits::Bits;
use crate::prelude::*;
-#[pyclass(name = "RM", module = "claripy.ast.fp", eq)]
+static PY_FP_CACHE: LazyLock>> = LazyLock::new(DashMap::new);
+
+#[pyclass(name = "RM", module = "clarirs.ast.fp", eq)]
#[derive(Clone, PartialEq, Eq, Default)]
#[allow(non_camel_case_types)]
pub enum PyRM {
@@ -29,7 +33,7 @@ impl From for FPRM {
}
}
-#[pyclass(name = "FSort", module = "claripy.ast.fp")]
+#[pyclass(name = "FSort", module = "clarirs.ast.fp")]
#[derive(Clone)]
pub struct PyFSort(FSort);
@@ -53,31 +57,45 @@ pub fn fsort_double() -> PyFSort {
PyFSort(FSort::f64())
}
-#[pyclass(extends=Bits, subclass, frozen, weakref, module="claripy.ast.bits")]
-#[derive(Default)]
-pub struct FP;
+#[pyclass(extends=Bits, subclass, frozen, weakref, module="clarirs.ast.bits")]
+pub struct FP {
+ pub(crate) inner: FloatAst<'static>,
+}
impl FP {
- pub fn new() -> Self {
- FP {}
+ pub fn new(py: Python, inner: FloatAst<'static>) -> Result, ClaripyError> {
+ if let Some(cache_hit) = PY_FP_CACHE.get(&inner.hash()).and_then(|cache_hit| {
+ cache_hit
+ .bind(py)
+ .upgrade_as::()
+ .expect("bool cache poisoned")
+ }) {
+ Ok(cache_hit.unbind())
+ } else {
+ let this = Py::new(
+ py,
+ PyClassInitializer::from(Base::new())
+ .add_subclass(Bits::new())
+ .add_subclass(FP {
+ inner: inner.clone(),
+ }),
+ )?;
+ let weakref = PyWeakrefReference::new_bound(this.bind(py))?;
+ PY_FP_CACHE.insert(inner.hash(), weakref.unbind());
+
+ Ok(this)
+ }
}
}
-impl PyAst for FP {
- fn new_from_astref(ast_ref: &AstRef<'static>) -> PyClassInitializer {
- Bits::new_from_astref(ast_ref).add_subclass(FP::new())
- }
-
- fn as_base(self_: PyRef) -> PyRef {
- self_.into_super().into_super()
- }
+#[pyfunction]
+pub fn FPS(py: Python, name: &str, sort: PyFSort) -> Result, ClaripyError> {
+ FP::new(py, GLOBAL_CONTEXT.fps(name, sort)?)
}
-pyop!(FPS, fps, FP, name: String, sort: PyFSort);
-
#[pyfunction]
pub fn FPV(py: Python, value: f64, sort: PyFSort) -> Result, ClaripyError> {
- py_ast_from_astref(
+ FP::new(
py,
GLOBAL_CONTEXT
.fpv(>::into(value).to_fsort(sort.into(), FPRM::default()))?,
@@ -91,171 +109,189 @@ pub fn FpToFP(
sort: PyFSort,
rm: Option,
) -> Result, ClaripyError> {
- py_ast_from_astref(
+ FP::new(
py,
- GLOBAL_CONTEXT.fp_to_fp(&get_astref(fp), sort, rm.unwrap_or_default())?,
+ GLOBAL_CONTEXT.fp_to_fp(&fp.inner, sort, rm.unwrap_or_default())?,
)
}
#[pyfunction(name = "bvToFpUnsigned", signature = (bv, sort, rm = None))]
pub fn BvToFpUnsigned(
py: Python,
- bv: PyRef,
+ bv: Bound,
sort: PyFSort,
rm: Option,
) -> Result, ClaripyError> {
- py_ast_from_astref(
+ FP::new(
py,
- GLOBAL_CONTEXT.bv_to_fp_unsigned(&get_astref(bv), sort, rm.unwrap_or_default())?,
+ GLOBAL_CONTEXT.bv_to_fp_unsigned(&bv.get().inner, sort, rm.unwrap_or_default())?,
)
}
-pyop!(fpToIEEEBV, fp_to_ieeebv, BV, FP);
+#[pyfunction(name = "fpToIEEEBV", signature = (fp))]
+pub fn fpToIEEEBV(py: Python, fp: Bound) -> Result, ClaripyError> {
+ BV::new(py, GLOBAL_CONTEXT.fp_to_ieeebv(&fp.get().inner)?)
+}
#[pyfunction(name = "fpToUBV", signature = (fp, len, rm = None))]
pub fn FpToUbv(
py: Python,
- fp: PyRef,
+ fp: Bound,
len: u32,
rm: Option,
) -> Result, ClaripyError> {
- py_ast_from_astref(
+ BV::new(
py,
- GLOBAL_CONTEXT.fp_to_ubv(&get_astref(fp), len, rm.unwrap_or_default())?,
+ GLOBAL_CONTEXT.fp_to_ubv(&fp.get().inner, len, rm.unwrap_or_default())?,
)
}
#[pyfunction(name = "fpToSBV", signature = (fp, len, rm = None))]
pub fn FpToBv(
py: Python,
- fp: PyRef,
+ fp: Bound,
len: u32,
rm: Option,
) -> Result, ClaripyError> {
- py_ast_from_astref(
+ BV::new(
py,
- GLOBAL_CONTEXT.fp_to_sbv(&get_astref(fp), len, rm.unwrap_or_default())?,
+ GLOBAL_CONTEXT.fp_to_sbv(&fp.get().inner, len, rm.unwrap_or_default())?,
)
}
#[pyfunction(name = "fpNeg", signature = (lhs, rm = None))]
-pub fn FpNeg(py: Python, lhs: PyRef, rm: Option) -> Result, ClaripyError> {
- py_ast_from_astref(
+pub fn FpNeg(py: Python, lhs: Bound, rm: Option) -> Result, ClaripyError> {
+ FP::new(
py,
- GLOBAL_CONTEXT.fp_neg(&get_astref(lhs), rm.unwrap_or_default())?,
+ GLOBAL_CONTEXT.fp_neg(&lhs.get().inner, rm.unwrap_or_default())?,
)
}
#[pyfunction(name = "fpAbs", signature = (lhs, rm = None))]
-pub fn FpAbs(py: Python, lhs: PyRef, rm: Option) -> Result, ClaripyError> {
- py_ast_from_astref(
+pub fn FpAbs(py: Python, lhs: Bound, rm: Option) -> Result, ClaripyError> {
+ FP::new(
py,
- GLOBAL_CONTEXT.fp_abs(&get_astref(lhs), rm.unwrap_or_default())?,
+ GLOBAL_CONTEXT.fp_abs(&lhs.get().inner, rm.unwrap_or_default())?,
)
}
#[pyfunction(name = "fpAdd", signature = (lhs, rhs, rm = None))]
pub fn FpAdd(
py: Python,
- lhs: PyRef,
- rhs: PyRef,
+ lhs: Bound,
+ rhs: Bound,
rm: Option,
) -> Result, ClaripyError> {
- py_ast_from_astref(
+ FP::new(
py,
- GLOBAL_CONTEXT.fp_add(&get_astref(lhs), &get_astref(rhs), rm.unwrap_or_default())?,
+ GLOBAL_CONTEXT.fp_add(&lhs.get().inner, &rhs.get().inner, rm.unwrap_or_default())?,
)
}
#[pyfunction(name = "fpSub", signature = (lhs, rhs, rm = None))]
pub fn FpSub(
py: Python,
- lhs: PyRef,
- rhs: PyRef,
+ lhs: Bound,
+ rhs: Bound,
rm: Option,
) -> Result, ClaripyError> {
- py_ast_from_astref(
+ FP::new(
py,
- GLOBAL_CONTEXT.fp_sub(&get_astref(lhs), &get_astref(rhs), rm.unwrap_or_default())?,
+ GLOBAL_CONTEXT.fp_sub(&lhs.get().inner, &rhs.get().inner, rm.unwrap_or_default())?,
)
}
#[pyfunction(name = "fpMul", signature = (lhs, rhs, rm = None))]
pub fn FpMul(
py: Python,
- lhs: PyRef,
- rhs: PyRef,
+ lhs: Bound,
+ rhs: Bound,
rm: Option,
) -> Result, ClaripyError> {
- py_ast_from_astref(
+ FP::new(
py,
- GLOBAL_CONTEXT.fp_mul(&get_astref(lhs), &get_astref(rhs), rm.unwrap_or_default())?,
+ GLOBAL_CONTEXT.fp_mul(&lhs.get().inner, &rhs.get().inner, rm.unwrap_or_default())?,
)
}
#[pyfunction(name = "fpDiv", signature = (lhs, rhs, rm = None))]
pub fn FpDiv(
py: Python,
- lhs: PyRef,
- rhs: PyRef,
+ lhs: Bound,
+ rhs: Bound,
rm: Option,
) -> Result, ClaripyError> {
- py_ast_from_astref(
+ FP::new(
py,
- GLOBAL_CONTEXT.fp_div(&get_astref(lhs), &get_astref(rhs), rm.unwrap_or_default())?,
+ GLOBAL_CONTEXT.fp_div(&lhs.get().inner, &rhs.get().inner, rm.unwrap_or_default())?,
)
}
#[pyfunction(name = "fpSqrt", signature = (lhs, rm = None))]
-pub fn FpSqrt(py: Python, lhs: PyRef, rm: Option) -> Result, ClaripyError> {
- py_ast_from_astref(
+pub fn FpSqrt(py: Python, lhs: Bound, rm: Option) -> Result, ClaripyError> {
+ FP::new(
py,
- GLOBAL_CONTEXT.fp_sqrt(&get_astref(lhs), rm.unwrap_or_default())?,
+ GLOBAL_CONTEXT.fp_sqrt(&lhs.get().inner, rm.unwrap_or_default())?,
)
}
#[pyfunction(name = "FpEq", signature = (lhs, rhs))]
-pub fn FpEq(py: Python, lhs: PyRef, rhs: PyRef) -> Result, ClaripyError> {
- py_ast_from_astref(
+pub fn FpEq(py: Python, lhs: Bound, rhs: Bound) -> Result, ClaripyError> {
+ Bool::new(
py,
- GLOBAL_CONTEXT.fp_eq(&get_astref(lhs), &get_astref(rhs))?,
+ GLOBAL_CONTEXT.fp_eq(&lhs.get().inner, &rhs.get().inner)?,
)
}
#[pyfunction(name = "fpNeq", signature = (lhs, rhs))]
-pub fn FpNeq(py: Python, lhs: PyRef, rhs: PyRef) -> Result, ClaripyError> {
- py_ast_from_astref(
+pub fn FpNeq(py: Python, lhs: Bound, rhs: Bound) -> Result