From 8822d341461e9efc9765d6a55f1138c270f1e173 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Thu, 12 Sep 2019 22:33:44 +0200 Subject: [PATCH] feat(interface-types) Continue. --- src/lib.rs | 446 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 357 insertions(+), 89 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9074697..a14534e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,7 @@ macro_rules! consume { } #[derive(PartialEq, Debug)] -enum InterfaceType { +pub enum InterfaceType { Int, Float, Any, @@ -65,7 +65,7 @@ impl TryFrom for InterfaceType { } #[derive(PartialEq, Debug)] -enum AdapterKind { +pub enum AdapterKind { Import, Export, HelperFunction, @@ -76,36 +76,91 @@ impl TryFrom for AdapterKind { fn try_from(code: u8) -> Result { Ok(match code { - 0 => Self::Import, - 1 => Self::Export, - 2 => Self::HelperFunction, + 0x0 => Self::Import, + 0x1 => Self::Export, + 0x2 => Self::HelperFunction, _ => return Err("Unknown adapter kind code."), }) } } -#[derive(Debug)] -struct Export<'input> { +#[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(u64, u64), + Const(InterfaceType, u64), + FoldSeq(u64), +} + +#[derive(PartialEq, Debug)] +pub struct Export<'input> { name: &'input str, input_types: Vec, output_types: Vec, } -#[derive(Debug)] -struct Type<'input> { +#[derive(PartialEq, Debug)] +pub struct Type<'input> { name: &'input str, fields: Vec<&'input str>, types: Vec, } -#[derive(Debug)] -struct ImportedFunction<'input> { +#[derive(PartialEq, Debug)] +pub struct ImportedFunction<'input> { namespace: &'input str, name: &'input str, input_types: Vec, output_types: Vec, } +#[derive(PartialEq, Debug)] +pub enum Adapter<'input> { + Import { + namespace: &'input str, + name: &'input str, + input_types: Vec, + output_types: Vec, + instructions: Vec>, + }, + Export { + name: &'input str, + input_types: Vec, + output_types: Vec, + instructions: Vec>, + }, + HelperFunction { + name: &'input str, + input_types: Vec, + output_types: Vec, + instructions: Vec>, + }, +} + +#[derive(PartialEq, Debug)] +pub struct Forward<'input> { + name: &'input str, +} + +#[derive(PartialEq, Debug)] +pub struct Interfaces<'input> { + exports: Vec>, + types: Vec>, + imported_functions: Vec>, + adapters: Vec>, + forwards: Vec>, +} + fn byte<'input, E: ParseError<&'input [u8]>>(input: &'input [u8]) -> IResult<&'input [u8], u8, E> { if input.is_empty() { return Err(Err::Error(make_error(input, ErrorKind::Eof))); @@ -184,116 +239,264 @@ fn ty<'input, E: ParseError<&'input [u8]>>( return Err(Err::Error(make_error(input, ErrorKind::Eof))); } - let (input, ty) = leb(input)?; + let (output, ty) = leb(input)?; match InterfaceType::try_from(ty) { - Ok(ty) => Ok((input, ty)), + Ok(ty) => Ok((output, ty)), Err(_) => Err(Err::Error(make_error(input, ErrorKind::ParseTo))), } } -pub fn parse<'input, E: ParseError<&'input [u8]>>( - bytes: &'input [u8], -) -> IResult<&'input [u8], bool, E> { - let mut input = bytes; +fn instructions<'input, E: ParseError<&'input [u8]>>( + input: &'input [u8], +) -> IResult<&'input [u8], Instruction, E> { + let (mut input, opcode) = byte(input)?; + Ok(match opcode { + 0x00 => { + consume!((input, argument_0) = leb(input)?); + (input, Instruction::ArgumentGet(argument_0)) + } + + 0x01 => { + consume!((input, argument_0) = leb(input)?); + (input, Instruction::Call(argument_0)) + } + + 0x02 => { + consume!((input, argument_0) = string(input)?); + (input, Instruction::CallExport(argument_0)) + } + + 0x03 => (input, Instruction::ReadUtf8), + + 0x04 => { + consume!((input, argument_0) = string(input)?); + (input, Instruction::WriteUtf8(argument_0)) + } + + 0x05 => { + consume!((input, argument_0) = ty(input)?); + (input, Instruction::AsWasm(argument_0)) + } + + 0x06 => { + consume!((input, argument_0) = ty(input)?); + (input, Instruction::AsInterface(argument_0)) + } + + 0x07 => (input, Instruction::TableRefAdd), + + 0x08 => (input, Instruction::TableRefGet), + + 0x09 => { + consume!((input, argument_0) = leb(input)?); + (input, Instruction::CallMethod(argument_0)) + } + + 0x0a => { + consume!((input, argument_0) = ty(input)?); + (input, Instruction::MakeRecord(argument_0)) + } + + 0x0c => { + consume!((input, argument_0) = leb(input)?); + consume!((input, argument_1) = leb(input)?); + (input, Instruction::GetField(argument_0, argument_1)) + } + + 0x0d => { + consume!((input, argument_0) = ty(input)?); + consume!((input, argument_1) = leb(input)?); + (input, Instruction::Const(argument_0, argument_1)) + } + + 0x0e => { + consume!((input, argument_0) = leb(input)?); + (input, Instruction::FoldSeq(argument_0)) + } + + _ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))), + }) +} + +pub fn exports<'input, E: ParseError<&'input [u8]>>( + input: &'input [u8], +) -> IResult<&'input [u8], Vec, E> { + let mut input = input; let mut exports = vec![]; + + consume!((input, number_of_exports) = leb(input)?); + + for _ in 0..number_of_exports { + consume!((input, export_name) = string(input)?); + consume!((input, export_input_types) = list(input, ty)?); + consume!((input, export_output_types) = list(input, ty)?); + + exports.push(Export { + name: export_name, + input_types: export_input_types, + output_types: export_output_types, + }); + } + + Ok((input, exports)) +} + +pub fn types<'input, E: ParseError<&'input [u8]>>( + input: &'input [u8], +) -> IResult<&'input [u8], Vec, E> { + let mut input = input; let mut types = vec![]; + + consume!((input, number_of_types) = leb(input)?); + + for _ in 0..number_of_types { + consume!((input, type_name) = string(input)?); + consume!((input, type_fields) = list(input, string)?); + consume!((input, type_types) = list(input, ty)?); + + types.push(Type { + name: type_name, + fields: type_fields, + types: type_types, + }); + } + + Ok((input, types)) +} + +pub fn imported_functions<'input, E: ParseError<&'input [u8]>>( + input: &'input [u8], +) -> IResult<&'input [u8], Vec, E> { + let mut input = input; let mut imported_functions = vec![]; - { - consume!((input, number_of_exports) = leb(input)?); - d!(number_of_exports); + consume!((input, number_of_imported_functions) = leb(input)?); - for _ in 0..number_of_exports { - consume!((input, export_name) = string(input)?); - consume!((input, export_input_types) = list(input, ty)?); - consume!((input, export_output_types) = list(input, ty)?); + for _ in 0..number_of_imported_functions { + consume!((input, imported_function_namespace) = string(input)?); + consume!((input, imported_function_name) = string(input)?); + consume!((input, imported_function_input_types) = list(input, ty)?); + consume!((input, imported_function_output_types) = list(input, ty)?); - exports.push(Export { - name: export_name, - input_types: export_input_types, - output_types: export_output_types, - }); - } + imported_functions.push(ImportedFunction { + namespace: imported_function_namespace, + name: imported_function_name, + input_types: imported_function_input_types, + output_types: imported_function_output_types, + }); } - { - consume!((input, number_of_types) = leb(input)?); - d!(number_of_types); + Ok((input, imported_functions)) +} - for _ in 0..number_of_types { - consume!((input, type_name) = string(input)?); - consume!((input, type_fields) = list(input, string)?); - consume!((input, type_types) = list(input, ty)?); +pub fn adapters<'input, E: ParseError<&'input [u8]>>( + input: &'input [u8], +) -> IResult<&'input [u8], Vec, E> { + let mut input = input; + let mut adapters = vec![]; - types.push(Type { - name: type_name, - fields: type_fields, - types: type_types, - }); - } - } + consume!((input, number_of_adapters) = leb(input)?); - { - consume!((input, number_of_imported_functions) = leb(input)?); - d!(number_of_imported_functions); + for _ in 0..number_of_adapters { + consume!((input, adapter_kind) = byte(input)?); + let adapter_kind = AdapterKind::try_from(adapter_kind) + .map_err(|_| Err::Error(make_error(input, ErrorKind::ParseTo)))?; - for _ in 0..number_of_imported_functions { - consume!((input, imported_function_namespace) = string(input)?); - consume!((input, imported_function_name) = string(input)?); - consume!((input, imported_function_input_types) = list(input, ty)?); - consume!((input, imported_function_output_types) = list(input, ty)?); + match adapter_kind { + AdapterKind::Import => { + consume!((input, adapter_namespace) = string(input)?); + consume!((input, adapter_name) = string(input)?); + consume!((input, adapter_input_types) = list(input, ty)?); + consume!((input, adapter_output_types) = list(input, ty)?); + consume!((input, adapter_instructions) = list(input, instructions)?); - imported_functions.push(ImportedFunction { - namespace: imported_function_namespace, - name: imported_function_name, - input_types: imported_function_input_types, - output_types: imported_function_output_types, - }); - } - } + adapters.push(Adapter::Import { + namespace: adapter_namespace, + name: adapter_name, + input_types: adapter_input_types, + output_types: adapter_output_types, + instructions: adapter_instructions, + }); + } - { - consume!((input, number_of_adapters) = leb(input)?); - d!(number_of_adapters); + AdapterKind::Export => { + consume!((input, adapter_name) = string(input)?); + consume!((input, adapter_input_types) = list(input, ty)?); + consume!((input, adapter_output_types) = list(input, ty)?); + consume!((input, adapter_instructions) = list(input, instructions)?); - for _ in 0..number_of_adapters { - consume!((input, adapter_kind) = byte(input)?); - let adapter_kind = AdapterKind::try_from(adapter_kind) - .map_err(|_| Err::Error(make_error(input, ErrorKind::ParseTo)))?; - d!(&adapter_kind); + adapters.push(Adapter::Export { + name: adapter_name, + input_types: adapter_input_types, + output_types: adapter_output_types, + instructions: adapter_instructions, + }); + } - match adapter_kind { - AdapterKind::Import => { - consume!((input, adapter_namespace) = string(input)?); - d!(adapter_namespace); + AdapterKind::HelperFunction => { + consume!((input, adapter_name) = string(input)?); + consume!((input, adapter_input_types) = list(input, ty)?); + consume!((input, adapter_output_types) = list(input, ty)?); + consume!((input, adapter_instructions) = list(input, instructions)?); - consume!((input, adapter_name) = string(input)?); - d!(adapter_name); - - consume!((input, adapter_input_types) = list(input, ty)?); - d!(adapter_input_types); - - consume!((input, adapter_output_types) = list(input, ty)?); - d!(adapter_output_types); - } - - _ => println!("kind = {:?}", adapter_kind), + adapters.push(Adapter::HelperFunction { + name: adapter_name, + input_types: adapter_input_types, + output_types: adapter_output_types, + instructions: adapter_instructions, + }); } } } - d!(exports); - d!(types); - d!(imported_functions); + Ok((input, adapters)) +} - Ok((&[] as &[u8], true)) +pub fn forwards<'input, E: ParseError<&'input [u8]>>( + input: &'input [u8], +) -> IResult<&'input [u8], Vec, E> { + let mut input = input; + let mut forwards = vec![]; + + consume!((input, number_of_forwards) = leb(input)?); + + for _ in 0..number_of_forwards { + consume!((input, forward_name) = string(input)?); + + forwards.push(Forward { name: forward_name }); + } + + Ok((input, forwards)) +} + +pub fn parse<'input, E: ParseError<&'input [u8]>>( + bytes: &'input [u8], +) -> IResult<&'input [u8], Interfaces, E> { + let mut input = bytes; + + consume!((input, exports) = exports(input)?); + consume!((input, types) = types(input)?); + consume!((input, imported_functions) = imported_functions(input)?); + consume!((input, adapters) = adapters(input)?); + consume!((input, forwards) = forwards(input)?); + + Ok(( + input, + Interfaces { + exports, + types, + imported_functions, + adapters, + forwards, + }, + )) } #[cfg(test)] mod tests { - use super::parse; + use super::*; use std::fs; use wasmer_clif_backend::CraneliftCompiler; use wasmer_runtime_core as runtime; @@ -326,6 +529,71 @@ mod tests { .unwrap() .as_slice(); - parse::<()>(custom_section_bytes); + match parse::<()>(custom_section_bytes) { + Ok((remainder, interfaces)) => { + assert!(remainder.is_empty()); + assert_eq!( + interfaces, + Interfaces { + exports: vec![ + Export { + name: "strlen", + input_types: vec![InterfaceType::I32], + output_types: vec![InterfaceType::I32] + }, + Export { + name: "write_null_byte", + input_types: vec![InterfaceType::I32, InterfaceType::I32], + output_types: vec![InterfaceType::I32], + } + ], + types: vec![], + imported_functions: vec![ + ImportedFunction { + namespace: "host", + name: "console_log", + input_types: vec![InterfaceType::String], + output_types: vec![], + }, + ImportedFunction { + namespace: "host", + name: "document_title", + input_types: vec![], + output_types: vec![InterfaceType::String], + } + ], + adapters: vec![ + Adapter::Import { + namespace: "host", + name: "console_log", + input_types: vec![InterfaceType::I32], + output_types: vec![], + instructions: vec![ + Instruction::ArgumentGet(0), + Instruction::ArgumentGet(0), + Instruction::CallExport("strlen"), + Instruction::ReadUtf8, + Instruction::Call(0), + ] + }, + Adapter::Import { + namespace: "host", + name: "document_title", + input_types: vec![], + output_types: vec![InterfaceType::I32], + instructions: vec![ + Instruction::Call(1), + Instruction::WriteUtf8("alloc"), + Instruction::CallExport("write_null_byte"), + ] + } + ], + forwards: vec![Forward { name: "main" }] + } + ); + } + + Err(_) => assert!(false), + } } }