diff --git a/lib/interface-types/src/instructions/interpreter.rs b/lib/interface-types/src/instructions/interpreter.rs index ee1b8c48c..11d6ddae6 100644 --- a/lib/interface-types/src/instructions/interpreter.rs +++ b/lib/interface-types/src/instructions/interpreter.rs @@ -1,16 +1,31 @@ -use crate::instructions::{stack::Stack, Instruction}; +use crate::instructions::{ + stack::{Stack, Stackable}, + Instruction, +}; use std::convert::TryFrom; -type ExecutableInstruction = Box; +type ExecutableInstruction = Box) -> Result<(), &'static str>>; pub(crate) struct Interpreter { - stack: Stack, - instructions: Vec, + executable_instructions: Vec, } impl Interpreter { - pub(crate) fn is_eos(&self) -> bool { - self.stack.is_empty() + fn iter(&self) -> impl Iterator + '_ { + self.executable_instructions.iter() + } + + pub(crate) fn run(&self) -> Result, &'static str> { + let mut stack = Stack::new(); + + for executable_instruction in self.iter() { + match executable_instruction(&mut stack) { + Ok(_) => continue, + Err(message) => return Err(message), + } + } + + Ok(stack) } } @@ -25,25 +40,34 @@ impl<'binary_input> TryFrom<&Vec>> for Interpreter { Instruction::ArgumentGet(index) => { let index = index.to_owned(); - Box::new(move |stack: &mut Stack| { + Box::new(move |stack: &mut Stack| -> Result<(), _> { println!("argument get {}", index); + stack.push(index); + + Ok(()) }) } Instruction::CallExport(export_name) => { let export_name = (*export_name).to_owned(); - Box::new(move |stack: &mut Stack| { + Box::new(move |_stack: &mut Stack| -> Result<(), _> { println!("call export {}", export_name); + + Ok(()) }) } - Instruction::ReadUtf8 => Box::new(|stack: &mut Stack| { + Instruction::ReadUtf8 => Box::new(|_stack: &mut Stack| -> Result<(), _> { println!("read utf8"); + + Ok(()) }), Instruction::Call(index) => { let index = index.to_owned(); - Box::new(move |stack: &mut Stack| { + Box::new(move |_stack: &mut Stack| -> Result<(), _> { println!("call {}", index); + + Ok(()) }) } _ => unimplemented!(), @@ -52,8 +76,7 @@ impl<'binary_input> TryFrom<&Vec>> for Interpreter { .collect(); Ok(Interpreter { - stack: Stack::new(), - instructions: executable_instructions, + executable_instructions, }) } } @@ -61,7 +84,7 @@ impl<'binary_input> TryFrom<&Vec>> for Interpreter { #[cfg(test)] mod tests { use super::Interpreter; - use crate::instructions::Instruction; + use crate::instructions::{stack::Stackable, Instruction}; use std::convert::TryInto; #[test] @@ -73,10 +96,20 @@ mod tests { Instruction::ReadUtf8, Instruction::Call(7), ]; - let interpreter: Result = (&instructions).try_into(); - assert!(interpreter.is_ok()); + let interpreter: Interpreter = (&instructions).try_into().unwrap(); - let interpreter = interpreter.unwrap(); - assert_eq!(interpreter.is_eos(), true); + assert_eq!(interpreter.executable_instructions.len(), 5); + } + + #[test] + fn test_interpreter_argument_get() { + let interpreter: Interpreter = (&vec![Instruction::ArgumentGet(42)]).try_into().unwrap(); + let run = interpreter.run(); + + assert!(run.is_ok()); + + let stack = run.unwrap(); + + assert_eq!(stack.as_slice(), &[42]); } } diff --git a/lib/interface-types/src/instructions/stack.rs b/lib/interface-types/src/instructions/stack.rs index 8a5bce471..ff68d9380 100644 --- a/lib/interface-types/src/instructions/stack.rs +++ b/lib/interface-types/src/instructions/stack.rs @@ -1,34 +1,62 @@ -use std::{iter::Rev, vec::Drain}; +pub(crate) trait Stackable { + type Item; -pub(super) struct Stack { - inner: Vec, + fn is_empty(&self) -> bool; + fn as_slice(&self) -> &[Self::Item]; + fn push(&mut self, item: Self::Item); + fn pop1(&mut self) -> Option; + fn pop(&mut self, n: usize) -> Option>; } -impl Stack { - pub(super) fn new() -> Self { +pub(crate) struct Stack { + inner: Vec, +} + +impl Stack { + pub fn new() -> Self { Self { inner: Vec::new() } } +} - pub(super) fn is_empty(&self) -> bool { +impl Stackable for Stack { + type Item = T; + + fn is_empty(&self) -> bool { self.inner.is_empty() } - pub(super) fn push(&mut self, item: u32) { + fn as_slice(&self) -> &[Self::Item] { + self.inner.as_slice() + } + + fn push(&mut self, item: Self::Item) { self.inner.push(item); } - pub(super) fn pop(&mut self) -> Option { + fn pop1(&mut self) -> Option { self.inner.pop() } - pub(super) fn pop_n(&mut self, n: usize) -> Rev> { - self.inner.drain(self.inner.len() - n..).rev() + fn pop(&mut self, n: usize) -> Option> { + if self.inner.len() < n { + None + } else { + let items = self + .inner + .drain(self.inner.len() - n..) + .rev() + .collect::>(); + + assert!(items.len() == n); + + Some(items) + } } } #[cfg(test)] mod tests { - use super::Stack; + use super::{Stack, Stackable}; #[test] fn test_is_empty() { @@ -40,16 +68,16 @@ mod tests { } #[test] - fn test_push_pop() { + fn test_push_pop1() { let mut stack = Stack::new(); stack.push(1); - assert_eq!(stack.pop(), Some(1)); + assert_eq!(stack.pop1(), Some(1)); assert_eq!(stack.is_empty(), true); } #[test] - fn test_pop_n() { + fn test_pop() { let mut stack = Stack::new(); stack.push(1); stack.push(2); @@ -58,9 +86,9 @@ mod tests { 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.pop(1), Some(vec![6])); + assert_eq!(stack.pop(2), Some(vec![5, 4])); + assert_eq!(stack.pop(3), Some(vec![3, 2, 1])); assert_eq!(stack.is_empty(), true); } }