diff --git a/crates/backend/Cargo.toml b/crates/backend/Cargo.toml index 4fa919602447..26c4ba2457aa 100644 --- a/crates/backend/Cargo.toml +++ b/crates/backend/Cargo.toml @@ -12,7 +12,7 @@ Backend code generation of the wasm-bindgen tool [features] spans = [] -extra-traits = ["syn/extra-traits"] +extra-traits = ["syn-next/extra-traits"] [dependencies] lazy_static = "1.0.0" @@ -20,5 +20,5 @@ log = "0.4" proc-macro2 = "0.4.8" quote = '0.6' serde_json = "1.0" -syn = { version = '0.14', features = ['full', 'visit'] } +syn-next = { version = '0.15.0-rc3', features = ['full', 'visit'] } wasm-bindgen-shared = { path = "../shared", version = "=0.2.19" } diff --git a/crates/backend/src/defined.rs b/crates/backend/src/defined.rs index f697b502b8df..a32ad59f8fba 100644 --- a/crates/backend/src/defined.rs +++ b/crates/backend/src/defined.rs @@ -224,6 +224,7 @@ impl ImportedTypes for syn::GenericArgument { syn::GenericArgument::Type(ty) => ty.imported_types(f), syn::GenericArgument::Binding(_) => {}, // TODO syn::GenericArgument::Const(_) => {}, // TODO + syn::GenericArgument::Constraint(_) => {}, // TODO } } } diff --git a/crates/backend/src/error.rs b/crates/backend/src/error.rs index b0c7776362aa..5a67523379b5 100644 --- a/crates/backend/src/error.rs +++ b/crates/backend/src/error.rs @@ -1,5 +1,6 @@ use proc_macro2::*; use quote::{ToTokens, TokenStreamExt}; +use syn::parse::Error; #[macro_export] macro_rules! err_span { @@ -18,11 +19,16 @@ macro_rules! bail_span { pub struct Diagnostic { inner: Repr, } + enum Repr { Single { text: String, span: Option<(Span, Span)>, }, + SynError { + error: String, + tokens: TokenStream, + }, Multi { diagnostics: Vec, } @@ -59,11 +65,23 @@ impl Diagnostic { 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 for Diagnostic { + fn from(err: Error) -> Diagnostic { + Diagnostic { + inner: Repr::SynError { + error: err.to_string(), + tokens: err.into_compile_error(), + } + } + } +} + fn extract_spans(node: &ToTokens) -> Option<(Span, Span)> { let mut t = TokenStream::new(); node.to_tokens(&mut t); @@ -92,6 +110,9 @@ impl ToTokens for Diagnostic { diagnostic.to_tokens(dst); } } + Repr::SynError { tokens, .. } => { + tokens.to_tokens(dst); + } } } } diff --git a/crates/macro-support/Cargo.toml b/crates/macro-support/Cargo.toml index bf0e116d2b08..52861eec3feb 100644 --- a/crates/macro-support/Cargo.toml +++ b/crates/macro-support/Cargo.toml @@ -12,10 +12,10 @@ The part of the implementation of the `#[wasm_bindgen]` attribute that is not in [features] spans = ["wasm-bindgen-backend/spans"] -extra-traits = ["syn/extra-traits"] +extra-traits = ["syn-next/extra-traits"] [dependencies] -syn = { version = '0.14', features = ['full'] } +syn-next = { version = '0.15.0-rc3', features = ['full'] } quote = '0.6' proc-macro2 = "0.4.9" wasm-bindgen-backend = { path = "../backend", version = "=0.2.19" } diff --git a/crates/macro-support/src/lib.rs b/crates/macro-support/src/lib.rs index cb777337444b..361d60461eef 100644 --- a/crates/macro-support/src/lib.rs +++ b/crates/macro-support/src/lib.rs @@ -20,8 +20,8 @@ mod parser; /// Takes the parsed input from a `#[wasm_bindgen]` macro and returns the generated bindings pub fn expand(attr: TokenStream, input: TokenStream) -> Result { - let item = syn_parse::(input, "rust item")?; - let opts = syn_parse(attr, "#[wasm_bindgen] attribute options")?; + let item = syn::parse2::(input)?; + let opts = syn::parse2(attr)?; let mut tokens = proc_macro2::TokenStream::new(); let mut program = backend::ast::Program::default(); @@ -29,10 +29,3 @@ pub fn expand(attr: TokenStream, input: TokenStream) -> Result(tokens: TokenStream, name: &str) -> Result { - syn::parse2(tokens.clone()) - .map_err(|err| { - Diagnostic::span_error(&tokens, format!("error parsing {}: {}", name, err)) - }) -} diff --git a/crates/macro-support/src/parser.rs b/crates/macro-support/src/parser.rs index 33ce3eb28c76..3de713e86cb2 100644 --- a/crates/macro-support/src/parser.rs +++ b/crates/macro-support/src/parser.rs @@ -5,6 +5,7 @@ use proc_macro2::{Delimiter, Ident, Span, TokenStream, TokenTree}; use quote::ToTokens; use shared; use syn; +use syn::parse::{Parse, ParseStream, Result as SynResult}; /// Parsed attributes from a `#[wasm_bindgen(..)]`. #[cfg_attr(feature = "extra-traits", derive(Debug, PartialEq, Eq))] @@ -39,7 +40,7 @@ impl BindgenAttrs { if group.delimiter() != Delimiter::Parenthesis { bail_span!(attr, "malformed #[wasm_bindgen] attribute"); } - super::syn_parse(group.stream(), "#[wasm_bindgen] attribute options") + Ok(syn::parse2(group.stream())?) } /// Get the first module attribute @@ -185,19 +186,15 @@ impl BindgenAttrs { } } -impl syn::synom::Synom for BindgenAttrs { - named!(parse -> Self, alt!( - do_parse!( - opts: call!( - syn::punctuated::Punctuated::<_, syn::token::Comma>::parse_terminated - ) >> - (BindgenAttrs { - attrs: opts.into_iter().collect(), - }) - ) => { |s| s } - | - epsilon!() => { |_| BindgenAttrs { attrs: Vec::new() } } - )); +impl Parse for BindgenAttrs { + fn parse(input: ParseStream) -> SynResult { + if input.is_empty() { + return Ok(BindgenAttrs { attrs: Vec::new() }) + } + + let opts = syn::punctuated::Punctuated::<_, syn::token::Comma>::parse_terminated(input)?; + Ok(BindgenAttrs { attrs: opts.into_iter().collect() }) + } } /// The possible attributes in the `#[wasm_bindgen]`. @@ -221,107 +218,91 @@ pub enum BindgenAttr { Extends(Ident), } -impl syn::synom::Synom for BindgenAttr { - named!(parse -> Self, alt!( - call!(term, "catch") => { |_| BindgenAttr::Catch } - | - call!(term, "constructor") => { |_| BindgenAttr::Constructor } - | - call!(term, "method") => { |_| BindgenAttr::Method } - | - do_parse!( - call!(term, "static_method_of") >> - punct!(=) >> - cls: call!(term2ident) >> - (cls) - )=> { BindgenAttr::StaticMethodOf } - | - do_parse!( - call!(term, "getter") >> - val: option!(do_parse!( - punct!(=) >> - s: call!(term2ident) >> - (s) - )) >> - (val) - )=> { BindgenAttr::Getter } - | - do_parse!( - call!(term, "setter") >> - val: option!(do_parse!( - punct!(=) >> - s: call!(term2ident) >> - (s) - )) >> - (val) - )=> { BindgenAttr::Setter } - | - call!(term, "indexing_getter") => { |_| BindgenAttr::IndexingGetter } - | - call!(term, "indexing_setter") => { |_| BindgenAttr::IndexingSetter } - | - call!(term, "indexing_deleter") => { |_| BindgenAttr::IndexingDeleter } - | - call!(term, "structural") => { |_| BindgenAttr::Structural } - | - call!(term, "readonly") => { |_| BindgenAttr::Readonly } - | - do_parse!( - call!(term, "js_namespace") >> - punct!(=) >> - ns: call!(term2ident) >> - (ns) - )=> { BindgenAttr::JsNamespace } - | - do_parse!( - call!(term, "module") >> - punct!(=) >> - s: syn!(syn::LitStr) >> - (s.value()) - )=> { BindgenAttr::Module } - | - do_parse!( - call!(term, "js_name") >> - punct!(=) >> - name: alt!( - syn!(syn::LitStr) => { |s| s.value() } - | - call!(term2ident) => { |s| s.to_string() } - ) >> - (name) - )=> { BindgenAttr::JsName } - | - do_parse!( - call!(term, "js_class") >> - punct!(=) >> - s: syn!(syn::LitStr) >> - (s.value()) - )=> { BindgenAttr::JsClass } - | - do_parse!( - call!(term, "extends") >> - punct!(=) >> - ns: call!(term2ident) >> - (ns) - )=> { BindgenAttr::Extends } - )); -} - -/// Consumes a `Ident` with the given name -fn term<'a>(cursor: syn::buffer::Cursor<'a>, name: &str) -> syn::synom::PResult<'a, ()> { - if let Some((ident, next)) = cursor.ident() { - if ident == name { - return Ok(((), next)); +impl Parse for BindgenAttr { + fn parse(input: ParseStream) -> SynResult { + let original = input.fork(); + let attr: Ident = input.parse()?; + if attr == "catch" { + return Ok(BindgenAttr::Catch) + } + if attr == "constructor" { + return Ok(BindgenAttr::Constructor) + } + if attr == "method" { + return Ok(BindgenAttr::Method) + } + if attr == "indexing_getter" { + return Ok(BindgenAttr::IndexingGetter) + } + if attr == "indexing_setter" { + return Ok(BindgenAttr::IndexingSetter) + } + if attr == "indexing_deleter" { + return Ok(BindgenAttr::IndexingDeleter) + } + if attr == "structural" { + return Ok(BindgenAttr::Structural) + } + if attr == "readonly" { + return Ok(BindgenAttr::Readonly) + } + if attr == "static_method_of" { + input.parse::()?; + return Ok(BindgenAttr::StaticMethodOf(input.parse::()?.0)) + } + if attr == "getter" { + if input.parse::().is_ok() { + return Ok(BindgenAttr::Getter(Some(input.parse::()?.0))) + } else { + return Ok(BindgenAttr::Getter(None)) + } } + if attr == "setter" { + if input.parse::().is_ok() { + return Ok(BindgenAttr::Setter(Some(input.parse::()?.0))) + } else { + return Ok(BindgenAttr::Setter(None)) + } + } + if attr == "js_namespace" { + input.parse::()?; + return Ok(BindgenAttr::JsNamespace(input.parse::()?.0)) + } + if attr == "extends" { + input.parse::()?; + return Ok(BindgenAttr::Extends(input.parse::()?.0)) + } + if attr == "module" { + input.parse::()?; + return Ok(BindgenAttr::Module(input.parse::()?.value())) + } + if attr == "js_class" { + input.parse::()?; + return Ok(BindgenAttr::JsClass(input.parse::()?.value())) + } + if attr == "js_name" { + input.parse::()?; + let val = match input.parse::() { + Ok(str) => str.value(), + Err(_) => input.parse::()?.0.to_string(), + }; + return Ok(BindgenAttr::JsName(val)) + } + + Err(original.error("unknown attribute")) } - syn::parse_error() } -/// Consumes a `Ident` and returns it. -fn term2ident<'a>(cursor: syn::buffer::Cursor<'a>) -> syn::synom::PResult<'a, Ident> { - match cursor.ident() { - Some(pair) => Ok(pair), - None => syn::parse_error(), +struct AnyIdent(Ident); + +impl Parse for AnyIdent { + fn parse(input: ParseStream) -> SynResult { + input.step(|cursor| { + match cursor.ident() { + Some((ident, remaining)) => Ok((AnyIdent(ident), remaining)), + None => Err(cursor.error("expected an identifier")), + } + }) } } @@ -823,6 +804,10 @@ impl<'a, 'b> MacroParse<()> for (&'a Ident, &'b mut syn::ImplItem) { &*item, "type definitions in impls aren't supported with #[wasm_bindgen]" ), + syn::ImplItem::Existential(_) => bail_span!( + &*item, + "existentials in impls aren't supported with #[wasm_bindgen]" + ), syn::ImplItem::Macro(_) => { bail_span!(&*item, "macros in impls aren't supported"); } diff --git a/crates/macro/ui-tests/attribute-fails-to-parse.stderr b/crates/macro/ui-tests/attribute-fails-to-parse.stderr index eb7960ebdeea..ca296af3fc7b 100644 --- a/crates/macro/ui-tests/attribute-fails-to-parse.stderr +++ b/crates/macro/ui-tests/attribute-fails-to-parse.stderr @@ -1,4 +1,4 @@ -error: error parsing #[wasm_bindgen] attribute options: failed to parse anything +error: unknown attribute --> $DIR/attribute-fails-to-parse.rs:5:16 | 5 | #[wasm_bindgen(nonsense)] diff --git a/crates/macro/ui-tests/invalid-attr.stderr b/crates/macro/ui-tests/invalid-attr.stderr index ee918ec531d1..9cc44d8df0ee 100644 --- a/crates/macro/ui-tests/invalid-attr.stderr +++ b/crates/macro/ui-tests/invalid-attr.stderr @@ -1,10 +1,10 @@ -error: error parsing #[wasm_bindgen] attribute options: failed to parse anything +error: unknown attribute --> $DIR/invalid-attr.rs:5:16 | 5 | #[wasm_bindgen(x)] | ^ -error: error parsing #[wasm_bindgen] attribute options: failed to parse anything +error: unknown attribute --> $DIR/invalid-attr.rs:10:20 | 10 | #[wasm_bindgen(y)] diff --git a/crates/webidl/Cargo.toml b/crates/webidl/Cargo.toml index bcf03b116627..8daf817a49b5 100644 --- a/crates/webidl/Cargo.toml +++ b/crates/webidl/Cargo.toml @@ -18,6 +18,6 @@ heck = "0.3" log = "0.4.1" proc-macro2 = "0.4.8" quote = '0.6' -syn = { version = '0.14', features = ['full'] } +syn-next = { version = '0.15.0-rc3', features = ['full'] } wasm-bindgen-backend = { version = "=0.2.19", path = "../backend" } weedle = "0.6"