2020-02-12 15:52:15 +01:00
|
|
|
/// This macro runs a parser, extracts the next input and the parser
|
|
|
|
/// output, and positions the next input on `$input`.
|
2019-09-12 22:44:20 +02:00
|
|
|
macro_rules! consume {
|
|
|
|
(($input:ident, $parser_output:ident) = $parser_expression:expr) => {
|
|
|
|
let (next_input, $parser_output) = $parser_expression;
|
|
|
|
$input = next_input;
|
|
|
|
};
|
2020-02-24 18:12:01 +01:00
|
|
|
|
|
|
|
(($input:ident, mut $parser_output:ident) = $parser_expression:expr) => {
|
|
|
|
let (next_input, mut $parser_output) = $parser_expression;
|
|
|
|
$input = next_input;
|
|
|
|
};
|
2019-09-12 22:44:20 +02:00
|
|
|
}
|
2019-09-26 14:14:46 +02:00
|
|
|
|
2020-02-12 15:52:15 +01:00
|
|
|
/// This macro creates an executable instruction for the interpreter.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
///
|
|
|
|
/// The following example creates a `foo` executable instruction,
|
|
|
|
/// which takes 2 arguments (`x` and `y`), and does something
|
|
|
|
/// mysterious by using the `interpreter::Runtime` API.
|
|
|
|
///
|
|
|
|
/// ```rust,ignore
|
|
|
|
/// executable_instruction!(
|
|
|
|
/// foo(x: u64, y: u64, instruction_name: String) -> _ {
|
|
|
|
/// // ^ output type is purposely blank
|
|
|
|
/// // ^^^^^^^^^^^^^^^^ the instruction name, for debugging purposes
|
|
|
|
/// // ^ the `y` argument
|
|
|
|
/// // ^ the `x` argument
|
|
|
|
///
|
|
|
|
/// // an executable instruction is a closure that takes a `Runtime` instance
|
|
|
|
/// move |runtime| -> _ {
|
|
|
|
/// // Do something.
|
|
|
|
///
|
|
|
|
/// Ok(())
|
|
|
|
/// }
|
|
|
|
/// );
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Check the existing executable instruction to get more examples.
|
2019-09-26 14:14:46 +02:00
|
|
|
macro_rules! executable_instruction {
|
|
|
|
($name:ident ( $($argument_name:ident: $argument_type:ty),* ) -> _ $implementation:block ) => {
|
|
|
|
use crate::interpreter::{ExecutableInstruction, wasm, stack::Stackable};
|
|
|
|
|
2019-09-28 00:55:35 +02:00
|
|
|
pub(crate) fn $name<Instance, Export, LocalImport, Memory, MemoryView>(
|
2019-09-26 14:14:46 +02:00
|
|
|
$($argument_name: $argument_type),*
|
2019-09-28 00:55:35 +02:00
|
|
|
) -> ExecutableInstruction<Instance, Export, LocalImport, Memory, MemoryView>
|
2019-09-26 14:14:46 +02:00
|
|
|
where
|
|
|
|
Export: wasm::structures::Export,
|
|
|
|
LocalImport: wasm::structures::LocalImport,
|
2019-09-28 00:55:35 +02:00
|
|
|
Memory: wasm::structures::Memory<MemoryView>,
|
|
|
|
MemoryView: wasm::structures::MemoryView,
|
|
|
|
Instance: wasm::structures::Instance<Export, LocalImport, Memory, MemoryView>,
|
2019-09-26 14:14:46 +02:00
|
|
|
{
|
2019-09-26 14:17:43 +02:00
|
|
|
Box::new($implementation)
|
2019-09-26 14:14:46 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
macro_rules! test_executable_instruction {
|
|
|
|
(
|
|
|
|
$test_name:ident =
|
|
|
|
instructions: [ $($instructions:expr),* $(,)* ],
|
|
|
|
invocation_inputs: [ $($invocation_inputs:expr),* $(,)* ],
|
|
|
|
instance: $instance:expr,
|
|
|
|
stack: [ $($stack:expr),* $(,)* ]
|
|
|
|
$(,)*
|
|
|
|
) => {
|
|
|
|
#[test]
|
|
|
|
#[allow(non_snake_case, unused)]
|
|
|
|
fn $test_name() {
|
|
|
|
use crate::interpreter::{
|
2019-09-28 00:55:35 +02:00
|
|
|
instructions::tests::{Export, Instance, LocalImport, Memory, MemoryView},
|
2019-09-26 14:14:46 +02:00
|
|
|
stack::Stackable,
|
|
|
|
wasm::values::{InterfaceType, InterfaceValue},
|
|
|
|
Instruction, Interpreter,
|
|
|
|
};
|
|
|
|
use std::{cell::Cell, collections::HashMap, convert::TryInto};
|
|
|
|
|
2019-09-28 00:55:35 +02:00
|
|
|
let interpreter: Interpreter<Instance, Export, LocalImport, Memory, MemoryView> =
|
2019-09-26 14:14:46 +02:00
|
|
|
(&vec![$($instructions),*]).try_into().unwrap();
|
|
|
|
|
|
|
|
let invocation_inputs = vec![$($invocation_inputs),*];
|
2019-10-03 00:13:07 +02:00
|
|
|
let mut instance = $instance;
|
|
|
|
let run = interpreter.run(&invocation_inputs, &mut instance);
|
2019-09-26 14:14:46 +02:00
|
|
|
|
|
|
|
assert!(run.is_ok());
|
|
|
|
|
|
|
|
let stack = run.unwrap();
|
|
|
|
|
|
|
|
assert_eq!(stack.as_slice(), &[$($stack),*]);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
(
|
|
|
|
$test_name:ident =
|
|
|
|
instructions: [ $($instructions:expr),* $(,)* ],
|
|
|
|
invocation_inputs: [ $($invocation_inputs:expr),* $(,)* ],
|
|
|
|
instance: $instance:expr,
|
|
|
|
error: $error:expr
|
|
|
|
$(,)*
|
|
|
|
) => {
|
|
|
|
#[test]
|
|
|
|
#[allow(non_snake_case, unused)]
|
|
|
|
fn $test_name() {
|
|
|
|
use crate::interpreter::{
|
2019-09-28 00:55:35 +02:00
|
|
|
instructions::tests::{Export, Instance, LocalImport, Memory, MemoryView},
|
2019-09-26 14:14:46 +02:00
|
|
|
stack::Stackable,
|
|
|
|
wasm::values::{InterfaceType, InterfaceValue},
|
|
|
|
Instruction, Interpreter,
|
|
|
|
};
|
|
|
|
use std::{cell::Cell, collections::HashMap, convert::TryInto};
|
|
|
|
|
2019-09-28 00:55:35 +02:00
|
|
|
let interpreter: Interpreter<Instance, Export, LocalImport, Memory, MemoryView> =
|
2019-09-26 14:14:46 +02:00
|
|
|
(&vec![$($instructions),*]).try_into().unwrap();
|
|
|
|
|
|
|
|
let invocation_inputs = vec![$($invocation_inputs),*];
|
2019-10-03 00:13:07 +02:00
|
|
|
let mut instance = $instance;
|
|
|
|
let run = interpreter.run(&invocation_inputs, &mut instance);
|
2019-09-26 14:14:46 +02:00
|
|
|
|
|
|
|
assert!(run.is_err());
|
|
|
|
|
|
|
|
let error = run.unwrap_err();
|
|
|
|
|
|
|
|
assert_eq!(error, String::from($error));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|