pub struct ExecutableModule<'a, T> { /* private fields */ }
Expand description
Executable module together with its imports.
An ExecutableModule
is a result of compiling a Block
of statements. A module can import
Value
s, 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.
ExecutableModule
s are generic with respect to the primitive value type, just like Value
.
The lifetime of a module depends on the lifetime of the code, but this dependency
can be eliminated via StripCode
implementation.
§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::Prim(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::Prim(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::Prim)
.collect();
module.set_import("xs", Value::Tuple(array));
assert_eq!(module.run()?, Value::Prim(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::Prim(3.0))
.with_import("y", Value::Prim(5.0))
.build();
assert_eq!(module.run()?, Value::Prim(8.0));
let mut env = Environment::from_iter(module.imports());
env.insert("x", Value::Prim(-1.0));
assert_eq!(module.run_in_env(&mut env)?, Value::Prim(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::Prim(5.0));
Implementations§
Source§impl<'a, T> ExecutableModule<'a, T>
impl<'a, T> ExecutableModule<'a, T>
Sourcepub fn set_import(&mut self, name: &str, value: Value<'a, T>) -> &mut Self
pub fn set_import(&mut self, name: &str, value: Value<'a, T>) -> &mut Self
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.
Sourcepub fn imports(&self) -> &ModuleImports<'a, T>
pub fn imports(&self) -> &ModuleImports<'a, T>
Returns shared reference to imports of this module.
Sourcepub fn with_arithmetic<'s>(
&'s self,
arithmetic: &'s dyn OrdArithmetic<T>,
) -> WithArithmetic<'s, 'a, T>
pub fn with_arithmetic<'s>( &'s self, arithmetic: &'s dyn OrdArithmetic<T>, ) -> WithArithmetic<'s, 'a, T>
Combines this module with the specified arithmetic
.
Source§impl<'a, T: Clone + Debug> ExecutableModule<'a, T>
impl<'a, T: Clone + Debug> ExecutableModule<'a, T>
Source§impl<'a, T: Clone + Debug> ExecutableModule<'a, T>where
StdArithmetic: OrdArithmetic<T>,
impl<'a, T: Clone + Debug> ExecutableModule<'a, T>where
StdArithmetic: OrdArithmetic<T>,
Sourcepub fn run(&self) -> Result<Value<'a, T>, ErrorWithBacktrace<'a>>
pub fn run(&self) -> Result<Value<'a, T>, ErrorWithBacktrace<'a>>
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.
Sourcepub fn run_in_env(
&self,
env: &mut Environment<'a, T>,
) -> Result<Value<'a, T>, ErrorWithBacktrace<'a>>
pub fn run_in_env( &self, env: &mut Environment<'a, T>, ) -> Result<Value<'a, T>, ErrorWithBacktrace<'a>>
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§
Source§impl<T: Clone> Clone for ExecutableModule<'_, T>
impl<T: Clone> Clone for ExecutableModule<'_, T>
Source§impl<'a, T: Debug> Debug for ExecutableModule<'a, T>
impl<'a, T: Debug> Debug for ExecutableModule<'a, T>
Source§impl<T: 'static + Clone> StripCode for ExecutableModule<'_, T>
impl<T: 'static + Clone> StripCode for ExecutableModule<'_, T>
Source§type Stripped = ExecutableModule<'static, T>
type Stripped = ExecutableModule<'static, T>
Source§fn strip_code(self) -> Self::Stripped
fn strip_code(self) -> Self::Stripped
Auto Trait Implementations§
impl<'a, T> Freeze for ExecutableModule<'a, T>
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§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self
to use its Binary
implementation when Debug
-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self
to use its Display
implementation when
Debug
-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self
to use its LowerExp
implementation when
Debug
-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self
to use its LowerHex
implementation when
Debug
-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self
to use its Octal
implementation when Debug
-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self
to use its Pointer
implementation when
Debug
-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self
to use its UpperExp
implementation when
Debug
-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self
to use its UpperHex
implementation when
Debug
-formatted.Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self
, then passes self.as_ref()
into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self
, then passes self.as_mut()
into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self
, then passes self.deref()
into the pipe function.Source§impl<T> PipeAsRef for T
impl<T> PipeAsRef for T
Source§impl<T> PipeBorrow for T
impl<T> PipeBorrow for T
Source§impl<T> PipeDeref for T
impl<T> PipeDeref for T
Source§impl<T> PipeRef for T
impl<T> PipeRef for T
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B>
of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B>
of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R>
view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R>
view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target
of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target
of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap()
only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut()
only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow()
only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut()
only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref()
only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut()
only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref()
only in debug builds, and is erased in release
builds.Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap<F, R>(self, func: F) -> Selfwhere
F: FnOnce(&Self) -> R,
fn tap<F, R>(self, func: F) -> Selfwhere
F: FnOnce(&Self) -> R,
Source§fn tap_dbg<F, R>(self, func: F) -> Selfwhere
F: FnOnce(&Self) -> R,
fn tap_dbg<F, R>(self, func: F) -> Selfwhere
F: FnOnce(&Self) -> R,
tap
in debug builds, and does nothing in release builds.Source§fn tap_mut<F, R>(self, func: F) -> Selfwhere
F: FnOnce(&mut Self) -> R,
fn tap_mut<F, R>(self, func: F) -> Selfwhere
F: FnOnce(&mut Self) -> R,
Source§fn tap_mut_dbg<F, R>(self, func: F) -> Selfwhere
F: FnOnce(&mut Self) -> R,
fn tap_mut_dbg<F, R>(self, func: F) -> Selfwhere
F: FnOnce(&mut Self) -> R,
tap_mut
in debug builds, and does nothing in release builds.Source§impl<T, U> TapAsRef<U> for Twhere
U: ?Sized,
impl<T, U> TapAsRef<U> for Twhere
U: ?Sized,
Source§fn tap_ref<F, R>(self, func: F) -> Self
fn tap_ref<F, R>(self, func: F) -> Self
Source§fn tap_ref_dbg<F, R>(self, func: F) -> Self
fn tap_ref_dbg<F, R>(self, func: F) -> Self
tap_ref
in debug builds, and does nothing in release builds.Source§fn tap_ref_mut<F, R>(self, func: F) -> Self
fn tap_ref_mut<F, R>(self, func: F) -> Self
Source§impl<T, U> TapBorrow<U> for Twhere
U: ?Sized,
impl<T, U> TapBorrow<U> for Twhere
U: ?Sized,
Source§fn tap_borrow<F, R>(self, func: F) -> Self
fn tap_borrow<F, R>(self, func: F) -> Self
Source§fn tap_borrow_dbg<F, R>(self, func: F) -> Self
fn tap_borrow_dbg<F, R>(self, func: F) -> Self
tap_borrow
in debug builds, and does nothing in release builds.Source§fn tap_borrow_mut<F, R>(self, func: F) -> Self
fn tap_borrow_mut<F, R>(self, func: F) -> Self
Source§impl<T> TapDeref for T
impl<T> TapDeref for T
Source§fn tap_deref_dbg<F, R>(self, func: F) -> Self
fn tap_deref_dbg<F, R>(self, func: F) -> Self
tap_deref
in debug builds, and does nothing in release builds.Source§fn tap_deref_mut<F, R>(self, func: F) -> Self
fn tap_deref_mut<F, R>(self, func: F) -> Self
self
for modification.