Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Nonanti/mathcore/llms.txt

Use this file to discover all available pages before exploring further.

MathCore includes a built-in recursive-descent parser (powered by nom) that converts human-readable mathematical expression strings into Expr trees. The entry point is MathCore::parse(), a static method that you can call without constructing a MathCore instance. The parser handles the full range of expressions: arithmetic, exponentiation, factorials, absolute values, function calls, and complex number literals — all in one pass, with correct operator precedence baked in.

MathCore::parse()

pub fn parse(expression: &str) -> Result<Expr, MathError>
Parses expression and returns the root Expr node on success, or a MathError::ParseError if the input is malformed or contains trailing characters that cannot be consumed.
use mathcore::MathCore;

// Parse a simple arithmetic expression
let expr = MathCore::parse("2 + 3 * 4")?;
println!("{}", expr); // ((2 + (3 * 4)))

// Parse a symbolic polynomial
let poly = MathCore::parse("x^3 - 2*x + 1")?;

// Parse a function call
let trig = MathCore::parse("sin(pi / 2)")?;

// Parse a complex literal
let z = MathCore::parse("3+4i")?;
Leading and trailing whitespace is stripped automatically. Spaces around operators are optional: "x+1", "x + 1", and "x + 1" all produce the same tree.

Operator Precedence

The parser implements standard mathematical precedence, from lowest to highest:
LevelOperatorsAssociativity
1+, -Left
2*, /, %Left
3^Right
4! (postfix)
5Unary -
6Primaries (literals, function calls, parentheses, |…|)
Because ^ is right-associative, 2^3^4 is parsed as 2^(3^4), matching conventional mathematical notation.
use mathcore::MathCore;

// Precedence: * binds tighter than +
let expr = MathCore::parse("2 + 3 * 4").unwrap();
// Tree: (2 + (3 * 4))  →  evaluates to 14

// Precedence: ^ binds tighter than *
let expr = MathCore::parse("2 * 3 ^ 4").unwrap();
// Tree: (2 * (3 ^ 4))  →  evaluates to 162

// Parentheses override precedence
let expr = MathCore::parse("(2 + 3) * 4").unwrap();
// Tree: ((2 + 3) * 4)  →  evaluates to 20

Supported Operators

Arithmetic Operators

OperatorNameExampleNotes
+Additionx + y
-Subtractionx - y
*Multiplicationx * y
/Divisionx / yRuntime DivisionByZero if denominator is zero
^Exponentiationx^2Right-associative
%Modulon % 3Real numbers only
!Factorial5!Postfix; non-negative integers only

Absolute Value

Absolute value is written with vertical bars, mirroring standard mathematical notation:
let expr = MathCore::parse("|x - 3|").unwrap();
// Produces: Expr::Unary { op: UnaryOp::Abs, expr: (x - 3) }
The bars may contain any expression, including nested function calls:
let expr = MathCore::parse("|sin(x) + cos(x)|").unwrap();
abs(x) (function form) and |x| (bar form) are both supported and produce the same Unary { op: UnaryOp::Abs, … } node.

Supported Functions

Trigonometric

SyntaxDescriptionArity
sin(x)Sine1
cos(x)Cosine1
tan(x)Tangent1
let math = mathcore::MathCore::new();
let val  = math.evaluate("sin(pi / 6)")?; // Expr::Number(0.5)
sec(x) is parsed as an Expr::Function { name: "sec", … } node, but the engine has no built-in evaluation rule for it. Calling evaluate or calculate on an expression containing sec will return MathError::UndefinedFunction("sec"). Parsing alone succeeds.

Exponential and Logarithmic

SyntaxDescriptionArity
exp(x)Natural exponential eˣ1
ln(x)Natural logarithm1
log(x, b)Logarithm base b2
sqrt(x)Square root1
MathCore::parse("exp(1)")?;       // e¹ ≈ 2.71828
MathCore::parse("ln(1)")?;        // 0.0
MathCore::parse("log(100, 10)")?; // 2.0
MathCore::parse("sqrt(9)")?;      // 3.0
sqrt of a negative number does not error — instead, the engine promotes the result to a complex value. For example, sqrt(-4) evaluates to Expr::Complex(0 + 2i).

