wain_syntax_text/
wat2wasm.rs

1use crate::ast as wat;
2use crate::source::{describe_position, TextSource};
3use std::collections::HashMap;
4use std::fmt;
5use std::mem;
6use wain_ast as wasm;
7
8#[cfg_attr(test, derive(Debug))]
9pub enum TransformErrorKind<'source> {
10    IdIsNotDefined {
11        id: &'source str,
12        what: &'static str,
13    },
14    IdAlreadyDefined {
15        id: &'source str,
16        idx: u32,
17        what: &'static str,
18    },
19    LabelAndIdMismatch {
20        label: Option<&'source str>,
21        id: &'source str,
22    },
23    FuncTypeMismatch {
24        left_params: Vec<wat::ValType>,
25        left_results: Vec<wat::ValType>,
26        right_params: Vec<wat::ValType>,
27        right_results: Vec<wat::ValType>,
28    },
29}
30
31#[cfg_attr(test, derive(Debug))]
32pub struct TransformError<'s> {
33    kind: TransformErrorKind<'s>,
34    offset: usize,
35    source: &'s str,
36}
37
38impl<'s> TransformError<'s> {
39    fn new(kind: TransformErrorKind<'s>, offset: usize, source: &'s str) -> Box<Self> {
40        Box::new(TransformError { kind, offset, source })
41    }
42
43    pub fn offset(&self) -> usize {
44        self.offset
45    }
46
47    pub fn source(&self) -> &'s str {
48        self.source
49    }
50}
51
52impl<'s> fmt::Display for TransformError<'s> {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        use TransformErrorKind::*;
55        match &self.kind {
56            IdIsNotDefined { id, what } => write!(f, "No identifier '{}' for {} is found", id, what)?,
57            IdAlreadyDefined { id, idx, what } => write!(
58                f,
59                "Identifier '{}' is already defined to be mapped to index {} for {}",
60                id, idx, what
61            )?,
62            LabelAndIdMismatch { label: Some(label), id } => write!(
63                f,
64                "in control instruction, label '{}' and identifier '{}' must be the same",
65                label, id
66            )?,
67            LabelAndIdMismatch { label: None, id } => write!(
68                f,
69                "in control instruction, no label specified but identifier '{}' is set",
70                id
71            )?,
72            FuncTypeMismatch {
73                left_params,
74                left_results,
75                right_params,
76                right_results,
77            } => {
78                fn write_type_seq(f: &mut fmt::Formatter<'_>, tys: &[wat::ValType]) -> fmt::Result {
79                    f.write_str("[")?;
80                    let mut tys = tys.iter();
81                    if let Some(ty) = tys.next() {
82                        write!(f, "{}", ty)?;
83                    }
84                    for ty in tys {
85                        write!(f, " {}", ty)?;
86                    }
87                    f.write_str("]")
88                }
89                write!(f, "function type mismatch between ")?;
90                write_type_seq(f, left_params)?;
91                write!(f, " -> ")?;
92                write_type_seq(f, left_results)?;
93                write!(f, " and ")?;
94                write_type_seq(f, right_params)?;
95                write!(f, " -> ")?;
96                write_type_seq(f, right_results)?;
97            }
98        }
99
100        describe_position(f, self.source, self.offset)
101    }
102}
103
104type Result<'s, T> = ::std::result::Result<T, Box<TransformError<'s>>>;
105
106type Indices<'s> = HashMap<&'s str, u32>;
107
108struct LabelStack<'s> {
109    source: &'s str,
110    stack: Vec<Option<&'s str>>,
111}
112
113impl<'s> LabelStack<'s> {
114    fn new(source: &'s str) -> Self {
115        Self { source, stack: vec![] }
116    }
117
118    fn resolve(&self, idx: wat::Index<'s>, offset: usize) -> Result<'s, u32> {
119        match idx {
120            wat::Index::Num(idx) => Ok(idx),
121            wat::Index::Ident(id) => {
122                if let Some(u) = self.find(id) {
123                    Ok(u)
124                } else {
125                    Err(TransformError::new(
126                        TransformErrorKind::IdIsNotDefined { id, what: "label" },
127                        offset,
128                        self.source,
129                    ))
130                }
131            }
132        }
133    }
134
135    fn push(&mut self, label: Option<&'s str>, id: Option<&'s str>, offset: usize) -> Result<'s, ()> {
136        let label = match (label, id) {
137            (Some(label), Some(id)) if label == id => label,
138            (_, Some(id)) => {
139                // When id is set, label must be specified since id indicates matching delimiters.
140                // https://webassembly.github.io/spec/core/text/instructions.html#control-instructions
141                return Err(TransformError::new(
142                    TransformErrorKind::LabelAndIdMismatch { label, id },
143                    offset,
144                    self.source,
145                ));
146            }
147            (Some(label), None) => label,
148            (None, None) => {
149                self.stack.push(None);
150                return Ok(());
151            }
152        };
153
154        // Note: Labels can be redefined.
155        //
156        //   (block $l (result i32)
157        //     (block $l (result i32) (i32.const 2))
158        //   )
159
160        self.stack.push(Some(label));
161        Ok(())
162    }
163
164    fn pop(&mut self) {
165        let popped = self.stack.pop().is_some();
166        assert!(popped);
167    }
168
169    // Each structured control instruction introduces an implicit label. Labels are targets for branch instructions that
170    // reference them with label indices. Indexing of labels is relative by nesting depth, that is, label 0 refers to the
171    // innermost structured control instruction enclosing the referring branch instruction, while increasing indices refer
172    // to those farther out.
173    //   https://webassembly.github.io/spec/core/syntax/instructions.html#control-instructions
174    fn find(&self, label: &'s str) -> Option<u32> {
175        self.stack.iter().rev().enumerate().find_map(|(i, l)| match l {
176            Some(l) if *l == label => Some(i as u32),
177            _ => None,
178        })
179    }
180}
181
182struct Context<'s> {
183    source: &'s str,
184    type_indices: Indices<'s>,
185    func_indices: Indices<'s>,
186    table_indices: Indices<'s>,
187    mem_indices: Indices<'s>,
188    global_indices: Indices<'s>,
189    local_indices: Indices<'s>,
190    next_local_idx: u32,
191    label_stack: LabelStack<'s>,
192    implicit_type_uses: Vec<u32>,
193    types: Vec<wat::FuncType<'s>>,
194}
195
196impl<'s> Context<'s> {
197    fn resolve_index(
198        &self,
199        indices: &Indices,
200        idx: wat::Index<'s>,
201        offset: usize,
202        what: &'static str,
203    ) -> Result<'s, u32> {
204        match idx {
205            wat::Index::Num(i) => Ok(i),
206            wat::Index::Ident(id) => {
207                if let Some(idx) = indices.get(id) {
208                    Ok(*idx)
209                } else {
210                    Err(TransformError::new(
211                        TransformErrorKind::IdIsNotDefined { id, what },
212                        offset,
213                        self.source,
214                    ))
215                }
216            }
217        }
218    }
219
220    fn resolve_type_idx(&mut self, ty: wat::TypeUse<'s>, offset: usize) -> Result<'s, u32> {
221        match ty.idx {
222            wat::TypeIndex::Explicit(idx) => {
223                let idx = self.resolve_index(&self.type_indices, idx, offset, "type")?;
224                if idx as usize >= self.types.len() {
225                    return Ok(idx);
226                }
227                let wat::FuncType { params, results, .. } = &self.types[idx as usize];
228                if ty.params.is_empty() && ty.results.is_empty()
229                    || ty.params.iter().map(|p| p.ty).eq(params.iter().map(|p| p.ty))
230                        && ty.results.iter().map(|r| r.ty).eq(results.iter().map(|r| r.ty))
231                {
232                    Ok(idx)
233                } else {
234                    Err(TransformError::new(
235                        TransformErrorKind::FuncTypeMismatch {
236                            left_params: ty.params.iter().map(|p| p.ty).collect(),
237                            left_results: ty.results.iter().map(|p| p.ty).collect(),
238                            right_params: params.iter().map(|p| p.ty).collect(),
239                            right_results: results.iter().map(|p| p.ty).collect(),
240                        },
241                        offset,
242                        self.source,
243                    ))
244                }
245            }
246            wat::TypeIndex::Implicit(idx) => Ok(self.implicit_type_uses[idx as usize]),
247        }
248    }
249
250    fn resolve_func_idx(&self, idx: wat::Index<'s>, offset: usize) -> Result<'s, u32> {
251        self.resolve_index(&self.func_indices, idx, offset, "function")
252    }
253
254    fn resolve_table_idx(&self, idx: wat::Index<'s>, offset: usize) -> Result<'s, u32> {
255        self.resolve_index(&self.table_indices, idx, offset, "table")
256    }
257
258    fn resolve_mem_idx(&self, idx: wat::Index<'s>, offset: usize) -> Result<'s, u32> {
259        self.resolve_index(&self.mem_indices, idx, offset, "memory")
260    }
261
262    fn resolve_global_idx(&self, idx: wat::Index<'s>, offset: usize) -> Result<'s, u32> {
263        self.resolve_index(&self.global_indices, idx, offset, "global")
264    }
265
266    fn start_func_scope(&mut self) {
267        self.next_local_idx = 0;
268        self.local_indices.clear();
269    }
270
271    fn new_local_idx(&mut self, id: Option<&'s str>, offset: usize) -> Result<'s, u32> {
272        let idx = self.next_local_idx;
273        if let Some(id) = id {
274            if let Some(idx) = self.local_indices.insert(id, idx) {
275                return Err(TransformError::new(
276                    TransformErrorKind::IdAlreadyDefined {
277                        id,
278                        idx,
279                        what: "local variable",
280                    },
281                    offset,
282                    self.source,
283                ));
284            }
285        }
286        self.next_local_idx += 1;
287        Ok(idx)
288    }
289
290    fn resolve_local_idx(&self, idx: wat::Index<'s>, offset: usize) -> Result<'s, u32> {
291        self.resolve_index(&self.local_indices, idx, offset, "local variable")
292    }
293}
294
295pub fn wat2wasm<'s>(mut parsed: wat::Parsed<'s>, source: &'s str) -> Result<'s, wasm::Root<'s, TextSource<'s>>> {
296    let mut ctx = Context {
297        source,
298        type_indices: parsed.type_indices,
299        func_indices: parsed.func_indices,
300        table_indices: parsed.table_indices,
301        mem_indices: parsed.mem_indices,
302        global_indices: parsed.global_indices,
303        local_indices: Indices::new(),
304        next_local_idx: 0,
305        label_stack: LabelStack::new(source),
306        implicit_type_uses: mem::take(&mut parsed.module.implicit_type_uses),
307        types: Vec::new(),
308    };
309    let module = parsed.module.transform(&mut ctx)?;
310    Ok(wasm::Root {
311        module,
312        source: TextSource(source),
313    })
314}
315
316trait Transform<'s>: Sized {
317    type Target;
318    fn transform(self, ctx: &mut Context<'s>) -> Result<'s, Self::Target>;
319}
320
321impl<'s, T: Transform<'s>> Transform<'s> for Vec<T> {
322    type Target = Vec<T::Target>;
323    fn transform(self, ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
324        self.into_iter().map(|n| n.transform(ctx)).collect()
325    }
326}
327
328impl<'s, T: Transform<'s>> Transform<'s> for Option<T> {
329    type Target = Option<T::Target>;
330    fn transform(self, ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
331        self.map(|n| n.transform(ctx)).transpose()
332    }
333}
334
335impl<'s> Transform<'s> for wat::Module<'s> {
336    type Target = wasm::Module<'s>;
337    fn transform(self, ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
338        ctx.types.reserve(self.types.len());
339        for type_def in self.types.iter() {
340            ctx.types.push(type_def.ty.clone());
341        }
342        Ok(wasm::Module {
343            start: self.start,
344            id: self.id,
345            types: self.types.transform(ctx)?,
346            exports: self.exports.transform(ctx)?,
347            funcs: self.funcs.transform(ctx)?,
348            elems: self.elems.transform(ctx)?,
349            tables: self.tables.transform(ctx)?,
350            data: self.data.transform(ctx)?,
351            memories: self.memories.transform(ctx)?,
352            globals: self.globals.transform(ctx)?,
353            entrypoint: self.entrypoint.transform(ctx)?,
354        })
355    }
356}
357
358impl<'s> Transform<'s> for wat::ValType {
359    type Target = wasm::ValType;
360    fn transform(self, _ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
361        Ok(match self {
362            wat::ValType::I32 => wasm::ValType::I32,
363            wat::ValType::I64 => wasm::ValType::I64,
364            wat::ValType::F32 => wasm::ValType::F32,
365            wat::ValType::F64 => wasm::ValType::F64,
366        })
367    }
368}
369
370impl<'s> Transform<'s> for wat::TypeDef<'s> {
371    type Target = wasm::FuncType;
372    fn transform(self, ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
373        Ok(wasm::FuncType {
374            start: self.start,
375            params: self
376                .ty
377                .params
378                .iter()
379                .map(|p| p.ty.transform(ctx))
380                .collect::<Result<'_, _>>()?,
381            results: self
382                .ty
383                .results
384                .iter()
385                .map(|p| p.ty.transform(ctx))
386                .collect::<Result<'_, _>>()?,
387        })
388    }
389}
390
391impl<'s> Transform<'s> for wat::Name<'s> {
392    type Target = wasm::Name<'s>;
393    fn transform(self, _ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
394        Ok(wasm::Name(self.0))
395    }
396}
397
398impl<'s> Transform<'s> for wat::Export<'s> {
399    type Target = wasm::Export<'s>;
400    fn transform(self, ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
401        let start = self.start;
402        Ok(wasm::Export {
403            start,
404            name: self.name.transform(ctx)?,
405            kind: match self.kind {
406                wat::ExportKind::Func => {
407                    let idx = ctx.resolve_func_idx(self.idx, start)?;
408                    wasm::ExportKind::Func(idx)
409                }
410                wat::ExportKind::Table => {
411                    let idx = ctx.resolve_table_idx(self.idx, start)?;
412                    wasm::ExportKind::Table(idx)
413                }
414                wat::ExportKind::Memory => {
415                    let idx = ctx.resolve_mem_idx(self.idx, start)?;
416                    wasm::ExportKind::Memory(idx)
417                }
418                wat::ExportKind::Global => {
419                    let idx = ctx.resolve_global_idx(self.idx, start)?;
420                    wasm::ExportKind::Global(idx)
421                }
422            },
423        })
424    }
425}
426
427impl<'s> Transform<'s> for wat::Import<'s> {
428    type Target = wasm::Import<'s>;
429    fn transform(self, ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
430        Ok(wasm::Import {
431            mod_name: self.mod_name.transform(ctx)?,
432            name: self.name.transform(ctx)?,
433        })
434    }
435}
436
437impl<'s> Transform<'s> for wat::Mem {
438    type Target = wasm::Mem;
439    fn transform(self, _ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
440        Ok(wasm::Mem {
441            align: self.align,
442            offset: self.offset,
443        })
444    }
445}
446
447impl<'s> Transform<'s> for wat::Instruction<'s> {
448    type Target = wasm::Instruction;
449    fn transform(self, ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
450        let start = self.start;
451        let kind = match self.kind {
452            wat::InsnKind::Block { label, ty, body, id } => {
453                ctx.label_stack.push(label, id, start)?;
454                let body = body.transform(ctx)?;
455                ctx.label_stack.pop();
456                wasm::InsnKind::Block {
457                    ty: ty.transform(ctx)?,
458                    body,
459                }
460            }
461            wat::InsnKind::Loop { label, ty, body, id } => {
462                ctx.label_stack.push(label, id, start)?;
463                let body = body.transform(ctx)?;
464                ctx.label_stack.pop();
465                wasm::InsnKind::Loop {
466                    ty: ty.transform(ctx)?,
467                    body,
468                }
469            }
470            wat::InsnKind::If {
471                label,
472                ty,
473                then_body,
474                else_id,
475                else_body,
476                end_id,
477            } => {
478                ctx.label_stack.push(label, else_id, start)?;
479                let then_body = then_body.transform(ctx)?;
480                ctx.label_stack.pop();
481                ctx.label_stack.push(label, end_id, start)?;
482                let else_body = else_body.transform(ctx)?;
483                ctx.label_stack.pop();
484                wasm::InsnKind::If {
485                    ty: ty.transform(ctx)?,
486                    then_body,
487                    else_body,
488                }
489            }
490            wat::InsnKind::Unreachable => wasm::InsnKind::Unreachable,
491            wat::InsnKind::Nop => wasm::InsnKind::Nop,
492            wat::InsnKind::Br(idx) => wasm::InsnKind::Br(ctx.label_stack.resolve(idx, start)?),
493            wat::InsnKind::BrIf(idx) => wasm::InsnKind::BrIf(ctx.label_stack.resolve(idx, start)?),
494            wat::InsnKind::BrTable { labels, default_label } => wasm::InsnKind::BrTable {
495                labels: labels
496                    .into_iter()
497                    .map(|idx| ctx.label_stack.resolve(idx, start))
498                    .collect::<Result<'_, _>>()?,
499                default_label: ctx.label_stack.resolve(default_label, start)?,
500            },
501            wat::InsnKind::Return => wasm::InsnKind::Return,
502            wat::InsnKind::Call(idx) => wasm::InsnKind::Call(ctx.resolve_func_idx(idx, start)?),
503            wat::InsnKind::CallIndirect(ty) => wasm::InsnKind::CallIndirect(ctx.resolve_type_idx(ty, start)?),
504            // Parametric instructions
505            wat::InsnKind::Drop => wasm::InsnKind::Drop,
506            wat::InsnKind::Select => wasm::InsnKind::Select,
507            // Variable instructions
508            wat::InsnKind::LocalGet(idx) => wasm::InsnKind::LocalGet(ctx.resolve_local_idx(idx, start)?),
509            wat::InsnKind::LocalSet(idx) => wasm::InsnKind::LocalSet(ctx.resolve_local_idx(idx, start)?),
510            wat::InsnKind::LocalTee(idx) => wasm::InsnKind::LocalTee(ctx.resolve_local_idx(idx, start)?),
511            wat::InsnKind::GlobalGet(idx) => wasm::InsnKind::GlobalGet(ctx.resolve_global_idx(idx, start)?),
512            wat::InsnKind::GlobalSet(idx) => wasm::InsnKind::GlobalSet(ctx.resolve_global_idx(idx, start)?),
513            // Memory instructions
514            wat::InsnKind::I32Load(mem) => wasm::InsnKind::I32Load(mem.transform(ctx)?),
515            wat::InsnKind::I64Load(mem) => wasm::InsnKind::I64Load(mem.transform(ctx)?),
516            wat::InsnKind::F32Load(mem) => wasm::InsnKind::F32Load(mem.transform(ctx)?),
517            wat::InsnKind::F64Load(mem) => wasm::InsnKind::F64Load(mem.transform(ctx)?),
518            wat::InsnKind::I32Load8S(mem) => wasm::InsnKind::I32Load8S(mem.transform(ctx)?),
519            wat::InsnKind::I32Load8U(mem) => wasm::InsnKind::I32Load8U(mem.transform(ctx)?),
520            wat::InsnKind::I32Load16S(mem) => wasm::InsnKind::I32Load16S(mem.transform(ctx)?),
521            wat::InsnKind::I32Load16U(mem) => wasm::InsnKind::I32Load16U(mem.transform(ctx)?),
522            wat::InsnKind::I64Load8S(mem) => wasm::InsnKind::I64Load8S(mem.transform(ctx)?),
523            wat::InsnKind::I64Load8U(mem) => wasm::InsnKind::I64Load8U(mem.transform(ctx)?),
524            wat::InsnKind::I64Load16S(mem) => wasm::InsnKind::I64Load16S(mem.transform(ctx)?),
525            wat::InsnKind::I64Load16U(mem) => wasm::InsnKind::I64Load16U(mem.transform(ctx)?),
526            wat::InsnKind::I64Load32S(mem) => wasm::InsnKind::I64Load32S(mem.transform(ctx)?),
527            wat::InsnKind::I64Load32U(mem) => wasm::InsnKind::I64Load32U(mem.transform(ctx)?),
528            wat::InsnKind::I32Store(mem) => wasm::InsnKind::I32Store(mem.transform(ctx)?),
529            wat::InsnKind::I64Store(mem) => wasm::InsnKind::I64Store(mem.transform(ctx)?),
530            wat::InsnKind::F32Store(mem) => wasm::InsnKind::F32Store(mem.transform(ctx)?),
531            wat::InsnKind::F64Store(mem) => wasm::InsnKind::F64Store(mem.transform(ctx)?),
532            wat::InsnKind::I32Store8(mem) => wasm::InsnKind::I32Store8(mem.transform(ctx)?),
533            wat::InsnKind::I32Store16(mem) => wasm::InsnKind::I32Store16(mem.transform(ctx)?),
534            wat::InsnKind::I64Store8(mem) => wasm::InsnKind::I64Store8(mem.transform(ctx)?),
535            wat::InsnKind::I64Store16(mem) => wasm::InsnKind::I64Store16(mem.transform(ctx)?),
536            wat::InsnKind::I64Store32(mem) => wasm::InsnKind::I64Store32(mem.transform(ctx)?),
537            wat::InsnKind::MemorySize => wasm::InsnKind::MemorySize,
538            wat::InsnKind::MemoryGrow => wasm::InsnKind::MemoryGrow,
539            // Numeric instructions
540            // https://webassembly.github.io/spec/core/text/instructions.html#numeric-instructions
541            // Constants
542            wat::InsnKind::I32Const(val) => wasm::InsnKind::I32Const(val),
543            wat::InsnKind::I64Const(val) => wasm::InsnKind::I64Const(val),
544            wat::InsnKind::F32Const(val) => wasm::InsnKind::F32Const(val),
545            wat::InsnKind::F64Const(val) => wasm::InsnKind::F64Const(val),
546            // i32 operations
547            wat::InsnKind::I32Clz => wasm::InsnKind::I32Clz,
548            wat::InsnKind::I32Ctz => wasm::InsnKind::I32Ctz,
549            wat::InsnKind::I32Popcnt => wasm::InsnKind::I32Popcnt,
550            wat::InsnKind::I32Add => wasm::InsnKind::I32Add,
551            wat::InsnKind::I32Sub => wasm::InsnKind::I32Sub,
552            wat::InsnKind::I32Mul => wasm::InsnKind::I32Mul,
553            wat::InsnKind::I32DivS => wasm::InsnKind::I32DivS,
554            wat::InsnKind::I32DivU => wasm::InsnKind::I32DivU,
555            wat::InsnKind::I32RemS => wasm::InsnKind::I32RemS,
556            wat::InsnKind::I32RemU => wasm::InsnKind::I32RemU,
557            wat::InsnKind::I32And => wasm::InsnKind::I32And,
558            wat::InsnKind::I32Or => wasm::InsnKind::I32Or,
559            wat::InsnKind::I32Xor => wasm::InsnKind::I32Xor,
560            wat::InsnKind::I32Shl => wasm::InsnKind::I32Shl,
561            wat::InsnKind::I32ShrS => wasm::InsnKind::I32ShrS,
562            wat::InsnKind::I32ShrU => wasm::InsnKind::I32ShrU,
563            wat::InsnKind::I32Rotl => wasm::InsnKind::I32Rotl,
564            wat::InsnKind::I32Rotr => wasm::InsnKind::I32Rotr,
565            // i64 operations
566            wat::InsnKind::I64Clz => wasm::InsnKind::I64Clz,
567            wat::InsnKind::I64Ctz => wasm::InsnKind::I64Ctz,
568            wat::InsnKind::I64Popcnt => wasm::InsnKind::I64Popcnt,
569            wat::InsnKind::I64Add => wasm::InsnKind::I64Add,
570            wat::InsnKind::I64Sub => wasm::InsnKind::I64Sub,
571            wat::InsnKind::I64Mul => wasm::InsnKind::I64Mul,
572            wat::InsnKind::I64DivS => wasm::InsnKind::I64DivS,
573            wat::InsnKind::I64DivU => wasm::InsnKind::I64DivU,
574            wat::InsnKind::I64RemS => wasm::InsnKind::I64RemS,
575            wat::InsnKind::I64RemU => wasm::InsnKind::I64RemU,
576            wat::InsnKind::I64And => wasm::InsnKind::I64And,
577            wat::InsnKind::I64Or => wasm::InsnKind::I64Or,
578            wat::InsnKind::I64Xor => wasm::InsnKind::I64Xor,
579            wat::InsnKind::I64Shl => wasm::InsnKind::I64Shl,
580            wat::InsnKind::I64ShrS => wasm::InsnKind::I64ShrS,
581            wat::InsnKind::I64ShrU => wasm::InsnKind::I64ShrU,
582            wat::InsnKind::I64Rotl => wasm::InsnKind::I64Rotl,
583            wat::InsnKind::I64Rotr => wasm::InsnKind::I64Rotr,
584            // f32 operations
585            wat::InsnKind::F32Abs => wasm::InsnKind::F32Abs,
586            wat::InsnKind::F32Neg => wasm::InsnKind::F32Neg,
587            wat::InsnKind::F32Ceil => wasm::InsnKind::F32Ceil,
588            wat::InsnKind::F32Floor => wasm::InsnKind::F32Floor,
589            wat::InsnKind::F32Trunc => wasm::InsnKind::F32Trunc,
590            wat::InsnKind::F32Nearest => wasm::InsnKind::F32Nearest,
591            wat::InsnKind::F32Sqrt => wasm::InsnKind::F32Sqrt,
592            wat::InsnKind::F32Add => wasm::InsnKind::F32Add,
593            wat::InsnKind::F32Sub => wasm::InsnKind::F32Sub,
594            wat::InsnKind::F32Mul => wasm::InsnKind::F32Mul,
595            wat::InsnKind::F32Div => wasm::InsnKind::F32Div,
596            wat::InsnKind::F32Min => wasm::InsnKind::F32Min,
597            wat::InsnKind::F32Max => wasm::InsnKind::F32Max,
598            wat::InsnKind::F32Copysign => wasm::InsnKind::F32Copysign,
599            // f64 operations
600            wat::InsnKind::F64Abs => wasm::InsnKind::F64Abs,
601            wat::InsnKind::F64Neg => wasm::InsnKind::F64Neg,
602            wat::InsnKind::F64Ceil => wasm::InsnKind::F64Ceil,
603            wat::InsnKind::F64Floor => wasm::InsnKind::F64Floor,
604            wat::InsnKind::F64Trunc => wasm::InsnKind::F64Trunc,
605            wat::InsnKind::F64Nearest => wasm::InsnKind::F64Nearest,
606            wat::InsnKind::F64Sqrt => wasm::InsnKind::F64Sqrt,
607            wat::InsnKind::F64Add => wasm::InsnKind::F64Add,
608            wat::InsnKind::F64Sub => wasm::InsnKind::F64Sub,
609            wat::InsnKind::F64Mul => wasm::InsnKind::F64Mul,
610            wat::InsnKind::F64Div => wasm::InsnKind::F64Div,
611            wat::InsnKind::F64Min => wasm::InsnKind::F64Min,
612            wat::InsnKind::F64Max => wasm::InsnKind::F64Max,
613            wat::InsnKind::F64Copysign => wasm::InsnKind::F64Copysign,
614            // i32 comparison
615            wat::InsnKind::I32Eqz => wasm::InsnKind::I32Eqz,
616            wat::InsnKind::I32Eq => wasm::InsnKind::I32Eq,
617            wat::InsnKind::I32Ne => wasm::InsnKind::I32Ne,
618            wat::InsnKind::I32LtS => wasm::InsnKind::I32LtS,
619            wat::InsnKind::I32LtU => wasm::InsnKind::I32LtU,
620            wat::InsnKind::I32GtS => wasm::InsnKind::I32GtS,
621            wat::InsnKind::I32GtU => wasm::InsnKind::I32GtU,
622            wat::InsnKind::I32LeS => wasm::InsnKind::I32LeS,
623            wat::InsnKind::I32LeU => wasm::InsnKind::I32LeU,
624            wat::InsnKind::I32GeS => wasm::InsnKind::I32GeS,
625            wat::InsnKind::I32GeU => wasm::InsnKind::I32GeU,
626            // i64 comparison
627            wat::InsnKind::I64Eqz => wasm::InsnKind::I64Eqz,
628            wat::InsnKind::I64Eq => wasm::InsnKind::I64Eq,
629            wat::InsnKind::I64Ne => wasm::InsnKind::I64Ne,
630            wat::InsnKind::I64LtS => wasm::InsnKind::I64LtS,
631            wat::InsnKind::I64LtU => wasm::InsnKind::I64LtU,
632            wat::InsnKind::I64GtS => wasm::InsnKind::I64GtS,
633            wat::InsnKind::I64GtU => wasm::InsnKind::I64GtU,
634            wat::InsnKind::I64LeS => wasm::InsnKind::I64LeS,
635            wat::InsnKind::I64LeU => wasm::InsnKind::I64LeU,
636            wat::InsnKind::I64GeS => wasm::InsnKind::I64GeS,
637            wat::InsnKind::I64GeU => wasm::InsnKind::I64GeU,
638            // f32 comparison
639            wat::InsnKind::F32Eq => wasm::InsnKind::F32Eq,
640            wat::InsnKind::F32Ne => wasm::InsnKind::F32Ne,
641            wat::InsnKind::F32Lt => wasm::InsnKind::F32Lt,
642            wat::InsnKind::F32Gt => wasm::InsnKind::F32Gt,
643            wat::InsnKind::F32Le => wasm::InsnKind::F32Le,
644            wat::InsnKind::F32Ge => wasm::InsnKind::F32Ge,
645            // f64 comparison
646            wat::InsnKind::F64Eq => wasm::InsnKind::F64Eq,
647            wat::InsnKind::F64Ne => wasm::InsnKind::F64Ne,
648            wat::InsnKind::F64Lt => wasm::InsnKind::F64Lt,
649            wat::InsnKind::F64Gt => wasm::InsnKind::F64Gt,
650            wat::InsnKind::F64Le => wasm::InsnKind::F64Le,
651            wat::InsnKind::F64Ge => wasm::InsnKind::F64Ge,
652            // Conversion
653            wat::InsnKind::I32WrapI64 => wasm::InsnKind::I32WrapI64,
654            wat::InsnKind::I32TruncF32S => wasm::InsnKind::I32TruncF32S,
655            wat::InsnKind::I32TruncF32U => wasm::InsnKind::I32TruncF32U,
656            wat::InsnKind::I32TruncF64S => wasm::InsnKind::I32TruncF64S,
657            wat::InsnKind::I32TruncF64U => wasm::InsnKind::I32TruncF64U,
658            wat::InsnKind::I64ExtendI32S => wasm::InsnKind::I64ExtendI32S,
659            wat::InsnKind::I64ExtendI32U => wasm::InsnKind::I64ExtendI32U,
660            wat::InsnKind::I64TruncF32S => wasm::InsnKind::I64TruncF32S,
661            wat::InsnKind::I64TruncF32U => wasm::InsnKind::I64TruncF32U,
662            wat::InsnKind::I64TruncF64S => wasm::InsnKind::I64TruncF64S,
663            wat::InsnKind::I64TruncF64U => wasm::InsnKind::I64TruncF64U,
664            wat::InsnKind::F32ConvertI32S => wasm::InsnKind::F32ConvertI32S,
665            wat::InsnKind::F32ConvertI32U => wasm::InsnKind::F32ConvertI32U,
666            wat::InsnKind::F32ConvertI64S => wasm::InsnKind::F32ConvertI64S,
667            wat::InsnKind::F32ConvertI64U => wasm::InsnKind::F32ConvertI64U,
668            wat::InsnKind::F32DemoteF64 => wasm::InsnKind::F32DemoteF64,
669            wat::InsnKind::F64ConvertI32S => wasm::InsnKind::F64ConvertI32S,
670            wat::InsnKind::F64ConvertI32U => wasm::InsnKind::F64ConvertI32U,
671            wat::InsnKind::F64ConvertI64S => wasm::InsnKind::F64ConvertI64S,
672            wat::InsnKind::F64ConvertI64U => wasm::InsnKind::F64ConvertI64U,
673            wat::InsnKind::F64PromoteF32 => wasm::InsnKind::F64PromoteF32,
674            wat::InsnKind::I32ReinterpretF32 => wasm::InsnKind::I32ReinterpretF32,
675            wat::InsnKind::I64ReinterpretF64 => wasm::InsnKind::I64ReinterpretF64,
676            wat::InsnKind::F32ReinterpretI32 => wasm::InsnKind::F32ReinterpretI32,
677            wat::InsnKind::F64ReinterpretI64 => wasm::InsnKind::F64ReinterpretI64,
678            // Sign extension
679            wat::InsnKind::I32Extend8S => wasm::InsnKind::I32Extend8S,
680            wat::InsnKind::I32Extend16S => wasm::InsnKind::I32Extend16S,
681            wat::InsnKind::I64Extend8S => wasm::InsnKind::I64Extend8S,
682            wat::InsnKind::I64Extend16S => wasm::InsnKind::I64Extend16S,
683            wat::InsnKind::I64Extend32S => wasm::InsnKind::I64Extend32S,
684        };
685        Ok(wasm::Instruction { start, kind })
686    }
687}
688
689impl<'s> Transform<'s> for wat::Func<'s> {
690    type Target = wasm::Func<'s>;
691    fn transform(self, ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
692        Ok(wasm::Func {
693            start: self.start,
694            kind: match self.kind {
695                wat::FuncKind::Import(import) => wasm::FuncKind::Import(import.transform(ctx)?),
696                wat::FuncKind::Body { locals, body } => {
697                    ctx.start_func_scope();
698                    for param in self.ty.params.iter() {
699                        ctx.new_local_idx(param.id, self.start)?;
700                    }
701                    for local in locals.iter() {
702                        ctx.new_local_idx(local.id, self.start)?;
703                    }
704
705                    wasm::FuncKind::Body {
706                        locals: locals.iter().map(|l| l.ty.transform(ctx)).collect::<Result<'_, _>>()?,
707                        expr: body.transform(ctx)?,
708                    }
709                }
710            },
711            idx: ctx.resolve_type_idx(self.ty, self.start)?,
712        })
713    }
714}
715
716impl<'s> Transform<'s> for wat::Elem<'s> {
717    type Target = wasm::ElemSegment;
718    fn transform(self, ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
719        let start = self.start;
720        Ok(wasm::ElemSegment {
721            start,
722            idx: ctx.resolve_table_idx(self.idx, start)?,
723            offset: self.offset.transform(ctx)?,
724            init: self
725                .init
726                .into_iter()
727                .map(|idx| ctx.resolve_func_idx(idx, start))
728                .collect::<Result<'_, _>>()?,
729        })
730    }
731}
732
733impl<'s> Transform<'s> for wat::Limits {
734    type Target = wasm::Limits;
735    fn transform(self, _ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
736        Ok(match self {
737            wat::Limits::Range { min, max } => wasm::Limits::Range(min, max),
738            wat::Limits::From { min } => wasm::Limits::From(min),
739        })
740    }
741}
742
743impl<'s> Transform<'s> for wat::Table<'s> {
744    type Target = wasm::Table<'s>;
745    fn transform(self, ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
746        Ok(wasm::Table {
747            start: self.start,
748            ty: wasm::TableType {
749                limit: self.ty.limit.transform(ctx)?,
750            },
751            import: self.import.transform(ctx)?,
752        })
753    }
754}
755
756impl<'s> Transform<'s> for wat::Data<'s> {
757    type Target = wasm::DataSegment<'s>;
758    fn transform(self, ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
759        Ok(wasm::DataSegment {
760            start: self.start,
761            idx: ctx.resolve_mem_idx(self.idx, self.start)?,
762            offset: self.offset.transform(ctx)?,
763            data: self.data,
764        })
765    }
766}
767
768impl<'s> Transform<'s> for wat::Memory<'s> {
769    type Target = wasm::Memory<'s>;
770    fn transform(self, ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
771        Ok(wasm::Memory {
772            start: self.start,
773            ty: wasm::MemType {
774                limit: self.ty.limit.transform(ctx)?,
775            },
776            import: self.import.transform(ctx)?,
777        })
778    }
779}
780
781impl<'s> Transform<'s> for wat::Global<'s> {
782    type Target = wasm::Global<'s>;
783    fn transform(self, ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
784        Ok(wasm::Global {
785            start: self.start,
786            mutable: self.ty.mutable,
787            ty: self.ty.ty.transform(ctx)?,
788            kind: match self.kind {
789                wat::GlobalKind::Import(import) => wasm::GlobalKind::Import(import.transform(ctx)?),
790                wat::GlobalKind::Init(init) => wasm::GlobalKind::Init(init.transform(ctx)?),
791            },
792        })
793    }
794}
795
796impl<'s> Transform<'s> for wat::Start<'s> {
797    type Target = wasm::StartFunction;
798    fn transform(self, ctx: &mut Context<'s>) -> Result<'s, Self::Target> {
799        Ok(wasm::StartFunction {
800            start: self.start,
801            idx: ctx.resolve_func_idx(self.idx, self.start)?,
802        })
803    }
804}