inf_wast/core/
import.rs

1use crate::core::*;
2use crate::kw;
3use crate::parser::{Cursor, Parse, Parser, Peek, Result};
4use crate::token::{Id, NameAnnotation, Span};
5
6/// An `import` statement and entry in a WebAssembly module.
7#[derive(Debug, Clone)]
8pub struct Import<'a> {
9    /// Where this `import` was defined
10    pub span: Span,
11    /// The module that this statement is importing from
12    pub module: &'a str,
13    /// The name of the field in the module this statement imports from.
14    pub field: &'a str,
15    /// The item that's being imported.
16    pub item: ItemSig<'a>,
17}
18
19impl<'a> Parse<'a> for Import<'a> {
20    fn parse(parser: Parser<'a>) -> Result<Self> {
21        let span = parser.parse::<kw::import>()?.0;
22        let module = parser.parse()?;
23        let field = parser.parse()?;
24        let item = parser.parens(|p| p.parse())?;
25        Ok(Import {
26            span,
27            module,
28            field,
29            item,
30        })
31    }
32}
33
34#[derive(Debug, Clone)]
35#[allow(missing_docs)]
36pub struct ItemSig<'a> {
37    /// Where this item is defined in the source.
38    pub span: Span,
39    /// An optional identifier used during name resolution to refer to this item
40    /// from the rest of the module.
41    pub id: Option<Id<'a>>,
42    /// An optional name which, for functions, will be stored in the
43    /// custom `name` section.
44    pub name: Option<NameAnnotation<'a>>,
45    /// What kind of item this is.
46    pub kind: ItemKind<'a>,
47}
48
49#[derive(Debug, Clone)]
50#[allow(missing_docs)]
51pub enum ItemKind<'a> {
52    Func(TypeUse<'a, FunctionType<'a>>),
53    Table(TableType<'a>),
54    Memory(MemoryType),
55    Global(GlobalType<'a>),
56    Tag(TagType<'a>),
57}
58
59impl<'a> Parse<'a> for ItemSig<'a> {
60    fn parse(parser: Parser<'a>) -> Result<Self> {
61        let mut l = parser.lookahead1();
62        if l.peek::<kw::func>()? {
63            let span = parser.parse::<kw::func>()?.0;
64            Ok(ItemSig {
65                span,
66                id: parser.parse()?,
67                name: parser.parse()?,
68                kind: ItemKind::Func(parser.parse()?),
69            })
70        } else if l.peek::<kw::table>()? {
71            let span = parser.parse::<kw::table>()?.0;
72            Ok(ItemSig {
73                span,
74                id: parser.parse()?,
75                name: None,
76                kind: ItemKind::Table(parser.parse()?),
77            })
78        } else if l.peek::<kw::memory>()? {
79            let span = parser.parse::<kw::memory>()?.0;
80            Ok(ItemSig {
81                span,
82                id: parser.parse()?,
83                name: None,
84                kind: ItemKind::Memory(parser.parse()?),
85            })
86        } else if l.peek::<kw::global>()? {
87            let span = parser.parse::<kw::global>()?.0;
88            Ok(ItemSig {
89                span,
90                id: parser.parse()?,
91                name: None,
92                kind: ItemKind::Global(parser.parse()?),
93            })
94        } else if l.peek::<kw::tag>()? {
95            let span = parser.parse::<kw::tag>()?.0;
96            Ok(ItemSig {
97                span,
98                id: parser.parse()?,
99                name: None,
100                kind: ItemKind::Tag(parser.parse()?),
101            })
102        } else {
103            Err(l.error())
104        }
105    }
106}
107
108/// A listing of a inline `(import "foo")` statement.
109///
110/// Note that when parsing this type it is somewhat unconventional that it
111/// parses its own surrounding parentheses. This is typically an optional type,
112/// so it's so far been a bit nicer to have the optionality handled through
113/// `Peek` rather than `Option<T>`.
114#[derive(Debug, Copy, Clone)]
115#[allow(missing_docs)]
116pub struct InlineImport<'a> {
117    pub module: &'a str,
118    pub field: &'a str,
119}
120
121impl<'a> Parse<'a> for InlineImport<'a> {
122    fn parse(parser: Parser<'a>) -> Result<Self> {
123        parser.parens(|p| {
124            p.parse::<kw::import>()?;
125            Ok(InlineImport {
126                module: p.parse()?,
127                field: p.parse()?,
128            })
129        })
130    }
131}
132
133impl Peek for InlineImport<'_> {
134    fn peek(cursor: Cursor<'_>) -> Result<bool> {
135        let cursor = match cursor.lparen()? {
136            Some(cursor) => cursor,
137            None => return Ok(false),
138        };
139        let cursor = match cursor.keyword()? {
140            Some(("import", cursor)) => cursor,
141            _ => return Ok(false),
142        };
143        let cursor = match cursor.string()? {
144            Some((_, cursor)) => cursor,
145            None => return Ok(false),
146        };
147        let cursor = match cursor.string()? {
148            Some((_, cursor)) => cursor,
149            None => return Ok(false),
150        };
151
152        Ok(cursor.rparen()?.is_some())
153    }
154
155    fn display() -> &'static str {
156        "inline import"
157    }
158}