use crate::{ast::*, instructions::Instruction}; use nom::{ error::{make_error, ErrorKind, ParseError}, Err, IResult, }; use std::{convert::TryFrom, str}; impl TryFrom for InterfaceType { type Error = &'static str; fn try_from(code: u64) -> Result { Ok(match code { 0x7fff => Self::Int, 0x7ffe => Self::Float, 0x7ffd => Self::Any, 0x7ffc => Self::String, 0x7ffb => Self::Seq, 0x7f => Self::I32, 0x7e => Self::I64, 0x7d => Self::F32, 0x7c => Self::F64, 0x6f => Self::AnyRef, _ => return Err("Unknown interface type code."), }) } } impl TryFrom for AdapterKind { type Error = &'static str; fn try_from(code: u8) -> Result { Ok(match code { 0x0 => Self::Import, 0x1 => Self::Export, 0x2 => Self::HelperFunction, _ => return Err("Unknown adapter kind code."), }) } } 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))); } Ok((&input[1..], input[0])) } fn leb<'input, E: ParseError<&'input [u8]>>(input: &'input [u8]) -> IResult<&'input [u8], u64, E> { if input.is_empty() { return Err(Err::Error(make_error(input, ErrorKind::Eof))); } let (output, bytes) = match input.iter().position(|&byte| byte & 0x80 == 0) { Some(position) => (&input[position + 1..], &input[..position + 1]), None => (&[] as &[u8], input), }; Ok(( output, bytes .iter() .rev() .fold(0, |acc, byte| (acc << 7) | (byte & 0x7f) as u64), )) } fn string<'input, E: ParseError<&'input [u8]>>( input: &'input [u8], ) -> IResult<&'input [u8], &'input str, E> { if input.is_empty() { return Err(Err::Error(make_error(input, ErrorKind::Eof))); } let length = input[0] as usize; let input = &input[1..]; if input.len() < length { return Err(Err::Error(make_error(input, ErrorKind::Eof))); } Ok((&input[length..], unsafe { str::from_utf8_unchecked(&input[..length]) })) } fn list<'input, I, E: ParseError<&'input [u8]>>( input: &'input [u8], item_parser: fn(&'input [u8]) -> IResult<&'input [u8], I, E>, ) -> IResult<&'input [u8], Vec, E> { if input.is_empty() { return Err(Err::Error(make_error(input, ErrorKind::Eof))); } let length = input[0] as usize; let mut input = &input[1..]; if input.len() < length { return Err(Err::Error(make_error(input, ErrorKind::Eof))); } let mut items = vec![]; for _ in 0..length { consume!((input, item) = item_parser(input)?); items.push(item); } Ok((input, items)) } fn ty<'input, E: ParseError<&'input [u8]>>( input: &'input [u8], ) -> IResult<&'input [u8], InterfaceType, E> { if input.is_empty() { return Err(Err::Error(make_error(input, ErrorKind::Eof))); } let (output, ty) = leb(input)?; match InterfaceType::try_from(ty) { Ok(ty) => Ok((output, ty)), Err(_) => Err(Err::Error(make_error(input, ErrorKind::ParseTo))), } } 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) = ty(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)) } 0x0f => { consume!((input, argument_0) = ty(input)?); (input, Instruction::Add(argument_0)) } 0x10 => { consume!((input, argument_0) = ty(input)?); consume!((input, argument_1) = string(input)?); (input, Instruction::MemToSeq(argument_0, argument_1)) } 0x11 => { consume!((input, argument_0) = ty(input)?); consume!((input, argument_1) = string(input)?); (input, Instruction::Load(argument_0, argument_1)) } 0x12 => { consume!((input, argument_0) = ty(input)?); (input, Instruction::SeqNew(argument_0)) } 0x13 => (input, Instruction::ListPush), 0x14 => { consume!((input, argument_0) = leb(input)?); consume!((input, argument_1) = leb(input)?); (input, Instruction::RepeatWhile(argument_0, argument_1)) } _ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))), }) } 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)) } 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)) } 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_imported_functions) = leb(input)?); 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)?); imported_functions.push(ImportedFunction { namespace: imported_function_namespace, name: imported_function_name, input_types: imported_function_input_types, output_types: imported_function_output_types, }); } Ok((input, imported_functions)) } fn adapters<'input, E: ParseError<&'input [u8]>>( input: &'input [u8], ) -> IResult<&'input [u8], Vec, E> { let mut input = input; let mut adapters = vec![]; consume!((input, number_of_adapters) = leb(input)?); 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)))?; 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)?); adapters.push(Adapter::Import { namespace: adapter_namespace, name: adapter_name, input_types: adapter_input_types, output_types: adapter_output_types, instructions: adapter_instructions, }); } 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)?); adapters.push(Adapter::Export { name: adapter_name, input_types: adapter_input_types, output_types: adapter_output_types, instructions: adapter_instructions, }); } 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)?); adapters.push(Adapter::HelperFunction { name: adapter_name, input_types: adapter_input_types, output_types: adapter_output_types, instructions: adapter_instructions, }); } } } Ok((input, adapters)) } 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::*; #[test] fn test_byte() { let input = &[0x01, 0x02, 0x03]; let output = Ok((&[0x02, 0x03][..], 0x01u8)); assert_eq!(byte::<()>(input), output); } #[test] fn test_leb_1_byte() { let input = &[0x01, 0x02, 0x03]; let output = Ok((&[0x02, 0x03][..], 0x01u64)); assert_eq!(leb::<()>(input), output); } #[test] fn test_leb_3_bytes() { let input = &[0xfc, 0xff, 0x01, 0x02]; let output = Ok((&[0x02][..], 0x7ffcu64)); assert_eq!(leb::<()>(input), output); } #[test] fn test_string() { let input = &[ 0x03, // string of 3 bytes 0x61, // "a" 0x62, // "b" 0x63, // "c" 0x64, 0x65, ]; let output = Ok((&[0x64, 0x65][..], "abc")); assert_eq!(string::<()>(input), output); } #[test] fn test_list() { let input = &[ 0x02, // list of 2 items 0x01, // string of 1 byte 0x61, // "a" 0x02, // string of 2 bytes 0x62, // "b" 0x63, // "c" 0x07, ]; let output = Ok((&[0x07][..], vec!["a", "bc"])); assert_eq!(list::<&str, ()>(input, string), output); } #[test] fn test_ty() { let input = &[ 0x0a, // list of 10 items 0xff, 0xff, 0x01, // Int 0xfe, 0xff, 0x01, // Float 0xfd, 0xff, 0x01, // Any 0xfc, 0xff, 0x01, // String 0xfb, 0xff, 0x01, // Seq 0x7f, // I32 0x7e, // I64 0x7d, // F32 0x7c, // F64 0x6f, // AnyRef 0x01, ]; let output = Ok(( &[0x01][..], vec![ InterfaceType::Int, InterfaceType::Float, InterfaceType::Any, InterfaceType::String, InterfaceType::Seq, InterfaceType::I32, InterfaceType::I64, InterfaceType::F32, InterfaceType::F64, InterfaceType::AnyRef, ], )); assert_eq!(list::(input, ty), output); } #[test] fn test_instructions() { let input = &[ 0x14, // list of 20 items 0x00, 0x01, // ArgumentGet(1) 0x01, 0x01, // Call(1) 0x02, 0x03, 0x61, 0x62, 0x63, // CallExport("abc") 0x03, // ReadUtf8 0x04, 0x03, 0x61, 0x62, 0x63, // WriteUtf8("abc") 0x05, 0xff, 0xff, 0x01, // AsWasm(Int) 0x06, 0x7e, // AsInterface(I64) 0x07, // TableRefAdd 0x08, // TableRefGet 0x09, 0x01, // CallMethod(1) 0x0a, 0x7f, // MakeRecord(I32) 0x0c, 0xff, 0xff, 0x01, 0x02, // GetField(Int, 2) 0x0d, 0x7f, 0x01, // Const(I32, 1) 0x0e, 0x01, // FoldSeq(1) 0x0f, 0x7f, // Add(I32) 0x10, 0x7f, 0x03, 0x61, 0x62, 0x63, // MemToSeq(I32, "abc") 0x11, 0x7f, 0x03, 0x61, 0x62, 0x63, // Load(I32, "abc") 0x12, 0x7f, // SeqNew(I32) 0x13, // ListPush 0x14, 0x01, 0x02, // RepeatWhile(1, 2) 0x0a, ]; let output = Ok(( &[0x0a][..], vec![ Instruction::ArgumentGet(1), Instruction::Call(1), Instruction::CallExport("abc"), Instruction::ReadUtf8, Instruction::WriteUtf8("abc"), Instruction::AsWasm(InterfaceType::Int), Instruction::AsInterface(InterfaceType::I64), Instruction::TableRefAdd, Instruction::TableRefGet, Instruction::CallMethod(1), Instruction::MakeRecord(InterfaceType::I32), Instruction::GetField(InterfaceType::Int, 2), Instruction::Const(InterfaceType::I32, 1), Instruction::FoldSeq(1), Instruction::Add(InterfaceType::I32), Instruction::MemToSeq(InterfaceType::I32, "abc"), Instruction::Load(InterfaceType::I32, "abc"), Instruction::SeqNew(InterfaceType::I32), Instruction::ListPush, Instruction::RepeatWhile(1, 2), ], )); assert_eq!(list::(input, instructions), output); } #[test] fn test_exports() { let input = &[ 0x02, // 2 exports 0x02, // string of 2 bytes 0x61, 0x62, // "a", "b" 0x01, // list of 1 item 0x7f, // I32 0x01, // list of 1 item 0x7f, // I32 0x02, // string of 2 bytes 0x63, 0x64, // "c", "d" 0x00, // list of 0 item 0x00, // list of 0 item ]; let output = Ok(( &[] as &[u8], vec![ Export { name: "ab", input_types: vec![InterfaceType::I32], output_types: vec![InterfaceType::I32], }, Export { name: "cd", input_types: vec![], output_types: vec![], }, ], )); assert_eq!(exports::<()>(input), output); } #[test] fn test_types() { let input = &[ 0x01, // 1 type 0x02, // string of 2 bytes 0x61, 0x62, // "a", "b" 0x02, // list of 2 items 0x02, // string of 2 bytes 0x63, 0x64, // "c", "d" 0x01, // string of 1 byte 0x65, // "e" 0x02, // list of 2 items 0x7f, // I32 0x7f, // I32 ]; let output = Ok(( &[] as &[u8], vec![Type { name: "ab", fields: vec!["cd", "e"], types: vec![InterfaceType::I32, InterfaceType::I32], }], )); assert_eq!(types::<()>(input), output); } #[test] fn test_imported_functions() { let input = &[ 0x02, // 2 imported functions 0x01, // string of 1 byte 0x61, // "a" 0x01, // string of 1 byte 0x62, // "b" 0x01, // list of 1 item 0x7f, // I32 0x01, // list of 1 item 0x7e, // I64 0x01, // string of 1 byte 0x63, // "c" 0x01, // string of 1 byte 0x64, // "d" 0x01, // list of 1 item 0x7f, // I32 0x01, // list of 1 item 0x7e, // I64 ]; let output = Ok(( &[] as &[u8], vec![ ImportedFunction { namespace: "a", name: "b", input_types: vec![InterfaceType::I32], output_types: vec![InterfaceType::I64], }, ImportedFunction { namespace: "c", name: "d", input_types: vec![InterfaceType::I32], output_types: vec![InterfaceType::I64], }, ], )); assert_eq!(imported_functions::<()>(input), output); } #[test] fn test_adapters() { let input = &[ 0x03, // 3 adapters 0x00, // adapter kind: import 0x01, // string of 1 byte 0x61, // "a" 0x01, // string of 1 byte 0x62, // "b" 0x01, // list of 1 item 0x7f, // I32 0x01, // list of 1 item 0x7f, // I32 0x01, // list of 1 item 0x00, 0x01, // ArgumentGet(1) 0x01, // adapter kind: export 0x01, // string of 1 byte 0x63, // "c" 0x01, // list of 1 item 0x7f, // I32 0x01, // list of 1 item 0x7f, // I32 0x01, // list of 1 item 0x00, 0x01, // ArgumentGet(1) 0x02, // adapter kind: helper function 0x01, // string of 1 byte 0x64, // "d" 0x01, // list of 1 item 0x7f, // I32 0x01, // list of 1 item 0x7f, // I32 0x01, // list of 1 item 0x00, 0x01, // ArgumentGet(1) ]; let output = Ok(( &[] as &[u8], vec![ Adapter::Import { namespace: "a", name: "b", input_types: vec![InterfaceType::I32], output_types: vec![InterfaceType::I32], instructions: vec![Instruction::ArgumentGet(1)], }, Adapter::Export { name: "c", input_types: vec![InterfaceType::I32], output_types: vec![InterfaceType::I32], instructions: vec![Instruction::ArgumentGet(1)], }, Adapter::HelperFunction { name: "d", input_types: vec![InterfaceType::I32], output_types: vec![InterfaceType::I32], instructions: vec![Instruction::ArgumentGet(1)], }, ], )); assert_eq!(adapters::<()>(input), output); } #[test] fn test_forwards() { let input = &[ 0x02, // 2 adapters 0x01, // string of 1 byte 0x61, // "a" 0x02, // string of 2 bytes 0x62, 0x63, // "b", "c" ]; let output = Ok(( &[] as &[u8], vec![Forward { name: "a" }, Forward { name: "bc" }], )); assert_eq!(forwards::<()>(input), output); } }