microsoft/rulesxp
Rust
Captured source
source ↗microsoft/rulesxp
Description: Mini Rules evaluator for JSONLogic or S-expression based rules
Language: Rust
License: MIT
Stars: 3
Forks: 2
Open issues: 3
Created: 2025-10-01T00:57:27Z
Pushed: 2026-08-01T10:25:39Z
Default branch: main
Fork: no
Archived: no
README:
!RulesXP   [![CI]][actions] [![Fuzzing]][fuzz] [![codecov]][codecov-link] [![Crates.io]][crates.io] [![Documentation]][docs.rs]
RulesXP: Multi-Language Rules Expression Evaluator
RulesXP is a minimalistic expression evaluator that supports both JSONLogic and Scheme syntax with strict typing. It's designed for reliable rule evaluation with predictable behavior.
Note that this project is a work in progress and the API and feature set are expected to change
[CI]: https://github.com/microsoft/rulesxp/workflows/CI/badge.svg [actions]: https://github.com/microsoft/rulesxp/actions/workflows/ci.yml [Fuzzing]: https://github.com/microsoft/rulesxp/actions/workflows/fuzz.yml/badge.svg [fuzz]: https://github.com/microsoft/rulesxp/actions/workflows/fuzz.yml [codecov]: https://codecov.io/gh/microsoft/rulesxp/graph/badge.svg [codecov-link]: https://codecov.io/gh/microsoft/rulesxp [crates.io]: https://crates.io/crates/rulesxp [Documentation]: https://docs.rs/rulesxp/badge.svg [docs.rs]: https://docs.rs/rulesxp
Features
Dual Language Support
The project supports minimalistic subsets of:
- [JSONLogic](https://jsonlogic.com/): JSON-based rules engine syntax
- [Scheme R7RS](https://en.wikipedia.org/wiki/Scheme_\(programming_language\)): Small Lisp-family functional programming syntax
Strict Typing
- No Type Coercion:
1 !== "1"and0 !== false. No "truthiness" or automatic conversions - Type Error Detection: Type mismatches caught at evaluation time
Core Data Types
- Numbers: 64-bit integers (
42,-5,#xFF) - Booleans:
true/false(JSONLogic) or#t/#f(Scheme) - Strings:
"hello world" - Lists:
[1,2,3](JSONLogic) or(list 1 2 3)(Scheme) - Symbols: Identifiers like
foo,+,>=
Language Examples
JSONLogic Syntax
{"===": [1, 1]} // Strict equality
{"and": [true, false]} // Boolean logic
{"+": [1, 2, 3]} // Arithmetic
{"if": [true, "yes", "no"]} // Conditionals
{"":[5,3]}]}` | `(and #t (> 5 3))` | `true` |
## Installation & Usage
### As a Library
Add to your `Cargo.toml`:[dependencies] rulesxp = "0.1.0"
### Basic Usage
use rulesxp::{jsonlogic::parse_jsonlogic, scheme::parse_scheme, evaluator::*};
fn main() -> Result> { let mut env = create_global_env();
// JSONLogic evaluation let jsonlogic_expr = parse_jsonlogic(r#"{"and": [true, {">": [5, 3]}]}"#)?; let result = eval(&jsonlogic_expr, &mut env)?; println!("Result: {}", result); // true
// Scheme evaluation let scheme_expr = parse_scheme("(and #t (> 5 3))")?; let result = eval(&scheme_expr, &mut env)?; println!("Result: {}", result); // #t
Ok(()) }
### Command Line Tools #### Interactive REPL (a demo is also available)
cargo run --example repl --features="scheme jsonlogic"
## Supported Operations
### Arithmetic
- `+`, `-`, `*`: Basic arithmetic with overflow detection
- Supports variadic operations: `(+ 1 2 3 4)` or `{"+": [1,2,3,4]}`
### Comparisons
- `===`, `!==`: Strict equality (no type coercion)
- `>`, `=`, ` i64 {
a + b
}
// Fallible builtin: returns Result
fn safe_div(a: i64, b: i64) -> Result {
if b == 0 {
Err(Error::EvalError("division by zero".into()))
} else {
Ok(a / b)
}
}
let mut env = evaluator::create_global_env();
env.register_builtin_operation::("add2", add2);
env.register_builtin_operation::("safe-div", safe_div);
// Now you can call (add2 7 5) or (safe-div 6 3) from Scheme
// Or you can call {"add2" : [7, 5]} or {"safe-div" : [6, 3]} from JSONLogicList and variadic builtins
For list-style and variadic behavior, use the iterator-based parameter types from rulesxp::evaluator.
use rulesxp::{Error, Value, evaluator};
use rulesxp::evaluator::{Arity, NumIter, ValueIter};
// Single list argument: (sum-list (list 1 2 3 4)) => 10
fn sum_list(nums: NumIter) -> i64 {
nums.sum()
}
// Variadic over all arguments: (count-numbers 1 "x" 2 #t 3) => 3
fn count_numbers(args: ValueIter) -> i64 {
args.filter(|v| matches!(v, Value::Number(_))).count() as i64
}
let mut env = evaluator::create_global_env();
// List parameter from a single list argument
env.register_builtin_operation::,)>("sum-list", sum_list);
// Variadic builtin with explicit arity metadata
env.register_variadic_builtin_operation::,)>(
"count-numbers",
Arity::AtLeast(0),
count_numbers,
);The typed registration APIs currently support:
- Parameter types (as elements of the
Argstuple): i64(number)bool(boolean)&str(borrowed string slices)Value(owned access to the raw AST value)ValueIter(iterate over&Valuefrom a list/rest argument)NumIter(iterate over numeric elements asi64)BoolIter(iterate over boolean elements asbool)StringIter(iterate over string elements as&str)
- Return types:
ResultResultwhereT: Into(for examplei64,
bool, &str, arrays/vectors of those types, or Vec)
- bare
TwhereT: Into(for infallible helpers, which are
automatically wrapped as Ok(T))
Arity is enforced automatically. Conversion errors yield TypeError, and builtin errors are surfaced directly as Error values.
Current Status
Implemented
- [x] JSONLogic and Scheme parsers
- [x] Core arithmetic, boolean, and comparison operations
- [x] String operations and list construction
- [x] Error handling with clear messages
- [x] Interactive REPL with dual-language support
Future Plans
- [ ] Additional language syntax support
- [ ] Stabilized Rust API
- [ ] ABI for FFI from C++/C#
Minimum supported Rust version
Rust 1.90.
Contributing
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit Contributor License Agreements.
When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the...
Excerpt shown — open the source for the full document.