1use proc_macro2::{Span, TokenStream};
2use quote::ToTokens;
3use std::collections::HashMap;
4use std::path::{Path, PathBuf};
5use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
6use syn::parse::{Error, Parse, ParseStream, Result};
7use syn::punctuated::Punctuated;
8use syn::{Token, braced, token};
9use wit_bindgen_core::WorldGenerator;
10use wit_bindgen_core::wit_parser::{PackageId, Resolve, WorldId};
11use wit_bindgen_core::{AsyncFilterSet, ChainableMethodFilterSet};
12use wit_bindgen_rust::{Opts, Ownership, WithOption};
13
14#[proc_macro]
15pub fn generate(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
16 syn::parse_macro_input!(input as Config)
17 .expand()
18 .unwrap_or_else(Error::into_compile_error)
19 .into()
20}
21
22fn render_error(
23 err: &(dyn std::error::Error + 'static),
24 sourcemap: &Option<&wit_bindgen_core::wit_parser::SourceMap>,
25) -> String {
26 if let Some(sourcemap) = sourcemap {
27 if let Some(e) = err.downcast_ref::<wit_bindgen_core::wit_parser::ParseError>() {
28 return e.render(sourcemap);
29 }
30 if let Some(e) = err.downcast_ref::<wit_bindgen_core::wit_parser::ResolveError>() {
31 return e.render(sourcemap);
32 }
33 }
34
35 err.to_string()
36}
37
38fn anyhow_to_syn(
39 span: Span,
40 err: anyhow::Error,
41 sourcemap: Option<&wit_bindgen_core::wit_parser::SourceMap>,
42) -> Error {
43 let err = attach_with_context(err);
44 let mut msg = render_error(err.as_ref(), &sourcemap);
45 for cause in err.chain().skip(1) {
46 let cause = render_error(cause, &sourcemap);
47 msg.push_str(&format!("\n\nCaused by:\n {cause}"));
48 }
49 Error::new(span, msg)
50}
51
52fn attach_with_context(err: anyhow::Error) -> anyhow::Error {
53 if let Some(e) = err.downcast_ref::<wit_bindgen_rust::MissingWith>() {
54 let option = e.0.clone();
55 return err.context(format!(
56 "missing one of:\n\
57 * `generate_all` option\n\
58 * `with: {{ \"{option}\": path::to::bindings, }}`\n\
59 * `with: {{ \"{option}\": generate, }}`\
60 "
61 ));
62 }
63 err
64}
65
66struct Config {
67 opts: Opts,
68 resolve: Resolve,
69 world: WorldId,
70 files: Vec<PathBuf>,
71 debug: bool,
72}
73
74enum Source {
76 Paths(Vec<PathBuf>),
78 Inline(String, Option<Vec<PathBuf>>),
80}
81
82impl Parse for Config {
83 fn parse(input: ParseStream<'_>) -> Result<Self> {
84 let call_site = Span::call_site();
85 let mut opts = Opts::default();
86 let mut world = None;
87 let mut source = None;
88 let mut features = Vec::new();
89 let mut sync_configured = false;
90 let mut method_chaining_configured = false;
91 let mut debug = false;
92
93 if input.peek(token::Brace) {
94 let content;
95 syn::braced!(content in input);
96 let fields = Punctuated::<Opt, Token![,]>::parse_terminated(&content)?;
97 for field in fields.into_pairs() {
98 match field.into_value() {
99 Opt::Path(span, p) => {
100 let paths = p
101 .into_iter()
102 .map(|f| f.evaluate_string())
103 .collect::<Result<Vec<_>>>()?
104 .into_iter()
105 .map(PathBuf::from)
106 .collect();
107
108 source = Some(match source {
109 Some(Source::Paths(_)) | Some(Source::Inline(_, Some(_))) => {
110 return Err(Error::new(span, "cannot specify second source"));
111 }
112 Some(Source::Inline(i, None)) => Source::Inline(i, Some(paths)),
113 None => Source::Paths(paths),
114 })
115 }
116 Opt::World(s) => {
117 if world.is_some() {
118 return Err(Error::new(s.span(), "cannot specify second world"));
119 }
120 world = Some(s.value());
121 }
122 Opt::Inline(s) => {
123 source = Some(match source {
124 Some(Source::Inline(_, _)) => {
125 return Err(Error::new(s.span(), "cannot specify second source"));
126 }
127 Some(Source::Paths(p)) => Source::Inline(s.value(), Some(p)),
128 None => Source::Inline(s.value(), None),
129 })
130 }
131 Opt::UseStdFeature => opts.std_feature = true,
132 Opt::RawStrings => opts.raw_strings = true,
133 Opt::Ownership(ownership) => opts.ownership = ownership,
134 Opt::Skip(list) => opts.skip.extend(list.iter().map(|i| i.value())),
135 Opt::RuntimePath(path) => opts.runtime_path = Some(path.value()),
136 Opt::MapType(path) => opts.map_type = Some(path.value()),
137 Opt::BitflagsPath(path) => opts.bitflags_path = Some(path.value()),
138 Opt::Stubs => {
139 opts.stubs = true;
140 }
141 Opt::ExportPrefix(prefix) => opts.export_prefix = Some(prefix.value()),
142 Opt::AdditionalDerives(paths) => {
143 opts.additional_derive_attributes = paths
144 .into_iter()
145 .map(|p| p.into_token_stream().to_string())
146 .collect()
147 }
148 Opt::AdditionalDerivesIgnore(list) => {
149 opts.additional_derive_ignore =
150 list.into_iter().map(|i| i.value()).collect()
151 }
152 Opt::AdditionalTypeAttributes(list) => opts.additional_type_attributes = list,
153 Opt::AdditionalMemberAttributes(list) => {
154 opts.additional_member_attributes = list
155 }
156 Opt::With(with) => {
157 let mut with: Vec<_> = with.into_iter().collect();
161 with.sort_by(|a, b| a.0.cmp(&b.0));
162 opts.with.extend(with)
163 }
164 Opt::GenerateAll => {
165 opts.generate_all = true;
166 }
167 Opt::TypeSectionSuffix(suffix) => {
168 opts.type_section_suffix = Some(suffix.value());
169 }
170 Opt::DisableRunCtorsOnceWorkaround(enable) => {
171 opts.disable_run_ctors_once_workaround = enable.value();
172 }
173 Opt::DefaultBindingsModule(enable) => {
174 opts.default_bindings_module = Some(enable.value());
175 }
176 Opt::ExportMacroName(name) => {
177 opts.export_macro_name = Some(name.value());
178 }
179 Opt::PubExportMacro(enable) => {
180 opts.pub_export_macro = enable.value();
181 }
182 Opt::GenerateUnusedTypes(enable) => {
183 opts.generate_unused_types = enable.value();
184 }
185 Opt::Features(f) => {
186 features.extend(f.into_iter().map(|f| f.value()));
187 }
188 Opt::DisableCustomSectionLinkHelpers(disable) => {
189 opts.disable_custom_section_link_helpers = disable.value();
190 }
191 Opt::Debug(enable) => {
192 debug = enable.value();
193 }
194 Opt::Sync(val, span) => {
195 if sync_configured {
196 return Err(Error::new(span, "cannot specify second sync config"));
197 }
198 sync_configured = true;
199 opts.async_ = val;
200 }
201 Opt::ChainableMethods(val, span) => {
202 if method_chaining_configured {
203 return Err(Error::new(
204 span,
205 "cannot specify second method chaining config",
206 ));
207 }
208 method_chaining_configured = true;
209 opts.chainable_methods = val;
210 }
211 Opt::MergeStructurallyEqualTypes(enable) => {
212 opts.merge_structurally_equal_types = Some(Some(enable.value()))
213 }
214 }
215 }
216 } else {
217 world = input.parse::<Option<syn::LitStr>>()?.map(|s| s.value());
218 if input.parse::<Option<syn::token::In>>()?.is_some() {
219 source = Some(Source::Paths(vec![PathBuf::from(
220 input.parse::<syn::LitStr>()?.value(),
221 )]));
222 }
223 }
224 let (resolve, main_packages, files) = parse_source(&source, &features)?;
225 let world = resolve
226 .select_world(&main_packages, world.as_deref())
227 .map_err(|e| anyhow_to_syn(call_site, e, None))?;
228 Ok(Config {
229 opts,
230 resolve,
231 world,
232 files,
233 debug,
234 })
235 }
236}
237
238fn parse_source(
240 source: &Option<Source>,
241 features: &[String],
242) -> syn::Result<(Resolve, Vec<PackageId>, Vec<PathBuf>)> {
243 let mut resolve = Resolve::default();
244 resolve.features.extend(features.iter().cloned());
245 let mut files = Vec::new();
246 let mut pkgs = Vec::new();
247 let root = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
248
249 let mut try_parse = || -> anyhow::Result<()> {
250 let mut parse = |paths: &[PathBuf]| -> anyhow::Result<()> {
251 for path in paths {
252 let p = root.join(path);
253 let normalized_path = match std::fs::canonicalize(&p) {
257 Ok(p) => p,
258 Err(_) => p.to_path_buf(),
259 };
260 let (pkg, sources) = resolve.push_path(normalized_path)?;
261 pkgs.push(pkg);
262 files.extend(sources.paths().map(|p| p.to_owned()));
263 }
264 Ok(())
265 };
266 let default = root.join("wit");
267
268 match source {
269 Some(Source::Inline(s, path)) => {
270 match path {
271 Some(p) => parse(p)?,
272 None => {
277 if default.exists() {
278 parse(&[default])?;
279 }
280 }
281 }
282 pkgs.clear();
283 pkgs.push(resolve.push_str("macro-input", s)?);
284 Ok(())
285 }
286 Some(Source::Paths(p)) => parse(p),
287 None => parse(&[default]),
288 }
289 };
290
291 try_parse().map_err(|e| anyhow_to_syn(Span::call_site(), e, Some(&resolve.source_map)))?;
292
293 Ok((resolve, pkgs, files))
294}
295
296impl Config {
297 fn expand(mut self) -> Result<TokenStream> {
298 let mut files = Default::default();
299 let mut generator = self.opts.build();
300 generator
301 .generate(&mut self.resolve, self.world, &mut files)
302 .map_err(|e| anyhow_to_syn(Span::call_site(), e, None))?;
303 let (_, src) = files.iter().next().unwrap();
304 let mut src = std::str::from_utf8(src).unwrap().to_string();
305
306 if std::env::var("WIT_BINDGEN_DEBUG").is_ok() || self.debug {
311 static INVOCATION: AtomicUsize = AtomicUsize::new(0);
312 let root = Path::new(env!("DEBUG_OUTPUT_DIR"));
313 let world_name = &self.resolve.worlds[self.world].name;
314 let n = INVOCATION.fetch_add(1, Relaxed);
315 let path = root.join(format!("{world_name}{n}.rs"));
316
317 let contents = match fmt(&src) {
319 Ok(formatted) => formatted,
320 Err(_) => src.clone(),
321 };
322 std::fs::write(&path, contents.as_bytes()).unwrap();
323
324 src = format!("include!({path:?});");
325 }
326 let mut contents = src.parse::<TokenStream>().unwrap();
327
328 for file in self.files.iter() {
331 contents.extend(
332 format!(
333 "const _: &[u8] = include_bytes!(r#\"{}\"#);\n",
334 file.display()
335 )
336 .parse::<TokenStream>()
337 .unwrap(),
338 );
339 }
340
341 Ok(contents)
342 }
343}
344
345mod kw {
346 syn::custom_keyword!(std_feature);
347 syn::custom_keyword!(raw_strings);
348 syn::custom_keyword!(skip);
349 syn::custom_keyword!(world);
350 syn::custom_keyword!(path);
351 syn::custom_keyword!(inline);
352 syn::custom_keyword!(ownership);
353 syn::custom_keyword!(runtime_path);
354 syn::custom_keyword!(map_type);
355 syn::custom_keyword!(bitflags_path);
356 syn::custom_keyword!(exports);
357 syn::custom_keyword!(stubs);
358 syn::custom_keyword!(export_prefix);
359 syn::custom_keyword!(additional_derives);
360 syn::custom_keyword!(additional_derives_ignore);
361 syn::custom_keyword!(additional_type_attributes);
362 syn::custom_keyword!(additional_member_attributes);
363 syn::custom_keyword!(with);
364 syn::custom_keyword!(generate_all);
365 syn::custom_keyword!(type_section_suffix);
366 syn::custom_keyword!(disable_run_ctors_once_workaround);
367 syn::custom_keyword!(default_bindings_module);
368 syn::custom_keyword!(export_macro_name);
369 syn::custom_keyword!(pub_export_macro);
370 syn::custom_keyword!(generate_unused_types);
371 syn::custom_keyword!(features);
372 syn::custom_keyword!(disable_custom_section_link_helpers);
373 syn::custom_keyword!(imports);
374 syn::custom_keyword!(debug);
375 syn::custom_keyword!(chainable_methods);
376 syn::custom_keyword!(sync);
377 syn::custom_keyword!(merge_structurally_equal_types);
378}
379
380#[derive(Clone)]
381enum ExportKey {
382 World,
383 Name(syn::LitStr),
384}
385
386impl Parse for ExportKey {
387 fn parse(input: ParseStream<'_>) -> Result<Self> {
388 let l = input.lookahead1();
389 Ok(if l.peek(kw::world) {
390 input.parse::<kw::world>()?;
391 Self::World
392 } else {
393 Self::Name(input.parse()?)
394 })
395 }
396}
397
398impl From<ExportKey> for wit_bindgen_rust::ExportKey {
399 fn from(key: ExportKey) -> Self {
400 match key {
401 ExportKey::World => Self::World,
402 ExportKey::Name(s) => Self::Name(s.value()),
403 }
404 }
405}
406
407#[cfg(feature = "macro-string")]
408type PathType = macro_string::MacroString;
409#[cfg(not(feature = "macro-string"))]
410type PathType = syn::LitStr;
411
412trait EvaluateString {
413 fn evaluate_string(&self) -> Result<String>;
414}
415
416#[cfg(feature = "macro-string")]
417impl EvaluateString for macro_string::MacroString {
418 fn evaluate_string(&self) -> Result<String> {
419 self.eval()
420 }
421}
422
423#[cfg(not(feature = "macro-string"))]
424impl EvaluateString for syn::LitStr {
425 fn evaluate_string(&self) -> Result<String> {
426 Ok(self.value())
427 }
428}
429
430enum Opt {
431 World(syn::LitStr),
432 Path(Span, Vec<PathType>),
433 Inline(syn::LitStr),
434 UseStdFeature,
435 RawStrings,
436 Skip(Vec<syn::LitStr>),
437 Ownership(Ownership),
438 RuntimePath(syn::LitStr),
439 MapType(syn::LitStr),
440 BitflagsPath(syn::LitStr),
441 Stubs,
442 ExportPrefix(syn::LitStr),
443 AdditionalDerives(Vec<syn::Path>),
445 AdditionalDerivesIgnore(Vec<syn::LitStr>),
446 AdditionalTypeAttributes(Vec<(String, String)>),
447 AdditionalMemberAttributes(Vec<(String, String)>),
448 With(HashMap<String, WithOption>),
449 GenerateAll,
450 TypeSectionSuffix(syn::LitStr),
451 DisableRunCtorsOnceWorkaround(syn::LitBool),
452 DefaultBindingsModule(syn::LitStr),
453 ExportMacroName(syn::LitStr),
454 PubExportMacro(syn::LitBool),
455 GenerateUnusedTypes(syn::LitBool),
456 Features(Vec<syn::LitStr>),
457 DisableCustomSectionLinkHelpers(syn::LitBool),
458 Sync(AsyncFilterSet, Span),
459 Debug(syn::LitBool),
460 ChainableMethods(ChainableMethodFilterSet, Span),
461 MergeStructurallyEqualTypes(syn::LitBool),
462}
463
464impl Parse for Opt {
465 fn parse(input: ParseStream<'_>) -> Result<Self> {
466 let l = input.lookahead1();
467 if l.peek(kw::path) {
468 input.parse::<kw::path>()?;
469 input.parse::<Token![:]>()?;
470 if input.peek(token::Bracket) {
474 let contents;
475 syn::bracketed!(contents in input);
476 let span = input.span();
477 let list = Punctuated::<PathType, Token![,]>::parse_terminated(&contents)?;
478 Ok(Opt::Path(span, list.into_iter().collect()))
479 } else {
480 let span = input.span();
481 let path: PathType = input.parse()?;
482 Ok(Opt::Path(span, vec![path]))
483 }
484 } else if l.peek(kw::inline) {
485 input.parse::<kw::inline>()?;
486 input.parse::<Token![:]>()?;
487 Ok(Opt::Inline(input.parse()?))
488 } else if l.peek(kw::world) {
489 input.parse::<kw::world>()?;
490 input.parse::<Token![:]>()?;
491 Ok(Opt::World(input.parse()?))
492 } else if l.peek(kw::std_feature) {
493 input.parse::<kw::std_feature>()?;
494 Ok(Opt::UseStdFeature)
495 } else if l.peek(kw::raw_strings) {
496 input.parse::<kw::raw_strings>()?;
497 Ok(Opt::RawStrings)
498 } else if l.peek(kw::ownership) {
499 input.parse::<kw::ownership>()?;
500 input.parse::<Token![:]>()?;
501 let ownership = input.parse::<syn::Ident>()?;
502 Ok(Opt::Ownership(match ownership.to_string().as_str() {
503 "Owning" => Ownership::Owning,
504 "Borrowing" => Ownership::Borrowing {
505 duplicate_if_necessary: {
506 let contents;
507 braced!(contents in input);
508 let field = contents.parse::<syn::Ident>()?;
509 match field.to_string().as_str() {
510 "duplicate_if_necessary" => {
511 contents.parse::<Token![:]>()?;
512 contents.parse::<syn::LitBool>()?.value
513 }
514 name => {
515 return Err(Error::new(
516 field.span(),
517 format!(
518 "unrecognized `Ownership::Borrowing` field: `{name}`; \
519 expected `duplicate_if_necessary`"
520 ),
521 ));
522 }
523 }
524 },
525 },
526 name => {
527 return Err(Error::new(
528 ownership.span(),
529 format!(
530 "unrecognized ownership: `{name}`; \
531 expected `Owning` or `Borrowing`"
532 ),
533 ));
534 }
535 }))
536 } else if l.peek(kw::skip) {
537 input.parse::<kw::skip>()?;
538 input.parse::<Token![:]>()?;
539 let contents;
540 syn::bracketed!(contents in input);
541 let list = Punctuated::<_, Token![,]>::parse_terminated(&contents)?;
542 Ok(Opt::Skip(list.iter().cloned().collect()))
543 } else if l.peek(kw::runtime_path) {
544 input.parse::<kw::runtime_path>()?;
545 input.parse::<Token![:]>()?;
546 Ok(Opt::RuntimePath(input.parse()?))
547 } else if l.peek(kw::map_type) {
548 input.parse::<kw::map_type>()?;
549 input.parse::<Token![:]>()?;
550 Ok(Opt::MapType(input.parse()?))
551 } else if l.peek(kw::bitflags_path) {
552 input.parse::<kw::bitflags_path>()?;
553 input.parse::<Token![:]>()?;
554 Ok(Opt::BitflagsPath(input.parse()?))
555 } else if l.peek(kw::stubs) {
556 input.parse::<kw::stubs>()?;
557 Ok(Opt::Stubs)
558 } else if l.peek(kw::export_prefix) {
559 input.parse::<kw::export_prefix>()?;
560 input.parse::<Token![:]>()?;
561 Ok(Opt::ExportPrefix(input.parse()?))
562 } else if l.peek(kw::additional_derives) {
563 input.parse::<kw::additional_derives>()?;
564 input.parse::<Token![:]>()?;
565 let contents;
566 syn::bracketed!(contents in input);
567 let list = Punctuated::<_, Token![,]>::parse_terminated(&contents)?;
568 Ok(Opt::AdditionalDerives(list.iter().cloned().collect()))
569 } else if l.peek(kw::additional_derives_ignore) {
570 input.parse::<kw::additional_derives_ignore>()?;
571 input.parse::<Token![:]>()?;
572 let contents;
573 syn::bracketed!(contents in input);
574 let list = Punctuated::<_, Token![,]>::parse_terminated(&contents)?;
575 Ok(Opt::AdditionalDerivesIgnore(list.iter().cloned().collect()))
576 } else if l.peek(kw::additional_type_attributes) {
577 input.parse::<kw::additional_type_attributes>()?;
578 input.parse::<Token![:]>()?;
579 let contents;
580 braced!(contents in input);
581 let fields: Punctuated<_, Token![,]> =
582 contents.parse_terminated(attr_map_field_parse, Token![,])?;
583 Ok(Opt::AdditionalTypeAttributes(
584 fields.into_iter().flatten().collect(),
585 ))
586 } else if l.peek(kw::additional_member_attributes) {
587 input.parse::<kw::additional_member_attributes>()?;
588 input.parse::<Token![:]>()?;
589 let contents;
590 braced!(contents in input);
591 let fields: Punctuated<_, Token![,]> =
592 contents.parse_terminated(attr_map_field_parse, Token![,])?;
593 Ok(Opt::AdditionalMemberAttributes(
594 fields.into_iter().flatten().collect(),
595 ))
596 } else if l.peek(kw::with) {
597 input.parse::<kw::with>()?;
598 input.parse::<Token![:]>()?;
599 let contents;
600 let _lbrace = braced!(contents in input);
601 let fields: Punctuated<_, Token![,]> =
602 contents.parse_terminated(with_field_parse, Token![,])?;
603 Ok(Opt::With(HashMap::from_iter(fields)))
604 } else if l.peek(kw::generate_all) {
605 input.parse::<kw::generate_all>()?;
606 Ok(Opt::GenerateAll)
607 } else if l.peek(kw::type_section_suffix) {
608 input.parse::<kw::type_section_suffix>()?;
609 input.parse::<Token![:]>()?;
610 Ok(Opt::TypeSectionSuffix(input.parse()?))
611 } else if l.peek(kw::disable_run_ctors_once_workaround) {
612 input.parse::<kw::disable_run_ctors_once_workaround>()?;
613 input.parse::<Token![:]>()?;
614 Ok(Opt::DisableRunCtorsOnceWorkaround(input.parse()?))
615 } else if l.peek(kw::default_bindings_module) {
616 input.parse::<kw::default_bindings_module>()?;
617 input.parse::<Token![:]>()?;
618 Ok(Opt::DefaultBindingsModule(input.parse()?))
619 } else if l.peek(kw::export_macro_name) {
620 input.parse::<kw::export_macro_name>()?;
621 input.parse::<Token![:]>()?;
622 Ok(Opt::ExportMacroName(input.parse()?))
623 } else if l.peek(kw::pub_export_macro) {
624 input.parse::<kw::pub_export_macro>()?;
625 input.parse::<Token![:]>()?;
626 Ok(Opt::PubExportMacro(input.parse()?))
627 } else if l.peek(kw::generate_unused_types) {
628 input.parse::<kw::generate_unused_types>()?;
629 input.parse::<Token![:]>()?;
630 Ok(Opt::GenerateUnusedTypes(input.parse()?))
631 } else if l.peek(kw::features) {
632 input.parse::<kw::features>()?;
633 input.parse::<Token![:]>()?;
634 let contents;
635 syn::bracketed!(contents in input);
636 let list = Punctuated::<_, Token![,]>::parse_terminated(&contents)?;
637 Ok(Opt::Features(list.into_iter().collect()))
638 } else if l.peek(kw::disable_custom_section_link_helpers) {
639 input.parse::<kw::disable_custom_section_link_helpers>()?;
640 input.parse::<Token![:]>()?;
641 Ok(Opt::DisableCustomSectionLinkHelpers(input.parse()?))
642 } else if l.peek(kw::debug) {
643 input.parse::<kw::debug>()?;
644 input.parse::<Token![:]>()?;
645 Ok(Opt::Debug(input.parse()?))
646 } else if l.peek(kw::chainable_methods) {
647 let span = input.parse::<kw::chainable_methods>()?.span;
648 input.parse::<Token![:]>()?;
649
650 let mut set = ChainableMethodFilterSet::default();
651 let contents;
652 syn::bracketed!(contents in input);
653 for val in contents.parse_terminated(|p| p.parse::<syn::LitStr>(), Token![,])? {
654 set.push(&val.value());
655 }
656 Ok(Opt::ChainableMethods(set, span))
657 } else if l.peek(kw::sync) {
658 let span = input.parse::<kw::sync>()?.span;
659 input.parse::<Token![:]>()?;
660 let mut set = AsyncFilterSet::default();
661 if input.peek(syn::LitBool) {
662 if input.parse::<syn::LitBool>()?.value {
663 set.push("all");
664 }
665 } else {
666 let contents;
667 syn::bracketed!(contents in input);
668 for val in contents.parse_terminated(|p| p.parse::<syn::LitStr>(), Token![,])? {
669 set.push(&val.value());
670 }
671 }
672 Ok(Opt::Sync(set, span))
673 } else if input.peek(Token![async]) {
674 let span = input.parse::<Token![async]>()?.span;
675 Err(Error::new(
676 span,
677 "the `async` option has been removed: functions that are `async` \
678 in WIT get async bindings by default, and `sync` opts them out",
679 ))
680 } else if l.peek(kw::merge_structurally_equal_types) {
681 input.parse::<kw::merge_structurally_equal_types>()?;
682 input.parse::<Token![:]>()?;
683 Ok(Opt::MergeStructurallyEqualTypes(input.parse()?))
684 } else {
685 Err(l.error())
686 }
687 }
688}
689
690fn attr_map_field_parse(input: ParseStream<'_>) -> Result<Vec<(String, String)>> {
692 let selector = input.parse::<syn::LitStr>()?;
693 input.parse::<Token![:]>()?;
694 let contents;
695 let bracket = syn::bracketed!(contents in input);
696 let attrs = contents.call(syn::Attribute::parse_outer)?;
697 if !contents.is_empty() {
698 return Err(contents.error("expected an outer attribute, `#[...]`"));
699 }
700 if attrs.is_empty() {
702 return Err(Error::new(
703 bracket.span.join(),
704 "attribute list must not be empty",
705 ));
706 }
707 let selector = selector.value();
708 Ok(attrs
709 .into_iter()
710 .map(|a| (selector.clone(), a.to_token_stream().to_string()))
711 .collect())
712}
713
714fn with_field_parse(input: ParseStream<'_>) -> Result<(String, WithOption)> {
715 let interface = input.parse::<syn::LitStr>()?.value();
716 input.parse::<Token![:]>()?;
717 let start = input.span();
718 let path = input.parse::<syn::Path>()?;
719
720 let span = start
722 .join(path.segments.last().unwrap().ident.span())
723 .unwrap_or(start);
724
725 if path.is_ident("generate") {
726 return Ok((interface, WithOption::Generate));
727 }
728
729 let mut buf = String::new();
730 let append = |buf: &mut String, segment: syn::PathSegment| -> Result<()> {
731 if !segment.arguments.is_none() {
732 return Err(Error::new(
733 span,
734 "Module path must not contain angles or parens",
735 ));
736 }
737
738 buf.push_str(&segment.ident.to_string());
739
740 Ok(())
741 };
742
743 if path.leading_colon.is_some() {
744 buf.push_str("::");
745 }
746
747 let mut segments = path.segments.into_iter();
748
749 if let Some(segment) = segments.next() {
750 append(&mut buf, segment)?;
751 }
752
753 for segment in segments {
754 buf.push_str("::");
755 append(&mut buf, segment)?;
756 }
757
758 Ok((interface, WithOption::Path(buf)))
759}
760
761fn fmt(input: &str) -> Result<String> {
763 let syntax_tree = syn::parse_file(input)?;
764 Ok(prettyplease::unparse(&syntax_tree))
765}