RepoMicrosoftMicrosoftpublished Oct 1, 2025seen Jun 26

microsoft/rulesxp

Rust

Open original ↗

Captured source

source ↗
published Oct 1, 2025seen Jun 26captured 2whttp 200method plain

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" and 0 !== 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 JSONLogic

List 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 Args tuple):
  • i64 (number)
  • bool (boolean)
  • &str (borrowed string slices)
  • Value (owned access to the raw AST value)
  • ValueIter (iterate over &Value from a list/rest argument)
  • NumIter (iterate over numeric elements as i64)
  • BoolIter (iterate over boolean elements as bool)
  • StringIter (iterate over string elements as &str)
  • Return types:
  • Result
  • Result where T: Into (for example i64,

bool, &str, arrays/vectors of those types, or Vec)

  • bare T where T: 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.