wat_ast/
section.rs

1use wast::parser::{Parse, Parser, Result};
2
3use crate::{
4    AsAtoms, Atom, Expr, Expression, ExpressionParser, FuncType, GlobalType,
5    ImportDesc, Index, InlineExport, MemType, SExpr, TypeUse,
6};
7
8/// https://webassembly.github.io/spec/core/text/modules.html#text-module
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub enum Section {
11    Type(TypeSection),
12    Import(ImportSection),
13    Function(FunctionSection),
14    Memory(MemorySection),
15    Global(GlobalSection),
16    Data(DataSection),
17}
18
19impl Section {
20    pub(crate) fn exprs(&self) -> Vec<Expr> {
21        match self {
22            Self::Type(s) => s.exprs(),
23            Self::Import(s) => s.exprs(),
24            Self::Function(s) => s.exprs(),
25            Self::Memory(s) => s.exprs(),
26            Self::Global(s) => s.exprs(),
27            Self::Data(s) => s.exprs(),
28        }
29    }
30}
31
32impl Parse<'_> for Section {
33    fn parse(parser: Parser<'_>) -> Result<Self> {
34        while !parser.is_empty() {
35            if parser.peek2::<wast::kw::r#type>() {
36                return Ok(Self::Type(parser.parse()?));
37            } else if parser.peek2::<wast::kw::import>() {
38                return Ok(Self::Import(parser.parse()?));
39            } else if parser.peek2::<wast::kw::func>() {
40                return Ok(Self::Function(parser.parse()?));
41            } else if parser.peek2::<wast::kw::memory>() {
42                return Ok(Self::Memory(parser.parse()?));
43            } else if parser.peek2::<wast::kw::global>() {
44                return Ok(Self::Global(parser.parse()?));
45            } else if parser.peek2::<wast::kw::data>() {
46                return Ok(Self::Data(parser.parse()?));
47            } else {
48                return Err(parser.error("unexpected section"));
49            }
50        }
51
52        Err(parser.error("empty section"))
53    }
54}
55
56#[derive(Debug, Clone, PartialEq, Eq)]
57pub struct TypeSection {
58    entries: Vec<TypeSectionEntry>,
59}
60
61impl TypeSection {
62    pub fn with_entries(entries: Vec<TypeSectionEntry>) -> Self {
63        Self { entries }
64    }
65
66    pub(crate) fn exprs(&self) -> Vec<Expr> {
67        self.entries
68            .iter()
69            .map(|e| Expr::SExpr(Box::new(e.clone())))
70            .collect()
71    }
72}
73
74impl Parse<'_> for TypeSection {
75    fn parse(parser: Parser<'_>) -> Result<Self> {
76        let mut entries = Vec::new();
77
78        while !parser.is_empty() {
79            entries.push(parser.parens(|p| p.parse::<TypeSectionEntry>())?);
80
81            if !parser.peek2::<wast::kw::r#type>() {
82                break;
83            }
84        }
85
86        Ok(Self { entries })
87    }
88}
89
90#[derive(Debug, Clone, PartialEq, Eq)]
91pub struct TypeSectionEntry {
92    idx:       Option<Index>,
93    func_type: FuncType,
94}
95
96impl TypeSectionEntry {
97    pub fn new(idx: Option<Index>, func_type: FuncType) -> Self {
98        Self { idx, func_type }
99    }
100}
101
102impl SExpr for TypeSectionEntry {
103    fn car(&self) -> String {
104        "type".to_owned()
105    }
106
107    fn cdr(&self) -> Vec<Expr> {
108        let mut v = Vec::new();
109
110        if let Some(ref idx) = self.idx {
111            v.push(Expr::Atom(Atom::new(idx.to_string())));
112        }
113
114        v.push(Expr::SExpr(Box::new(self.func_type.clone())));
115
116        v
117    }
118}
119
120impl Parse<'_> for TypeSectionEntry {
121    fn parse(parser: Parser<'_>) -> Result<Self> {
122        parser.parse::<wast::kw::r#type>()?;
123
124        let idx = parser.parse::<Option<Index>>()?;
125        let func_type = parser.parens(|p| p.parse::<FuncType>())?;
126
127        Ok(Self { idx, func_type })
128    }
129}
130
131#[derive(Debug, Clone, PartialEq, Eq)]
132pub struct ImportSection {
133    entries: Vec<ImportSectionEntry>,
134}
135
136impl ImportSection {
137    pub fn with_entries(entries: Vec<ImportSectionEntry>) -> Self {
138        Self { entries }
139    }
140
141    pub(crate) fn exprs(&self) -> Vec<Expr> {
142        self.entries
143            .iter()
144            .map(|e| Expr::SExpr(Box::new(e.clone())))
145            .collect()
146    }
147}
148
149impl Parse<'_> for ImportSection {
150    fn parse(parser: Parser<'_>) -> Result<Self> {
151        let mut entries = Vec::new();
152
153        while !parser.is_empty() {
154            entries.push(parser.parens(ImportSectionEntry::parse)?);
155
156            if !parser.peek2::<wast::kw::import>() {
157                break;
158            }
159        }
160
161        Ok(Self { entries })
162    }
163}
164
165#[derive(Debug, Clone, PartialEq, Eq)]
166pub struct ImportSectionEntry {
167    module: String,
168    name:   String,
169    desc:   ImportDesc,
170}
171
172impl ImportSectionEntry {
173    pub fn new(module: String, name: String, desc: ImportDesc) -> Self {
174        Self { module, name, desc }
175    }
176}
177
178impl SExpr for ImportSectionEntry {
179    fn car(&self) -> String {
180        "import".to_owned()
181    }
182
183    fn cdr(&self) -> Vec<Expr> {
184        let mut v = Vec::with_capacity(3);
185
186        v.append(
187            &mut self
188                .module
189                .as_atoms()
190                .iter()
191                .map(|a| Expr::Atom(a.clone()))
192                .collect(),
193        );
194        v.append(
195            &mut self
196                .name
197                .as_atoms()
198                .iter()
199                .map(|a| Expr::Atom(a.clone()))
200                .collect(),
201        );
202        v.push(Expr::SExpr(Box::new(self.desc.clone())));
203
204        v
205    }
206}
207
208impl Parse<'_> for ImportSectionEntry {
209    fn parse(parser: Parser<'_>) -> Result<Self> {
210        parser.parse::<wast::kw::import>()?;
211
212        let module = parser.parse::<String>()?;
213        let name = parser.parse::<String>()?;
214        let desc = parser.parens(ImportDesc::parse)?;
215
216        Ok(Self { module, name, desc })
217    }
218}
219
220#[derive(Debug, Clone, PartialEq, Eq)]
221pub struct FunctionSection {
222    entries: Vec<FunctionSectionEntry>,
223}
224
225impl FunctionSection {
226    pub fn with_entries(entries: Vec<FunctionSectionEntry>) -> Self {
227        Self { entries }
228    }
229
230    pub(crate) fn exprs(&self) -> Vec<Expr> {
231        self.entries
232            .iter()
233            .map(|e| Expr::SExpr(Box::new(e.clone())))
234            .collect()
235    }
236}
237
238impl Parse<'_> for FunctionSection {
239    fn parse(parser: Parser<'_>) -> Result<Self> {
240        let mut entries = Vec::new();
241
242        while !parser.is_empty() {
243            entries.push(parser.parens(|p| p.parse::<FunctionSectionEntry>())?);
244
245            if !parser.peek2::<wast::kw::func>() {
246                break;
247            }
248        }
249
250        Ok(Self { entries })
251    }
252}
253
254#[derive(Debug, Clone, PartialEq, Eq)]
255pub struct FunctionSectionEntry {
256    idx:           Option<Index>,
257    inline_export: Option<InlineExport>,
258    type_use:      TypeUse,
259    exprs:         Vec<Expression>,
260}
261
262impl FunctionSectionEntry {
263    pub fn new(
264        idx: Option<Index>,
265        inline_export: Option<InlineExport>,
266        type_use: TypeUse,
267        exprs: Vec<Expression>,
268    ) -> Self {
269        Self {
270            idx,
271            inline_export,
272            type_use,
273            exprs,
274        }
275    }
276}
277
278impl SExpr for FunctionSectionEntry {
279    fn car(&self) -> String {
280        "func".to_owned()
281    }
282
283    fn cdr(&self) -> Vec<Expr> {
284        let mut v = Vec::new();
285
286        if let Some(ref idx) = self.idx {
287            v.push(Expr::Atom(Atom::new(idx.to_string())));
288        }
289
290        if let Some(ref inline_export) = self.inline_export {
291            v.push(Expr::SExpr(Box::new(inline_export.clone())));
292        }
293
294        v.append(&mut self.type_use.exprs());
295        v.append(&mut self.exprs.iter().map(|e| e.expr()).collect());
296
297        v
298    }
299}
300
301impl Parse<'_> for FunctionSectionEntry {
302    fn parse(parser: Parser<'_>) -> Result<Self> {
303        parser.parse::<wast::kw::func>()?;
304
305        let idx = parser.parse::<Option<Index>>()?;
306        let mut inline_export = None;
307
308        if parser.peek2::<wast::kw::export>() {
309            inline_export = Some(parser.parens(InlineExport::parse)?);
310        }
311
312        let type_use = parser.parse::<TypeUse>()?;
313        let expressions_parser = ExpressionParser::default();
314        let exprs = expressions_parser.parse(parser)?;
315
316        Ok(Self {
317            idx,
318            inline_export,
319            type_use,
320            exprs,
321        })
322    }
323}
324
325#[derive(Debug, Clone, PartialEq, Eq)]
326pub struct MemorySection {
327    entries: Vec<MemorySectionEntry>,
328}
329
330impl MemorySection {
331    pub fn with_entries(entries: Vec<MemorySectionEntry>) -> Self {
332        Self { entries }
333    }
334
335    pub(crate) fn exprs(&self) -> Vec<Expr> {
336        self.entries
337            .iter()
338            .map(|e| Expr::SExpr(Box::new(e.clone())))
339            .collect()
340    }
341}
342
343impl Parse<'_> for MemorySection {
344    fn parse(parser: Parser<'_>) -> Result<Self> {
345        let mut entries = Vec::new();
346
347        while !parser.is_empty() {
348            entries.push(parser.parens(|p| p.parse::<MemorySectionEntry>())?);
349
350            if !parser.peek2::<wast::kw::memory>() {
351                break;
352            }
353        }
354
355        Ok(Self { entries })
356    }
357}
358
359#[derive(Debug, Clone, PartialEq, Eq)]
360pub struct MemorySectionEntry {
361    idx:           Option<Index>,
362    inline_export: Option<InlineExport>,
363    mem_type:      MemType,
364}
365
366impl MemorySectionEntry {
367    pub fn new(
368        idx: Option<Index>,
369        inline_export: Option<InlineExport>,
370        mem_type: MemType,
371    ) -> Self {
372        Self {
373            idx,
374            inline_export,
375            mem_type,
376        }
377    }
378}
379
380impl SExpr for MemorySectionEntry {
381    fn car(&self) -> String {
382        "memory".to_owned()
383    }
384
385    fn cdr(&self) -> Vec<Expr> {
386        let mut v = Vec::new();
387
388        if let Some(ref idx) = self.idx {
389            v.push(Expr::Atom(Atom::new(idx.to_string())));
390        }
391
392        if let Some(ref inline_export) = self.inline_export {
393            v.push(Expr::SExpr(Box::new(inline_export.clone())));
394        }
395
396        v.append(&mut self.mem_type.exprs());
397
398        v
399    }
400}
401
402impl Parse<'_> for MemorySectionEntry {
403    fn parse(parser: Parser<'_>) -> Result<Self> {
404        parser.parse::<wast::kw::memory>()?;
405
406        let idx = parser.parse::<Option<Index>>()?;
407        let mut inline_export = None;
408
409        if parser.peek2::<wast::kw::export>() {
410            inline_export = Some(parser.parens(InlineExport::parse)?);
411        }
412
413        let mem_type = parser.parse::<MemType>()?;
414
415        Ok(Self {
416            idx,
417            inline_export,
418            mem_type,
419        })
420    }
421}
422
423#[derive(Debug, Clone, PartialEq, Eq)]
424pub struct GlobalSection {
425    entries: Vec<GlobalSectionEntry>,
426}
427
428impl GlobalSection {
429    pub fn with_entries(entries: Vec<GlobalSectionEntry>) -> Self {
430        Self { entries }
431    }
432
433    pub(crate) fn exprs(&self) -> Vec<Expr> {
434        self.entries
435            .iter()
436            .map(|e| Expr::SExpr(Box::new(e.clone())))
437            .collect()
438    }
439}
440
441impl Parse<'_> for GlobalSection {
442    fn parse(parser: Parser<'_>) -> Result<Self> {
443        let mut entries = Vec::new();
444
445        while !parser.is_empty() {
446            entries.push(parser.parens(|p| p.parse::<GlobalSectionEntry>())?);
447
448            if !parser.peek2::<wast::kw::global>() {
449                break;
450            }
451        }
452
453        Ok(Self { entries })
454    }
455}
456
457#[derive(Debug, Clone, PartialEq, Eq)]
458pub struct GlobalSectionEntry {
459    idx:           Option<Index>,
460    inline_export: Option<InlineExport>,
461    global_type:   GlobalType,
462
463    /// An imported global does not have expr.
464    expr: Option<Expression>,
465}
466
467impl GlobalSectionEntry {
468    pub fn new(
469        idx: Option<Index>,
470        inline_export: Option<InlineExport>,
471        global_type: GlobalType,
472        expr: Option<Expression>,
473    ) -> Self {
474        Self {
475            idx,
476            inline_export,
477            global_type,
478            expr,
479        }
480    }
481}
482
483impl SExpr for GlobalSectionEntry {
484    fn car(&self) -> String {
485        "global".to_owned()
486    }
487
488    fn cdr(&self) -> Vec<Expr> {
489        let mut v = Vec::new();
490
491        if let Some(ref idx) = self.idx {
492            v.push(Expr::Atom(Atom::new(idx.to_string())));
493        }
494
495        if let Some(ref inline_export) = self.inline_export {
496            v.push(Expr::SExpr(Box::new(inline_export.clone())));
497        }
498
499        v.push(self.global_type.expr());
500
501        if let Some(ref expr) = self.expr {
502            v.push(expr.expr());
503        }
504
505        v
506    }
507}
508
509impl Parse<'_> for GlobalSectionEntry {
510    fn parse(parser: Parser<'_>) -> Result<Self> {
511        parser.parse::<wast::kw::global>()?;
512
513        let idx = parser.parse::<Option<Index>>()?;
514        let mut inline_export = None;
515
516        if parser.peek2::<wast::kw::export>() {
517            inline_export = Some(parser.parens(InlineExport::parse)?);
518        }
519
520        let global_type = parser.parse::<GlobalType>()?;
521        let mut exprs = ExpressionParser::default().parse(parser)?;
522        let expr;
523
524        if exprs.len() == 0 {
525            expr = None;
526        } else {
527            if exprs.len() != 1 {
528                return Err(parser.error("only one expr is expected"));
529            }
530
531            expr = Some(exprs.pop().unwrap());
532        }
533
534        Ok(Self {
535            idx,
536            inline_export,
537            global_type,
538            expr,
539        })
540    }
541}
542
543#[derive(Debug, Clone, PartialEq, Eq)]
544pub struct DataSection {
545    entries: Vec<DataSectionEntry>,
546}
547
548impl DataSection {
549    pub fn with_entries(entries: Vec<DataSectionEntry>) -> Self {
550        Self { entries }
551    }
552
553    pub(crate) fn exprs(&self) -> Vec<Expr> {
554        self.entries
555            .iter()
556            .map(|e| Expr::SExpr(Box::new(e.clone())))
557            .collect()
558    }
559}
560
561impl Parse<'_> for DataSection {
562    fn parse(parser: Parser<'_>) -> Result<Self> {
563        let mut entries = Vec::new();
564
565        while !parser.is_empty() {
566            entries.push(parser.parens(DataSectionEntry::parse)?);
567
568            if !parser.peek2::<wast::kw::data>() {
569                break;
570            }
571        }
572
573        Ok(Self { entries })
574    }
575}
576
577#[derive(Debug, Clone, PartialEq, Eq)]
578pub struct Offset(Expression);
579
580impl Offset {
581    pub fn new(expression: Expression) -> Self {
582        Self(expression)
583    }
584
585    pub(crate) fn expr(&self) -> Expr {
586        self.0.expr()
587    }
588}
589
590impl Parse<'_> for Offset {
591    fn parse(parser: Parser<'_>) -> Result<Self> {
592        let mut exprs = ExpressionParser::default().parse(parser)?;
593
594        if exprs.len() == 0 {
595            return Err(parser.error("init_expr is empty"));
596        }
597
598        if exprs.len() > 1 {
599            return Err(parser.error("only one init_expr operator is expected"));
600        }
601
602        Ok(Self(exprs.pop().unwrap()))
603    }
604}
605
606#[derive(Debug, Clone, PartialEq, Eq)]
607pub struct DataString {
608    strings: Vec<String>,
609}
610
611impl DataString {
612    pub fn with_strings(strings: Vec<String>) -> Self {
613        Self { strings }
614    }
615
616    pub(crate) fn exprs(&self) -> Vec<Expr> {
617        self.strings
618            .iter()
619            .map(|s| Expr::Atom(Atom::new(format!(r#""{}""#, s))))
620            .collect()
621    }
622}
623
624impl Parse<'_> for DataString {
625    fn parse(parser: Parser<'_>) -> Result<Self> {
626        let mut strings = Vec::new();
627
628        while !parser.is_empty() {
629            strings.push(parser.parse::<String>()?);
630        }
631
632        Ok(Self { strings })
633    }
634}
635
636/// https://webassembly.github.io/spec/core/text/modules.html#data-segments
637#[derive(Debug, Clone, PartialEq, Eq)]
638pub struct DataSectionEntry {
639    idx:         Option<Index>,
640    offset:      Offset,
641    data_string: DataString,
642}
643
644impl DataSectionEntry {
645    pub fn new(
646        idx: Option<Index>,
647        offset: Offset,
648        data_string: DataString,
649    ) -> Self {
650        Self {
651            idx,
652            offset,
653            data_string,
654        }
655    }
656}
657
658impl SExpr for DataSectionEntry {
659    fn car(&self) -> String {
660        "data".to_owned()
661    }
662
663    fn cdr(&self) -> Vec<Expr> {
664        let mut v = Vec::new();
665
666        if let Some(idx) = self.idx.clone() {
667            v.push(Expr::Atom(Atom::new(idx.to_string())));
668        }
669
670        v.push(self.offset.expr());
671        v.append(&mut self.data_string.exprs());
672
673        v
674    }
675}
676
677impl Parse<'_> for DataSectionEntry {
678    fn parse(parser: Parser<'_>) -> Result<Self> {
679        parser.parse::<wast::kw::data>()?;
680
681        let idx = parser.parse::<Option<Index>>()?;
682        let offset = parser.parse::<Offset>()?;
683        let data_string = parser.parse::<DataString>()?;
684
685        Ok(Self {
686            idx,
687            offset,
688            data_string,
689        })
690    }
691}