[][src]Struct arithmetic_eval::ExecutableModule

pub struct ExecutableModule<'a, T> { /* fields omitted */ }

Executable module together with its imports.

An ExecutableModule is a result of compiling a Block of statements. A module can import Values, such as commonly used functions. Importing is performed when building the module.

After the module is created, it can be run. If the last statement of the block is an expression (that is, not terminated with a ;), it is the result of the execution; otherwise, the result is Value::void(). It is possible to run a module multiple times and to change imports by using Self::set_import().

In some cases (e.g., when building a REPL) it is useful to get not only the outcome of the module execution, but the intermediate results as well. Use Self::run_in_env() for such cases.

Examples

Basic usage

use arithmetic_parser::grammars::{F32Grammar, Parse, Untyped};
use arithmetic_eval::{fns, Comparisons, ExecutableModule, Prelude, Value};

let module = Untyped::<F32Grammar>::parse_statements("xs.fold(-INFINITY, max)")?;
let mut module = ExecutableModule::builder("test", &module)?
    .with_imports_from(&Prelude)
    .with_imports_from(&Comparisons)
    .with_import("INFINITY", Value::Number(f32::INFINITY))
    // Set remaining imports to a fixed value.
    .set_imports(|_| Value::void());

// With the original imports, the returned value is `-INFINITY`.
assert_eq!(module.run()?, Value::Number(f32::NEG_INFINITY));

// Imports can be changed. Let's check that `xs` is indeed an import.
assert!(module.imports().contains("xs"));
// ...or even
assert!(module.imports()["fold"].is_function());
// It's possible to iterate over imports, too.
let imports = module.imports().iter()
    .map(|(name, _)| name)
    .collect::<HashSet<_>>();
assert!(imports.is_superset(&HashSet::from_iter(vec!["max", "fold"])));

// Change the `xs` import and run the module again.
let array = [1.0, -3.0, 2.0, 0.5].iter().copied()
    .map(Value::Number)
    .collect();
module.set_import("xs", Value::Tuple(array));
assert_eq!(module.run()?, Value::Number(2.0));

Reusing a module

The same module can be run with multiple imports:

let block = Untyped::<F32Grammar>::parse_statements("x + y")?;
let mut module = ExecutableModule::builder("test", &block)?
    .with_import("x", Value::Number(3.0))
    .with_import("y", Value::Number(5.0))
    .build();
assert_eq!(module.run()?, Value::Number(8.0));

let mut env = Environment::from_iter(module.imports());
env.insert("x", Value::Number(-1.0));
assert_eq!(module.run_in_env(&mut env)?, Value::Number(4.0));

Behavior on errors

run_in_env modifies the environment even if an error occurs during execution:

let module = Untyped::<F32Grammar>::parse_statements("x = 5; assert_eq(x, 4);")?;
let module = ExecutableModule::builder("test", &module)?
    .with_imports_from(&Assertions)
    .build();

let mut env = Environment::from_iter(module.imports());
assert!(module.run_in_env(&mut env).is_err());
assert_eq!(env["x"], Value::Number(5.0));

Implementations

impl<'a, T> ExecutableModule<'a, T>[src]

pub fn id(&self) -> &dyn ModuleId[src]

Gets the identifier of this module.

pub fn set_import(&mut self, name: &str, value: Value<'a, T>) -> &mut Self[src]

Sets the value of an imported variable.

Panics

Panics if the variable with the specified name is not an import. Check that the import exists beforehand via imports().contains() if this is unknown at compile time.

pub fn imports(&self) -> &ModuleImports<'a, T>[src]

Returns shared reference to imports of this module.

pub fn with_arithmetic<'s>(
    &'s self,
    arithmetic: &'s dyn OrdArithmetic<T>
) -> WithArithmetic<'s, 'a, T>
[src]

Combines this module with the specified arithmetic.

impl<'a, T: Clone + Debug> ExecutableModule<'a, T>[src]

pub fn builder<G, Id>(
    id: Id,
    block: &Block<'a, G>
) -> Result<ExecutableModuleBuilder<'a, T>, Error<'a>> where
    Id: ModuleId,
    G: Grammar<Lit = T>, 
[src]

Starts building a new module.

impl<'a, T: Clone + Debug> ExecutableModule<'a, T> where
    StdArithmetic: OrdArithmetic<T>, 
[src]

pub fn run(&self) -> Result<Value<'a, T>, ErrorWithBacktrace<'a>>[src]

Runs the module with the current values of imports. This is a read-only operation; neither the imports, nor other module state are modified by it.

pub fn run_in_env(
    &self,
    env: &mut Environment<'a, T>
) -> Result<Value<'a, T>, ErrorWithBacktrace<'a>>
[src]

Runs the module with the specified Environment. The environment may contain some of module imports; they will be used to override imports defined in the module.

On execution, the environment is modified to reflect assignments in the topmost scope of the module. The modification takes place regardless of whether or not the execution succeeds. That is, if an error occurs, all preceding assignments in the topmost scope still take place. See the relevant example.

Trait Implementations

impl<T: Clone, '_> Clone for ExecutableModule<'_, T>[src]

impl<'a, T: Debug> Debug for ExecutableModule<'a, T>[src]

impl<T: 'static + Clone, '_> StripCode for ExecutableModule<'_, T>[src]

type Stripped = ExecutableModule<'static, T>

Resulting type after code stripping.

Auto Trait Implementations

impl<'a, T> !RefUnwindSafe for ExecutableModule<'a, T>

impl<'a, T> !Send for ExecutableModule<'a, T>

impl<'a, T> !Sync for ExecutableModule<'a, T>

impl<'a, T> Unpin for ExecutableModule<'a, T> where
    T: Unpin

impl<'a, T> !UnwindSafe for ExecutableModule<'a, T>

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> Conv for T

impl<T> Conv for T

impl<T> FmtForward for T

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pipe for T where
    T: ?Sized

impl<T> Pipe for T

impl<T> PipeAsRef for T

impl<T> PipeBorrow for T

impl<T> PipeDeref for T

impl<T> PipeRef for T

impl<T> Tap for T

impl<T> Tap for T

impl<T, U> TapAsRef<U> for T where
    U: ?Sized

impl<T, U> TapBorrow<U> for T where
    U: ?Sized

impl<T> TapDeref for T

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

impl<T> TryConv for T

impl<T> TryConv for T

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

impl<V, T> VZip<V> for T where
    V: MultiLane<T>,