wain_ast/
lib.rs

1#![forbid(unsafe_code)]
2#![warn(clippy::dbg_macro)]
3
4pub mod source;
5
6use std::borrow::Cow;
7use std::fmt;
8
9// Root of the tree
10#[derive(Clone, Debug, PartialEq)]
11pub struct Root<'s, S: source::Source> {
12    pub module: Module<'s>,
13    pub source: S,
14}
15
16// Note: Since crate for syntax tree data structure is separated, all fields of AST node structs need
17// to be public. Or we need a factory function like Module::new() for each struct.
18
19// https://webassembly.github.io/spec/core/syntax/modules.html#indices
20pub type FuncIdx = u32;
21pub type TableIdx = u32;
22pub type MemIdx = u32;
23pub type GlobalIdx = u32;
24pub type TypeIdx = u32;
25pub type LocalIdx = u32;
26pub type LabelIdx = u32;
27
28// https://webassembly.github.io/spec/core/syntax/modules.html
29#[derive(Clone, Debug, Default, PartialEq)]
30pub struct Module<'s> {
31    pub start: usize,
32    pub id: Option<&'s str>,
33    pub types: Vec<FuncType>,
34    pub exports: Vec<Export<'s>>,
35    pub funcs: Vec<Func<'s>>,
36    pub elems: Vec<ElemSegment>,
37    pub tables: Vec<Table<'s>>,
38    pub data: Vec<DataSegment<'s>>,
39    pub memories: Vec<Memory<'s>>,
40    pub globals: Vec<Global<'s>>,
41    pub entrypoint: Option<StartFunction>,
42}
43
44// https://webassembly.github.io/spec/core/syntax/modules.html#syntax-module
45#[derive(Debug, Clone, PartialEq)]
46pub struct Import<'s> {
47    pub mod_name: Name<'s>,
48    pub name: Name<'s>,
49}
50
51// https://webassembly.github.io/spec/core/syntax/types.html#function-types
52#[derive(Debug, PartialEq, Clone)]
53pub struct FuncType {
54    pub start: usize,
55    pub params: Vec<ValType>,
56    pub results: Vec<ValType>,
57}
58
59// https://webassembly.github.io/spec/core/syntax/types.html#value-types
60#[derive(PartialEq, Clone, Copy, Debug)]
61pub enum ValType {
62    I32,
63    I64,
64    F32,
65    F64,
66}
67
68impl ValType {
69    #[must_use]
70    pub fn bytes(self) -> usize {
71        match self {
72            Self::I32 | Self::F32 => 4,
73            Self::I64 | Self::F64 => 8,
74        }
75    }
76}
77
78impl AsRef<str> for ValType {
79    fn as_ref(&self) -> &str {
80        match self {
81            Self::I32 => "i32",
82            Self::I64 => "i64",
83            Self::F32 => "f32",
84            Self::F64 => "f64",
85        }
86    }
87}
88
89impl fmt::Display for ValType {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        f.write_str(self.as_ref())
92    }
93}
94
95pub trait AsValType {
96    const VAL_TYPE: ValType;
97}
98
99impl AsValType for i32 {
100    const VAL_TYPE: ValType = ValType::I32;
101}
102
103impl AsValType for i64 {
104    const VAL_TYPE: ValType = ValType::I64;
105}
106
107impl AsValType for f32 {
108    const VAL_TYPE: ValType = ValType::F32;
109}
110
111impl AsValType for f64 {
112    const VAL_TYPE: ValType = ValType::F64;
113}
114
115// https://webassembly.github.io/spec/core/syntax/values.html#syntax-name
116//
117// Use Cow<'s, str> since it is String on text format and it is &str on binary format.
118// In text format, special characters in string literal are escaped. Unescaped string must
119// be allocated in heap. In binary format, it is directly encoded as bytes so borrowing the
120// part of source is enough.
121#[derive(Debug, Clone, PartialEq)]
122pub struct Name<'s>(pub Cow<'s, str>);
123
124// https://webassembly.github.io/spec/core/syntax/types.html#table-types
125// Note: elemtype is currently fixed to 'funcref'
126#[derive(Debug, Clone, PartialEq)]
127pub struct TableType {
128    pub limit: Limits,
129}
130
131// https://webassembly.github.io/spec/core/syntax/types.html#limits
132#[derive(Debug, Clone, PartialEq)]
133pub enum Limits {
134    Range(u32, u32),
135    From(u32),
136}
137
138// https://webassembly.github.io/spec/core/syntax/types.html#memory-types
139#[derive(Debug, Clone, PartialEq)]
140pub struct MemType {
141    pub limit: Limits,
142}
143
144// https://webassembly.github.io/spec/core/syntax/modules.html#exports
145#[derive(Debug, Clone, PartialEq)]
146pub enum ExportKind {
147    Func(FuncIdx),
148    Table(TableIdx),
149    Memory(MemIdx),
150    Global(GlobalIdx),
151}
152
153#[derive(Debug, Clone, PartialEq)]
154pub struct Export<'s> {
155    pub start: usize,
156    pub name: Name<'s>,
157    pub kind: ExportKind,
158}
159
160// https://webassembly.github.io/spec/core/syntax/modules.html#syntax-func
161#[derive(Debug, Clone, PartialEq)]
162pub enum FuncKind<'s> {
163    Import(Import<'s>),
164    Body {
165        locals: Vec<ValType>,
166        expr: Vec<Instruction>,
167    },
168}
169
170#[derive(Debug, Clone, PartialEq)]
171pub struct Func<'s> {
172    pub start: usize,
173    pub idx: TypeIdx,
174    pub kind: FuncKind<'s>,
175}
176
177// https://webassembly.github.io/spec/core/syntax/instructions.html#instructions
178#[derive(Debug, Clone, PartialEq)]
179pub struct Instruction {
180    pub start: usize,
181    pub kind: InsnKind,
182}
183
184// https://webassembly.github.io/spec/core/syntax/instructions.html#syntax-memarg
185#[derive(Debug, Clone, PartialEq)]
186pub struct Mem {
187    pub align: u32,
188    pub offset: u32,
189}
190
191// https://webassembly.github.io/spec/core/syntax/instructions.html#instructions
192#[derive(Debug, Clone, PartialEq)]
193pub enum InsnKind {
194    // Control instructions
195    // https://webassembly.github.io/spec/core/syntax/instructions.html#control-instructions
196    Block {
197        ty: Option<ValType>, // resulttype
198        body: Vec<Instruction>,
199    },
200    Loop {
201        ty: Option<ValType>, // resulttype
202        body: Vec<Instruction>,
203    },
204    If {
205        ty: Option<ValType>, // resulttype
206        then_body: Vec<Instruction>,
207        else_body: Vec<Instruction>,
208    },
209    Unreachable,
210    Nop,
211    Br(LabelIdx),
212    BrIf(LabelIdx),
213    BrTable {
214        labels: Vec<LabelIdx>,
215        default_label: LabelIdx,
216    },
217    Return,
218    Call(FuncIdx),
219    CallIndirect(TypeIdx),
220    // Parametric instructions
221    // https://webassembly.github.io/spec/core/syntax/instructions.html#parametric-instructions
222    Drop,
223    Select,
224    // Variable instructions
225    // https://webassembly.github.io/spec/core/syntax/instructions.html#variable-instructions
226    LocalGet(LocalIdx),
227    LocalSet(LocalIdx),
228    LocalTee(LocalIdx),
229    GlobalGet(GlobalIdx),
230    GlobalSet(GlobalIdx),
231    // Memory instructions
232    // https://webassembly.github.io/spec/core/syntax/instructions.html#memory-instructions
233    I32Load(Mem),
234    I64Load(Mem),
235    F32Load(Mem),
236    F64Load(Mem),
237    I32Load8S(Mem),
238    I32Load8U(Mem),
239    I32Load16S(Mem),
240    I32Load16U(Mem),
241    I64Load8S(Mem),
242    I64Load8U(Mem),
243    I64Load16S(Mem),
244    I64Load16U(Mem),
245    I64Load32S(Mem),
246    I64Load32U(Mem),
247    I32Store(Mem),
248    I64Store(Mem),
249    F32Store(Mem),
250    F64Store(Mem),
251    I32Store8(Mem),
252    I32Store16(Mem),
253    I64Store8(Mem),
254    I64Store16(Mem),
255    I64Store32(Mem),
256    MemorySize,
257    MemoryGrow,
258    // Numeric instructions
259    // https://webassembly.github.io/spec/core/syntax/instructions.html#numeric-instructions
260    // Constants
261    I32Const(i32),
262    I64Const(i64),
263    F32Const(f32),
264    F64Const(f64),
265    // i32 operations
266    I32Clz,
267    I32Ctz,
268    I32Popcnt,
269    I32Add,
270    I32Sub,
271    I32Mul,
272    I32DivS,
273    I32DivU,
274    I32RemS,
275    I32RemU,
276    I32And,
277    I32Or,
278    I32Xor,
279    I32Shl,
280    I32ShrS,
281    I32ShrU,
282    I32Rotl,
283    I32Rotr,
284    // i64 operations
285    I64Clz,
286    I64Ctz,
287    I64Popcnt,
288    I64Add,
289    I64Sub,
290    I64Mul,
291    I64DivS,
292    I64DivU,
293    I64RemS,
294    I64RemU,
295    I64And,
296    I64Or,
297    I64Xor,
298    I64Shl,
299    I64ShrS,
300    I64ShrU,
301    I64Rotl,
302    I64Rotr,
303    // f32 operations
304    F32Abs,
305    F32Neg,
306    F32Ceil,
307    F32Floor,
308    F32Trunc,
309    F32Nearest,
310    F32Sqrt,
311    F32Add,
312    F32Sub,
313    F32Mul,
314    F32Div,
315    F32Min,
316    F32Max,
317    F32Copysign,
318    // f64 operations
319    F64Abs,
320    F64Neg,
321    F64Ceil,
322    F64Floor,
323    F64Trunc,
324    F64Nearest,
325    F64Sqrt,
326    F64Add,
327    F64Sub,
328    F64Mul,
329    F64Div,
330    F64Min,
331    F64Max,
332    F64Copysign,
333    // i32 comparison
334    I32Eqz,
335    I32Eq,
336    I32Ne,
337    I32LtS,
338    I32LtU,
339    I32GtS,
340    I32GtU,
341    I32LeS,
342    I32LeU,
343    I32GeS,
344    I32GeU,
345    // i64 comparison
346    I64Eqz,
347    I64Eq,
348    I64Ne,
349    I64LtS,
350    I64LtU,
351    I64GtS,
352    I64GtU,
353    I64LeS,
354    I64LeU,
355    I64GeS,
356    I64GeU,
357    // f32 comparison
358    F32Eq,
359    F32Ne,
360    F32Lt,
361    F32Gt,
362    F32Le,
363    F32Ge,
364    // f64 comparison
365    F64Eq,
366    F64Ne,
367    F64Lt,
368    F64Gt,
369    F64Le,
370    F64Ge,
371    // Conversion
372    I32WrapI64,
373    I32TruncF32S,
374    I32TruncF32U,
375    I32TruncF64S,
376    I32TruncF64U,
377    I64ExtendI32S,
378    I64ExtendI32U,
379    I64TruncF32S,
380    I64TruncF32U,
381    I64TruncF64S,
382    I64TruncF64U,
383    F32ConvertI32S,
384    F32ConvertI32U,
385    F32ConvertI64S,
386    F32ConvertI64U,
387    F32DemoteF64,
388    F64ConvertI32S,
389    F64ConvertI32U,
390    F64ConvertI64S,
391    F64ConvertI64U,
392    F64PromoteF32,
393    I32ReinterpretF32,
394    I64ReinterpretF64,
395    F32ReinterpretI32,
396    F64ReinterpretI64,
397    I32Extend8S,
398    I32Extend16S,
399    I64Extend8S,
400    I64Extend16S,
401    I64Extend32S,
402}
403
404impl InsnKind {
405    #[must_use]
406    pub fn name(&self) -> &'static str {
407        use InsnKind::*;
408        match self {
409            Block { .. } => "block",
410            Loop { .. } => "loop",
411            If { .. } => "if",
412            Unreachable => "unreachable",
413            Nop => "nop",
414            Br(_) => "br",
415            BrIf(_) => "br_if",
416            BrTable { .. } => "br_table",
417            Return => "return",
418            Call(_) => "call",
419            CallIndirect(_) => "call_indirect",
420            Drop => "drop",
421            Select => "select",
422            LocalGet(_) => "local.get",
423            LocalSet(_) => "local.set",
424            LocalTee(_) => "local.tee",
425            GlobalGet(_) => "global.get",
426            GlobalSet(_) => "global.set",
427            I32Load(_) => "i32.load",
428            I64Load(_) => "i64.load",
429            F32Load(_) => "f32.load",
430            F64Load(_) => "f64.load",
431            I32Load8S(_) => "i32.load8_s",
432            I32Load8U(_) => "i32.load8_u",
433            I32Load16S(_) => "i32.load16_s",
434            I32Load16U(_) => "i32.load16_u",
435            I64Load8S(_) => "i64.load8_s",
436            I64Load8U(_) => "i64.load8_u",
437            I64Load16S(_) => "i64.load16_s",
438            I64Load16U(_) => "i64.load16_u",
439            I64Load32S(_) => "i64.load32_s",
440            I64Load32U(_) => "i64.load32_u",
441            I32Store(_) => "i32.store",
442            I64Store(_) => "i64.store",
443            F32Store(_) => "f32.store",
444            F64Store(_) => "f64.store",
445            I32Store8(_) => "i32.store8",
446            I32Store16(_) => "i32.store16",
447            I64Store8(_) => "i64.store8",
448            I64Store16(_) => "i64.store16",
449            I64Store32(_) => "i64.store32",
450            MemorySize => "memory.size",
451            MemoryGrow => "memory.grow",
452            I32Const(_) => "i32.const",
453            I64Const(_) => "i64.const",
454            F32Const(_) => "f32.const",
455            F64Const(_) => "f64.const",
456            I32Clz => "i32.clz",
457            I32Ctz => "i32.ctz",
458            I32Popcnt => "i32.popcnt",
459            I32Add => "i32.add",
460            I32Sub => "i32.sub",
461            I32Mul => "i32.mul",
462            I32DivS => "i32.div_s",
463            I32DivU => "i32.div_u",
464            I32RemS => "i32.rem_s",
465            I32RemU => "i32.rem_u",
466            I32And => "i32.and",
467            I32Or => "i32.or",
468            I32Xor => "i32.xor",
469            I32Shl => "i32.shl",
470            I32ShrS => "i32.shr_s",
471            I32ShrU => "i32.shr_u",
472            I32Rotl => "i32.rotl",
473            I32Rotr => "i32.rotr",
474            I64Clz => "i64.clz",
475            I64Ctz => "i64.ctz",
476            I64Popcnt => "i64.popcnd",
477            I64Add => "i64.add",
478            I64Sub => "i64.sub",
479            I64Mul => "i64.mul",
480            I64DivS => "i64.div_s",
481            I64DivU => "i64.div_u",
482            I64RemS => "i64.rem_s",
483            I64RemU => "i64.rem_u",
484            I64And => "i64.and",
485            I64Or => "i64.or",
486            I64Xor => "i64.xor",
487            I64Shl => "i64.shl",
488            I64ShrS => "i64.shr_s",
489            I64ShrU => "i64.shr_u",
490            I64Rotl => "i64.rotl",
491            I64Rotr => "i64.rotr",
492            F32Abs => "f32.abs",
493            F32Neg => "f32.neg",
494            F32Ceil => "f32.ceil",
495            F32Floor => "f32.floor",
496            F32Trunc => "f32.trunc",
497            F32Nearest => "f32.nearest",
498            F32Sqrt => "f32.sqrt",
499            F32Add => "f32.add",
500            F32Sub => "f32.sub",
501            F32Mul => "f32.mul",
502            F32Div => "f32.div",
503            F32Min => "f32.min",
504            F32Max => "f32.max",
505            F32Copysign => "f32.copysign",
506            F64Abs => "f64.abs",
507            F64Neg => "f64.neg",
508            F64Ceil => "f64.ceil",
509            F64Floor => "f64.floor",
510            F64Trunc => "f64.trunc",
511            F64Nearest => "f64.nearest",
512            F64Sqrt => "f64.sqrt",
513            F64Add => "f64.add",
514            F64Sub => "f64.sub",
515            F64Mul => "f64.mul",
516            F64Div => "f64.div",
517            F64Min => "f64.min",
518            F64Max => "f64.max",
519            F64Copysign => "f64.copysign",
520            // i32 comparison
521            I32Eqz => "i32.eqz",
522            I32Eq => "i32.eq",
523            I32Ne => "i32.ne",
524            I32LtS => "i32.lt_s",
525            I32LtU => "i32.lt_u",
526            I32GtS => "i32.gt_s",
527            I32GtU => "i32.gt_u",
528            I32LeS => "i32.le_s",
529            I32LeU => "i32.le_u",
530            I32GeS => "i32.ge_s",
531            I32GeU => "i32.ge_u",
532            // i64 comparison
533            I64Eqz => "i64.eqz",
534            I64Eq => "i64.eq",
535            I64Ne => "i64.ne",
536            I64LtS => "i64.lt_s",
537            I64LtU => "i64.lt_u",
538            I64GtS => "i64.gt_s",
539            I64GtU => "i64.gt_u",
540            I64LeS => "i64.le_s",
541            I64LeU => "i64.le_u",
542            I64GeS => "i64.ge_s",
543            I64GeU => "i64.ge_u",
544            // f32 comparison
545            F32Eq => "f32.eq",
546            F32Ne => "f32.ne",
547            F32Lt => "f32.lt",
548            F32Gt => "f32.gt",
549            F32Le => "f32.le",
550            F32Ge => "f32.ge",
551            // f64 comparison
552            F64Eq => "f64.eq",
553            F64Ne => "f64.ne",
554            F64Lt => "f64.lt",
555            F64Gt => "f64.gt",
556            F64Le => "f64.le",
557            F64Ge => "f64.ge",
558            // Conversion
559            I32WrapI64 => "i32.wrap_i64",
560            I32TruncF32S => "i32.trunc_f32_s",
561            I32TruncF32U => "i32.trunc_f32_u",
562            I32TruncF64S => "i32.trunc_f64_s",
563            I32TruncF64U => "i32.trunc_f64_u",
564            I64ExtendI32S => "i64.extend_i32_s",
565            I64ExtendI32U => "i64.extend_i32_u",
566            I64TruncF32S => "i64.trunc_f32_s",
567            I64TruncF32U => "i64.trunc_f32_u",
568            I64TruncF64S => "i64.trunc_f64_s",
569            I64TruncF64U => "i64.trunc_f64_u",
570            F32ConvertI32S => "f32.convert_i32_s",
571            F32ConvertI32U => "f32.convert_i32_u",
572            F32ConvertI64S => "f32.convert_i64_s",
573            F32ConvertI64U => "f32.convert_i64_u",
574            F32DemoteF64 => "f32.demote_f64",
575            F64ConvertI32S => "f64.convert_i32_s",
576            F64ConvertI32U => "f64.convert_i32_u",
577            F64ConvertI64S => "f64.convert_i64_s",
578            F64ConvertI64U => "f64.convert_i64_u",
579            F64PromoteF32 => "f64.promote_f32",
580            I32ReinterpretF32 => "i32.reinterpret_f32",
581            I64ReinterpretF64 => "i64.reinterpret_f64",
582            F32ReinterpretI32 => "f32.reinterpret_i32",
583            F64ReinterpretI64 => "f64.reinterpret_i64",
584            // sign extension
585            I32Extend8S => "i32.extend8_s",
586            I32Extend16S => "i32.extend16_s",
587            I64Extend8S => "i64.extend8_s",
588            I64Extend16S => "i64.extend16_s",
589            I64Extend32S => "i64.extend32_s",
590        }
591    }
592}
593
594// https://webassembly.github.io/spec/core/syntax/modules.html#element-segments
595#[derive(Debug, Clone, PartialEq)]
596pub struct ElemSegment {
597    pub start: usize,
598    pub idx: TableIdx,
599    pub offset: Vec<Instruction>, // expr
600    pub init: Vec<FuncIdx>,
601}
602
603// https://webassembly.github.io/spec/core/syntax/modules.html#tables
604#[derive(Debug, Clone, PartialEq)]
605pub struct Table<'s> {
606    pub start: usize,
607    pub ty: TableType,
608    pub import: Option<Import<'s>>,
609}
610
611// https://webassembly.github.io/spec/core/syntax/modules.html#data-segments
612#[derive(Debug, Clone, PartialEq)]
613pub struct DataSegment<'s> {
614    pub start: usize,
615    pub idx: MemIdx,
616    pub offset: Vec<Instruction>, // expr
617    pub data: Cow<'s, [u8]>,
618}
619
620// https://webassembly.github.io/spec/core/syntax/modules.html#memories
621#[derive(Debug, Clone, PartialEq)]
622pub struct Memory<'s> {
623    pub start: usize,
624    pub ty: MemType,
625    pub import: Option<Import<'s>>,
626}
627
628// https://webassembly.github.io/spec/core/syntax/modules.html#globals
629// https://webassembly.github.io/spec/core/syntax/types.html#global-types
630#[derive(Debug, Clone, PartialEq)]
631pub enum GlobalKind<'s> {
632    Import(Import<'s>),
633    Init(Vec<Instruction>), // expr
634}
635
636#[derive(Debug, Clone, PartialEq)]
637pub struct Global<'s> {
638    pub start: usize,
639    pub mutable: bool,
640    pub ty: ValType,
641    pub kind: GlobalKind<'s>,
642}
643
644// https://webassembly.github.io/spec/core/syntax/modules.html#start-function
645#[derive(Debug, Clone, PartialEq)]
646pub struct StartFunction {
647    pub start: usize,
648    pub idx: FuncIdx,
649}