use crate::parser::instructions::parse_expression;
use crate::parser::types::{
parse_global_type, parse_memory_type, parse_reference_type, parse_table_type, parse_value_type,
};
use crate::parser::values::{match_byte, parse_byte_vector, parse_name, parse_u32, parse_vector};
use crate::{
Data, Element, ElementInitializer, Export, ExportDescription, Expression, Global, Import,
ImportDescription, Memory, ReferenceType, ResultType, Start, Table,
};
use nom::branch::alt;
use nom::bytes::complete::take;
use nom::combinator::{all_consuming, map};
use nom::multi::fold_many_m_n;
use nom::sequence::{preceded, tuple};
use nom::IResult;
pub fn parse_import(input: &[u8]) -> IResult<&[u8], Import> {
map(
tuple((parse_name, parse_name, parse_import_description)),
|(module, import, description)| Import::new(module, import, description),
)(input)
}
fn parse_import_description(input: &[u8]) -> IResult<&[u8], ImportDescription> {
alt((
map(
preceded(match_byte(0x00), parse_u32),
ImportDescription::Function,
),
map(
preceded(match_byte(0x01), parse_table_type),
ImportDescription::Table,
),
map(
preceded(match_byte(0x02), parse_memory_type),
ImportDescription::Memory,
),
map(
preceded(match_byte(0x03), parse_global_type),
ImportDescription::Global,
),
))(input)
}
pub fn parse_table(input: &[u8]) -> IResult<&[u8], Table> {
map(parse_table_type, Table::from)(input)
}
pub fn parse_memory(input: &[u8]) -> IResult<&[u8], Memory> {
map(parse_memory_type, Memory::from)(input)
}
pub fn parse_global(input: &[u8]) -> IResult<&[u8], Global> {
map(
tuple((parse_global_type, parse_expression)),
|(kind, initializer)| Global::new(kind, initializer),
)(input)
}
pub fn parse_data(input: &[u8]) -> IResult<&[u8], Data> {
alt((
map(
preceded(
match_byte(0x00),
tuple((parse_expression, parse_byte_vector)),
),
|(offset, bytes)| Data::active(0, offset, bytes.into()),
),
map(preceded(match_byte(0x01), parse_byte_vector), |bytes| {
Data::passive(bytes.into())
}),
map(
preceded(
match_byte(0x02),
tuple((parse_u32, parse_expression, parse_byte_vector)),
),
|(memory, offset, bytes)| Data::active(memory, offset, bytes.into()),
),
))(input)
}
pub fn parse_start(input: &[u8]) -> IResult<&[u8], Start> {
map(parse_u32, Start::new)(input)
}
pub fn parse_export(input: &[u8]) -> IResult<&[u8], Export> {
map(
tuple((parse_name, parse_export_description)),
|(export, description)| Export::new(export, description),
)(input)
}
fn parse_export_description(input: &[u8]) -> IResult<&[u8], ExportDescription> {
alt((
map(
preceded(match_byte(0x00), parse_u32),
ExportDescription::Function,
),
map(
preceded(match_byte(0x01), parse_u32),
ExportDescription::Table,
),
map(
preceded(match_byte(0x02), parse_u32),
ExportDescription::Memory,
),
map(
preceded(match_byte(0x03), parse_u32),
ExportDescription::Global,
),
))(input)
}
pub fn parse_element(input: &[u8]) -> IResult<&[u8], Element> {
alt((
map(
preceded(
match_byte(0x00),
tuple((parse_expression, parse_vector(parse_u32))),
),
|(offset, functions)| {
Element::active(
0,
offset,
ReferenceType::Function,
functions.to_initializers(),
)
},
),
map(
preceded(
match_byte(0x01),
preceded(match_byte(0x00), parse_vector(parse_u32)),
),
|functions| Element::passive(ReferenceType::Function, functions.to_initializers()),
),
map(
preceded(
match_byte(0x02),
tuple((
parse_u32,
parse_expression,
preceded(match_byte(0x00), parse_vector(parse_u32)),
)),
),
|(table, offset, functions)| {
Element::active(
table,
offset,
ReferenceType::Function,
functions.to_initializers(),
)
},
),
map(
preceded(
match_byte(0x03),
preceded(match_byte(0x00), parse_vector(parse_u32)),
),
|functions| Element::declarative(ReferenceType::Function, functions.to_initializers()),
),
map(
preceded(
match_byte(0x04),
tuple((parse_expression, parse_vector(parse_expression))),
),
|(offset, initializers)| {
Element::active(0, offset, ReferenceType::Function, initializers)
},
),
map(
preceded(
match_byte(0x05),
tuple((parse_reference_type, parse_vector(parse_expression))),
),
|(kind, initializers)| Element::passive(kind, initializers),
),
map(
preceded(
match_byte(0x06),
tuple((
parse_u32,
parse_expression,
parse_reference_type,
parse_vector(parse_expression),
)),
),
|(table, offset, kind, initializers)| {
Element::active(table, offset, kind, initializers)
},
),
map(
preceded(
match_byte(0x07),
tuple((parse_reference_type, parse_vector(parse_expression))),
),
|(kind, initializers)| Element::declarative(kind, initializers),
),
))(input)
}
pub fn parse_code(input: &[u8]) -> IResult<&[u8], (ResultType, Expression)> {
let (input, size) = parse_u32(input)?;
let (remaining, input) = take(size as usize)(input)?;
let (_, code) = all_consuming(tuple((parse_locals, parse_expression)))(input)?;
Ok((remaining, code))
}
pub fn parse_locals(input: &[u8]) -> IResult<&[u8], ResultType> {
let (input, length) = parse_u32(input)?;
let length = length as usize;
let (remaining, value_types) = fold_many_m_n(
length,
length,
tuple((parse_u32, parse_value_type)),
Vec::new,
|mut accumulator, (count, kind)| {
accumulator.reserve(count as usize);
accumulator.extend((0..count).map(|_| kind));
accumulator
},
)(input)?;
Ok((remaining, value_types.into()))
}