Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
alexcrichton committed Sep 4, 2018
1 parent cfb4be8 commit af44d4b
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 128 deletions.
4 changes: 2 additions & 2 deletions crates/backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ 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"
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" }
1 change: 1 addition & 0 deletions crates/backend/src/defined.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}
Expand Down
21 changes: 21 additions & 0 deletions crates/backend/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use proc_macro2::*;
use quote::{ToTokens, TokenStreamExt};
use syn::parse::Error;

#[macro_export]
macro_rules! err_span {
Expand All @@ -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<Diagnostic>,
}
Expand Down Expand Up @@ -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<Error> 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);
Expand Down Expand Up @@ -92,6 +110,9 @@ impl ToTokens for Diagnostic {
diagnostic.to_tokens(dst);
}
}
Repr::SynError { tokens, .. } => {
tokens.to_tokens(dst);
}
}
}
}
4 changes: 2 additions & 2 deletions crates/macro-support/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
11 changes: 2 additions & 9 deletions crates/macro-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,12 @@ mod parser;

/// Takes the parsed input from a `#[wasm_bindgen]` macro and returns the generated bindings
pub fn expand(attr: TokenStream, input: TokenStream) -> Result<TokenStream, Diagnostic> {
let item = syn_parse::<syn::Item>(input, "rust item")?;
let opts = syn_parse(attr, "#[wasm_bindgen] attribute options")?;
let item = syn::parse2::<syn::Item>(input)?;
let opts = syn::parse2(attr)?;

let mut tokens = proc_macro2::TokenStream::new();
let mut program = backend::ast::Program::default();
item.macro_parse(&mut program, (Some(opts), &mut tokens))?;
program.try_to_tokens(&mut tokens)?;
Ok(tokens)
}

fn syn_parse<T: syn::synom::Synom>(tokens: TokenStream, name: &str) -> Result<T, Diagnostic> {
syn::parse2(tokens.clone())
.map_err(|err| {
Diagnostic::span_error(&tokens, format!("error parsing {}: {}", name, err))
})
}
207 changes: 96 additions & 111 deletions crates/macro-support/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))]
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<Self> {
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]`.
Expand All @@ -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<Self> {
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::<Token![=]>()?;
return Ok(BindgenAttr::StaticMethodOf(input.parse::<AnyIdent>()?.0))
}
if attr == "getter" {
if input.parse::<Token![=]>().is_ok() {
return Ok(BindgenAttr::Getter(Some(input.parse::<AnyIdent>()?.0)))
} else {
return Ok(BindgenAttr::Getter(None))
}
}
if attr == "setter" {
if input.parse::<Token![=]>().is_ok() {
return Ok(BindgenAttr::Setter(Some(input.parse::<AnyIdent>()?.0)))
} else {
return Ok(BindgenAttr::Setter(None))
}
}
if attr == "js_namespace" {
input.parse::<Token![=]>()?;
return Ok(BindgenAttr::JsNamespace(input.parse::<AnyIdent>()?.0))
}
if attr == "extends" {
input.parse::<Token![=]>()?;
return Ok(BindgenAttr::Extends(input.parse::<AnyIdent>()?.0))
}
if attr == "module" {
input.parse::<Token![=]>()?;
return Ok(BindgenAttr::Module(input.parse::<syn::LitStr>()?.value()))
}
if attr == "js_class" {
input.parse::<Token![=]>()?;
return Ok(BindgenAttr::JsClass(input.parse::<syn::LitStr>()?.value()))
}
if attr == "js_name" {
input.parse::<Token![=]>()?;
let val = match input.parse::<syn::LitStr>() {
Ok(str) => str.value(),
Err(_) => input.parse::<AnyIdent>()?.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<Self> {
input.step(|cursor| {
match cursor.ident() {
Some((ident, remaining)) => Ok((AnyIdent(ident), remaining)),
None => Err(cursor.error("expected an identifier")),
}
})
}
}

Expand Down Expand Up @@ -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");
}
Expand Down
2 changes: 1 addition & 1 deletion crates/macro/ui-tests/attribute-fails-to-parse.stderr
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down
4 changes: 2 additions & 2 deletions crates/macro/ui-tests/invalid-attr.stderr
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down
2 changes: 1 addition & 1 deletion crates/webidl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"

0 comments on commit af44d4b

Please sign in to comment.