1use super::*;
2mod fmt;
3mod from_reader;
4mod to_winmd;
5use crate::Result;
6pub use from_reader::from_reader;
7use syn::spanned::Spanned;
8
9// TODO: may want to finally get rid of `syn` as it also doesn't support preserving code comments
10
11impl File {
12 pub fn parse_str(input: &str) -> Result<Self> {
13 Ok(syn::parse_str::<Self>(input)?)
14 }
15
16 // Note: this isn't called automatically by `parse_str` to avoid canonicalizing when we're merely formatting IDL.
17 pub fn canonicalize(&mut self) -> Result<()> {
18 // TODO maybe we rewrite the `File` here to resolve any `super` references and use declarations so that
19 // subsequently the rdl-to-winmd conversion can just assume everything's fully qualified?
20 // * super can't refer to something outside of the IDL file
21 // * use declarations are only used for unqualified names that aren't defined in the IDL file
22 // * use declarations don't support globs and must name all externally defined types
23 // This way we can quickly kick out common invalid IDL files before we lost file/span context info
24
25 Ok(())
26 }
27
28 pub fn fmt(&self) -> String {
29 fmt::Writer::new(self).into_string()
30 }
31
32 pub fn into_winmd(mut self) -> Result<Vec<u8>> {
33 self.canonicalize()?;
34 to_winmd::rdl_to_winmd(&self)
35 }
36}
37
38// The value of the IDL-specific memory representation is that it allows for constructs that are not modeled in the abstract Module
39// tree such as the use declarations and if we get rid of it we'd always "format" IDL by stripping out any of that into a single
40// canonical form which would not be very friendly to developers.
41#[derive(Debug)]
42pub struct File {
43 pub winrt: bool,
44 pub references: Vec<syn::ItemUse>,
45 pub modules: Vec<Module>,
46}
47
48// TODO: need to change these to unpack the syn types and store strings we can reference for efficiency along with spans since the syn
49// is made for value semantics.
50
51#[derive(Clone, Debug)]
52pub struct Module {
53 pub namespace: String,
54 pub members: Vec<ModuleMember>,
55}
56
57#[derive(Clone, Debug)]
58pub enum ModuleMember {
59 Module(Module),
60 Interface(Interface),
61 Struct(Struct),
62 Enum(Enum),
63 Class(Class),
64 Function(Function),
65 Constant(Constant),
66}
67
68impl ModuleMember {
69 pub fn name(&self) -> &str {
70 match self {
71 Self::Module(module: &Module) => crate::extension(&module.namespace),
72 Self::Interface(member: &Interface) => &member.name,
73 Self::Struct(member: &Struct) => &member.name,
74 Self::Enum(member: &Enum) => &member.name,
75 Self::Class(member: &Class) => &member.name,
76 Self::Function(member: &Function) => &member.name,
77 Self::Constant(member: &Constant) => &member.name,
78 }
79 }
80}
81
82#[derive(Clone, Debug)]
83pub struct Enum {
84 pub winrt: bool,
85 pub name: String,
86 pub item: syn::ItemEnum,
87}
88
89#[derive(Clone, Debug)]
90pub struct Constant {
91 pub name: String,
92 pub item: syn::ItemConst,
93}
94
95#[derive(Clone, Debug)]
96pub struct Struct {
97 pub winrt: bool,
98 pub name: String,
99 pub attributes: Vec<syn::Attribute>,
100 pub span: proc_macro2::Span,
101 pub fields: Vec<Field>,
102}
103
104#[derive(Clone, Debug)]
105pub struct Field {
106 pub name: String,
107 pub attributes: Vec<syn::Attribute>,
108 pub span: proc_macro2::Span,
109 pub ty: syn::Type,
110}
111
112#[derive(Clone, Debug)]
113pub struct Class {
114 pub name: String,
115 pub attributes: Vec<syn::Attribute>,
116 pub base: Option<syn::TypePath>,
117 pub extends: Vec<syn::TypePath>,
118}
119
120#[derive(Clone, Debug)]
121pub struct Function {
122 pub name: String,
123 pub item: syn::TraitItemFn,
124}
125
126#[derive(Clone, Debug)]
127pub struct Interface {
128 pub winrt: bool,
129 pub name: String,
130 pub generics: Vec<String>,
131 pub attributes: Vec<syn::Attribute>,
132 pub extends: Vec<syn::TypePath>,
133 pub methods: Vec<syn::TraitItemFn>,
134}
135
136syn::custom_keyword!(interface);
137syn::custom_keyword!(class);
138
139fn winrt(input: syn::parse::ParseStream) -> syn::Result<bool> {
140 let attributes: Vec = input.call(function:syn::Attribute::parse_inner)?;
141 if attributes.len() == 1 {
142 if let syn::Meta::Path(path: &Path) = &attributes[0].meta {
143 if path.is_ident("winrt") {
144 return Ok(true);
145 }
146
147 if path.is_ident("win32") {
148 return Ok(false);
149 }
150 }
151 }
152
153 Err(syn::Error::new(input.span(), message:"A single `#![win32]` or `#![winrt]` attribute required"))
154}
155
156impl syn::parse::Parse for File {
157 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
158 let mut references: Vec = vec![];
159 let mut modules: Vec = vec![];
160 let winrt: bool = winrt(input)?;
161
162 while !input.is_empty() {
163 let lookahead: Lookahead1<'_> = input.lookahead1();
164 if lookahead.peek(syn::Token![mod]) {
165 modules.push(Module::parse(namespace:"", winrt, input)?);
166 } else if lookahead.peek(syn::Token![use]) {
167 references.push(input.parse()?);
168 } else {
169 return Err(lookahead.error());
170 }
171 }
172 Ok(Self { winrt, references, modules })
173 }
174}
175
176impl Module {
177 fn name(&self) -> &str {
178 self.namespace.rsplit_once('.').map_or(&self.namespace, |(_, name: &str)| name)
179 }
180
181 fn parse(namespace: &str, winrt: bool, input: syn::parse::ParseStream) -> syn::Result<Self> {
182 input.parse::<syn::Token![mod]>()?;
183 let name: String = input.parse::<syn::Ident>()?.to_string();
184
185 let namespace: String = if namespace.is_empty() { name.to_string() } else { format!("{namespace}.{name}") };
186
187 let content: ParseBuffer<'_>;
188 syn::braced!(content in input);
189 let mut members: Vec = vec![];
190 while !content.is_empty() {
191 members.push(ModuleMember::parse(&namespace, winrt, &content)?);
192 }
193 Ok(Self { namespace, members })
194 }
195}
196
197impl ModuleMember {
198 fn parse(namespace: &str, winrt: bool, input: syn::parse::ParseStream) -> syn::Result<Self> {
199 let attributes: Vec<syn::Attribute> = input.call(syn::Attribute::parse_outer)?;
200 let lookahead = input.lookahead1();
201 if lookahead.peek(syn::Token![mod]) {
202 if let Some(attribute) = attributes.first() {
203 return Err(syn::Error::new(attribute.span(), "`use` attributes not supported"));
204 }
205 Ok(ModuleMember::Module(Module::parse(namespace, winrt, input)?))
206 } else if lookahead.peek(interface) {
207 Ok(ModuleMember::Interface(Interface::parse(namespace, winrt, attributes, input)?))
208 } else if lookahead.peek(syn::Token![struct]) {
209 Ok(ModuleMember::Struct(Struct::parse(namespace, winrt, attributes, input)?))
210 } else if lookahead.peek(syn::Token![enum]) {
211 Ok(ModuleMember::Enum(Enum::parse(namespace, winrt, attributes, input)?))
212 } else if lookahead.peek(class) {
213 Ok(ModuleMember::Class(Class::parse(attributes, input)?))
214 } else if lookahead.peek(syn::Token![fn]) {
215 Ok(ModuleMember::Function(Function::parse(namespace, attributes, input)?))
216 } else if lookahead.peek(syn::Token![const]) {
217 Ok(ModuleMember::Constant(Constant::parse(namespace, attributes, input)?))
218 } else {
219 Err(lookahead.error())
220 }
221 }
222}
223
224impl Class {
225 fn parse(attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> {
226 input.parse::<class>()?;
227 let name: String = input.parse::<syn::Ident>()?.to_string();
228 let mut extends: Vec = Vec::new();
229 let mut base: Option = None;
230
231 if input.peek(syn::Token![:]) {
232 input.parse::<syn::Token![:]>()?;
233 while !input.peek(syn::Token![;]) {
234 if input.peek(token:class) {
235 input.parse::<class>()?;
236 base = Some(input.parse()?);
237 } else {
238 extends.push(input.parse()?);
239 }
240 _ = input.parse::<syn::Token![,]>();
241 }
242 }
243
244 input.parse::<syn::Token![;]>()?;
245 Ok(Self { attributes, name, base, extends })
246 }
247}
248
249impl Interface {
250 fn parse(_namespace: &str, winrt: bool, attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> {
251 input.parse::<interface>()?;
252 let name = input.parse::<syn::Ident>()?.to_string();
253
254 let mut generics = Vec::new();
255
256 if input.peek(syn::Token![<]) {
257 input.parse::<syn::Token![<]>()?;
258 while input.peek(syn::Ident) {
259 generics.push(input.parse::<syn::Ident>()?.to_string());
260 _ = input.parse::<syn::Token![,]>();
261 }
262
263 input.parse::<syn::Token![>]>()?;
264 }
265
266 let mut extends = Vec::new();
267
268 if input.peek(syn::Token![:]) {
269 input.parse::<syn::Token![:]>()?;
270 while !input.peek(syn::token::Brace) {
271 extends.push(input.parse()?);
272 _ = input.parse::<syn::Token![,]>();
273 }
274 }
275
276 let content;
277 syn::braced!(content in input);
278 let mut methods = vec![];
279 while !content.is_empty() {
280 methods.push(content.parse()?);
281 }
282 Ok(Self { winrt, attributes, generics, extends, name, methods })
283 }
284}
285
286impl Struct {
287 fn parse(_namespace: &str, winrt: bool, attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> {
288 // TODO: need to validate that the struct is valid according to the constraints of the winmd type system.
289 // Same for the other types. That way we can spit out errors quickly for things like unnamed fields.
290 let span = input.span();
291 let item: syn::ItemStruct = input.parse()?;
292 let name = item.ident.to_string();
293 let mut fields = vec![];
294
295 let syn::Fields::Named(named) = item.fields else {
296 return Err(syn::Error::new(item.span(), "unnamed fields not supported"));
297 };
298
299 for field in named.named {
300 fields.push(Field {
301 span: field.span(),
302 attributes: field.attrs,
303 // Simply unwrapping since we already know that it is a named field.
304 name: field.ident.unwrap().to_string(),
305 ty: field.ty,
306 });
307 }
308
309 Ok(Self { winrt, name, attributes, span, fields })
310 }
311}
312
313impl Enum {
314 fn parse(_namespace: &str, winrt: bool, attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> {
315 let mut item: syn::ItemEnum = input.parse()?;
316 item.attrs = attributes;
317 let name: String = item.ident.to_string();
318 Ok(Self { winrt, name, item })
319 }
320}
321
322impl Constant {
323 fn parse(_namespace: &str, attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> {
324 let mut item: syn::ItemConst = input.parse()?;
325 item.attrs = attributes;
326 let name: String = item.ident.to_string();
327 Ok(Self { name, item })
328 }
329}
330
331impl Function {
332 fn parse(_namespace: &str, attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> {
333 let mut item: syn::TraitItemFn = input.parse()?;
334 item.attrs = attributes;
335 let name: String = item.sig.ident.to_string();
336 Ok(Self { name, item })
337 }
338}
339