2467b7139b
* napi procedural macro for basic rust/JavaScript types * introduce the `compat-mode` for `napi` and `napi-derive` crates for backward compatible * remove #[inline] and let compiler to decide the inline behavior * cli now can produce the `.d.ts` file for native binding * many tests and example for the new procedural macro Co-authored-by: LongYinan <lynweklm@gmail.com>
136 lines
3.5 KiB
Rust
136 lines
3.5 KiB
Rust
use proc_macro2::*;
|
|
use quote::{ToTokens, TokenStreamExt};
|
|
use syn::parse::Error;
|
|
|
|
/// Provide a Diagnostic with the given span and message
|
|
#[macro_export]
|
|
macro_rules! err_span {
|
|
($span:expr, $($msg:tt)*) => (
|
|
$crate::Diagnostic::spanned_error(&$span, format!($($msg)*))
|
|
)
|
|
}
|
|
|
|
/// Immediately fail and return an Err, with the arguments passed to err_span!
|
|
#[macro_export]
|
|
macro_rules! bail_span {
|
|
($($t:tt)*) => (
|
|
return Err(err_span!($($t)*).into())
|
|
)
|
|
}
|
|
|
|
/// A struct representing a diagnostic to emit to the end-user as an error.
|
|
#[derive(Debug)]
|
|
pub struct Diagnostic {
|
|
inner: Repr,
|
|
}
|
|
|
|
pub type BindgenResult<T> = Result<T, Diagnostic>;
|
|
|
|
#[derive(Debug)]
|
|
enum Repr {
|
|
Single {
|
|
text: String,
|
|
span: Option<(Span, Span)>,
|
|
},
|
|
SynError(Error),
|
|
Multi {
|
|
diagnostics: Vec<Diagnostic>,
|
|
},
|
|
}
|
|
|
|
impl Diagnostic {
|
|
/// Generate a `Diagnostic` from an informational message with no Span
|
|
pub fn error<T: Into<String>>(text: T) -> Diagnostic {
|
|
Diagnostic {
|
|
inner: Repr::Single {
|
|
text: text.into(),
|
|
span: None,
|
|
},
|
|
}
|
|
}
|
|
|
|
/// Generate a `Diagnostic` from a Span and an informational message
|
|
pub fn span_error<T: Into<String>>(span: Span, text: T) -> Diagnostic {
|
|
Diagnostic {
|
|
inner: Repr::Single {
|
|
text: text.into(),
|
|
span: Some((span, span)),
|
|
},
|
|
}
|
|
}
|
|
|
|
/// Generate a `Diagnostic` from the span of any tokenizable object and a message
|
|
pub fn spanned_error<T: Into<String>>(node: &dyn ToTokens, text: T) -> Diagnostic {
|
|
Diagnostic {
|
|
inner: Repr::Single {
|
|
text: text.into(),
|
|
span: extract_spans(node),
|
|
},
|
|
}
|
|
}
|
|
|
|
/// Attempt to generate a `Diagnostic` from a vector of other `Diagnostic` instances.
|
|
/// If the `Vec` is empty, returns `Ok(())`, otherwise returns the new `Diagnostic`
|
|
pub fn from_vec(diagnostics: Vec<Diagnostic>) -> BindgenResult<()> {
|
|
if diagnostics.is_empty() {
|
|
Ok(())
|
|
} else {
|
|
Err(Diagnostic {
|
|
inner: Repr::Multi { diagnostics },
|
|
})
|
|
}
|
|
}
|
|
|
|
/// Immediately trigger a panic from this `Diagnostic`
|
|
#[allow(unconditional_recursion)]
|
|
pub fn panic(&self) -> ! {
|
|
match &self.inner {
|
|
Repr::Single { text, .. } => panic!("{}", text),
|
|
Repr::SynError(error) => panic!("{}", error),
|
|
Repr::Multi { diagnostics } => diagnostics[0].panic(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Error> for Diagnostic {
|
|
fn from(err: Error) -> Diagnostic {
|
|
Diagnostic {
|
|
inner: Repr::SynError(err),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn extract_spans(node: &dyn ToTokens) -> Option<(Span, Span)> {
|
|
let mut t = TokenStream::new();
|
|
node.to_tokens(&mut t);
|
|
let mut tokens = t.into_iter();
|
|
let start = tokens.next().map(|t| t.span());
|
|
let end = tokens.last().map(|t| t.span());
|
|
start.map(|start| (start, end.unwrap_or(start)))
|
|
}
|
|
|
|
impl ToTokens for Diagnostic {
|
|
fn to_tokens(&self, dst: &mut TokenStream) {
|
|
match &self.inner {
|
|
Repr::Single { text, span } => {
|
|
let cs2 = (Span::call_site(), Span::call_site());
|
|
let (start, end) = span.unwrap_or(cs2);
|
|
dst.append(Ident::new("compile_error", start));
|
|
dst.append(Punct::new('!', Spacing::Alone));
|
|
let mut message = TokenStream::new();
|
|
message.append(Literal::string(text));
|
|
let mut group = Group::new(Delimiter::Brace, message);
|
|
group.set_span(end);
|
|
dst.append(group);
|
|
}
|
|
Repr::Multi { diagnostics } => {
|
|
for diagnostic in diagnostics {
|
|
diagnostic.to_tokens(dst);
|
|
}
|
|
}
|
|
Repr::SynError(err) => {
|
|
err.to_compile_error().to_tokens(dst);
|
|
}
|
|
}
|
|
}
|
|
}
|