feat(interface-types) Continue.

This commit is contained in:
Ivan Enderlin 2019-09-19 23:05:17 +02:00
parent 2f3c37fbd5
commit c63345029e
2 changed files with 95 additions and 34 deletions

View File

@ -1,16 +1,31 @@
use crate::instructions::{stack::Stack, Instruction}; use crate::instructions::{
stack::{Stack, Stackable},
Instruction,
};
use std::convert::TryFrom; use std::convert::TryFrom;
type ExecutableInstruction = Box<dyn Fn(&mut Stack)>; type ExecutableInstruction = Box<dyn Fn(&mut Stack<u64>) -> Result<(), &'static str>>;
pub(crate) struct Interpreter { pub(crate) struct Interpreter {
stack: Stack, executable_instructions: Vec<ExecutableInstruction>,
instructions: Vec<ExecutableInstruction>,
} }
impl Interpreter { impl Interpreter {
pub(crate) fn is_eos(&self) -> bool { fn iter(&self) -> impl Iterator<Item = &ExecutableInstruction> + '_ {
self.stack.is_empty() self.executable_instructions.iter()
}
pub(crate) fn run(&self) -> Result<Stack<u64>, &'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<Instruction<'binary_input>>> for Interpreter {
Instruction::ArgumentGet(index) => { Instruction::ArgumentGet(index) => {
let index = index.to_owned(); let index = index.to_owned();
Box::new(move |stack: &mut Stack| { Box::new(move |stack: &mut Stack<u64>| -> Result<(), _> {
println!("argument get {}", index); println!("argument get {}", index);
stack.push(index);
Ok(())
}) })
} }
Instruction::CallExport(export_name) => { Instruction::CallExport(export_name) => {
let export_name = (*export_name).to_owned(); let export_name = (*export_name).to_owned();
Box::new(move |stack: &mut Stack| { Box::new(move |_stack: &mut Stack<u64>| -> Result<(), _> {
println!("call export {}", export_name); println!("call export {}", export_name);
Ok(())
}) })
} }
Instruction::ReadUtf8 => Box::new(|stack: &mut Stack| { Instruction::ReadUtf8 => Box::new(|_stack: &mut Stack<u64>| -> Result<(), _> {
println!("read utf8"); println!("read utf8");
Ok(())
}), }),
Instruction::Call(index) => { Instruction::Call(index) => {
let index = index.to_owned(); let index = index.to_owned();
Box::new(move |stack: &mut Stack| { Box::new(move |_stack: &mut Stack<u64>| -> Result<(), _> {
println!("call {}", index); println!("call {}", index);
Ok(())
}) })
} }
_ => unimplemented!(), _ => unimplemented!(),
@ -52,8 +76,7 @@ impl<'binary_input> TryFrom<&Vec<Instruction<'binary_input>>> for Interpreter {
.collect(); .collect();
Ok(Interpreter { Ok(Interpreter {
stack: Stack::new(), executable_instructions,
instructions: executable_instructions,
}) })
} }
} }
@ -61,7 +84,7 @@ impl<'binary_input> TryFrom<&Vec<Instruction<'binary_input>>> for Interpreter {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Interpreter; use super::Interpreter;
use crate::instructions::Instruction; use crate::instructions::{stack::Stackable, Instruction};
use std::convert::TryInto; use std::convert::TryInto;
#[test] #[test]
@ -73,10 +96,20 @@ mod tests {
Instruction::ReadUtf8, Instruction::ReadUtf8,
Instruction::Call(7), Instruction::Call(7),
]; ];
let interpreter: Result<Interpreter, _> = (&instructions).try_into(); let interpreter: Interpreter = (&instructions).try_into().unwrap();
assert!(interpreter.is_ok());
let interpreter = interpreter.unwrap(); assert_eq!(interpreter.executable_instructions.len(), 5);
assert_eq!(interpreter.is_eos(), true); }
#[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]);
} }
} }

View File

@ -1,34 +1,62 @@
use std::{iter::Rev, vec::Drain}; pub(crate) trait Stackable {
type Item;
pub(super) struct Stack { fn is_empty(&self) -> bool;
inner: Vec<u32>, fn as_slice(&self) -> &[Self::Item];
fn push(&mut self, item: Self::Item);
fn pop1(&mut self) -> Option<Self::Item>;
fn pop(&mut self, n: usize) -> Option<Vec<Self::Item>>;
} }
impl Stack { pub(crate) struct Stack<T> {
pub(super) fn new() -> Self { inner: Vec<T>,
}
impl<T> Stack<T> {
pub fn new() -> Self {
Self { inner: Vec::new() } Self { inner: Vec::new() }
} }
}
pub(super) fn is_empty(&self) -> bool { impl<T> Stackable for Stack<T> {
type Item = T;
fn is_empty(&self) -> bool {
self.inner.is_empty() 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); self.inner.push(item);
} }
pub(super) fn pop(&mut self) -> Option<u32> { fn pop1(&mut self) -> Option<Self::Item> {
self.inner.pop() self.inner.pop()
} }
pub(super) fn pop_n(&mut self, n: usize) -> Rev<Drain<u32>> { fn pop(&mut self, n: usize) -> Option<Vec<Self::Item>> {
self.inner.drain(self.inner.len() - n..).rev() if self.inner.len() < n {
None
} else {
let items = self
.inner
.drain(self.inner.len() - n..)
.rev()
.collect::<Vec<Self::Item>>();
assert!(items.len() == n);
Some(items)
}
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Stack; use super::{Stack, Stackable};
#[test] #[test]
fn test_is_empty() { fn test_is_empty() {
@ -40,16 +68,16 @@ mod tests {
} }
#[test] #[test]
fn test_push_pop() { fn test_push_pop1() {
let mut stack = Stack::new(); let mut stack = Stack::new();
stack.push(1); stack.push(1);
assert_eq!(stack.pop(), Some(1)); assert_eq!(stack.pop1(), Some(1));
assert_eq!(stack.is_empty(), true); assert_eq!(stack.is_empty(), true);
} }
#[test] #[test]
fn test_pop_n() { fn test_pop() {
let mut stack = Stack::new(); let mut stack = Stack::new();
stack.push(1); stack.push(1);
stack.push(2); stack.push(2);
@ -58,9 +86,9 @@ mod tests {
stack.push(5); stack.push(5);
stack.push(6); stack.push(6);
assert_eq!(stack.pop_n(1).collect::<Vec<_>>(), &[6]); assert_eq!(stack.pop(1), Some(vec![6]));
assert_eq!(stack.pop_n(2).collect::<Vec<_>>(), &[5, 4]); assert_eq!(stack.pop(2), Some(vec![5, 4]));
assert_eq!(stack.pop_n(3).collect::<Vec<_>>(), &[3, 2, 1]); assert_eq!(stack.pop(3), Some(vec![3, 2, 1]));
assert_eq!(stack.is_empty(), true); assert_eq!(stack.is_empty(), true);
} }
} }