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: Span = parser.parse::<kw::import>()?.0;
22 let module: &str = parser.parse()?;
23 let field: &str = parser.parse()?;
24 let item: ItemSig<'_> = parser.parens(|p: Parser<'a>| 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: Parser<'a>| {
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}
159