use crate::{ast::*, interpreter::Instruction, types::*};
use nom::{
error::{make_error, ErrorKind, ParseError},
Err, IResult,
};
use std::rc::Rc;
use std::{convert::TryFrom, str};
impl TryFrom<u8> for TypeKind {
type Error = &'static str;
fn try_from(code: u8) -> Result<Self, Self::Error> {
Ok(match code {
0x00 => Self::Function,
0x01 => Self::Record,
_ => return Err("Unknown type kind code."),
})
}
}
impl TryFrom<u8> for InterfaceKind {
type Error = &'static str;
fn try_from(code: u8) -> Result<Self, Self::Error> {
Ok(match code {
0x00 => Self::Type,
0x01 => Self::Import,
0x02 => Self::Adapter,
0x03 => Self::Export,
0x04 => Self::Implementation,
_ => return Err("Unknown interface 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 uleb<'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(length) if length <= 8 => (&input[length + 1..], &input[..=length]),
Some(_) => return Err(Err::Error(make_error(input, ErrorKind::TooLarge))),
None => return Err(Err::Error(make_error(input, ErrorKind::Eof))),
};
Ok((
output,
bytes
.iter()
.rev()
.fold(0, |acc, byte| (acc << 7) | u64::from(byte & 0x7f)),
))
}
fn record_field<'input, E: ParseError<&'input [u8]>>(
mut input: &'input [u8],
) -> IResult<&'input [u8], RecordFieldType, E> {
if input.is_empty() {
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
}
consume!((input, name) = owned_string(input)?);
consume!((input, ty) = ty(input)?);
Ok((input, RecordFieldType { name, ty }))
}
fn function_arg<'input, E: ParseError<&'input [u8]>>(
mut input: &'input [u8],
) -> IResult<&'input [u8], FunctionArg, E> {
if input.is_empty() {
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
}
consume!((input, name) = owned_string(input)?);
consume!((input, ty) = ty(input)?);
Ok((input, FunctionArg { name, ty }))
}
fn ty<'input, E: ParseError<&'input [u8]>>(
mut input: &'input [u8],
) -> IResult<&'input [u8], InterfaceType, E> {
if input.is_empty() {
return Err(Err::Error(make_error(input, ErrorKind::Eof)));
}
consume!((input, opcode) = byte(input)?);
let ty = match opcode {
0x00 => InterfaceType::S8,
0x01 => InterfaceType::S16,
0x02 => InterfaceType::S32,
0x03 => InterfaceType::S64,
0x04 => InterfaceType::U8,
0x05 => InterfaceType::U16,
0x06 => InterfaceType::U32,
0x07 => InterfaceType::U64,
0x08 => InterfaceType::F32,
0x09 => InterfaceType::F64,
0x0a => InterfaceType::String,
0x36 => {
consume!((input, array_value_type) = ty(input)?);
InterfaceType::Array(Box::new(array_value_type))
}
0x0b => InterfaceType::Anyref,
0x0c => InterfaceType::I32,
0x0d => InterfaceType::I64,
0x0e => {
consume!((input, record_id) = uleb(input)?);
InterfaceType::Record(record_id)
}
_ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))),
};
Ok((input, ty))
}
fn record_type<'input, E: ParseError<&'input [u8]>>(
input: &'input [u8],
) -> IResult<&'input [u8], RecordType, E> {
use crate::vec1::Vec1;
let (output, name) = owned_string(input)?;
let (output, fields) = list(output, record_field)?;
Ok((
output,
RecordType {
name,
fields: Vec1::new(fields).expect("Record must have at least one field, zero given."),
},
))
}
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..],
str::from_utf8(&input[..length])
.map_err(|_| Err::Error(make_error(input, ErrorKind::ParseTo)))?,
))
}
fn owned_string<'input, E: ParseError<&'input [u8]>>(
input: &'input [u8],
) -> IResult<&'input [u8], String, 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..],
String::from_utf8(input[..length].to_vec())
.map_err(|_| Err::Error(make_error(input, ErrorKind::ParseTo)))?,
))
}
#[allow(clippy::type_complexity)]
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<I>, 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::with_capacity(length as usize);
for _ in 0..length {
consume!((input, item) = item_parser(input)?);
items.push(item);
}
Ok((input, items))
}
fn instruction<'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) = uleb(input)?);
(
input,
Instruction::ArgumentGet {
index: argument_0 as u32,
},
)
}
0x01 => {
consume!((input, argument_0) = uleb(input)?);
(
input,
Instruction::CallCore {
function_index: argument_0 as u32,
},
)
}
0x02 => (input, Instruction::S8FromI32),
0x03 => (input, Instruction::S8FromI64),
0x04 => (input, Instruction::S16FromI32),
0x05 => (input, Instruction::S16FromI64),
0x06 => (input, Instruction::S32FromI32),
0x07 => (input, Instruction::S32FromI64),
0x08 => (input, Instruction::S64FromI32),
0x09 => (input, Instruction::S64FromI64),
0x0a => (input, Instruction::I32FromS8),
0x0b => (input, Instruction::I32FromS16),
0x0c => (input, Instruction::I32FromS32),
0x0d => (input, Instruction::I32FromS64),
0x0e => (input, Instruction::I64FromS8),
0x0f => (input, Instruction::I64FromS16),
0x10 => (input, Instruction::I64FromS32),
0x11 => (input, Instruction::I64FromS64),
0x12 => (input, Instruction::U8FromI32),
0x13 => (input, Instruction::U8FromI64),
0x14 => (input, Instruction::U16FromI32),
0x15 => (input, Instruction::U16FromI64),
0x16 => (input, Instruction::U32FromI32),
0x17 => (input, Instruction::U32FromI64),
0x18 => (input, Instruction::U64FromI32),
0x19 => (input, Instruction::U64FromI64),
0x1a => (input, Instruction::I32FromU8),
0x1b => (input, Instruction::I32FromU16),
0x1c => (input, Instruction::I32FromU32),
0x1d => (input, Instruction::I32FromU64),
0x1e => (input, Instruction::I64FromU8),
0x1f => (input, Instruction::I64FromU16),
0x20 => (input, Instruction::I64FromU32),
0x21 => (input, Instruction::I64FromU64),
0x22 => (input, Instruction::StringLiftMemory),
0x23 => (input, Instruction::StringLowerMemory),
0x24 => (input, Instruction::StringSize),
0x37 => {
consume!((input, value_type) = ty(input)?);
(input, Instruction::ArrayLiftMemory { value_type })
}
0x38 => {
consume!((input, value_type) = ty(input)?);
(input, Instruction::ArrayLowerMemory { value_type })
}
0x3A => {
consume!((input, record_type_id) = uleb(input)?);
(
input,
Instruction::RecordLiftMemory {
record_type_id: record_type_id as u32,
},
)
}
0x3B => {
consume!((input, record_type_id) = uleb(input)?);
(
input,
Instruction::RecordLowerMemory {
record_type_id: record_type_id as u32,
},
)
}
0x34 => (input, Instruction::Dup),
0x35 => (input, Instruction::Swap2),
_ => return Err(Err::Error(make_error(input, ErrorKind::ParseTo))),
})
}
fn types<'input, E: ParseError<&'input [u8]>>(
mut input: &'input [u8],
) -> IResult<&'input [u8], Vec<Type>, E> {
consume!((input, number_of_types) = uleb(input)?);
let mut types = Vec::with_capacity(number_of_types as usize);
for _ in 0..number_of_types {
consume!((input, type_kind) = byte(input)?);
let type_kind = TypeKind::try_from(type_kind)
.map_err(|_| Err::Error(make_error(input, ErrorKind::ParseTo)))?;
match type_kind {
TypeKind::Function => {
consume!((input, arguments) = list(input, function_arg)?);
consume!((input, output_types) = list(input, ty)?);
types.push(Type::Function {
arguments: Rc::new(arguments),
output_types: Rc::new(output_types),
});
}
TypeKind::Record => {
consume!((input, record_type) = record_type(input)?);
types.push(Type::Record(Rc::new(record_type)));
}
}
}
Ok((input, types))
}
fn imports<'input, E: ParseError<&'input [u8]>>(
mut input: &'input [u8],
) -> IResult<&'input [u8], Vec<Import>, E> {
consume!((input, number_of_imports) = uleb(input)?);
let mut imports = Vec::with_capacity(number_of_imports as usize);
for _ in 0..number_of_imports {
consume!((input, namespace) = string(input)?);
consume!((input, name) = string(input)?);
consume!((input, function_type) = uleb(input)?);
imports.push(Import {
namespace,
name,
function_type: function_type as u32,
});
}
Ok((input, imports))
}
fn adapters<'input, E: ParseError<&'input [u8]>>(
mut input: &'input [u8],
) -> IResult<&'input [u8], Vec<Adapter>, E> {
consume!((input, number_of_adapters) = uleb(input)?);
let mut adapters = Vec::with_capacity(number_of_adapters as usize);
for _ in 0..number_of_adapters {
consume!((input, function_type) = uleb(input)?);
consume!((input, instructions) = list(input, instruction)?);
adapters.push(Adapter {
function_type: function_type as u32,
instructions,
});
}
Ok((input, adapters))
}
fn exports<'input, E: ParseError<&'input [u8]>>(
mut input: &'input [u8],
) -> IResult<&'input [u8], Vec<Export>, E> {
consume!((input, number_of_exports) = uleb(input)?);
let mut exports = Vec::with_capacity(number_of_exports as usize);
for _ in 0..number_of_exports {
consume!((input, name) = string(input)?);
consume!((input, function_type) = uleb(input)?);
exports.push(Export {
name,
function_type: function_type as u32,
});
}
Ok((input, exports))
}
fn implementations<'input, E: ParseError<&'input [u8]>>(
mut input: &'input [u8],
) -> IResult<&'input [u8], Vec<Implementation>, E> {
consume!((input, number_of_implementations) = uleb(input)?);
let mut implementations = Vec::with_capacity(number_of_implementations as usize);
for _ in 0..number_of_implementations {
consume!((input, core_function_type) = uleb(input)?);
consume!((input, adapter_function_type) = uleb(input)?);
implementations.push(Implementation {
core_function_type: core_function_type as u32,
adapter_function_type: adapter_function_type as u32,
});
}
Ok((input, implementations))
}
fn interfaces<'input, E: ParseError<&'input [u8]>>(
bytes: &'input [u8],
) -> IResult<&'input [u8], Interfaces, E> {
let mut input = bytes;
let mut all_types = vec![];
let mut all_imports = vec![];
let mut all_adapters = vec![];
let mut all_exports = vec![];
let mut all_implementations = vec![];
while !input.is_empty() {
consume!((input, interface_kind) = byte(input)?);
let interface_kind = InterfaceKind::try_from(interface_kind)
.map_err(|_| Err::Error(make_error(input, ErrorKind::ParseTo)))?;
match interface_kind {
InterfaceKind::Type => {
consume!((input, mut new_types) = types(input)?);
all_types.append(&mut new_types);
}
InterfaceKind::Import => {
consume!((input, mut new_imports) = imports(input)?);
all_imports.append(&mut new_imports);
}
InterfaceKind::Adapter => {
consume!((input, mut new_adapters) = adapters(input)?);
all_adapters.append(&mut new_adapters);
}
InterfaceKind::Export => {
consume!((input, mut new_exports) = exports(input)?);
all_exports.append(&mut new_exports);
}
InterfaceKind::Implementation => {
consume!((input, mut new_implementations) = implementations(input)?);
all_implementations.append(&mut new_implementations)
}
}
}
Ok((
input,
Interfaces {
types: all_types,
imports: all_imports,
adapters: all_adapters,
exports: all_exports,
implementations: all_implementations,
},
))
}
pub fn parse<'input, E: ParseError<&'input [u8]>>(
bytes: &'input [u8],
) -> IResult<&'input [u8], Interfaces, E> {
interfaces(bytes)
}
#[cfg(test)]
mod tests {
use super::*;
use nom::{error, Err};
#[test]
fn test_byte() {
let input = &[0x01, 0x02, 0x03];
let output = Ok((&[0x02, 0x03][..], 0x01u8));
assert_eq!(byte::<()>(input), output);
}
#[test]
fn test_uleb_1_byte() {
let input = &[0x01, 0x02, 0x03];
let output = Ok((&[0x02, 0x03][..], 0x01u64));
assert_eq!(uleb::<()>(input), output);
}
#[test]
fn test_uleb_3_bytes() {
let input = &[0xfc, 0xff, 0x01, 0x02];
let output = Ok((&[0x02][..], 0x7ffcu64));
assert_eq!(uleb::<()>(input), output);
}
#[test]
fn test_uleb_from_dwarf_standard() {
macro_rules! assert_uleb {
($to_parse:expr => $expected_result:expr) => {
assert_eq!(uleb::<()>($to_parse), Ok((&[][..], $expected_result)));
};
}
assert_uleb!(&[2u8] => 2u64);
assert_uleb!(&[127u8] => 127u64);
assert_uleb!(&[0x80, 1u8] => 128u64);
assert_uleb!(&[1u8 | 0x80, 1] => 129u64);
assert_uleb!(&[2u8 | 0x80, 1] => 130u64);
assert_uleb!(&[57u8 | 0x80, 100] => 12857u64);
}
#[test]
fn test_uleb_eof() {
let input = &[0x80];
assert_eq!(
uleb::<(&[u8], error::ErrorKind)>(input),
Err(Err::Error((&input[..], error::ErrorKind::Eof))),
);
}
#[test]
fn test_uleb_overflow() {
let input = &[
0x01 | 0x80,
0x02 | 0x80,
0x03 | 0x80,
0x04 | 0x80,
0x05 | 0x80,
0x06 | 0x80,
0x07 | 0x80,
0x08 | 0x80,
0x09 | 0x80,
0x0a,
];
assert_eq!(
uleb::<(&[u8], error::ErrorKind)>(input),
Err(Err::Error((&input[..], error::ErrorKind::TooLarge))),
);
}
#[test]
fn test_ty() {
let input = &[
0x0f,
0x00,
0x01,
0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08,
0x09,
0x0a,
0x0b,
0x0c,
0x0d,
0x0e, 0x01, 0x02,
0x01,
];
let output = Ok((
&[0x01][..],
vec![
InterfaceType::S8,
InterfaceType::S16,
InterfaceType::S32,
InterfaceType::S64,
InterfaceType::U8,
InterfaceType::U16,
InterfaceType::U32,
InterfaceType::U64,
InterfaceType::F32,
InterfaceType::F64,
InterfaceType::String,
InterfaceType::Anyref,
InterfaceType::I32,
InterfaceType::I64,
InterfaceType::Record(RecordType {
fields: vec1![InterfaceType::S32],
}),
],
));
assert_eq!(list::<_, ()>(input, ty), output);
}
#[test]
fn test_record_type() {
let input = &[
0x03,
0x01,
0x0a,
0x02,
0x0a,
0x0c,
0x03,
0x0a,
0x0e,
0x02,
0x0c,
0x0c,
0x09,
0x01,
];
let output = Ok((
&[0x01][..],
vec![
RecordType {
fields: vec1![InterfaceType::String],
},
RecordType {
fields: vec1![InterfaceType::String, InterfaceType::I32],
},
RecordType {
fields: vec1![
InterfaceType::String,
InterfaceType::Record(RecordType {
fields: vec1![InterfaceType::I32, InterfaceType::I32],
}),
InterfaceType::F64,
],
},
],
));
assert_eq!(list::<_, ()>(input, record_type), output);
}
#[test]
fn test_string() {
let input = &[
0x03,
0x61,
0x62,
0x63,
0x64, 0x65,
];
let output = Ok((&[0x64, 0x65][..], "abc"));
assert_eq!(string::<()>(input), output);
}
#[test]
fn test_list() {
let input = &[
0x02,
0x01,
0x61,
0x02,
0x62,
0x63,
0x07,
];
let output = Ok((&[0x07][..], vec!["a", "bc"]));
assert_eq!(list::<_, ()>(input, string), output);
}
#[test]
fn test_instructions() {
let input = &[
0x27,
0x00, 0x01,
0x01, 0x01,
0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08,
0x09,
0x0a,
0x0b,
0x0c,
0x0d,
0x0e,
0x0f,
0x10,
0x11,
0x12,
0x13,
0x14,
0x15,
0x16,
0x17,
0x18,
0x19,
0x1a,
0x1b,
0x1c,
0x1d,
0x1e,
0x1f,
0x20,
0x21,
0x22,
0x23,
0x24,
0x25, 0x01,
0x26, 0x01,
0x0a,
];
let output = Ok((
&[0x0a][..],
vec![
Instruction::ArgumentGet { index: 1 },
Instruction::CallCore { function_index: 1 },
Instruction::S8FromI32,
Instruction::S8FromI64,
Instruction::S16FromI32,
Instruction::S16FromI64,
Instruction::S32FromI32,
Instruction::S32FromI64,
Instruction::S64FromI32,
Instruction::S64FromI64,
Instruction::I32FromS8,
Instruction::I32FromS16,
Instruction::I32FromS32,
Instruction::I32FromS64,
Instruction::I64FromS8,
Instruction::I64FromS16,
Instruction::I64FromS32,
Instruction::I64FromS64,
Instruction::U8FromI32,
Instruction::U8FromI64,
Instruction::U16FromI32,
Instruction::U16FromI64,
Instruction::U32FromI32,
Instruction::U32FromI64,
Instruction::U64FromI32,
Instruction::U64FromI64,
Instruction::I32FromU8,
Instruction::I32FromU16,
Instruction::I32FromU32,
Instruction::I32FromU64,
Instruction::I64FromU8,
Instruction::I64FromU16,
Instruction::I64FromU32,
Instruction::I64FromU64,
Instruction::StringLiftMemory,
Instruction::StringLowerMemory,
Instruction::StringSize,
],
));
assert_eq!(list::<_, ()>(input, instruction), output);
}
#[test]
fn test_exports() {
let input = &[
0x02,
0x02,
0x61, 0x62,
0x01,
0x02,
0x63, 0x64,
0x02,
];
let output = Ok((
&[] as &[u8],
vec![
Export {
name: "ab",
function_type: 1,
},
Export {
name: "cd",
function_type: 2,
},
],
));
assert_eq!(exports::<()>(input), output);
}
#[test]
fn test_types() {
let input = &[
0x02,
0x00,
0x02,
0x02,
0x02,
0x01,
0x02,
0x01,
0x02,
0x02,
0x02,
];
let output = Ok((
&[] as &[u8],
vec![
Type::Function {
inputs: vec![InterfaceType::S32, InterfaceType::S32],
outputs: vec![InterfaceType::S32],
},
Type::Record(RecordType {
fields: vec1![InterfaceType::S32, InterfaceType::S32],
}),
],
));
assert_eq!(types::<()>(input), output);
}
#[test]
fn test_imports() {
let input = &[
0x02,
0x01,
0x61,
0x01,
0x62,
0x01,
0x01,
0x63,
0x01,
0x64,
0x02,
];
let output = Ok((
&[] as &[u8],
vec![
Import {
namespace: "a",
name: "b",
function_type: 1,
},
Import {
namespace: "c",
name: "d",
function_type: 2,
},
],
));
assert_eq!(imports::<()>(input), output);
}
#[test]
fn test_adapters() {
let input = &[
0x01,
0x00,
0x01,
0x00, 0x01,
];
let output = Ok((
&[] as &[u8],
vec![Adapter {
function_type: 0,
instructions: vec![Instruction::ArgumentGet { index: 1 }],
}],
));
assert_eq!(adapters::<()>(input), output);
}
#[test]
fn test_parse() {
let input = &[
0x00,
0x01,
0x00,
0x01,
0x00,
0x01,
0x01,
0x01,
0x01,
0x02,
0x61, 0x62,
0x01,
0x63,
0x00,
0x02,
0x01,
0x00,
0x01,
0x00, 0x01,
0x03,
0x01,
0x02,
0x61, 0x62,
0x01,
0x04,
0x01,
0x02,
0x03,
];
let output = Ok((
&[] as &[u8],
Interfaces {
types: vec![Type::Function {
inputs: vec![InterfaceType::S8],
outputs: vec![InterfaceType::S16],
}],
imports: vec![Import {
namespace: "ab",
name: "c",
function_type: 0,
}],
adapters: vec![Adapter {
function_type: 0,
instructions: vec![Instruction::ArgumentGet { index: 1 }],
}],
exports: vec![Export {
name: "ab",
function_type: 1,
}],
implementations: vec![Implementation {
core_function_type: 2,
adapter_function_type: 3,
}],
},
));
assert_eq!(interfaces::<()>(input), output);
}
}