Exprimo
CAUTION: Beware of Sneaky Bugs in the Early Project Stages! There will be bug, probably alot at first :D
Exprimo is a JavaScript evaluator written in Rust, inspired by the functionality of angular-expressions. Designed to be simple and blazingly fast.
Description
Exprimo parses and evaluates JavaScript expressions efficiently and securely. It utilizes the power of Rust and its excellent memory safety guarantees to provide a reliable and fast JavaScript expression evaluator.
Installation
Before you can use Exprimo, you need to have Rust installed on your system. If you don't have it installed, you can download Rust from the official website here.
Once Rust is installed, you can install Exprimo by running:
Trace logging to console can be added to the package, it is by default disabled as probably don't need it unless working on it, or need to debug AST error if required.
This will install Scribe Rust and will need LOG_LEVEL=TRACE in environment variables for logs to output.
= { = "*", = ["logging"]
Usage
First, you need to import Exprimo and create an instance of Evaluator:
use ; // CustomFunction for example context
use Value;
use HashMap;
use Arc; // For custom functions map
// 1. Set up your context (variables accessible in expressions)
let mut context = new;
context.insert;
context.insert;
// 2. Define custom functions map (even if empty)
let custom_functions: = new;
// Example: To use custom functions, you would populate this map:
// #[derive(Debug)] struct MyToUpper;
// impl CustomFunction for MyToUpper { /* ... */ }
// custom_functions.insert("toUpperCase".to_string(), Arc::new(MyToUpper));
// 3. Create the evaluator instance
// (Assuming no logger for this basic example for brevity; add logger if feature "logging" is enabled)
let evaluator = new;
Then, you can evaluate JavaScript expressions:
let age_expr = "user_age > 25";
// Example with a (hypothetical) custom function if it were registered:
// let name_expr = "toUpperCase(user_name)";
let is_older = evaluator.evaluate.unwrap;
// let uppercased_name = evaluator.evaluate(name_expr).unwrap();
println!; // >Is older: true
// println!("Uppercased name: {}", uppercased_name);
Truthiness Rules
Exprimo evaluates the truthiness of values as follows:
- Booleans:
trueis truthy,falseis falsy. - Null:
nullis falsy. - Numbers:
0andNaNare falsy. All other numbers (including negative numbers and Infinity) are truthy. - Strings: Empty strings (
"") are falsy. All other strings are truthy. - Arrays: Empty arrays (
[]) are currently treated as falsy. This behavior might differ from standard JavaScript, where empty arrays are truthy. - Objects: Empty objects (
{}) are currently treated as falsy. This behavior might differ from standard JavaScript, where empty objects are truthy.
Custom Functions
You can extend Exprimo's capabilities by defining your own functions in Rust and making them available to the evaluator.
Custom functions must implement the exprimo::CustomFunction trait. This trait requires a call method that takes a slice of serde_json::Value arguments (&[Value]) and returns a Result<Value, exprimo::CustomFuncError>.
Example: A toUpperCase function
use ;
use Value;
use HashMap;
use Arc;
use fmt; // Required for #[derive(Debug)] on the custom function struct
// The CustomFunction trait requires the Debug trait.
;
Key points for custom functions:
- Your struct must implement
exprimo::CustomFunction(which also requiresstd::fmt::Debug). - The
callmethod receives arguments as&[Value]. You are responsible for:- Checking argument count (arity).
- Checking argument types.
- Performing the function logic.
- Returning
Ok(Value)on success orErr(exprimo::CustomFuncError)on failure (e.g.,CustomFuncError::ArityError,CustomFuncError::ArgumentError).
- Wrap your function instance in
Arc::new()before inserting into thecustom_functionsmap. - The keys in the
custom_functionsmap are the names used to call the functions in expressions.
Built-in Properties and Methods
Exprimo provides a few built-in properties and methods for common operations, primarily for arrays and objects.
Arrays
Arrays in Exprimo are represented by serde_json::Value::Array.
-
.length: Returns the number of elements in an array.- Example: If
myArrayis[10, 20, 30]:myArray. // Evaluates to 3
- Example: If
-
.includes(valueToFind): Checks if an array containsvalueToFind.- It uses an abstract equality comparison similar to JavaScript's
SameValueZero(e.g.,NaNis equal toNaN,+0is equal to-0). - Returns
trueif the value is found,falseotherwise. - Example:
. // Evaluates to true . // Evaluates to false
- It uses an abstract equality comparison similar to JavaScript's
Objects
Objects in Exprimo are represented by serde_json::Value::Object.
.hasOwnProperty(key): Checks if an object contains the specifiedkeyas its own direct property.- The
keyargument is coerced to a string. For example, if you pass a number123, it will be treated as the string"123". - Returns
trueif the key is found,falseotherwise. - Example: If
myObjectis{ "name": "Alice", "age": 30 }:myObject. // Evaluates to true myObject. // Evaluates to false . // Evaluates to true (123 is coerced to "123")
- The
Examples
Running examples
LOG_LEVEL=TRACE
Contributing
Contributions to Exprimo are welcome! Please submit a pull request on GitHub.
License
Exprimo is licensed under the MIT license. Please see the LICENSE file in the GitHub
repository for more information.