Expand description

lavendeux-parser is an exensible parsing engine for mathematical expressions. It supports variable and function assignments, a variety of datatypes, and can be extended easily at runtime through extensions written in javascript.

Extensions are run in a sandboxed environment with no host or network access. This project is the engine behind Lavendeux.

For help on the syntax of expressions, visit https://rscarson.github.io/lavendeux

Getting Started

To use it, create a ParserState object, and use it to tokenize input with Token::new:

use lavendeux_parser::{ParserState, ParserError, Token, Value};
 
fn main() -> Result<(), ParserError> {
    // Create a new parser, and tokenize 2 lines
    let mut state : ParserState = ParserState::new();
    let lines = Token::new("x=9\nsqrt(x) @bin", &mut state)?;
 
    // The resulting token contains the resulting values and text
    assert_eq!(lines.text(), "9\n0b11");
    assert_eq!(lines.child(1).unwrap().value(), Value::Integer(3));
     
    Ok(())
}

The result will be a Token object:

use lavendeux_parser::{ParserState, ParserError, Token, Value};
 
fn main() -> Result<(), ParserError> {
    let mut state : ParserState = ParserState::new();
    let lines = Token::new("x=9\nsqrt(x) @bin", &mut state)?;
 
    // String representation of the full result
    assert_eq!(lines.text(), "9\n0b11"); 
 
    // String representation of the first line's result
    assert_eq!(lines.child(0).unwrap().text(), "9");
 
    // Actual value of the first line's result
    // Values are integers, floats, booleans or strings
    let value = lines.child(0).unwrap().value();
    assert_eq!(value.as_int().unwrap(), 9);
    assert_eq!(true, matches!(value, Value::Integer(_)));
 
    Ok(())
}

A number of functions and @decorators are available for expressions to use - add more using the state:

use lavendeux_parser::{ParserState, ParserError, DecoratorDefinition, FunctionDefinition, FunctionArgument, Value};
use lavendeux_parser::errors::*;
  
let mut state : ParserState = ParserState::new();
state.decorators.register(DecoratorDefinition {
    name: &["upper", "uppercase"],
    description: "Outputs an uppercase version of the input",
    argument: ExpectedTypes::Any,
    handler: |_, input| Ok(input.as_string().to_uppercase())
});
 
// Functions take in an array of values, and return a single value
state.functions.register(FunctionDefinition {
    name: "echo",
    description: "Echo back the provided input",
    arguments: || vec![
        FunctionArgument::new_required("input", ExpectedTypes::String),
    ],
    handler: |_, args: &[Value]| {
        Ok(Value::String(args[0].as_string()))
    }
});
 
// Expressions being parsed can now call new_function(), and use the @new_decorator

Using Extensions

Extensions give a more flexible way of adding functionality at runtime. Extensions are written in javascript.

Extensions are enabled by default, and can be excluded by disabling the crate’s “extensions” feature

Extensions can be loaded as follows:

use lavendeux_parser::{ParserState, ParserError, Value, Token};
 
fn main() -> Result<(), ParserError> {
    let mut state : ParserState = ParserState::new();
 
    // Load one extension
    state.extensions.load("example_extensions/colour_utils.js")?;
 
    // Load a whole directory
    state.extensions.load_all("./example_extensions")?;
 
    // Once loaded, functions and @decorators decribed in the extensions
    // can be called in expressions being parsed
    let token = Token::new("complement(0xFF0000) @colour", &mut state)?;
    assert_eq!(token.text(), "#ffff00");
    Ok(())
}

Extensions give a more flexible way of adding functionality at runtime. Extensions are written in javascript.

Re-exports

pub use errors::ParserError;

Modules

Module defining errors that can occur during parsing

Structs

Holds the definition of a builtin callable decorator

Holds a set of callable decorators

Represents a single loaded extension. It describes the functions and decorators it adds, as well as metadata about the extension and it’s author.

Describes an argument for a callable function

Holds the definition of a builtin callable function

Holds a set of callable functions

Represents the current state of the parser Holds the functions, decorators, variables and extensions available for expressions to use

Represents a token tree for a parsed expression The root contains the text result of parsing the expression, as well as one child per line being parsed

Enums

Represents a single value resulting from a calculation Can take the form of an integer, float, boolean or string

Type Definitions

The datatype for floating point values

The datatype for integer values