1use crate::core::*;
2use crate::kw;
3use crate::parser::{Cursor, Parse, Parser, Peek, Result};
4use crate::token::{Id, LParen, NameAnnotation, Span};
5
6#[derive(Debug, Clone)]
8pub struct Imports<'a> {
9 pub span: Span,
11 pub items: ImportItems<'a>,
13}
14
15#[derive(Debug, Clone)]
18pub enum ImportItems<'a> {
19 Single {
25 module: &'a str,
27 name: &'a str,
29 sig: ItemSig<'a>,
31 },
32
33 Group1 {
39 module: &'a str,
41 items: Vec<ImportGroup1Item<'a>>,
43 },
44
45 Group2 {
51 module: &'a str,
53 sig: ItemSig<'a>,
55 items: Vec<ImportGroup2Item<'a>>,
57 },
58}
59
60#[derive(Debug, Clone)]
66pub struct ImportGroup1Item<'a> {
67 pub span: Span,
69 pub name: &'a str,
71 pub sig: ItemSig<'a>,
73}
74
75#[derive(Debug, Clone)]
77pub struct ImportGroup2Item<'a> {
78 pub span: Span,
80 pub name: &'a str,
82}
83
84enum CompactImportEncoding {
85 Unknown,
86 Encoding1,
87 Encoding2,
88}
89
90impl<'a> Imports<'a> {
91 pub fn single(span: Span, module: &'a str, name: &'a str, sig: ItemSig<'a>) -> Self {
93 Self {
94 span,
95 items: ImportItems::Single { module, name, sig },
96 }
97 }
98
99 pub fn num_items(&self) -> usize {
101 match &self.items {
102 ImportItems::Single {
103 module: _,
104 name: _,
105 sig: _,
106 } => 1,
107 ImportItems::Group1 { module: _, items } => items.len(),
108 ImportItems::Group2 {
109 module: _,
110 sig: _,
111 items,
112 } => items.len(),
113 }
114 }
115
116 pub fn item_sigs(&self) -> Vec<&ItemSig<'a>> {
119 let res = match &self.items {
120 ImportItems::Single {
121 module: _,
122 name: _,
123 sig,
124 } => vec![sig],
125 ImportItems::Group1 { module: _, items } => {
126 items.iter().map(|item| &item.sig).collect()
127 }
128 ImportItems::Group2 {
129 module: _,
130 sig,
131 items,
132 } => vec![sig; items.len()],
133 };
134 debug_assert!(res.len() == self.num_items());
135 res
136 }
137
138 pub fn unique_sigs_mut(&mut self) -> Vec<&mut ItemSig<'a>> {
142 match &mut self.items {
143 ImportItems::Single {
144 module: _,
145 name: _,
146 sig: item,
147 } => vec![item],
148 ImportItems::Group1 { module: _, items } => {
149 items.iter_mut().map(|item| &mut item.sig).collect()
150 }
151 ImportItems::Group2 {
152 module: _,
153 sig,
154 items: _,
155 } => vec![sig],
156 }
157 }
158}
159
160struct ImportGroupItemCommon<'a> {
161 span: Span,
162 name: &'a str,
163 sig: Option<ItemSig<'a>>,
164}
165
166impl<'a> Parse<'a> for Imports<'a> {
167 fn parse(parser: Parser<'a>) -> Result<Self> {
168 let span = parser.parse::<kw::import>()?.0;
169 let module = parser.parse()?;
170 if parser.peek::<LParen>()? {
171 let mut encoding = CompactImportEncoding::Unknown;
172 let mut items = Vec::new();
173 while parser.peek2::<kw::item>()? {
174 let item: ImportGroupItemCommon = parser.parens(|p| p.parse())?;
175 match item.sig {
176 Some(_) => {
177 match encoding {
179 CompactImportEncoding::Unknown => {
180 encoding = CompactImportEncoding::Encoding1
181 }
182 CompactImportEncoding::Encoding1 => {}
183 CompactImportEncoding::Encoding2 => {
184 return Err(parser.error("unexpected import type"));
185 }
186 }
187 }
188 None => {
189 match encoding {
191 CompactImportEncoding::Unknown => {
192 encoding = CompactImportEncoding::Encoding2
193 }
194 CompactImportEncoding::Encoding1 => {
195 return Err(parser.error("unexpected `)`"));
196 }
197 CompactImportEncoding::Encoding2 => {}
198 }
199 }
200 }
201 items.push(item);
202 }
203
204 match encoding {
205 CompactImportEncoding::Unknown => Err(parser.error("expected import items")),
206 CompactImportEncoding::Encoding1 => Ok(Imports {
207 span,
208 items: ImportItems::Group1 {
209 module,
210 items: items
211 .into_iter()
212 .map(|item| ImportGroup1Item {
213 span: item.span,
214 name: item.name,
215 sig: item.sig.unwrap(),
216 })
217 .collect(),
218 },
219 }),
220 CompactImportEncoding::Encoding2 => {
221 let sig: ItemSig = parser.parens(|p| p.parse())?;
222 if let Some(id) = sig.id {
223 return Err(parser.error_at(id.span(), "identifier not allowed"));
224 }
225 Ok(Imports {
226 span,
227 items: ImportItems::Group2 {
228 module,
229 sig,
230 items: items
231 .into_iter()
232 .map(|item| ImportGroup2Item {
233 span: item.span,
234 name: item.name,
235 })
236 .collect(),
237 },
238 })
239 }
240 }
241 } else {
242 let field = parser.parse()?;
244 let sig = parser.parens(|p| p.parse())?;
245 Ok(Imports::single(span, module, field, sig))
246 }
247 }
248}
249
250impl<'a> Parse<'a> for ImportGroupItemCommon<'a> {
251 fn parse(parser: Parser<'a>) -> Result<Self> {
252 let span = parser.parse::<kw::item>()?.0;
253 Ok(ImportGroupItemCommon {
254 span,
255 name: parser.parse()?,
256 sig: if parser.is_empty() {
257 None
258 } else {
259 Some(parser.parens(|p| p.parse())?)
260 },
261 })
262 }
263}
264
265#[derive(Debug, Clone)]
266#[allow(missing_docs)]
267pub struct ItemSig<'a> {
268 pub span: Span,
270 pub id: Option<Id<'a>>,
273 pub name: Option<NameAnnotation<'a>>,
276 pub kind: ItemKind<'a>,
278}
279
280#[derive(Debug, Clone)]
281#[allow(missing_docs)]
282pub enum ItemKind<'a> {
283 Func(TypeUse<'a, FunctionType<'a>>),
284 Table(TableType<'a>),
285 Memory(MemoryType),
286 Global(GlobalType<'a>),
287 Tag(TagType<'a>),
288 FuncExact(TypeUse<'a, FunctionType<'a>>),
289}
290
291impl<'a> Parse<'a> for ItemSig<'a> {
292 fn parse(parser: Parser<'a>) -> Result<Self> {
293 let mut l = parser.lookahead1();
294 if l.peek::<kw::func>()? {
295 let span = parser.parse::<kw::func>()?.0;
296 let id = parser.parse()?;
297 let name = parser.parse()?;
298 let kind = if parser.peek2::<kw::exact>()? {
299 ItemKind::FuncExact(parser.parens(|p| {
300 p.parse::<kw::exact>()?;
301 p.parse()
302 })?)
303 } else {
304 ItemKind::Func(parser.parse()?)
305 };
306 Ok(ItemSig {
307 span,
308 id,
309 name,
310 kind,
311 })
312 } else if l.peek::<kw::table>()? {
313 let span = parser.parse::<kw::table>()?.0;
314 Ok(ItemSig {
315 span,
316 id: parser.parse()?,
317 name: None,
318 kind: ItemKind::Table(parser.parse()?),
319 })
320 } else if l.peek::<kw::memory>()? {
321 let span = parser.parse::<kw::memory>()?.0;
322 Ok(ItemSig {
323 span,
324 id: parser.parse()?,
325 name: None,
326 kind: ItemKind::Memory(parser.parse()?),
327 })
328 } else if l.peek::<kw::global>()? {
329 let span = parser.parse::<kw::global>()?.0;
330 Ok(ItemSig {
331 span,
332 id: parser.parse()?,
333 name: None,
334 kind: ItemKind::Global(parser.parse()?),
335 })
336 } else if l.peek::<kw::tag>()? {
337 let span = parser.parse::<kw::tag>()?.0;
338 Ok(ItemSig {
339 span,
340 id: parser.parse()?,
341 name: None,
342 kind: ItemKind::Tag(parser.parse()?),
343 })
344 } else {
345 Err(l.error())
346 }
347 }
348}
349
350#[derive(Debug, Copy, Clone)]
357#[allow(missing_docs)]
358pub struct InlineImport<'a> {
359 pub module: &'a str,
360 pub field: &'a str,
361}
362
363impl<'a> Parse<'a> for InlineImport<'a> {
364 fn parse(parser: Parser<'a>) -> Result<Self> {
365 parser.parens(|p| {
366 p.parse::<kw::import>()?;
367 Ok(InlineImport {
368 module: p.parse()?,
369 field: p.parse()?,
370 })
371 })
372 }
373}
374
375impl Peek for InlineImport<'_> {
376 fn peek(cursor: Cursor<'_>) -> Result<bool> {
377 let cursor = match cursor.lparen()? {
378 Some(cursor) => cursor,
379 None => return Ok(false),
380 };
381 let cursor = match cursor.keyword()? {
382 Some(("import", cursor)) => cursor,
383 _ => return Ok(false),
384 };
385 let cursor = match cursor.string()? {
386 Some((_, cursor)) => cursor,
387 None => return Ok(false),
388 };
389 let cursor = match cursor.string()? {
390 Some((_, cursor)) => cursor,
391 None => return Ok(false),
392 };
393
394 Ok(cursor.rparen()?.is_some())
395 }
396
397 fn display() -> &'static str {
398 "inline import"
399 }
400}