Utility

SyntaxDescriptionArity
abs(x)Absolute value / complex norm1
min(a, b)Minimum of numeric arguments≥ 1
max(a, b)Maximum of numeric arguments≥ 1
MathCore::parse("min(3, 1, 4, 1, 5)")?; // parses successfully; evaluates to 1.0
MathCore::parse("max(a, b)")?;           // parses successfully; evaluation errors if a or b are symbolic
min and max require all arguments to evaluate to Expr::Number. Passing symbolic arguments returns MathError::InvalidOperation("min requires numeric arguments") at evaluation time.

Mathematical Constants

The following identifiers are resolved as numeric constants by the engine (via Context::with_defaults()):
NameValueSource constant
pi3.141592653589793f64::consts::PI
e2.718281828459045f64::consts::E
tau6.283185307179586f64::consts::TAU
The parser treats these as ordinary Symbol nodes; the engine resolves them against the context at evaluation time.
use mathcore::MathCore;

let math = MathCore::new();

let circle = math.calculate("2 * pi * 5").unwrap(); // circumference, r=5
let euler  = math.calculate("e^(pi)").unwrap();     // e^π ≈ 23.1407
let turn   = math.calculate("tau / 2").unwrap();    // π ≈ 3.14159

Complex Number Literals

Complex numbers are written as <real><sign><imag>i, where both the real and imaginary parts are numeric literals:
MathCore::parse("3+4i")?;   // Complex64 { re: 3.0, im:  4.0 }
MathCore::parse("1-2i")?;   // Complex64 { re: 1.0, im: -2.0 }
MathCore::parse("0+1i")?;   // Complex64 { re: 0.0, im:  1.0 }
The parser checks for the complex form before the plain number form, so 3+4i is consumed as a single token rather than 3 followed by +4i.
Complex literals are strictly <number><+|-><number>i with no spaces. 3 + 4i is not a complex literal — it is parsed as the addition of 3 and the multiplication of 4 by the symbol i.

Expression Syntax Examples

Input stringResulting Expr structure
"42"Number(42.0)
"3.14"Number(3.14)
"-2.5e-3"Number(-0.0025)
"x"Symbol("x")
"var_123"Symbol("var_123")
"3+4i"Complex(3.0 + 4.0i)
"x + 1"Binary { Add, Symbol("x"), Number(1.0) }
"x^2"Binary { Power, Symbol("x"), Number(2.0) }
"sin(x)"Function { "sin", [Symbol("x")] }
"log(x, 10)"Function { "log", [Symbol("x"), Number(10.0)] }
"5!"Unary { Factorial, Number(5.0) }
"|x - 1|"Unary { Abs, Binary { Subtract, Symbol("x"), Number(1.0) } }
"-(x + 1)"Unary { Negate, Binary { Add, Symbol("x"), Number(1.0) } }
"2 + 3 * 4"Binary { Add, Number(2.0), Binary { Multiply, Number(3.0), Number(4.0) } }

Variables and Identifiers

Any identifier that is not recognised as a built-in function name becomes an Expr::Symbol. Identifier syntax follows standard programming conventions: it must start with a letter or underscore, and may contain letters, digits, and underscores.
MathCore::parse("x")?;        // Symbol("x")
MathCore::parse("alpha")?;    // Symbol("alpha")
MathCore::parse("_temp")?;    // Symbol("_temp")
MathCore::parse("x_1")?;      // Symbol("x_1")
Symbols are resolved at evaluation time, not parse time. You can parse any expression with free variables and inspect the tree, simplify it, differentiate it, and so on. Values are only required when you call evaluate or calculate.
use mathcore::MathCore;
use std::collections::HashMap;

let math = MathCore::new();
let mut vars = HashMap::new();
vars.insert("x".to_string(), 3.0);

let result = math.evaluate_with_vars("x^2 + 2*x + 1", &vars).unwrap();
// → 16.0  (since (3)^2 + 2*(3) + 1 = 16)
Because pi, e, and tau are just Symbol nodes resolved in the default context, you can shadow them by inserting your own values into a custom Context. This is intentional, but use it carefully.

Build docs developers (and LLMs) love