1use crate::component::*;
2use crate::kw;
3use crate::parser::{Cursor, Parse, Parser, Peek, Result};
4use crate::token::{Id, Index, LParen, NameAnnotation, Span};
5
6/// An `import` statement and entry in a WebAssembly component.
7#[derive(Debug)]
8pub 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
17impl<'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)]
28pub struct ComponentExternName<'a>(pub &'a str);
29
30impl<'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)]
52pub 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
65impl<'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)]
73pub struct ItemSigNoName<'a>(pub ItemSig<'a>);
74
75impl<'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
81fn 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)]
118pub 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)]
135pub enum TypeBounds<'a> {
136 /// The equality type bounds.
137 Eq(Index<'a>),
138 /// A resource type is imported/exported,
139 SubResource,
140}
141
142impl<'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)]
163pub struct InlineImport<'a> {
164 /// The name of the item being imported.
165 pub name: ComponentExternName<'a>,
166}
167
168impl<'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
177impl 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