use std::borrow::Cow;
use std::collections::HashMap;
use std::fmt;
type Indices<'s> = HashMap<&'s str, u32>;
#[cfg_attr(test, derive(Debug))]
pub struct Parsed<'s> {
pub module: Module<'s>,
pub type_indices: Indices<'s>,
pub func_indices: Indices<'s>,
pub table_indices: Indices<'s>,
pub mem_indices: Indices<'s>,
pub global_indices: Indices<'s>,
}
#[cfg_attr(test, derive(Debug))]
pub struct Module<'s> {
pub start: usize,
pub id: Option<&'s str>,
pub types: Vec<TypeDef<'s>>,
pub exports: Vec<Export<'s>>,
pub funcs: Vec<Func<'s>>,
pub elems: Vec<Elem<'s>>,
pub tables: Vec<Table<'s>>,
pub data: Vec<Data<'s>>,
pub memories: Vec<Memory<'s>>,
pub globals: Vec<Global<'s>>,
pub entrypoint: Option<Start<'s>>,
pub implicit_type_uses: Vec<u32>,
}
#[cfg_attr(test, derive(Debug))]
pub struct TypeDef<'s> {
pub start: usize,
pub id: Option<&'s str>,
pub ty: FuncType<'s>,
}
#[derive(Clone)]
#[cfg_attr(test, derive(Debug))]
pub struct FuncType<'s> {
pub start: usize,
pub params: Vec<Param<'s>>,
pub results: Vec<FuncResult>,
}
#[derive(Clone)]
#[cfg_attr(test, derive(Debug))]
pub struct Param<'s> {
pub start: usize,
pub id: Option<&'s str>,
pub ty: ValType,
}
#[derive(Clone)]
#[cfg_attr(test, derive(Debug))]
pub struct FuncResult {
pub start: usize,
pub ty: ValType,
}
#[derive(PartialEq, Clone, Copy)]
#[cfg_attr(test, derive(Debug))]
pub enum ValType {
I32,
I64,
F32,
F64,
}
#[cfg_attr(test, derive(Debug))]
pub struct Import {
pub mod_name: Name,
pub name: Name,
}
#[cfg_attr(test, derive(Debug))]
pub struct Name(pub String);
#[cfg_attr(test, derive(Debug, PartialEq))]
pub enum TypeIndex<'s> {
Explicit(Index<'s>),
Implicit(u32),
}
#[cfg_attr(test, derive(Debug))]
pub struct TypeUse<'s> {
pub start: usize,
pub idx: TypeIndex<'s>,
pub params: Vec<Param<'s>>,
pub results: Vec<FuncResult>,
}
pub struct ImplicitTypeUse<'s> {
pub start: usize,
pub params: Vec<Param<'s>>,
pub results: Vec<FuncResult>,
}
#[cfg_attr(test, derive(Debug, PartialEq))]
pub enum Index<'s> {
Num(u32),
Ident(&'s str),
}
impl<'s> fmt::Display for Index<'s> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Index::Num(i) => write!(f, "{}", i),
Index::Ident(i) => write!(f, "{}", i),
}
}
}
#[cfg_attr(test, derive(Debug))]
pub struct TableType {
pub limit: Limits,
}
#[cfg_attr(test, derive(Debug))]
pub enum Limits {
Range { min: u32, max: u32 },
From { min: u32 },
}
#[cfg_attr(test, derive(Debug))]
pub struct MemType {
pub limit: Limits,
}
#[cfg_attr(test, derive(Debug))]
pub struct GlobalType {
pub mutable: bool,
pub ty: ValType,
}
#[cfg_attr(test, derive(Debug))]
pub struct Export<'s> {
pub start: usize,
pub name: Name,
pub kind: ExportKind,
pub idx: Index<'s>,
}
#[cfg_attr(test, derive(Debug))]
pub enum ExportKind {
Func,
Table,
Memory,
Global,
}
#[cfg_attr(test, derive(Debug))]
pub enum FuncKind<'s> {
Import(Import),
Body {
locals: Vec<Local<'s>>,
body: Vec<Instruction<'s>>,
},
}
#[cfg_attr(test, derive(Debug))]
pub struct Func<'s> {
pub start: usize,
pub id: Option<&'s str>,
pub ty: TypeUse<'s>,
pub kind: FuncKind<'s>,
}
#[cfg_attr(test, derive(Debug))]
pub struct Local<'s> {
pub start: usize,
pub id: Option<&'s str>,
pub ty: ValType,
}
#[cfg_attr(test, derive(Debug))]
pub struct Instruction<'s> {
pub start: usize,
pub kind: InsnKind<'s>,
}
#[cfg_attr(test, derive(Debug))]
pub struct Mem {
pub align: u32,
pub offset: u32,
}
#[cfg_attr(test, derive(Debug))]
pub enum InsnKind<'s> {
Block {
label: Option<&'s str>,
ty: Option<ValType>,
body: Vec<Instruction<'s>>,
id: Option<&'s str>,
},
Loop {
label: Option<&'s str>,
ty: Option<ValType>,
body: Vec<Instruction<'s>>,
id: Option<&'s str>,
},
If {
label: Option<&'s str>,
ty: Option<ValType>,
then_body: Vec<Instruction<'s>>,
else_id: Option<&'s str>,
else_body: Vec<Instruction<'s>>,
end_id: Option<&'s str>,
},
Unreachable,
Nop,
Br(Index<'s>),
BrIf(Index<'s>),
BrTable {
labels: Vec<Index<'s>>,
default_label: Index<'s>,
},
Return,
Call(Index<'s>),
CallIndirect(TypeUse<'s>),
Drop,
Select,
LocalGet(Index<'s>),
LocalSet(Index<'s>),
LocalTee(Index<'s>),
GlobalGet(Index<'s>),
GlobalSet(Index<'s>),
I32Load(Mem),
I64Load(Mem),
F32Load(Mem),
F64Load(Mem),
I32Load8S(Mem),
I32Load8U(Mem),
I32Load16S(Mem),
I32Load16U(Mem),
I64Load8S(Mem),
I64Load8U(Mem),
I64Load16S(Mem),
I64Load16U(Mem),
I64Load32S(Mem),
I64Load32U(Mem),
I32Store(Mem),
I64Store(Mem),
F32Store(Mem),
F64Store(Mem),
I32Store8(Mem),
I32Store16(Mem),
I64Store8(Mem),
I64Store16(Mem),
I64Store32(Mem),
MemorySize,
MemoryGrow,
I32Const(i32),
I64Const(i64),
F32Const(f32),
F64Const(f64),
I32Clz,
I32Ctz,
I32Popcnt,
I32Add,
I32Sub,
I32Mul,
I32DivS,
I32DivU,
I32RemS,
I32RemU,
I32And,
I32Or,
I32Xor,
I32Shl,
I32ShrS,
I32ShrU,
I32Rotl,
I32Rotr,
I64Clz,
I64Ctz,
I64Popcnt,
I64Add,
I64Sub,
I64Mul,
I64DivS,
I64DivU,
I64RemS,
I64RemU,
I64And,
I64Or,
I64Xor,
I64Shl,
I64ShrS,
I64ShrU,
I64Rotl,
I64Rotr,
F32Abs,
F32Neg,
F32Ceil,
F32Floor,
F32Trunc,
F32Nearest,
F32Sqrt,
F32Add,
F32Sub,
F32Mul,
F32Div,
F32Min,
F32Max,
F32Copysign,
F64Abs,
F64Neg,
F64Ceil,
F64Floor,
F64Trunc,
F64Nearest,
F64Sqrt,
F64Add,
F64Sub,
F64Mul,
F64Div,
F64Min,
F64Max,
F64Copysign,
I32Eqz,
I32Eq,
I32Ne,
I32LtS,
I32LtU,
I32GtS,
I32GtU,
I32LeS,
I32LeU,
I32GeS,
I32GeU,
I64Eqz,
I64Eq,
I64Ne,
I64LtS,
I64LtU,
I64GtS,
I64GtU,
I64LeS,
I64LeU,
I64GeS,
I64GeU,
F32Eq,
F32Ne,
F32Lt,
F32Gt,
F32Le,
F32Ge,
F64Eq,
F64Ne,
F64Lt,
F64Gt,
F64Le,
F64Ge,
I32WrapI64,
I32TruncF32S,
I32TruncF32U,
I32TruncF64S,
I32TruncF64U,
I64ExtendI32S,
I64ExtendI32U,
I64TruncF32S,
I64TruncF32U,
I64TruncF64S,
I64TruncF64U,
F32ConvertI32S,
F32ConvertI32U,
F32ConvertI64S,
F32ConvertI64U,
F32DemoteF64,
F64ConvertI32S,
F64ConvertI32U,
F64ConvertI64S,
F64ConvertI64U,
F64PromoteF32,
I32ReinterpretF32,
I64ReinterpretF64,
F32ReinterpretI32,
F64ReinterpretI64,
}
impl<'s> InsnKind<'s> {
pub fn is_block(&self) -> bool {
use InsnKind::*;
match self {
Block { .. } | Loop { .. } | If { .. } => true,
_ => false,
}
}
}
#[cfg_attr(test, derive(Debug))]
pub struct Elem<'s> {
pub start: usize,
pub idx: Index<'s>,
pub offset: Vec<Instruction<'s>>,
pub init: Vec<Index<'s>>,
}
#[cfg_attr(test, derive(Debug))]
pub struct Table<'s> {
pub start: usize,
pub id: Option<&'s str>,
pub ty: TableType,
pub import: Option<Import>,
}
#[cfg_attr(test, derive(Debug))]
pub struct Data<'s> {
pub start: usize,
pub idx: Index<'s>,
pub offset: Vec<Instruction<'s>>,
pub data: Cow<'s, [u8]>,
}
#[cfg_attr(test, derive(Debug))]
pub struct Memory<'s> {
pub start: usize,
pub id: Option<&'s str>,
pub ty: MemType,
pub import: Option<Import>,
}
#[cfg_attr(test, derive(Debug))]
pub enum GlobalKind<'s> {
Import(Import),
Init(Vec<Instruction<'s>>),
}
#[cfg_attr(test, derive(Debug))]
pub struct Global<'s> {
pub start: usize,
pub id: Option<&'s str>,
pub ty: GlobalType,
pub kind: GlobalKind<'s>,
}
#[cfg_attr(test, derive(Debug))]
pub struct Start<'s> {
pub start: usize,
pub idx: Index<'s>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn insn_is_block() {
let insn = InsnKind::Block {
label: None,
ty: None,
body: vec![],
id: None,
};
assert!(insn.is_block());
assert!(!InsnKind::Nop.is_block());
}
}