### 10 releases

0.2.0 | Sep 7, 2022 |
---|---|

0.1.2 | Sep 2, 2022 |

0.1.1 | Aug 28, 2022 |

0.0.6 | Aug 26, 2022 |

0.0.2 | Jan 23, 2022 |

#**125** in Parser tooling

**MIT**license

23KB

362 lines

**m**athematical **ex**pression **e**valuator.

## How to Use

`use` `mexe``::`eval`;`
`fn` `main``(``)`` ``{`
`let` forty_six `=` `eval``(``"`(5 * 8) + 6`"``)``.``unwrap``(``)``;`
`let` two `=` `eval``(``"`1 + 1`"``)``.``unwrap``(``)``;`
`println!``(``"``{}` & `{}``"``,` forty_six`,` two`)``;`
`assert_eq!``(`forty_six`,` `46.``0``)``;`
`assert_eq!``(`two`,` `2.``0``)``;`
`}`

Note: the above

s work, but for float comparison in general use a
crate such as `assert_eq`

.`float-cmp`

## Why?

If you need to evaluate simple arithmetic expressions, this crate offers a fast and lightweight solution.

In our current benchmarks,
it's about 4-10x faster than

, about 2x faster than `meval`

, and
the fully-featured `fasteval`

is generally the slowest. Note that those crates
do much more than `evalexpr`

-- especially `mexe`

. Our focus on a very small
problem makes it easier for us to ship a fast and lean library.`evalexpr`

## Includes

- sum
- subtraction
- multiplication
- division
- integers
- floats
- parentheses
- arbitrary whitespace

Floats are represented as

where `X .Y`

`X`

and `Y`

are non-empty sequences of
digits. The notation with exponents for floats or omitting either side of the
point is not accepted.## Goals

- Minimal
- Fast: O(n)
- No dependencies
- Minimal allocations
- Thoroughly tested

## Run Tests and Benchmarks

Unit tests and integration tests:

`cargo`` test`

We leverage the

crate to generate valid
random inputs for `glc`

. The command below will run an ignored integration test
that runs indefinitely and shows the output in the terminal until you stop it
with `mexe`

:`CTRL``+`C

`cargo`` test`` --`test integration without_bounds` --`` --nocapture --ignored`

Benchmarks:

`cargo`` bench`` --`` bench_cmp ``#`` comparison with other crates
`cargo bench -- bench_mexe # only mexe

### Running the fuzzer

Fuzz tests have been ran with cargo-fuzz.

To run it yourself, you need to install the nightly toolchain
(

) and the tool itself:
`rustup`` toolchain install nightly`

(check for more detailed instructions and
dependencies in the project's readme).`cargo`` install cargo-fuzz`

After that run:

`cargo`` fuzz init`
`cargo`` fuzz add fn_eval`

Go to

and paste this code:`fuzz/fuzz_targets/fn_eval.rs`

`#!``[``no_main``]`
`use` `libfuzzer_sys``::`fuzz_target`;`
`fuzz_target!``(``|``data``:` `&`[`u8`]`|` `{`
`//` fuzzed code goes here
`if` `let` `Ok``(`text`)` `=` `std``::``str``::`from_utf8`(`data`)` `{`
`let` `_` `=` `mexe``::`eval`(`text`)``;`
`}`
`}``)``;`

Now finally run:

`cargo`` +nightly fuzz run fn_eval`

## Grammar

`E ``->` T E`'`
E`'` `->` `+` T E`'`
E`'` `->` `-` T E`'`
E`'` `->` ε
T `->` F T`'`
T`'` `->` `*` F T`'`
T`'` `->` `/` F T`'`
T`'` `->` ε
F `->` `(` E `)`
F `->` n
F `->` `-` `(` E `)`
F `->` `-` n

where

is the empty string and `ε`

is a terminal number token. Grammar idea
adapted from this post.`n`

Our first implementation uses an LL(1) parser.