diff --git a/lib/interface-types/src/ast.rs b/lib/interface-types/src/ast.rs index 63cb7789f..a3df0d8d8 100644 --- a/lib/interface-types/src/ast.rs +++ b/lib/interface-types/src/ast.rs @@ -1,3 +1,4 @@ +use crate::instructions::Instruction; use std::str; #[derive(PartialEq, Debug)] @@ -21,30 +22,6 @@ pub(crate) enum AdapterKind { HelperFunction, } -#[derive(PartialEq, Debug)] -pub enum Instruction<'input> { - ArgumentGet(u64), - Call(u64), - CallExport(&'input str), - ReadUtf8, - WriteUtf8(&'input str), - AsWasm(InterfaceType), - AsInterface(InterfaceType), - TableRefAdd, - TableRefGet, - CallMethod(u64), - MakeRecord(InterfaceType), - GetField(InterfaceType, u64), - Const(InterfaceType, u64), - FoldSeq(u64), - Add(InterfaceType), - MemToSeq(InterfaceType, &'input str), - Load(InterfaceType, &'input str), - SeqNew(InterfaceType), - ListPush, - RepeatWhile(u64, u64), -} - #[derive(PartialEq, Debug)] pub struct Export<'input> { pub name: &'input str, diff --git a/lib/interface-types/src/decoders/binary.rs b/lib/interface-types/src/decoders/binary.rs index b86cdc303..2fd6a7b4b 100644 --- a/lib/interface-types/src/decoders/binary.rs +++ b/lib/interface-types/src/decoders/binary.rs @@ -1,4 +1,4 @@ -use crate::ast::*; +use crate::{ast::*, instructions::Instruction}; use nom::{ error::{make_error, ErrorKind, ParseError}, Err, IResult, diff --git a/lib/interface-types/src/encoders/wat.rs b/lib/interface-types/src/encoders/wat.rs index e7e02a3fe..b11b65dc2 100644 --- a/lib/interface-types/src/encoders/wat.rs +++ b/lib/interface-types/src/encoders/wat.rs @@ -1,5 +1,6 @@ -use crate::ast::{ - Adapter, Export, Forward, ImportedFunction, Instruction, InterfaceType, Interfaces, Type, +use crate::{ + ast::{Adapter, Export, Forward, ImportedFunction, InterfaceType, Interfaces, Type}, + instructions::Instruction, }; impl From<&InterfaceType> for String { @@ -267,7 +268,7 @@ impl<'input> From<&Interfaces<'input>> for String { #[cfg(test)] mod tests { - use crate::ast::*; + use crate::{ast::*, instructions::Instruction}; #[test] fn test_interface_types() { diff --git a/lib/interface-types/src/instructions/interpreter.rs b/lib/interface-types/src/instructions/interpreter.rs new file mode 100644 index 000000000..61c113343 --- /dev/null +++ b/lib/interface-types/src/instructions/interpreter.rs @@ -0,0 +1,83 @@ +use crate::instructions::{stack::Stack, Instruction}; +use std::convert::TryFrom; + +type ExecutableInstruction = dyn Fn(&mut Stack); +//trait ExecutableInstruction: Fn(&mut Stack) {} + +pub(crate) struct Interpreter { + stack: Stack, + instructions: Vec>, +} + +impl Interpreter { + pub(crate) fn is_eos(&self) -> bool { + self.stack.is_empty() + } +} + +impl<'binary_input> TryFrom<&Vec>> for Interpreter { + type Error = &'static str; + + fn try_from(instructions: &Vec) -> Result { + let executable_instructions = instructions + .iter() + .map(|instruction| -> Box { + match instruction { + Instruction::ArgumentGet(index) => { + let index = index.to_owned(); + + Box::new(move |stack: &mut Stack| { + println!("argument get {}", index); + }) + } + Instruction::CallExport(export_name) => { + let export_name = (*export_name).to_owned(); + + Box::new(move |stack: &mut Stack| { + println!("call export {}", export_name); + }) + } + Instruction::ReadUtf8 => Box::new(|stack: &mut Stack| { + println!("read utf8"); + }), + Instruction::Call(index) => { + let index = index.to_owned(); + + Box::new(move |stack: &mut Stack| { + println!("call {}", index); + }) + } + _ => unimplemented!(), + } + }) + .collect::>(); + + Ok(Interpreter { + stack: Stack::new(), + instructions: executable_instructions, + }) + } +} + +#[cfg(test)] +mod tests { + use super::Interpreter; + use crate::instructions::Instruction; + use std::convert::TryInto; + + #[test] + fn test_interpreter_from_instructions() { + let instructions = vec![ + Instruction::ArgumentGet(0), + Instruction::ArgumentGet(0), + Instruction::CallExport("strlen"), + Instruction::ReadUtf8, + Instruction::Call(7), + ]; + let interpreter: Result = (&instructions).try_into(); + assert!(interpreter.is_ok()); + + let interpreter = interpreter.unwrap(); + assert_eq!(interpreter.is_eos(), true); + } +} diff --git a/lib/interface-types/src/instructions/mod.rs b/lib/interface-types/src/instructions/mod.rs new file mode 100644 index 000000000..eb62f43d2 --- /dev/null +++ b/lib/interface-types/src/instructions/mod.rs @@ -0,0 +1,28 @@ +use crate::ast::InterfaceType; + +pub mod interpreter; +mod stack; + +#[derive(PartialEq, Debug)] +pub enum Instruction<'input> { + ArgumentGet(u64), + Call(u64), + CallExport(&'input str), + ReadUtf8, + WriteUtf8(&'input str), + AsWasm(InterfaceType), + AsInterface(InterfaceType), + TableRefAdd, + TableRefGet, + CallMethod(u64), + MakeRecord(InterfaceType), + GetField(InterfaceType, u64), + Const(InterfaceType, u64), + FoldSeq(u64), + Add(InterfaceType), + MemToSeq(InterfaceType, &'input str), + Load(InterfaceType, &'input str), + SeqNew(InterfaceType), + ListPush, + RepeatWhile(u64, u64), +} diff --git a/lib/interface-types/src/instructions/stack.rs b/lib/interface-types/src/instructions/stack.rs new file mode 100644 index 000000000..8a5bce471 --- /dev/null +++ b/lib/interface-types/src/instructions/stack.rs @@ -0,0 +1,66 @@ +use std::{iter::Rev, vec::Drain}; + +pub(super) struct Stack { + inner: Vec, +} + +impl Stack { + pub(super) fn new() -> Self { + Self { inner: Vec::new() } + } + + pub(super) fn is_empty(&self) -> bool { + self.inner.is_empty() + } + + pub(super) fn push(&mut self, item: u32) { + self.inner.push(item); + } + + pub(super) fn pop(&mut self) -> Option { + self.inner.pop() + } + + pub(super) fn pop_n(&mut self, n: usize) -> Rev> { + self.inner.drain(self.inner.len() - n..).rev() + } +} + +#[cfg(test)] +mod tests { + use super::Stack; + + #[test] + fn test_is_empty() { + let mut stack = Stack::new(); + assert_eq!(stack.is_empty(), true); + + stack.push(1); + assert_eq!(stack.is_empty(), false); + } + + #[test] + fn test_push_pop() { + let mut stack = Stack::new(); + stack.push(1); + + assert_eq!(stack.pop(), Some(1)); + assert_eq!(stack.is_empty(), true); + } + + #[test] + fn test_pop_n() { + let mut stack = Stack::new(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + stack.push(5); + stack.push(6); + + assert_eq!(stack.pop_n(1).collect::>(), &[6]); + assert_eq!(stack.pop_n(2).collect::>(), &[5, 4]); + assert_eq!(stack.pop_n(3).collect::>(), &[3, 2, 1]); + assert_eq!(stack.is_empty(), true); + } +} diff --git a/lib/interface-types/src/lib.rs b/lib/interface-types/src/lib.rs index d9fc90ea6..9ba79d7b9 100644 --- a/lib/interface-types/src/lib.rs +++ b/lib/interface-types/src/lib.rs @@ -3,12 +3,13 @@ pub mod ast; mod macros; pub mod decoders; pub mod encoders; +pub mod instructions; pub use decoders::binary::parse as parse_binary; #[cfg(test)] mod tests { - use crate::{ast::*, encoders::wat::*, parse_binary}; + use crate::{ast::*, encoders::wat::*, instructions::Instruction, parse_binary}; use std::fs; use wasmer_clif_backend::CraneliftCompiler; use wasmer_runtime_core as runtime;