5 releases (3 breaking)

0.4.0-beta.1 Sep 22, 2024
0.3.0 May 24, 2021
0.2.0 Dec 5, 2020
0.2.0-beta.1 Oct 4, 2020
0.1.0 Jun 1, 2020

#251 in Programming languages

MIT/Apache

505KB
11K SLoC

Simple Arithmetic Interpreter

Build Status License: MIT OR Apache-2.0 rust 1.70+ required no_std supported

Links: Docs on docs.rs crate docs (master)

This library provides a simple interpreter, which can be used for some grammars recognized by arithmetic-parser, e.g., integer-, real-, complex-valued and modular arithmetic. (Both built-in integer types and big integers from num-bigint are supported.) The interpreter provides support for native functions, which allows to overcome some syntax limitations (e.g., the lack of control flow can be solved with native if / while functions). Native functions and opaque reference types allow effectively embedding the interpreter into larger Rust applications.

The interpreter is somewhat opinionated on how to interpret language features (e.g., in terms of arithmetic ops for tuple / object arguments). On the other hand, handling primitive types is fully customizable, just like their parsing in arithmetic-parser. The primary goal is to be intuitive for simple grammars (such as the aforementioned real-valued arithmetic).

The interpreter is quite slow – 1–2 orders of magnitude slower than native arithmetic.

Usage

Add this to your Crate.toml:

[dependencies]
arithmetic-eval = "0.4.0-beta.1"

Script samples

A simple script relying entirely on standard functions.

minmax = |...xs| xs.fold(#{ min: INF, max: -INF }, |acc, x| #{
     min: if(x < acc.min, x, acc.min),
     max: if(x > acc.max, x, acc.max),
});
assert_eq(minmax(3, 7, 2, 4).min, 2);
assert_eq(minmax(5, -4, 6, 9, 1), #{ min: -4, max: 9 });

Recursive quick sort implementation:

sort = defer(|sort| {
    // `defer` allows to define a function recursively
    |xs| {
        if(xs == (), || (), || {
            (pivot, ...rest) = xs;
            lesser_part = sort(rest.filter(|x| x < pivot));
            greater_part = sort(rest.filter(|x| x >= pivot));
            lesser_part.push(pivot).merge(greater_part)
        })()
    }
});

assert_eq(sort((1, 7, -3, 2, -1, 4, 2)), (-3, -1, 1, 2, 2, 4, 7));

// Generate a larger array to sort. `rand_num` is a custom native function
// that generates random numbers in the specified range.
xs = sort(array(1000, |_| rand_num(0, 100)));
// Check that elements in `xs` are monotonically non-decreasing.
{ sorted } = xs.fold(
    #{ prev: -1, sorted: true },
    |{ prev, sorted }, x| #{
        prev: x,
        sorted: sorted && prev <= x
    },
);
assert(sorted);

Defining a type:

Vector = {
    len = |{ x, y }| sqrt(x * x + y * y);
    scale = |self| if(self.x == 0 && self.y == 0,
        || self,
        || self / self.len(),
    )();
    #{ len, scale }
};

assert_close(#{ x: 3, y: 4 }.{Vector.len}(), 5);
// ...is same as
assert_close({Vector.len}(#{ x: 3, y: 4 }), 5);
scaled = #{ x: 3, y: -4 }.{Vector.scale}();
assert_close(scaled.x, 0.6);
assert_close(scaled.y, -0.8);

Please see the crate docs and examples for more examples.

See also

  • arithmetic-typing is a type checker / inference tool for ASTs evaluated by this crate.

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in arithmetic-eval by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~1.2–2MB
~38K SLoC