wat_ast/
expression.rs

1use wast::parser::{Parse, Parser, Result};
2
3use crate::{
4    Atom, Expr, Index, Indexes, Integer, SExpr, SymbolicIndex, ValueType,
5};
6
7pub fn fold(i: Instruction) -> Expression {
8    Expression::Folded(i)
9}
10
11pub fn global_get<S: AsRef<str>>(s: S) -> Instruction {
12    Instruction::GlobalGet(GlobalGet {
13        idx:   Index::Symbolic(SymbolicIndex::new(s.as_ref().to_owned())),
14        exprs: vec![],
15    })
16}
17
18pub fn i32_const<S: AsRef<str>>(s: S) -> Instruction {
19    Instruction::I32Const(I32Const {
20        integer: Integer::new(s.as_ref().to_owned()),
21        exprs:   vec![],
22    })
23}
24
25pub fn i64_const<S: AsRef<str>>(s: S) -> Instruction {
26    Instruction::I64Const(I64Const {
27        integer: Integer::new(s.as_ref().to_owned()),
28        exprs:   vec![],
29    })
30}
31
32pub fn local_get<S: AsRef<str>>(s: S) -> Instruction {
33    Instruction::LocalGet(LocalGet {
34        idx:   Index::Symbolic(SymbolicIndex::new(s.as_ref().to_owned())),
35        exprs: vec![],
36    })
37}
38
39enum Paren {
40    None,
41    Left,
42    Right,
43}
44
45#[derive(Debug, Clone, PartialEq, Eq)]
46struct Level {
47    expr:     Expression,
48    subexprs: Vec<Expression>,
49}
50
51#[derive(Debug, Clone, PartialEq, Eq)]
52pub enum Expression {
53    Unfolded(Instruction),
54    Folded(Instruction),
55}
56
57impl Expression {
58    pub(crate) fn expr(&self) -> Expr {
59        match self {
60            Self::Unfolded(i) => Expr::Atom(i.as_atom()),
61            Self::Folded(i) => Expr::SExpr(Box::new(i.clone())),
62        }
63    }
64
65    fn subexprs(&mut self) -> &mut Vec<Expression> {
66        match self {
67            Self::Unfolded(i) => i.subexprs(),
68            Self::Folded(i) => i.subexprs(),
69        }
70    }
71}
72
73#[derive(Default)]
74pub(crate) struct ExpressionParser {
75    exprs: Vec<Expression>,
76    stack: Vec<Level>,
77}
78
79impl ExpressionParser {
80    pub fn parse(mut self, parser: Parser) -> Result<Vec<Expression>> {
81        while !parser.is_empty() || !self.stack.is_empty() {
82            match self.paren(parser)? {
83                Paren::Left => {
84                    let instr = parser.parse::<Instruction>()?;
85                    self.stack.push(Level {
86                        expr:     Expression::Folded(instr),
87                        subexprs: Vec::new(),
88                    });
89                },
90                Paren::None => {
91                    let instr = parser.parse::<Instruction>()?;
92                    let expr = Expression::Unfolded(instr);
93
94                    match self.stack.last_mut() {
95                        Some(level) => level.subexprs.push(expr),
96                        None => self.exprs.push(expr),
97                    }
98                },
99                Paren::Right => match self.stack.pop() {
100                    Some(mut level) => {
101                        level.expr.subexprs().append(&mut level.subexprs);
102
103                        if let Some(top) = self.stack.last_mut() {
104                            top.subexprs.push(level.expr);
105                        } else {
106                            self.exprs.push(level.expr);
107                        }
108                    },
109                    None => {},
110                },
111            }
112        }
113
114        Ok(self.exprs.clone())
115    }
116
117    /// Parses either `(`, `)`, or nothing.
118    fn paren(&self, parser: Parser) -> Result<Paren> {
119        parser.step(|cursor| {
120            Ok(match cursor.lparen() {
121                Some(rest) => (Paren::Left, rest),
122                None if self.stack.is_empty() => (Paren::None, cursor),
123                None => match cursor.rparen() {
124                    Some(rest) => (Paren::Right, rest),
125                    None => (Paren::None, cursor),
126                },
127            })
128        })
129    }
130}
131
132#[macro_export]
133macro_rules! instructions {
134    (pub enum Instruction {
135        $(
136            $name:ident : $keyword:tt : $instr:tt {
137                $($field_name:ident: $field_type:ty),*
138            },
139        )*
140    }) => {
141        mod kw {
142            $(
143                wast::custom_keyword!($keyword = $instr);
144            )*
145        }
146
147        #[derive(Debug, Clone, PartialEq, Eq)]
148        pub enum Instruction {
149            $(
150                $name($name),
151            )*
152        }
153
154
155        impl Instruction {
156            pub fn subexprs(&mut self) -> &mut Vec<Expression> {
157                match self {
158                    $(
159                        Self::$name(i) => &mut i.exprs,
160                    )*
161                }
162            }
163        }
164
165        impl Instruction {
166            pub fn as_atom(&self) -> Atom {
167                match self {
168                    $(
169                        Self::$name(i) => i.as_atom(),
170                    )*
171                }
172            }
173        }
174
175        impl Parse<'_> for Instruction {
176            fn parse(parser: Parser<'_>) -> Result<Self> {
177                let mut l = parser.lookahead1();
178
179                $(
180                    if l.peek::<kw::$keyword>() {
181                        return Ok(Self::$name(parser.parse()?));
182                    }
183                )*
184
185                Err(l.error())
186            }
187        }
188
189        impl SExpr for Instruction {
190            fn car(&self) -> std::string::String {
191                match self {
192                    $(
193                        Self::$name(i) => i.car(),
194                    )*
195                }
196            }
197
198            fn cdr(&self) -> Vec<Expr> {
199                match self {
200                    $(
201                        Self::$name(i) => i.cdr(),
202                    )*
203                }
204            }
205        }
206
207        $(
208            #[derive(Debug, Clone, PartialEq, Eq)]
209            pub struct $name {
210                $(
211                    pub $field_name: $field_type,
212                )*
213                pub exprs: Vec<Expression>,
214            }
215
216            impl $name {
217                pub fn as_atom(&self) -> Atom {
218                    #[allow(unused_mut)]
219                    let mut s = std::string::String::new();
220
221                    $(
222                        s.push(' ');
223                        s.push_str(
224                            &self
225                                .$field_name
226                                .as_atoms()
227                                .iter()
228                                .map(ToString::to_string)
229                                .collect::<Vec<std::string::String>>()
230                                .join(" ")
231                        );
232                    )*
233
234                    Atom::new(s)
235                }
236            }
237
238            impl SExpr for $name {
239                fn car(&self) -> std::string::String {
240                    format!("{}", $instr)
241                }
242
243                fn cdr(&self) -> Vec<Expr> {
244                    let mut v = Vec::new();
245
246                    $(
247                        v.append(
248                            &mut self
249                                .clone()
250                                .$field_name
251                                .as_atoms()
252                                .iter()
253                                .map(|a| Expr::Atom(a.clone()))
254                                .collect()
255                        );
256                    )*
257
258                    v.append(
259                        &mut self
260                            .exprs
261                            .iter()
262                            .map(|e| e.expr())
263                            .collect()
264                    );
265
266                    v
267                }
268            }
269
270            impl Parse<'_> for $name {
271                fn parse(parser: Parser<'_>) -> Result<Self> {
272                    parser.parse::<kw::$keyword>()?;
273
274                    $(
275                        let $field_name = parser.parse::<$field_type>()?;
276                    )*
277
278                    Ok(Self {
279                        $(
280                            $field_name,
281                        )*
282                        exprs: Vec::new(),
283                    })
284                }
285            }
286        )*
287    };
288}
289
290instructions!(
291    pub enum Instruction {
292        Block      : block       : "block"       { idx: Option<Index> },
293        Br         : br          : "br"          { idx: Index },
294        BrIf       : br_if       : "br_if"       { idx: Index },
295        BrTable    : br_table    : "br_table"    { idxs: Indexes },
296        Call       : call        : "call"        { idx: Index },
297        Drop       : drop        : "drop"        {},
298        Else       : r#else      : "else"        {},
299        GlobalGet  : global_get  : "global.get"  { idx: Index },
300        GlobalSet  : global_set  : "global.set"  { idx: Index },
301        I32Add     : i32_add     : "i32.add"     {},
302        I32Const   : i32_const   : "i32.const"   { integer: Integer },
303        I32Eq      : i32_eq      : "i32.eq"      {},
304        I32Eqz     : i32_eqz     : "i32.eqz"     {},
305        I32GtU     : i32_gt_u    : "i32.gt_u"    {},
306        I32Load    : i32_load    : "i32.load"    {},
307        I32LtS     : i32_lt_s    : "i32.lt_s"    {},
308        I32LtU     : i32_lt_u    : "i32.lt_u"    {},
309        I32Mul     : i32_mul     : "i32.mul"     {},
310        I32Ne      : i32_ne      : "i32.ne"      {},
311        I32RemU    : i32_rem_u   : "i32.rem_u"   {},
312        I32ShrU    : i32_shr_u   : "i32.shr_u"   {},
313        I32Sub     : i32_sub     : "i32.sub"     {},
314        I64Const   : i64_const   : "i64.const"   { integer: Integer },
315        If         : r#if        : "if"          {},
316        Local      : local       : "local"       { idx: Index, value_type: ValueType },
317        LocalGet   : local_get   : "local.get"   { idx: Index },
318        LocalSet   : local_set   : "local.set"   { idx: Index },
319        LocalTee   : local_tee   : "local.tee"   { idx: Index },
320        Loop       : r#loop      : "loop"        { idx: Option<Index> },
321        MemoryGrow : memory_grow : "memory.grow" {},
322        Return     : r#return    : "return"      {},
323        Then       : then        : "then"        {},
324    }
325);
326
327pub trait AsAtoms {
328    fn as_atoms(&self) -> Vec<Atom>;
329}
330
331impl AsAtoms for String {
332    fn as_atoms(&self) -> Vec<Atom> {
333        vec![Atom::new(format!(r#""{}""#, self))]
334    }
335}
336
337impl<T: AsAtoms + Clone> AsAtoms for Option<T> {
338    fn as_atoms(&self) -> Vec<Atom> {
339        self.clone().map_or(Vec::new(), |x| x.as_atoms())
340    }
341}