1#![doc = include_str!("README.md")]
4#![deny(clippy::unnecessary_wraps)]
5
6use proc_macro::TokenStream;
7use std::error::Error;
8
9mod op2;
10mod webidl;
11
12#[doc = include_str!("op2/README.md")]
14#[proc_macro_attribute]
15pub fn op2(attr: TokenStream, item: TokenStream) -> TokenStream {
16 op2_macro(attr, item)
17}
18
19fn op2_macro(attr: TokenStream, item: TokenStream) -> TokenStream {
20 match crate::op2::op2(attr.into(), item.into()) {
21 Ok(output) => output.into(),
22 Err(err) => {
23 let mut err: &dyn Error = &err;
24 let mut output = "Failed to parse #[op2]:\n".to_owned();
25 loop {
26 output += &format!(" - {err}\n");
27 if let Some(source) = err.source() {
28 err = source;
29 } else {
30 break;
31 }
32 }
33 panic!("{output}");
34 }
35 }
36}
37
38#[proc_macro_derive(WebIDL, attributes(webidl, options))]
39pub fn webidl(item: TokenStream) -> TokenStream {
40 match webidl::webidl(item.into()) {
41 Ok(output) => output.into(),
42 Err(err) => err.into_compile_error().into(),
43 }
44}
45
46#[cfg(test)]
47mod infra {
48 use std::path::PathBuf;
49 use syn::File;
50
51 pub fn run_macro_expansion_test<F, I>(input: PathBuf, expander: F)
52 where
53 F: FnOnce(File) -> I,
54 I: Iterator<Item = proc_macro2::TokenStream>,
55 {
56 let update_expected = std::env::var("UPDATE_EXPECTED").is_ok();
57
58 let source =
59 std::fs::read_to_string(&input).expect("Failed to read test file");
60
61 const PRELUDE: &str = r"// Copyright 2018-2025 the Deno authors. MIT license.
62
63#![deny(warnings)]
64deno_ops_compile_test_runner::prelude!();";
65
66 if !source.starts_with(PRELUDE) {
67 panic!("Source does not start with expected prelude:]n{PRELUDE}");
68 }
69
70 let file =
71 syn::parse_str::<File>(&source).expect("Failed to parse Rust file");
72
73 let expected_out = expander(file)
74 .map(|tokens| {
75 println!("======== Raw tokens ========:\n{}", tokens.clone());
76 let tree = syn::parse2(tokens).unwrap();
77 let actual = prettyplease::unparse(&tree);
78 println!("======== Generated ========:\n{}", actual);
79 actual
80 })
81 .collect::<Vec<String>>()
82 .join("\n");
83
84 if update_expected {
85 std::fs::write(input.with_extension("out"), expected_out)
86 .expect("Failed to write expectation file");
87 } else {
88 let expected = std::fs::read_to_string(input.with_extension("out"))
89 .expect("Failed to read expectation file");
90
91 pretty_assertions::assert_eq!(
92 expected,
93 expected_out,
94 "Failed to match expectation. Use UPDATE_EXPECTED=1."
95 );
96 }
97 }
98}