1 | use crate::component::*; |
2 | use crate::kw; |
3 | use crate::parser::{Cursor, Parse, Parser, Peek, Result}; |
4 | use crate::token::{Id, Index, LParen, NameAnnotation, Span}; |
5 | |
6 | /// An `import` statement and entry in a WebAssembly component. |
7 | #[derive (Debug)] |
8 | pub struct ComponentImport<'a> { |
9 | /// Where this `import` was defined |
10 | pub span: Span, |
11 | /// The name of the item being imported. |
12 | pub name: ComponentExternName<'a>, |
13 | /// The item that's being imported. |
14 | pub item: ItemSig<'a>, |
15 | } |
16 | |
17 | impl<'a> Parse<'a> for ComponentImport<'a> { |
18 | fn parse(parser: Parser<'a>) -> Result<Self> { |
19 | let span: Span = parser.parse::<kw::import>()?.0; |
20 | let name: ComponentExternName<'_> = parser.parse()?; |
21 | let item: ItemSig<'_> = parser.parens(|p: Parser<'a>| p.parse())?; |
22 | Ok(ComponentImport { span, name, item }) |
23 | } |
24 | } |
25 | |
26 | /// The different ways an import can be named. |
27 | #[derive (Debug, Copy, Clone)] |
28 | pub struct ComponentExternName<'a>(pub &'a str); |
29 | |
30 | impl<'a> Parse<'a> for ComponentExternName<'a> { |
31 | fn parse(parser: Parser<'a>) -> Result<Self> { |
32 | // Prior to WebAssembly/component-model#263 the syntactic form |
33 | // `(interface "...")` was supported for interface names. This is no |
34 | // longer part of the syntax of the binary format nor the text format, |
35 | // but continue to parse this as "sugar" for the current format. This |
36 | // is intended to avoid breaking folks and provide a smoother transition |
37 | // forward. |
38 | let name: &str = if parser.peek::<LParen>()? { |
39 | parser.parens(|p: Parser<'a>| { |
40 | p.parse::<kw::interface>()?; |
41 | p.parse() |
42 | })? |
43 | } else { |
44 | parser.parse()? |
45 | }; |
46 | Ok(ComponentExternName(name)) |
47 | } |
48 | } |
49 | |
50 | /// An item signature for imported items. |
51 | #[derive (Debug)] |
52 | pub struct ItemSig<'a> { |
53 | /// Where this item is defined in the source. |
54 | pub span: Span, |
55 | /// An optional identifier used during name resolution to refer to this item |
56 | /// from the rest of the component. |
57 | pub id: Option<Id<'a>>, |
58 | /// An optional name which, for functions, will be stored in the |
59 | /// custom `name` section. |
60 | pub name: Option<NameAnnotation<'a>>, |
61 | /// What kind of item this is. |
62 | pub kind: ItemSigKind<'a>, |
63 | } |
64 | |
65 | impl<'a> Parse<'a> for ItemSig<'a> { |
66 | fn parse(parser: Parser<'a>) -> Result<Self> { |
67 | parse_item_sig(parser, name:true) |
68 | } |
69 | } |
70 | |
71 | /// An item signature for imported items. |
72 | #[derive (Debug)] |
73 | pub struct ItemSigNoName<'a>(pub ItemSig<'a>); |
74 | |
75 | impl<'a> Parse<'a> for ItemSigNoName<'a> { |
76 | fn parse(parser: Parser<'a>) -> Result<Self> { |
77 | Ok(ItemSigNoName(parse_item_sig(parser, name:false)?)) |
78 | } |
79 | } |
80 | |
81 | fn parse_item_sig<'a>(parser: Parser<'a>, name: bool) -> Result<ItemSig<'a>> { |
82 | let mut l = parser.lookahead1(); |
83 | let (span, parse_kind): (_, fn(Parser<'a>) -> Result<ItemSigKind<'a>>) = |
84 | if l.peek::<kw::core>()? { |
85 | let span = parser.parse::<kw::core>()?.0; |
86 | parser.parse::<kw::module>()?; |
87 | (span, |parser| Ok(ItemSigKind::CoreModule(parser.parse()?))) |
88 | } else if l.peek::<kw::func>()? { |
89 | let span = parser.parse::<kw::func>()?.0; |
90 | (span, |parser| Ok(ItemSigKind::Func(parser.parse()?))) |
91 | } else if l.peek::<kw::component>()? { |
92 | let span = parser.parse::<kw::component>()?.0; |
93 | (span, |parser| Ok(ItemSigKind::Component(parser.parse()?))) |
94 | } else if l.peek::<kw::instance>()? { |
95 | let span = parser.parse::<kw::instance>()?.0; |
96 | (span, |parser| Ok(ItemSigKind::Instance(parser.parse()?))) |
97 | } else if l.peek::<kw::value>()? { |
98 | let span = parser.parse::<kw::value>()?.0; |
99 | (span, |parser| Ok(ItemSigKind::Value(parser.parse()?))) |
100 | } else if l.peek::<kw::r#type>()? { |
101 | let span = parser.parse::<kw::r#type>()?.0; |
102 | (span, |parser| { |
103 | Ok(ItemSigKind::Type(parser.parens(|parser| parser.parse())?)) |
104 | }) |
105 | } else { |
106 | return Err(l.error()); |
107 | }; |
108 | Ok(ItemSig { |
109 | span, |
110 | id: if name { parser.parse()? } else { None }, |
111 | name: if name { parser.parse()? } else { None }, |
112 | kind: parse_kind(parser)?, |
113 | }) |
114 | } |
115 | |
116 | /// The kind of signatures for imported items. |
117 | #[derive (Debug)] |
118 | pub enum ItemSigKind<'a> { |
119 | /// The item signature is for a core module. |
120 | CoreModule(CoreTypeUse<'a, ModuleType<'a>>), |
121 | /// The item signature is for a function. |
122 | Func(ComponentTypeUse<'a, ComponentFunctionType<'a>>), |
123 | /// The item signature is for a component. |
124 | Component(ComponentTypeUse<'a, ComponentType<'a>>), |
125 | /// The item signature is for an instance. |
126 | Instance(ComponentTypeUse<'a, InstanceType<'a>>), |
127 | /// The item signature is for a value. |
128 | Value(ComponentValTypeUse<'a>), |
129 | /// The item signature is for a type. |
130 | Type(TypeBounds<'a>), |
131 | } |
132 | |
133 | /// Represents the bounds applied to types being imported. |
134 | #[derive (Debug)] |
135 | pub enum TypeBounds<'a> { |
136 | /// The equality type bounds. |
137 | Eq(Index<'a>), |
138 | /// A resource type is imported/exported, |
139 | SubResource, |
140 | } |
141 | |
142 | impl<'a> Parse<'a> for TypeBounds<'a> { |
143 | fn parse(parser: Parser<'a>) -> Result<Self> { |
144 | let mut l: Lookahead1<'_> = parser.lookahead1(); |
145 | if l.peek::<kw::eq>()? { |
146 | parser.parse::<kw::eq>()?; |
147 | Ok(Self::Eq(parser.parse()?)) |
148 | } else if l.peek::<kw::sub>()? { |
149 | parser.parse::<kw::sub>()?; |
150 | parser.parse::<kw::resource>()?; |
151 | Ok(Self::SubResource) |
152 | } else { |
153 | Err(l.error()) |
154 | } |
155 | } |
156 | } |
157 | |
158 | /// A listing of a inline `(import "foo")` statement. |
159 | /// |
160 | /// This is the same as `core::InlineImport` except only one string import is |
161 | /// required. |
162 | #[derive (Debug, Clone)] |
163 | pub struct InlineImport<'a> { |
164 | /// The name of the item being imported. |
165 | pub name: ComponentExternName<'a>, |
166 | } |
167 | |
168 | impl<'a> Parse<'a> for InlineImport<'a> { |
169 | fn parse(parser: Parser<'a>) -> Result<Self> { |
170 | parser.parens(|p: Parser<'a>| { |
171 | p.parse::<kw::import>()?; |
172 | Ok(InlineImport { name: p.parse()? }) |
173 | }) |
174 | } |
175 | } |
176 | |
177 | impl Peek for InlineImport<'_> { |
178 | fn peek(cursor: Cursor<'_>) -> Result<bool> { |
179 | let cursor = match cursor.lparen()? { |
180 | Some(cursor) => cursor, |
181 | None => return Ok(false), |
182 | }; |
183 | let cursor = match cursor.keyword()? { |
184 | Some(("import" , cursor)) => cursor, |
185 | _ => return Ok(false), |
186 | }; |
187 | |
188 | // (import "foo") |
189 | if let Some((_, cursor)) = cursor.string()? { |
190 | return Ok(cursor.rparen()?.is_some()); |
191 | } |
192 | |
193 | // (import (interface "foo")) |
194 | let cursor = match cursor.lparen()? { |
195 | Some(cursor) => cursor, |
196 | None => return Ok(false), |
197 | }; |
198 | let cursor = match cursor.keyword()? { |
199 | Some(("interface" , cursor)) => cursor, |
200 | _ => return Ok(false), |
201 | }; |
202 | let cursor = match cursor.string()? { |
203 | Some((_, cursor)) => cursor, |
204 | _ => return Ok(false), |
205 | }; |
206 | let cursor = match cursor.rparen()? { |
207 | Some(cursor) => cursor, |
208 | _ => return Ok(false), |
209 | }; |
210 | Ok(cursor.rparen()?.is_some()) |
211 | } |
212 | |
213 | fn display() -> &'static str { |
214 | "inline import" |
215 | } |
216 | } |
217 | |