[−][src]Crate arithmetic_eval
Simple interpreter for ASTs produced by arithmetic-parser
.
Assumptions
- There is only one numeric type, which is complete w.r.t. all arithmetic operations.
This is expressed via type constraints, in
Interpreter
. - Arithmetic operations are assumed to be infallible; panics during their execution are not caught by the interpreter.
- Grammar literals are directly parsed to the aforementioned numeric type.
These assumptions do not hold for some grammars parsed by the crate. For example, finite cyclic groups have two types (scalars and group elements) and thus cannot be effectively interpreted.
Semantics
- All variables are immutable. Re-declaring a var shadows the previous declaration.
- Functions are first-class (in fact, a function is just a variant of the
Value
enum). - Functions can capture variables (including other functions). All captures are by value.
- Arithmetic operations are defined on primitive vars and tuples. With tuples, operations
are performed per-element. Binary operations require tuples of the same size,
or a tuple and a primitive value. As an example,
(1, 2) + 3
and(2, 3) / (4, 5)
are valid, but(1, 2) * (3, 4, 5)
isn't. - Methods are considered syntactic sugar for functions, with the method receiver considered
the first function argument. For example,
(1, 2).map(sin)
is equivalent tomap((1, 2), sin)
. - No type checks are performed before evaluation.
- Type annotations are completely ignored. This means that the interpreter may execute code that is incorrect with annotations (e.g., assignment of a tuple to a variable which is annotated to have a numeric type).
Examples
use arithmetic_parser::{grammars::F32Grammar, Grammar, GrammarExt, Span}; use arithmetic_eval::{fns, Interpreter, Value}; const MIN: fns::Binary<fn(f32, f32) -> f32> = fns::Binary::new(|x, y| if x < y { x } else { y }); const MAX: fns::Binary<fn(f32, f32) -> f32> = fns::Binary::new(|x, y| if x > y { x } else { y }); let mut context = Interpreter::new(); // Add some native functions to the interpreter. context .insert_native_fn("min", MIN) .insert_native_fn("max", MAX) .insert_native_fn("assert", fns::Assert); let program = r#" # The interpreter supports all parser features, including # function definitions, tuples and blocks. order = |x, y| (min(x, y), max(x, y)); assert(order(0.5, -1) == (-1, 0.5)); (_, M) = order(3^2, { x = 3; x + 5 }); M "#; let program = F32Grammar::parse_statements(Span::new(program)).unwrap(); let ret = context.evaluate(&program).unwrap(); assert_eq!(ret, Value::Number(9.0));
Modules
fns | Standard functions for the interpreter. |
Structs
Backtrace | Call backtrace. |
BacktraceElement | Function call. |
CallContext | Opaque context for native calls. |
ErrorWithBacktrace | Error with the associated backtrace. |
ExecutableModule | Executable module together with its imports. |
InterpretedFn | Function defined within the interpreter. |
Interpreter | Simple interpreter for arithmetic expressions. |
SpannedEvalError | Evaluation error together with one or more relevant code spans. |
Enums
AuxErrorInfo | Auxiliary information about error. |
EvalError | Errors that can occur during interpreting expressions and statements. |
Function | Function definition. Functions can be either native (defined in the Rust code) or defined in the interpreter. |
RepeatedAssignmentContext | Context for |
TupleLenMismatchContext | Context for |
Value | Values produced by expressions during their interpretation. |
Traits
NativeFn | Function on zero or more |
Type Definitions
EvalResult | Result of an expression evaluation. |
SpannedValue | Value together with a span that has produced it. |