expr-solver-lib 1.0.3

A simple math expression solver library
Documentation
expr-solver-lib-1.0.3 has been yanked.

Rust

expr-solver

A mathematical expression evaluator library written in Rust with support for custom functions, constants, and bytecode compilation.

Features

  • Mathematical expressions - Arithmetic, comparisons, and built-in functions
  • 128-bit decimal precision - No floating-point errors using rust_decimal
  • Custom symbols - Register your own constants and functions
  • Rich error messages - Syntax errors with source location highlighting
  • Bytecode compilation - Compile expressions to portable binary format
  • Stack-based VM - Efficient execution on a virtual machine

How It Works

The library implements a classic compiler pipeline:

Source → Lexer → Parser → AST → Semantic Analysis → IR → Bytecode → VM
  1. Lexer - Tokenizes the input string into operators, numbers, and identifiers
  2. Parser - Uses operator precedence climbing to build an Abstract Syntax Tree (AST)
  3. Semantic Analysis - Resolves symbols and validates function arities
  4. IR Builder - Converts the AST into stack-based bytecode instructions
  5. Virtual Machine - Executes the bytecode on a stack-based VM

This architecture allows for:

  • Separating parsing from execution
  • Compiling expressions once and running them multiple times
  • Serializing compiled bytecode to disk for later use

Usage

As a Library

Add this to your Cargo.toml:

[dependencies]
expr-solver-lib = "1.0.3"

As a binary

Add this to your Cargo.toml:

[dependencies]
expr-solver-bin = "1.0.3"

Basic Example

use expr_solver::Eval;

fn main() {
    // Quick one-liner evaluation
    match Eval::evaluate("2+3*4") {
        Ok(result) => println!("Result: {}", result),
        Err(e) => eprintln!("Error: {}", e),
    }

    // Or create an evaluator instance for more control
    let mut eval = Eval::new("sqrt(16) + pi");
    match eval.run() {
        Ok(result) => println!("Result: {}", result),
        Err(e) => eprintln!("Error: {}", e),
    }
}

Advanced Example

use expr_solver::{Eval, SymTable};
use rust_decimal_macros::dec;

fn main() {
    // Create a custom symbol table
    let mut table = SymTable::stdlib();
    table.add_const("x", dec!(10)).unwrap();
    table.add_func("double", 1, false, |args| Ok(args[0] * dec!(2))).unwrap();

    // Evaluate with custom symbols
    let mut eval = Eval::with_table("double(x) + sqrt(25)", table);
    let result = eval.run().unwrap();
    println!("Result: {}", result); // 25
}

Compile and Execute

use expr_solver::Eval;
use std::path::PathBuf;

fn main() {
    // Compile expression to bytecode
    let mut eval = Eval::new("2 + 3 * 4");
    eval.compile_to_file(&PathBuf::from("expr.bin")).unwrap();

    // Load and execute the compiled bytecode
    let mut eval = Eval::new_from_file(PathBuf::from("expr.bin"));
    let result = eval.run().unwrap();
    println!("Result: {}", result); // 14
}

Viewing Assembly

You can inspect the generated bytecode as human-readable assembly:

use expr_solver::Eval;

fn main() {
    let mut eval = Eval::new("2 + 3 * 4");
    println!("{}", eval.get_assembly().unwrap());
}

Output:

; VERSION 1.0.2
0000 PUSH 2
0001 PUSH 3
0002 PUSH 4
0003 MUL
0004 ADD

The assembly shows the stack-based bytecode instructions that will be executed by the VM.

Precision and Data Types

All calculations are performed using 128-bit Decimal type from the rust_decimal crate, providing exact decimal arithmetic without floating-point errors.

Note: Some trigonometric and hyperbolic functions (asin, acos, atan, atan2, sinh, cosh, tanh, cbrt, exp2, log2, hypot) internally convert to/from f64 for computation, which may introduce minor precision differences. All constants (pi, e, tau, ln2, ln10, sqrt2) are computed using native Decimal operations for maximum precision.

Built-in Functions

Function Arguments Description Notes
Arithmetic
abs(x) 1 Absolute value
sign(x) 1 Sign (-1, 0, or 1)
floor(x) 1 Round down to integer
ceil(x) 1 Round up to integer
round(x) 1 Round to nearest integer
trunc(x) 1 Truncate to integer
fract(x) 1 Fractional part
mod(x, y) 2 Remainder of x/y
clamp(x, min, max) 3 Constrain value between bounds
Trigonometry
sin(x) 1 Sine
cos(x) 1 Cosine
tan(x) 1 Tangent
asin(x) 1 Arcsine Uses f64 internally
acos(x) 1 Arccosine Uses f64 internally
atan(x) 1 Arctangent Uses f64 internally
atan2(y, x) 2 Two-argument arctangent Uses f64 internally
Hyperbolic
sinh(x) 1 Hyperbolic sine Uses f64 internally
cosh(x) 1 Hyperbolic cosine Uses f64 internally
tanh(x) 1 Hyperbolic tangent Uses f64 internally
Exponential/Logarithmic
sqrt(x) 1 Square root
cbrt(x) 1 Cube root Uses f64 internally
pow(x, y) 2 x raised to power y
exp(x) 1 e raised to power x
exp2(x) 1 2 raised to power x Uses f64 internally
log(x) 1 Natural logarithm
log2(x) 1 Base-2 logarithm Uses f64 internally
log10(x) 1 Base-10 logarithm
hypot(x, y) 2 Euclidean distance √(x²+y²) Uses f64 internally
Variadic
min(x, ...) 1+ Minimum value Accepts any number of arguments
max(x, ...) 1+ Maximum value Accepts any number of arguments
sum(x, ...) 1+ Sum of values Accepts any number of arguments
avg(x, ...) 1+ Average of values Accepts any number of arguments
Special
if(cond, t, f) 3 Conditional: returns t if cond≠0, else f

Built-in Constants

Constant Value Description
pi 3.14159... π (pi)
e 2.71828... Euler's number
tau 6.28318... 2π (tau)
ln2 0.69314... Natural logarithm of 2
ln10 2.30258... Natural logarithm of 10
sqrt2 1.41421... Square root of 2

Note: All function and constant names are case-insensitive.

Supported Operators

Operator Type Associativity Precedence Description
! Postfix Unary Left 6 Factorial
^ Binary Right 5 Exponentiation
- Prefix Unary Right 4 Negation
*, / Binary Left 3 Multiplication, Division
+, - Binary Left 2 Addition, Subtraction
==, !=, <, <=, >, >= Binary Left 1 Comparisons (return 1 or 0)
() Grouping - - Parentheses for grouping

Command Line Usage

# Evaluate an expression
expr-solver "2 + 3 * 4"

# Use the -e flag
expr-solver -e "sin(pi/2)"

# Define custom constants
expr-solver -D x=10 -D y=20 "x + y"

# Compile to binary
expr-solver -e "2+3*4" -o expr.bin

# Execute compiled binary
expr-solver -i expr.bin

# View assembly
expr-solver -e "2+3" -a

# List available functions and constants
expr-solver -t

Testing

Run the test suite:

# Run all tests
cargo test

License

This project is licensed under the MIT License.