1 | use crate::core::*; |
2 | use crate::kw; |
3 | use crate::parser::{Cursor, Parse, Parser, Peek, Result}; |
4 | use crate::token::{Id, NameAnnotation, Span}; |
5 | |
6 | /// An `import` statement and entry in a WebAssembly module. |
7 | #[derive (Debug, Clone)] |
8 | pub 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 | |
19 | impl<'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)] |
36 | pub 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)] |
51 | pub 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 | |
59 | impl<'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)] |
116 | pub struct InlineImport<'a> { |
117 | pub module: &'a str, |
118 | pub field: &'a str, |
119 | } |
120 | |
121 | impl<'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 | |
133 | impl 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 | |