nyar_wasm/operations/branch/
mod.rs

1use super::*;
2use std::collections::BTreeMap;
3
4/// ```v
5/// match var {
6///     case 0:
7///         ...
8///     case 2:
9///         ...
10///     else:
11///         ...
12/// }
13/// ```
14#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub struct EnumerationTable {
16    pub branches: BTreeMap<u32, Vec<WasiInstruction>>,
17    pub default: Vec<WasiInstruction>,
18    pub r#return: Vec<WasiType>,
19}
20
21/// ```v
22/// switch {
23///     when x == 0:
24///         ...
25///     when x == 2:
26///         ...
27///     else:
28///         ...
29/// }
30/// ```
31#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
32pub struct JumpTable {
33    pub branches: Vec<JumpCondition>,
34    pub default: Vec<WasiInstruction>,
35    pub r#return: Vec<WasiType>,
36}
37
38#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
39pub struct JumpBranch {
40    /// The conditional jump branch
41    pub main: JumpCondition,
42    /// The default jump branch
43    pub default: Vec<WasiInstruction>,
44    /// Compile with `select`, otherwise `if else end` will be used
45    pub select: bool,
46    /// The return type of the block
47    pub r#return: Vec<WasiType>,
48}
49
50#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
51pub struct JumpCondition {
52    /// The condition of the if statement
53    pub condition: Vec<WasiInstruction>,
54    /// The action if condition is true
55    pub action: Vec<WasiInstruction>,
56}
57
58impl JumpBranch {
59    /// Create a `if ... then ... end` branch
60    pub fn if_then(r#if: Vec<WasiInstruction>, then: Vec<WasiInstruction>) -> Self {
61        Self { main: JumpCondition { condition: r#if, action: then }, default: vec![], select: false, r#return: vec![] }
62    }
63    /// Create a `if ... then ... else ... end` branch
64    pub fn if_then_else(r#if: Vec<WasiInstruction>, then: Vec<WasiInstruction>, r#else: Vec<WasiInstruction>) -> Self {
65        Self { main: JumpCondition { condition: r#if, action: then }, default: r#else, select: false, r#return: vec![] }
66    }
67    /// Set the return type of the if statement
68    pub fn with_return_type(self, r#type: Vec<WasiType>) -> Self {
69        Self { r#return: r#type, ..self }
70    }
71    /// Whether to execute branches in parallel
72    pub fn with_parallel(self, select: bool) -> Self {
73        Self { select, ..self }
74    }
75}
76
77impl JumpCondition {
78    pub fn new(condition: Vec<WasiInstruction>, action: Vec<WasiInstruction>) -> Self {
79        Self { condition, action }
80    }
81}
82
83impl WasiInstruction {
84    pub fn if_then(r#if: Vec<WasiInstruction>, then: Vec<WasiInstruction>) -> Self {
85        JumpBranch::if_then(r#if, then).into()
86    }
87    pub fn if_then_else(r#if: Vec<WasiInstruction>, then: Vec<WasiInstruction>, r#else: Vec<WasiInstruction>) -> Self {
88        JumpBranch::if_then_else(r#if, then, r#else).into()
89    }
90}
91
92impl Emit for JumpBranch {
93    fn emit<W: Write>(&self, w: &mut WastEncoder<W>) -> std::fmt::Result {
94        for i in &self.main.condition {
95            i.emit(w)?;
96        }
97        let recover = std::mem::take(&mut w.stack);
98        write!(w, "(if")?;
99        w.indent();
100        write!(w, "(then")?;
101        w.indent();
102        for i in &self.main.action {
103            i.emit(w)?;
104        }
105        w.dedent(1);
106        write!(w, "(else")?;
107        w.indent();
108        for i in &self.default {
109            i.emit(w)?;
110        }
111        w.dedent(1);
112        w.dedent(1);
113        w.stack = recover;
114        Ok(())
115    }
116}
117
118impl From<JumpBranch> for WasiInstruction {
119    fn from(value: JumpBranch) -> Self {
120        Self::JumpBranch(value)
121    }
122}