use egg::Id;
use std::fmt::{self, Display};
use std::str::FromStr;
use wasm_encoder::{AbstractHeapType, HeapType};
macro_rules! lang {
(
$(#[$attr:meta])*
pub enum $lang:ident {
$(
$(#[$docs:meta])*
$case:ident $(($($inner:tt)*))? = $name:tt,
)*
}
) => {
$(#[$attr])*
pub enum $lang {
$(
$(#[$docs])*
$case $(($($inner)*))?,
)*
}
impl Display for $lang {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
$(
lang!(@first _x $lang::$case $(($($inner)*))?) => {
lang!(@fmt f _x $name $($($inner)*)?)
}
)*
}
}
}
impl egg::Language for Lang {
fn matches(&self, other: &Self) -> bool {
match (self, other) {
$(
(
lang!(@first _x $lang::$case $(($($inner)*))?),
lang!(@first _y $lang::$case $(($($inner)*))?),
) => lang!(@matches _x _y $($($inner)*)?),
)*
_ => false,
}
}
fn children(&self) -> &[Id] {
match self {
$(
lang!(@last _x $lang::$case $(($($inner)*))?) => {
lang!(@children _x $($($inner)*)?)
}
)*
}
}
fn children_mut(&mut self) -> &mut [Id] {
match self {
$(
lang!(@last _x $lang::$case $(($($inner)*))?) => {
lang!(@children_mut _x $($($inner)*)?)
}
)*
}
}
fn display_op(&self) -> &dyn std::fmt::Display {
self
}
fn from_op_str(op_str: &str, children: Vec<Id>) -> Result<Self, String> {
$(
lang!(@from_op_str op_str children $name $lang::$case $(($($inner)*))?);
)*
Err(format!("invalid token {:?}", op_str))
}
}
};
(@first $x:ident $lang:ident :: $case:ident) => ($lang::$case);
(@first $x:ident $lang:ident :: $case:ident ($($t:tt)* )) => ($lang::$case($x, ..));
(@last $x:ident $lang:ident :: $case:ident) => ($lang::$case);
(@last $x:ident $lang:ident :: $case:ident ($($t:tt)* )) => ($lang::$case(.., $x));
(@children $x:ident $($t:tt)*) => (
lang!(@if_last_is_child ($($t)*) { Children::as_slice($x) } else { &[] })
);
(@children_mut $x:ident $($t:tt)*) => (
lang!(@if_last_is_child ($($t)*) { Children::as_slice_mut($x) } else { &mut [] })
);
(@fmt $fmt:ident $payload:ident $opname:tt) => ($fmt.write_str($opname));
(@fmt $fmt:ident $payload:ident $opname:tt $($t:tt)*) => (
lang!(@if_first_is_child ($($t)*) {
$fmt.write_str($opname)
} else {
write!($fmt, "{}.{}", $opname, $payload)
})
);
(@matches $x:ident $y:ident) => (true);
(@matches $x:ident $y:ident $($t:tt)*) => (
lang!(@if_first_is_child ($($t)*) { true } else { $x == $y })
);
(@if_last_is_child ($t1:ty, $t2:ty) { $($t:tt)* } else { $($f:tt)* }) => ($($t)*);
(@if_last_is_child ([Id; $n:tt]) { $($t:tt)* } else { $($f:tt)* }) => ($($t)*);
(@if_last_is_child (Vec<Id>) { $($t:tt)* } else { $($f:tt)* }) => ($($t)*);
(@if_last_is_child (Id) { $($t:tt)* } else { $($f:tt)* }) => ($($t)*);
(@if_last_is_child ($($ty:tt)*) { $($t:tt)* } else { $($f:tt)* }) => ($($f)*);
(@if_first_is_child ($t1:ty, $t2:ty) { $($t:tt)* } else { $($f:tt)* }) => ($($f)*);
(@if_first_is_child ([Id; $n:tt]) { $($t:tt)* } else { $($f:tt)* }) => ($($t)*);
(@if_first_is_child (Vec<Id>) { $($t:tt)* } else { $($f:tt)* }) => ($($t)*);
(@if_first_is_child (Id) { $($t:tt)* } else { $($f:tt)* }) => ($($t)*);
(@if_first_is_child ($($ty:tt)*) { $($t:tt)* } else { $($f:tt)* }) => ($($f)*);
(@from_op_str $op:ident $children:ident $name:tt $lang:ident :: $case:ident) => ({
if $op == $name {
if $children.len() != 0 {
return Err(format!("expected zero children"))
}
return Ok($lang::$case);
}
});
(@from_op_str $op:ident $children:ident $name:tt $lang:ident::$case:ident($($t:tt)*)) => (
lang!(@if_first_is_child ($($t)*) {
if $op == $name {
return Ok($lang::$case(Children::from($children)?))
}
} else {
if let Some(suffix) = $op.strip_prefix(concat!($name, ".")) {
lang!(@if_last_is_child ($($t)*) {{
return Ok($lang::$case(
match suffix.parse() {
Ok(e) => e,
Err(e) => return Err(e.to_string()),
},
Children::from($children)?,
));
}} else {{
if $children.len() != 0 {
return Err(format!("expected zero children"))
}
return Ok($lang::$case(
match suffix.parse() {
Ok(e) => e,
Err(e) => return Err(e.to_string()),
},
));
}})
}
})
);
}
lang! {
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
pub enum Lang {
I32Add([Id; 2]) = "i32.add",
I64Add([Id; 2]) = "i64.add",
I32Sub([Id; 2]) = "i32.sub",
I64Sub([Id; 2]) = "i64.sub",
I32Mul([Id; 2]) = "i32.mul",
I64Mul([Id; 2]) = "i64.mul",
I32And([Id; 2]) = "i32.and",
I64And([Id; 2]) = "i64.and",
I32Or([Id; 2]) = "i32.or",
I64Or([Id; 2]) = "i64.or",
I32Xor([Id; 2]) = "i32.xor",
I64Xor([Id; 2]) = "i64.xor",
I32Shl([Id; 2]) = "i32.shl",
I64Shl([Id; 2]) = "i64.shl",
I32ShrU([Id; 2]) = "i32.shr_u",
I64ShrU([Id; 2]) = "i64.shr_u",
I32DivU([Id; 2]) = "i32.div_u",
I64DivU([Id; 2]) = "i64.div_u",
I32DivS([Id; 2]) = "i32.div_s",
I64DivS([Id; 2]) = "i64.div_s",
I32ShrS([Id; 2]) = "i32.shr_s",
I64ShrS([Id; 2]) = "i64.shr_s",
I32RotR([Id; 2]) = "i32.rotr",
I64RotR([Id; 2]) = "i64.rotr",
I32RotL([Id; 2]) = "i32.rotl",
I64RotL([Id; 2]) = "i64.rotl",
I32RemS([Id; 2]) = "i32.rem_s",
I64RemS([Id; 2]) = "i64.rem_s",
I32RemU([Id; 2]) = "i32.rem_u",
I64RemU([Id; 2]) = "i64.rem_u",
I32Eq([Id; 2]) = "i32.eq",
I64Eq([Id; 2]) = "i64.eq",
I32Ne([Id; 2]) = "i32.ne",
I64Ne([Id; 2]) = "i64.ne",
I32LtS([Id; 2]) = "i32.lt_s",
I64LtS([Id; 2]) = "i64.lt_s",
I32LtU([Id; 2]) = "i32.lt_u",
I64LtU([Id; 2]) = "i64.lt_u",
I32GtS([Id; 2]) = "i32.gt_s",
I64GtS([Id; 2]) = "i64.gt_s",
I32GtU([Id; 2]) = "i32.gt_u",
I64GtU([Id; 2]) = "i64.gt_u",
I32LeS([Id; 2]) = "i32.le_s",
I64LeS([Id; 2]) = "i64.le_s",
I32LeU([Id; 2]) = "i32.le_u",
I64LeU([Id; 2]) = "i64.le_u",
I32GeS([Id; 2]) = "i32.ge_s",
I64GeS([Id; 2]) = "i64.ge_s",
I32GeU([Id; 2]) = "i32.ge_u",
I64GeU([Id; 2]) = "i64.ge_u",
F32Add([Id; 2]) = "f32.add",
F64Add([Id; 2]) = "f64.add",
F32Sub([Id; 2]) = "f32.sub",
F64Sub([Id; 2]) = "f64.sub",
F32Mul([Id; 2]) = "f32.mul",
F64Mul([Id; 2]) = "f64.mul",
F32Div([Id; 2]) = "f32.div",
F64Div([Id; 2]) = "f64.div",
F32Min([Id; 2]) = "f32.min",
F64Min([Id; 2]) = "f64.min",
F32Max([Id; 2]) = "f32.max",
F64Max([Id; 2]) = "f64.max",
F32Copysign([Id; 2]) = "f32.copysign",
F64Copysign([Id; 2]) = "f64.copysign",
V128Not([Id; 1]) = "v128.not",
V128AnyTrue([Id; 1]) = "v128.any_true",
V128And([Id; 2]) = "v128.and",
V128AndNot([Id; 2]) = "v128.and_not",
V128Or([Id; 2]) = "v128.or",
V128Xor([Id; 2]) = "v128.xor",
V128Bitselect([Id; 3]) = "v128.bitselect",
F32Eq([Id; 2]) = "f32.eq",
F64Eq([Id; 2]) = "f64.eq",
F32Ne([Id; 2]) = "f32.ne",
F64Ne([Id; 2]) = "f64.ne",
F32Lt([Id; 2]) = "f32.lt",
F64Lt([Id; 2]) = "f64.lt",
F32Gt([Id; 2]) = "f32.gt",
F64Gt([Id; 2]) = "f64.gt",
F32Le([Id; 2]) = "f32.le",
F64Le([Id; 2]) = "f64.le",
F32Ge([Id; 2]) = "f32.ge",
F64Ge([Id; 2]) = "f64.ge",
I32Eqz([Id; 1]) = "i32.eqz",
I64Eqz([Id; 1]) = "i64.eqz",
I32Popcnt([Id; 1]) = "i32.popcnt",
I64Popcnt([Id; 1]) = "i64.popcnt",
I32Clz([Id; 1]) = "i32.clz",
I32Ctz([Id; 1]) = "i32.ctz",
I64Ctz([Id; 1]) = "i64.ctz",
I64Clz([Id; 1]) = "i64.clz",
F32Abs([Id; 1]) = "f32.abs",
F64Abs([Id; 1]) = "f64.abs",
F32Neg([Id; 1]) = "f32.neg",
F64Neg([Id; 1]) = "f64.neg",
F32Sqrt([Id; 1]) = "f32.sqrt",
F64Sqrt([Id; 1]) = "f64.sqrt",
F32Ceil([Id; 1]) = "f32.ceil",
F64Ceil([Id; 1]) = "f64.ceil",
F32Floor([Id; 1]) = "f32.floor",
F64Floor([Id; 1]) = "f64.floor",
F32Trunc([Id; 1]) = "f32.trunc",
F64Trunc([Id; 1]) = "f64.trunc",
F32Nearest([Id; 1]) = "f32.nearest",
F64Nearest([Id; 1]) = "f64.nearest",
LocalTee(u32, Id) = "local.tee",
LocalSet(u32, Id) = "local.set",
LocalGet(u32) = "local.get",
GlobalSet(u32, Id) = "global.set",
GlobalGet(u32) = "global.get",
Wrap([Id; 1]) = "wrap",
I32Extend8S([Id; 1]) = "i32.extend8_s",
I64Extend8S([Id; 1]) = "i64.extend8_s",
I32Extend16S([Id; 1]) = "i32.extend16_s",
I64Extend16S([Id; 1]) = "i64.extend16_s",
I64Extend32S([Id; 1]) = "i64.extend32_s",
I64ExtendI32S([Id; 1]) = "i64.extend_i32_s",
I64ExtendI32U([Id; 1]) = "i64.extend_i32_u",
I32TruncF32S([Id; 1]) = "i32.trunc_f32_s",
I32TruncF32U([Id; 1]) = "i32.trunc_f32_u",
I32TruncF64S([Id; 1]) = "i32.trunc_f64_s",
I32TruncF64U([Id; 1]) = "i32.trunc_f64_u",
I64TruncF32S([Id; 1]) = "i64.trunc_f32_s",
I64TruncF32U([Id; 1]) = "i64.trunc_f32_u",
I64TruncF64S([Id; 1]) = "i64.trunc_f64_s",
I64TruncF64U([Id; 1]) = "i64.trunc_f64_u",
F32ConvertI32S([Id; 1]) = "f32.convert_i32_s",
F32ConvertI32U([Id; 1]) = "f32.convert_i32_u",
F32ConvertI64S([Id; 1]) = "f32.convert_i64_s",
F32ConvertI64U([Id; 1]) = "f32.convert_i64_u",
F32DemoteF64([Id; 1]) = "f32.demote_f64",
F64ConvertI32S([Id; 1]) = "f64.convert_i32_s",
F64ConvertI32U([Id; 1]) = "f64.convert_i32_u",
F64ConvertI64S([Id; 1]) = "f64.convert_i64_s",
F64ConvertI64U([Id; 1]) = "f64.convert_i64_u",
F64PromoteF32([Id; 1]) = "f64.promote_f32",
I32ReinterpretF32([Id; 1]) = "i32.reinterpret_f32",
I64ReinterpretF64([Id; 1]) = "i64.reinterpret_f64",
F32ReinterpretI32([Id; 1]) = "f32.reinterpret_i32",
F64ReinterpretI64([Id; 1]) = "f64.reinterpret_i64",
I32TruncSatF32S([Id; 1]) = "i32.trunc_sat_f32_s",
I32TruncSatF32U([Id; 1]) = "i32.trunc_sat_f32_u",
I32TruncSatF64S([Id; 1]) = "i32.trunc_sat_f64_s",
I32TruncSatF64U([Id; 1]) = "i32.trunc_sat_f64_u",
I64TruncSatF32S([Id; 1]) = "i64.trunc_sat_f32_s",
I64TruncSatF32U([Id; 1]) = "i64.trunc_sat_f32_u",
I64TruncSatF64S([Id; 1]) = "i64.trunc_sat_f64_s",
I64TruncSatF64U([Id; 1]) = "i64.trunc_sat_f64_u",
Call(u32, Vec<Id>) = "call",
Drop([Id; 1]) = "drop",
Nop = "nop",
I32Load(MemArg, Id) = "i32.load",
I64Load(MemArg, Id) = "i64.load",
F32Load(MemArg, Id) = "f32.load",
F64Load(MemArg, Id) = "f64.load",
I32Load8S(MemArg, Id) = "i32.load8_s",
I32Load8U(MemArg, Id) = "i32.load8_u",
I32Load16S(MemArg, Id) = "i32.load16_s",
I32Load16U(MemArg, Id) = "i32.load16_u",
I64Load8S(MemArg, Id) = "i64.load8_s",
I64Load8U(MemArg, Id) = "i64.load8_u",
I64Load16S(MemArg, Id) = "i64.load16_s",
I64Load16U(MemArg, Id) = "i64.load16_u",
I64Load32S(MemArg, Id) = "i64.load32_s",
I64Load32U(MemArg, Id) = "i64.load32_u",
I32Store(MemArg, [Id; 2]) = "i32.store",
I64Store(MemArg, [Id; 2]) = "i64.store",
F32Store(MemArg, [Id; 2]) = "f32.store",
F64Store(MemArg, [Id; 2]) = "f64.store",
I32Store8(MemArg, [Id; 2]) = "i32.store8",
I32Store16(MemArg, [Id; 2]) = "i32.store16",
I64Store8(MemArg, [Id; 2]) = "i64.store8",
I64Store16(MemArg, [Id; 2]) = "i64.store16",
I64Store32(MemArg, [Id; 2]) = "i64.store32",
Select([Id; 3]) = "select",
MemoryGrow(u32, Id) = "memory.grow",
MemorySize(u32) = "memory.size",
MemoryInit(MemoryInit, [Id; 3]) = "memory.init",
DataDrop(u32) = "data.drop",
MemoryCopy(MemoryCopy, [Id; 3]) = "memory.copy",
MemoryFill(u32, [Id; 3]) = "memory.fill",
TableInit(TableInit, [Id; 3]) = "table.init",
ElemDrop(u32) = "elem.drop",
TableCopy(TableCopy, [Id; 3]) = "table.copy",
TableFill(u32, [Id; 3]) = "table.fill",
TableGet(u32, Id) = "table.get",
TableSet(u32, [Id; 2]) = "table.set",
TableGrow(u32, [Id; 2]) = "table.grow",
TableSize(u32) = "table.size",
RefIsNull(Id) = "ref.is_null",
V128Load(MemArg, Id) = "v128.load",
V128Load8x8S(MemArg, Id) = "v128.load8x8_s",
V128Load8x8U(MemArg, Id) = "v128.load8x8_u",
V128Load16x4S(MemArg, Id) = "v128.load16x4_s",
V128Load16x4U(MemArg, Id) = "v128.load16x4_u",
V128Load32x2S(MemArg, Id) = "v128.load32x2_s",
V128Load32x2U(MemArg, Id) = "v128.load32x2_u",
V128Load8Splat(MemArg, Id) = "v128.load8_splat",
V128Load16Splat(MemArg, Id) = "v128.load16_splat",
V128Load32Splat(MemArg, Id) = "v128.load32_splat",
V128Load64Splat(MemArg, Id) = "v128.load64_splat",
V128Load32Zero(MemArg, Id) = "v128.load32_zero",
V128Load64Zero(MemArg, Id) = "v128.load64_zero",
V128Store(MemArg, [Id; 2]) = "v128.store",
V128Load8Lane(MemArgLane, [Id; 2]) = "v128.load8_lane",
V128Load16Lane(MemArgLane, [Id; 2]) = "v128.load16_lane",
V128Load32Lane(MemArgLane, [Id; 2]) = "v128.load32_lane",
V128Load64Lane(MemArgLane, [Id; 2]) = "v128.load64_lane",
V128Store8Lane(MemArgLane, [Id; 2]) = "v128.store8_lane",
V128Store16Lane(MemArgLane, [Id; 2]) = "v128.store16_lane",
V128Store32Lane(MemArgLane, [Id; 2]) = "v128.store32_lane",
V128Store64Lane(MemArgLane, [Id; 2]) = "v128.store64_lane",
I8x16ExtractLaneS(u8, Id) = "i8x16.extract_lane_s",
I8x16ExtractLaneU(u8, Id) = "i8x16.extract_lane_u",
I8x16ReplaceLane(u8, [Id; 2]) = "i8x16.replace_lane",
I16x8ExtractLaneS(u8, Id) = "i16x8.extract_lane_s",
I16x8ExtractLaneU(u8, Id) = "i16x8.extract_lane_u",
I16x8ReplaceLane(u8, [Id; 2]) = "i16x8.replace_lane",
I32x4ExtractLane(u8, Id) = "i32x4.extract_lane",
I32x4ReplaceLane(u8, [Id; 2]) = "i32x4.replace_lane",
I64x2ExtractLane(u8, Id) = "i64x2.extract_lane",
I64x2ReplaceLane(u8, [Id; 2]) = "i64x2.replace_lane",
F32x4ExtractLane(u8, Id) = "f32x4.extract_lane",
F32x4ReplaceLane(u8, [Id; 2]) = "f32x4.replace_lane",
F64x2ExtractLane(u8, Id) = "f64x2.extract_lane",
F64x2ReplaceLane(u8, [Id; 2]) = "f64x2.replace_lane",
I8x16Swizzle([Id; 2]) = "i8x16.swizzle",
I8x16Shuffle(Shuffle, [Id; 2]) = "i8x16.shuffle",
I8x16Splat([Id; 1]) = "i8x16.splat",
I16x8Splat([Id; 1]) = "i16x8.splat",
I32x4Splat([Id; 1]) = "i32x4.splat",
I64x2Splat([Id; 1]) = "i64x2.splat",
F32x4Splat([Id; 1]) = "f32x4.splat",
F64x2Splat([Id; 1]) = "f64x2.splat",
I8x16Eq([Id; 2]) = "i8x16.eq",
I8x16Ne([Id; 2]) = "i8x16.ne",
I8x16LtS([Id; 2]) = "i8x16.lt_s",
I8x16LtU([Id; 2]) = "i8x16.lt_u",
I8x16GtS([Id; 2]) = "i8x16.gt_s",
I8x16GtU([Id; 2]) = "i8x16.gt_u",
I8x16LeS([Id; 2]) = "i8x16.le_s",
I8x16LeU([Id; 2]) = "i8x16.le_u",
I8x16GeS([Id; 2]) = "i8x16.ge_s",
I8x16GeU([Id; 2]) = "i8x16.ge_u",
I16x8Eq([Id; 2]) = "i16x8.eq",
I16x8Ne([Id; 2]) = "i16x8.ne",
I16x8LtS([Id; 2]) = "i16x8.lt_s",
I16x8LtU([Id; 2]) = "i16x8.lt_u",
I16x8GtS([Id; 2]) = "i16x8.gt_s",
I16x8GtU([Id; 2]) = "i16x8.gt_u",
I16x8LeS([Id; 2]) = "i16x8.le_s",
I16x8LeU([Id; 2]) = "i16x8.le_u",
I16x8GeS([Id; 2]) = "i16x8.ge_s",
I16x8GeU([Id; 2]) = "i16x8.ge_u",
I32x4Eq([Id; 2]) = "i32x4.eq",
I32x4Ne([Id; 2]) = "i32x4.ne",
I32x4LtS([Id; 2]) = "i32x4.lt_s",
I32x4LtU([Id; 2]) = "i32x4.lt_u",
I32x4GtS([Id; 2]) = "i32x4.gt_s",
I32x4GtU([Id; 2]) = "i32x4.gt_u",
I32x4LeS([Id; 2]) = "i32x4.le_s",
I32x4LeU([Id; 2]) = "i32x4.le_u",
I32x4GeS([Id; 2]) = "i32x4.ge_s",
I32x4GeU([Id; 2]) = "i32x4.ge_u",
I64x2Eq([Id; 2]) = "i64x2.eq",
I64x2Ne([Id; 2]) = "i64x2.ne",
I64x2LtS([Id; 2]) = "i64x2.lt_s",
I64x2GtS([Id; 2]) = "i64x2.gt_s",
I64x2LeS([Id; 2]) = "i64x2.le_s",
I64x2GeS([Id; 2]) = "i64x2.ge_s",
F32x4Eq([Id; 2]) = "f32x4.eq",
F32x4Ne([Id; 2]) = "f32x4.ne",
F32x4Lt([Id; 2]) = "f32x4.lt",
F32x4Gt([Id; 2]) = "f32x4.gt",
F32x4Le([Id; 2]) = "f32x4.le",
F32x4Ge([Id; 2]) = "f32x4.ge",
I8x16Abs([Id; 1]) = "i8x16.abs",
I8x16Neg([Id; 1]) = "i8x16.neg",
I8x16Popcnt([Id; 1]) = "i8x16.popcnt",
I8x16AllTrue([Id; 1]) = "i8x16.all_true",
I8x16Bitmask([Id; 1]) = "i8x16.bitmask",
I8x16NarrowI16x8S([Id; 2]) = "i8x16.narrow_i16x8_s",
I8x16NarrowI16x8U([Id; 2]) = "i8x16.narrow_i16x8_u",
I8x16Shl([Id; 2]) = "i8x16.shl",
I8x16ShrS([Id; 2]) = "i8x16.shr_s",
I8x16ShrU([Id; 2]) = "i8x16.shr_u",
I8x16Add([Id; 2]) = "i8x16.add",
I8x16AddSatS([Id; 2]) = "i8x16.add_sat_s",
I8x16AddSatU([Id; 2]) = "i8x16.add_sat_u",
I8x16Sub([Id; 2]) = "i8x16.sub",
I8x16SubSatS([Id; 2]) = "i8x16.sub_sat_s",
I8x16SubSatU([Id; 2]) = "i8x16.sub_sat_u",
I8x16MinS([Id; 2]) = "i8x16.min_s",
I8x16MinU([Id; 2]) = "i8x16.min_u",
I8x16MaxS([Id; 2]) = "i8x16.max_s",
I8x16MaxU([Id; 2]) = "i8x16.max_u",
I8x16AvgrU([Id; 2]) = "i8x16.avgr_u",
I16x8ExtAddPairwiseI8x16S([Id; 1]) = "i16x8.extadd_pairwise_i8x16_s",
I16x8ExtAddPairwiseI8x16U([Id; 1]) = "i16x8.extadd_pairwise_i8x16_u",
I16x8Abs([Id; 1]) = "i16x8.abs",
I16x8Neg([Id; 1]) = "i16x8.neg",
I16x8Q15MulrSatS([Id; 2]) = "i16x8.q15mulr_sat_s",
I16x8AllTrue([Id; 1]) = "i16x8.all_true",
I16x8Bitmask([Id; 1]) = "i16x8.bitmask",
I16x8NarrowI32x4S([Id; 2]) = "i16x8.narrow_i32x4_s",
I16x8NarrowI32x4U([Id; 2]) = "i16x8.narrow_i32x4_u",
I16x8ExtendLowI8x16S([Id; 1]) = "i16x8.extend_low_i8x16_s",
I16x8ExtendHighI8x16S([Id; 1]) = "i16x8.extend_high_i8x16_s",
I16x8ExtendLowI8x16U([Id; 1]) = "i16x8.extend_low_i8x16_u",
I16x8ExtendHighI8x16U([Id; 1]) = "i16x8.extend_high_i8x16_u",
I16x8Shl([Id; 2]) = "i16x8.shl",
I16x8ShrS([Id; 2]) = "i16x8.shr_s",
I16x8ShrU([Id; 2]) = "i16x8.shr_u",
I16x8Add([Id; 2]) = "i16x8.add",
I16x8AddSatS([Id; 2]) = "i16x8.add_sat_s",
I16x8AddSatU([Id; 2]) = "i16x8.add_sat_u",
I16x8Sub([Id; 2]) = "i16x8.sub",
I16x8SubSatS([Id; 2]) = "i16x8.sub_sat_s",
I16x8SubSatU([Id; 2]) = "i16x8.sub_sat_u",
I16x8Mul([Id; 2]) = "i16x8.mul",
I16x8MinS([Id; 2]) = "i16x8.min_s",
I16x8MinU([Id; 2]) = "i16x8.min_u",
I16x8MaxS([Id; 2]) = "i16x8.max_s",
I16x8MaxU([Id; 2]) = "i16x8.max_u",
I16x8AvgrU([Id; 2]) = "i16x8.avgr_u",
I16x8ExtMulLowI8x16S([Id; 2]) = "i16x8.extmul_low_i8x16_s",
I16x8ExtMulHighI8x16S([Id; 2]) = "i16x8.extmul_low_i8x16_s",
I16x8ExtMulLowI8x16U([Id; 2]) = "i16x8.extmul_low_i8x16_u",
I16x8ExtMulHighI8x16U([Id; 2]) = "i16x8.extmul_low_i8x16_u",
I32x4ExtAddPairwiseI16x8S([Id; 1]) = "i32x4.extadd_pairwise_i16x8_s",
I32x4ExtAddPairwiseI16x8U([Id; 1]) = "i32x4.extadd_pairwise_i16x8_u",
I32x4Abs([Id; 1]) = "i32x4.abs",
I32x4Neg([Id; 1]) = "i32x4.neg",
I32x4AllTrue([Id; 1]) = "i32x4.all_true",
I32x4Bitmask([Id; 1]) = "i32x4.bitmask",
I32x4ExtendLowI16x8S([Id; 1]) = "i32x4.extend_low_i16x8_s",
I32x4ExtendHighI16x8S([Id; 1]) = "i32x4.extend_high_i16x8_s",
I32x4ExtendLowI16x8U([Id; 1]) = "i32x4.extend_low_i16x8_u",
I32x4ExtendHighI16x8U([Id; 1]) = "i32x4.extend_high_i16x8_u",
I32x4Shl([Id; 2]) = "i32x4.shl",
I32x4ShrS([Id; 2]) = "i32x4.shr_s",
I32x4ShrU([Id; 2]) = "i32x4.shr_u",
I32x4Add([Id; 2]) = "i32x4.add",
I32x4Sub([Id; 2]) = "i32x4.sub",
I32x4Mul([Id; 2]) = "i32x4.mul",
I32x4MinS([Id; 2]) = "i32x4.min_s",
I32x4MinU([Id; 2]) = "i32x4.min_u",
I32x4MaxS([Id; 2]) = "i32x4.max_s",
I32x4MaxU([Id; 2]) = "i32x4.max_u",
I32x4DotI16x8S([Id; 2]) = "i32x4.dot_i16x8_s",
I32x4ExtMulLowI16x8S([Id; 2]) = "i32x4.extmul_low_i16x8_s",
I32x4ExtMulHighI16x8S([Id; 2]) = "i32x4.extmul_low_i16x8_s",
I32x4ExtMulLowI16x8U([Id; 2]) = "i32x4.extmul_low_i16x8_u",
I32x4ExtMulHighI16x8U([Id; 2]) = "i32x4.extmul_low_i16x8_u",
I64x2Abs([Id; 1]) = "i64x2.abs",
I64x2Neg([Id; 1]) = "i64x2.neg",
I64x2AllTrue([Id; 1]) = "i64x2.all_true",
I64x2Bitmask([Id; 1]) = "i64x2.bitmask",
I64x2ExtendLowI32x4S([Id; 1]) = "i64x2.extend_low_i32x4_s",
I64x2ExtendHighI32x4S([Id; 1]) = "i64x2.extend_high_i32x4_s",
I64x2ExtendLowI32x4U([Id; 1]) = "i64x2.extend_low_i32x4_u",
I64x2ExtendHighI32x4U([Id; 1]) = "i64x2.extend_high_i32x4_u",
I64x2Shl([Id; 2]) = "i64x2.shl",
I64x2ShrS([Id; 2]) = "i64x2.shr_s",
I64x2ShrU([Id; 2]) = "i64x2.shr_u",
I64x2Add([Id; 2]) = "i64x2.add",
I64x2Sub([Id; 2]) = "i64x2.sub",
I64x2Mul([Id; 2]) = "i64x2.mul",
I64x2ExtMulLowI32x4S([Id; 2]) = "i64x2.extmul_low_i32x4_s",
I64x2ExtMulHighI32x4S([Id; 2]) = "i64x2.extmul_low_i32x4_s",
I64x2ExtMulLowI32x4U([Id; 2]) = "i64x2.extmul_low_i32x4_u",
I64x2ExtMulHighI32x4U([Id; 2]) = "i64x2.extmul_low_i32x4_u",
F64x2Eq([Id; 2]) = "f64x2.eq",
F64x2Ne([Id; 2]) = "f64x2.ne",
F64x2Lt([Id; 2]) = "f64x2.lt",
F64x2Gt([Id; 2]) = "f64x2.gt",
F64x2Le([Id; 2]) = "f64x2.le",
F64x2Ge([Id; 2]) = "f64x2.ge",
F32x4Ceil([Id; 1]) = "f32x4.ceil",
F32x4Floor([Id; 1]) = "f32x4.floor",
F32x4Trunc([Id; 1]) = "f32x4.trunc",
F32x4Nearest([Id; 1]) = "f32x4.nearest",
F32x4Abs([Id; 1]) = "f32x4.abs",
F32x4Neg([Id; 1]) = "f32x4.neg",
F32x4Sqrt([Id; 1]) = "f32x4.sqrt",
F32x4Add([Id; 2]) = "f32x4.add",
F32x4Sub([Id; 2]) = "f32x4.sub",
F32x4Mul([Id; 2]) = "f32x4.mul",
F32x4Div([Id; 2]) = "f32x4.div",
F32x4Min([Id; 2]) = "f32x4.min",
F32x4Max([Id; 2]) = "f32x4.max",
F32x4PMin([Id; 2]) = "f32x4.pmin",
F32x4PMax([Id; 2]) = "f32x4.pmax",
F64x2Ceil([Id; 1]) = "f64x2.ceil",
F64x2Floor([Id; 1]) = "f64x2.floor",
F64x2Trunc([Id; 1]) = "f64x2.trunc",
F64x2Nearest([Id; 1]) = "f64x2.nearest",
F64x2Abs([Id; 1]) = "f64x2.abs",
F64x2Neg([Id; 1]) = "f64x2.neg",
F64x2Sqrt([Id; 1]) = "f64x2.sqrt",
F64x2Add([Id; 2]) = "f64x2.add",
F64x2Sub([Id; 2]) = "f64x2.sub",
F64x2Mul([Id; 2]) = "f64x2.mul",
F64x2Div([Id; 2]) = "f64x2.div",
F64x2Min([Id; 2]) = "f64x2.min",
F64x2Max([Id; 2]) = "f64x2.max",
F64x2PMin([Id; 2]) = "f64x2.pmin",
F64x2PMax([Id; 2]) = "f64x2.pmax",
I32x4TruncSatF32x4S([Id; 1]) = "i32x4.trunc_sat_f32x4_s",
I32x4TruncSatF32x4U([Id; 1]) = "i32x4.trunc_sat_f32x4_u",
F32x4ConvertI32x4S([Id; 1]) = "f32x4.convert_i32x4_s",
F32x4ConvertI32x4U([Id; 1]) = "f32x4.convert_i32x4_u",
I32x4TruncSatF64x2SZero([Id; 1]) = "i32x4.trunc_sat_f64x2_s_zero",
I32x4TruncSatF64x2UZero([Id; 1]) = "i32x4.trunc_sat_f64x2_u_zero",
F64x2ConvertLowI32x4S([Id; 1]) = "f64x2.convert_low_i32x4_s",
F64x2ConvertLowI32x4U([Id; 1]) = "f64x2.convert_low_i32x4_u",
F32x4DemoteF64x2Zero([Id; 1]) = "f32x4.demote_f64x2_zero",
F64x2PromoteLowF32x4([Id; 1]) = "f64x2.promote_low_f32x4",
I8x16RelaxedSwizzle([Id; 2]) = "i8x16.relaxed_swizzle",
I32x4RelaxedTruncF32x4S([Id; 1]) = "i32x4.relaxed_trunc_f32x4_s",
I32x4RelaxedTruncF32x4U([Id; 1]) = "i32x4.relaxed_trunc_f32x4_u",
I32x4RelaxedTruncF64x2SZero([Id; 1]) = "i32x4.relaxed_trunc_f64x2_s_zero",
I32x4RelaxedTruncF64x2UZero([Id; 1]) = "i32x4.relaxed_trunc_f64x2_u_zero",
F32x4RelaxedMadd([Id; 3]) = "f32x4.relaxed_madd",
F32x4RelaxedNmadd([Id; 3]) = "f32x4.relaxed_nmadd",
F64x2RelaxedMadd([Id; 3]) = "f64x2.relaxed_madd",
F64x2RelaxedNmadd([Id; 3]) = "f64x2.relaxed_nmadd",
I8x16RelaxedLaneselect([Id; 3]) = "i8x16.relaxed_laneselect",
I16x8RelaxedLaneselect([Id; 3]) = "i16x8.relaxed_laneselect",
I32x4RelaxedLaneselect([Id; 3]) = "i32x4.relaxed_laneselect",
I64x2RelaxedLaneselect([Id; 3]) = "i64x2.relaxed_laneselect",
F32x4RelaxedMin([Id; 2]) = "f32x4.relaxed_min",
F32x4RelaxedMax([Id; 2]) = "f32x4.relaxed_max",
F64x2RelaxedMin([Id; 2]) = "f64x2.relaxed_min",
F64x2RelaxedMax([Id; 2]) = "f64x2.relaxed_max",
I16x8RelaxedQ15mulrS([Id; 2]) = "i16x8.relaxed_q15_mulr_s",
I16x8RelaxedDotI8x16I7x16S([Id; 2]) = "i16x8.relaxed_dot_i8x16_i7x16_s",
I32x4RelaxedDotI8x16I7x16AddS([Id; 3]) = "i32x4.relaxed_dot_i8x16_i7x16_add_s",
RandI32 = "i32.rand",
RandI64 = "i64.rand",
RandF32 = "f32.rand",
RandF64 = "f64.rand",
Undef = "undef",
UnfoldI32(Id) = "i32.unfold",
UnfoldI64(Id) = "i64.unfold",
I32UseGlobal(Id) = "i32.use_of_global",
I64UseGlobal(Id) = "i64.use_of_global",
F32UseGlobal(Id) = "f32.use_of_global",
F64UseGlobal(Id) = "f64.use_of_global",
Container(Vec<Id>) = "container",
I32(i32) = "i32.const",
I64(i64) = "i64.const",
F32(F32) = "f32.const",
F64(F64) = "f64.const",
V128(i128) = "v128.const",
RefNull(RefType) = "ref.null",
RefFunc(u32) = "ref.func",
}
}
impl Default for Lang {
fn default() -> Self {
Lang::Undef
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct F32(u32);
impl F32 {
pub fn to_f32(self) -> f32 {
f32::from_bits(self.0)
}
}
impl FromStr for F32 {
type Err = <f32 as FromStr>::Err;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(F32(f32::from_str(&s.replace(",", "."))?.to_bits()))
}
}
impl From<f32> for F32 {
fn from(f: f32) -> Self {
Self(f.to_bits())
}
}
impl From<wasmparser::Ieee32> for F32 {
fn from(f: wasmparser::Ieee32) -> Self {
Self(f.bits())
}
}
impl fmt::Display for F32 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.to_f32(), f)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct F64(u64);
impl F64 {
pub fn to_f64(self) -> f64 {
f64::from_bits(self.0)
}
}
impl FromStr for F64 {
type Err = <f64 as FromStr>::Err;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(F64(f64::from_str(&s.replace(",", "."))?.to_bits()))
}
}
impl From<f64> for F64 {
fn from(f: f64) -> Self {
Self(f.to_bits())
}
}
impl From<wasmparser::Ieee64> for F64 {
fn from(f: wasmparser::Ieee64) -> Self {
Self(f.bits())
}
}
impl fmt::Display for F64 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.to_f64(), f)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub enum RefType {
Func,
Extern,
}
impl From<RefType> for HeapType {
fn from(rt: RefType) -> Self {
match rt {
RefType::Func => HeapType::Abstract {
shared: false,
ty: AbstractHeapType::Func,
},
RefType::Extern => HeapType::Abstract {
shared: false,
ty: AbstractHeapType::Extern,
},
}
}
}
impl FromStr for RefType {
type Err = Box<dyn std::error::Error + Send + Sync>;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"func" => Ok(RefType::Func),
"extern" => Ok(RefType::Extern),
s => Err(format!("{s} is not a valid reference type").into()),
}
}
}
impl fmt::Display for RefType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(match self {
RefType::Func => "func",
RefType::Extern => "extern",
})
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
pub struct MemArg {
pub static_offset: u64,
pub align: u8,
pub mem: u32,
}
impl fmt::Display for MemArg {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}.{}", self.static_offset, self.align, self.mem)
}
}
impl FromStr for MemArg {
type Err = String;
fn from_str(s: &str) -> Result<MemArg, String> {
let mut parts = s.split('.');
let static_offset = parts
.next()
.ok_or_else(|| format!("expected more static instr info"))?
.parse::<u64>()
.map_err(|e| e.to_string())?;
let align = parts
.next()
.ok_or_else(|| format!("expected more static instr info"))?
.parse::<u8>()
.map_err(|e| e.to_string())?;
let mem = parts
.next()
.ok_or_else(|| format!("expected more static instr info"))?
.parse::<u32>()
.map_err(|e| e.to_string())?;
if parts.next().is_some() {
return Err(format!("too much info after instruction"));
}
Ok(MemArg {
static_offset,
align,
mem,
})
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
pub struct MemArgLane {
pub memarg: MemArg,
pub lane: u8,
}
impl fmt::Display for MemArgLane {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}", self.memarg, self.lane)
}
}
impl FromStr for MemArgLane {
type Err = String;
fn from_str(s: &str) -> Result<MemArgLane, String> {
let mut parts = s.rsplitn(2, '.');
let lane = parts
.next()
.ok_or_else(|| format!("expected more static instr info"))?
.parse::<u8>()
.map_err(|e| e.to_string())?;
let memarg = parts
.next()
.ok_or_else(|| format!("expected more static instr info"))?
.parse::<MemArg>()
.map_err(|e| e.to_string())?;
if parts.next().is_some() {
return Err(format!("too much info after instruction"));
}
Ok(MemArgLane { lane, memarg })
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
pub struct Shuffle {
pub indices: [u8; 16],
}
impl fmt::Display for Shuffle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, idx) in self.indices.iter().enumerate() {
if i != 0 {
write!(f, ".")?;
}
write!(f, "{idx}")?;
}
Ok(())
}
}
impl FromStr for Shuffle {
type Err = String;
fn from_str(s: &str) -> Result<Shuffle, String> {
let indices = s
.split('.')
.map(|part| part.parse::<u8>())
.collect::<Result<Vec<_>, _>>()
.map_err(|_| format!("failed to parse integer"))?;
let indices: &[u8; 16] = indices
.as_slice()
.try_into()
.map_err(|_| format!("wrong number of lanes"))?;
Ok(Shuffle { indices: *indices })
}
}
trait Children: Sized {
fn from(list: Vec<Id>) -> Result<Self, String>;
fn as_slice(&self) -> &[Id];
fn as_slice_mut(&mut self) -> &mut [Id];
}
impl Children for Id {
fn from(mut list: Vec<Id>) -> Result<Id, String> {
if list.len() != 1 {
Err(format!("expected one child node, got {}", list.len()))
} else {
Ok(list.remove(0))
}
}
fn as_slice(&self) -> &[Id] {
std::slice::from_ref(self)
}
fn as_slice_mut(&mut self) -> &mut [Id] {
std::slice::from_mut(self)
}
}
impl<const N: usize> Children for [Id; N] {
fn from(list: Vec<Id>) -> Result<Self, String> {
if let Ok(result) = list.try_into() {
Ok(result)
} else {
Err(format!("expected {N} child nodes"))
}
}
fn as_slice(&self) -> &[Id] {
self
}
fn as_slice_mut(&mut self) -> &mut [Id] {
self
}
}
impl Children for Vec<Id> {
fn from(list: Vec<Id>) -> Result<Self, String> {
Ok(list)
}
fn as_slice(&self) -> &[Id] {
self
}
fn as_slice_mut(&mut self) -> &mut [Id] {
self
}
}
fn parse_pair<T: FromStr, U: FromStr>(s: &str) -> Result<(T, U), String>
where
T::Err: fmt::Display,
U::Err: fmt::Display,
{
let mut parts = s.split('.');
let t = parts
.next()
.ok_or_else(|| format!("expected more static instr info"))?
.parse::<T>()
.map_err(|e| e.to_string())?;
let u = parts
.next()
.ok_or_else(|| format!("expected more static instr info"))?
.parse::<U>()
.map_err(|e| e.to_string())?;
if parts.next().is_some() {
return Err(format!("too much info after instruction"));
}
Ok((t, u))
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
pub struct TableCopy {
pub src: u32,
pub dst: u32,
}
impl fmt::Display for TableCopy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}", self.src, self.dst)
}
}
impl FromStr for TableCopy {
type Err = String;
fn from_str(s: &str) -> Result<TableCopy, String> {
let (src, dst) = parse_pair(s)?;
Ok(TableCopy { src, dst })
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
pub struct MemoryCopy {
pub src: u32,
pub dst: u32,
}
impl fmt::Display for MemoryCopy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}", self.src, self.dst)
}
}
impl FromStr for MemoryCopy {
type Err = String;
fn from_str(s: &str) -> Result<MemoryCopy, String> {
let (src, dst) = parse_pair(s)?;
Ok(MemoryCopy { src, dst })
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
pub struct TableInit {
pub table: u32,
pub segment: u32,
}
impl fmt::Display for TableInit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}", self.table, self.segment)
}
}
impl FromStr for TableInit {
type Err = String;
fn from_str(s: &str) -> Result<TableInit, String> {
let (table, segment) = parse_pair(s)?;
Ok(TableInit { table, segment })
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone)]
pub struct MemoryInit {
pub memory: u32,
pub segment: u32,
}
impl fmt::Display for MemoryInit {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}.{}", self.memory, self.segment)
}
}
impl FromStr for MemoryInit {
type Err = String;
fn from_str(s: &str) -> Result<MemoryInit, String> {
let (memory, segment) = parse_pair(s)?;
Ok(MemoryInit { memory, segment })
}
}
#[cfg(test)]
mod tests {
use super::{Lang, MemArg, RefType};
use egg::{Id, Language};
#[test]
fn test_parsing2() {
let pairs = vec![
[Lang::GlobalGet(0), Lang::GlobalGet(1)],
[
Lang::LocalSet(0, Id::from(0)),
Lang::LocalSet(1, Id::from(1)),
],
[Lang::LocalGet(0), Lang::LocalGet(1)],
[
Lang::GlobalSet(0, Id::from(0)),
Lang::GlobalSet(1, Id::from(1)),
],
[
Lang::I32Load(
MemArg {
mem: 1,
align: 0,
static_offset: 120,
},
Id::from(0),
),
Lang::I32Load(
MemArg {
mem: 1,
align: 0,
static_offset: 0,
},
Id::from(0),
),
],
[Lang::LocalGet(0), Lang::LocalGet(1)],
[Lang::RefNull(RefType::Func), Lang::RefNull(RefType::Extern)],
];
for [l, r] in pairs {
assert_eq!(l.matches(&r), false);
}
}
}