feat(interface-types) Draft instruction interpreter.

This commit is contained in:
Ivan Enderlin 2019-09-19 00:18:36 +02:00
parent fc9389d932
commit dc3c72ea19
7 changed files with 185 additions and 29 deletions

View File

@ -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,

View File

@ -1,4 +1,4 @@
use crate::ast::*;
use crate::{ast::*, instructions::Instruction};
use nom::{
error::{make_error, ErrorKind, ParseError},
Err, IResult,

View File

@ -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() {

View File

@ -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<Box<dyn Fn(&mut Stack) + 'static>>,
}
impl Interpreter {
pub(crate) fn is_eos(&self) -> bool {
self.stack.is_empty()
}
}
impl<'binary_input> TryFrom<&Vec<Instruction<'binary_input>>> for Interpreter {
type Error = &'static str;
fn try_from(instructions: &Vec<Instruction>) -> Result<Self, Self::Error> {
let executable_instructions = instructions
.iter()
.map(|instruction| -> Box<dyn Fn(&mut Stack) + 'static> {
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::<Vec<_>>();
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<Interpreter, _> = (&instructions).try_into();
assert!(interpreter.is_ok());
let interpreter = interpreter.unwrap();
assert_eq!(interpreter.is_eos(), true);
}
}

View File

@ -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),
}

View File

@ -0,0 +1,66 @@
use std::{iter::Rev, vec::Drain};
pub(super) struct Stack {
inner: Vec<u32>,
}
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<u32> {
self.inner.pop()
}
pub(super) fn pop_n(&mut self, n: usize) -> Rev<Drain<u32>> {
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::<Vec<_>>(), &[6]);
assert_eq!(stack.pop_n(2).collect::<Vec<_>>(), &[5, 4]);
assert_eq!(stack.pop_n(3).collect::<Vec<_>>(), &[3, 2, 1]);
assert_eq!(stack.is_empty(), true);
}
}

View File

@ -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;