Remove proc_macro_diagnostic feature
This commit is contained in:
parent
78f0e9b1e6
commit
dcda57c8af
|
@ -1,8 +1,8 @@
|
||||||
use ansi_term::Style;
|
use ansi_term::Style;
|
||||||
use lalrpop_util::ParseError::*;
|
use lalrpop_util::ParseError::*;
|
||||||
use lexer::Token;
|
use lexer::Token;
|
||||||
use proc_macro::{Diagnostic, Level};
|
use proc_macro2::{Ident, TokenStream};
|
||||||
use proc_macro2::Ident;
|
use quote::{quote, quote_spanned};
|
||||||
|
|
||||||
pub type ParseError = lalrpop_util::ParseError<usize, Token, HtmlParseError>;
|
pub type ParseError = lalrpop_util::ParseError<usize, Token, HtmlParseError>;
|
||||||
|
|
||||||
|
@ -41,49 +41,76 @@ fn is_in_node_position(tokens: &[String]) -> bool {
|
||||||
input == output
|
input == output
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_error(input: &[Token], error: &ParseError) -> Diagnostic {
|
pub fn parse_error(input: &[Token], error: &ParseError) -> TokenStream {
|
||||||
match error {
|
match error {
|
||||||
InvalidToken { location } => {
|
InvalidToken { location } => {
|
||||||
let loc = &input[*location];
|
let span = input[*location].span();
|
||||||
Diagnostic::spanned(loc.span().unstable(), Level::Error, "invalid token")
|
quote_spanned! {span=>
|
||||||
|
compile_error! { "invalid token" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
UnrecognizedToken {
|
UnrecognizedToken {
|
||||||
token: None,
|
token: None,
|
||||||
expected,
|
expected,
|
||||||
} => {
|
} => {
|
||||||
let msg = format!("missing {}", pprint_tokens(&expected));
|
let msg = format!(
|
||||||
Diagnostic::spanned(
|
"unexpected end of macro; missing {}",
|
||||||
input[0].span().unstable().join(input[input.len() - 1].span().unstable()).unwrap(),
|
pprint_tokens(&expected)
|
||||||
Level::Error,
|
);
|
||||||
"unexpected end of macro",
|
quote! {
|
||||||
)
|
compile_error! { #msg }
|
||||||
.help(msg)
|
}
|
||||||
}
|
}
|
||||||
UnrecognizedToken {
|
UnrecognizedToken {
|
||||||
token: Some((_, token, _)),
|
token: Some((_, token, _)),
|
||||||
expected,
|
expected,
|
||||||
} => {
|
} => {
|
||||||
let msg = format!("expected {}", pprint_tokens(&expected));
|
let span = token.span();
|
||||||
let mut diag = Diagnostic::spanned(token.span().unstable(), Level::Error, msg);
|
let error_msg = format!("expected {}", pprint_tokens(&expected));
|
||||||
if is_in_node_position(expected) && token.is_ident() {
|
let error = quote_spanned! {span=>
|
||||||
|
compile_error! { #error_msg }
|
||||||
|
};
|
||||||
|
let help = if is_in_node_position(expected) && token.is_ident() {
|
||||||
// special case: you probably meant to quote that text
|
// special case: you probably meant to quote that text
|
||||||
diag = diag.help(format!(
|
let help_msg = format!(
|
||||||
"text nodes need to be quoted, eg. {}",
|
"text nodes need to be quoted, eg. {}",
|
||||||
Style::new().bold().paint("<p>\"Hello Joe!\"</p>")
|
Style::new().bold().paint("<p>\"Hello Joe!\"</p>")
|
||||||
))
|
);
|
||||||
}
|
Some(quote_spanned! {span=>
|
||||||
diag
|
compile_error! { #help_msg }
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
quote! {{
|
||||||
|
#error
|
||||||
|
#help
|
||||||
|
}}
|
||||||
}
|
}
|
||||||
ExtraToken {
|
ExtraToken {
|
||||||
token: (_, token, _),
|
token: (_, token, _),
|
||||||
} => Diagnostic::spanned(token.span().unstable(), Level::Error, "superfluous token"),
|
} => {
|
||||||
|
let span = token.span();
|
||||||
|
quote_spanned! {span=>
|
||||||
|
compile_error! { "superfluous token" }
|
||||||
|
}
|
||||||
|
}
|
||||||
User {
|
User {
|
||||||
error: HtmlParseError::TagMismatch { open, close },
|
error: HtmlParseError::TagMismatch { open, close },
|
||||||
} => Diagnostic::spanned(
|
} => {
|
||||||
close.span().unstable(),
|
let close_span = close.span();
|
||||||
Level::Error,
|
let close_msg = format!("expected closing tag '</{}>', found '</{}>'", open, close);
|
||||||
format!("expected closing tag '</{}>', found '</{}>'", open, close),
|
let close_error = quote_spanned! {close_span=>
|
||||||
)
|
compile_error! { #close_msg }
|
||||||
.span_help(open.span().unstable(), "opening tag is here:"),
|
};
|
||||||
|
let open_span = open.span();
|
||||||
|
let open_error = quote_spanned! {open_span=>
|
||||||
|
compile_error! { "unclosed tag" }
|
||||||
|
};
|
||||||
|
quote! {{
|
||||||
|
#close_error
|
||||||
|
#open_error
|
||||||
|
}}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use proc_macro::{Diagnostic, Level};
|
|
||||||
use proc_macro2::{Delimiter, Group, Ident, Literal, TokenStream, TokenTree};
|
use proc_macro2::{Delimiter, Group, Ident, Literal, TokenStream, TokenTree};
|
||||||
use quote::quote;
|
use quote::{quote, quote_spanned};
|
||||||
|
|
||||||
use config::{required_children, ATTR_EVENTS};
|
use config::{required_children, ATTR_EVENTS};
|
||||||
use error::ParseError;
|
use error::ParseError;
|
||||||
|
@ -19,38 +18,38 @@ pub enum Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Node {
|
impl Node {
|
||||||
pub fn into_token_stream(self) -> TokenStream {
|
pub fn into_token_stream(self) -> Result<TokenStream, TokenStream> {
|
||||||
match self {
|
match self {
|
||||||
Node::Element(el) => el.into_token_stream(),
|
Node::Element(el) => el.into_token_stream(),
|
||||||
Node::Text(text) => {
|
Node::Text(text) => {
|
||||||
let text = TokenTree::Literal(text);
|
let text = TokenTree::Literal(text);
|
||||||
quote!(Box::new(typed_html::dom::TextNode::new(#text.to_string())))
|
Ok(quote!(Box::new(typed_html::dom::TextNode::new(#text.to_string()))))
|
||||||
}
|
}
|
||||||
Node::Block(_) => panic!("cannot have a block in this position"),
|
Node::Block(_) => panic!("cannot have a block in this position"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_child_stream(self) -> TokenStream {
|
fn into_child_stream(self) -> Result<TokenStream, TokenStream> {
|
||||||
match self {
|
match self {
|
||||||
Node::Element(el) => {
|
Node::Element(el) => {
|
||||||
let el = el.into_token_stream();
|
let el = el.into_token_stream()?;
|
||||||
quote!(
|
Ok(quote!(
|
||||||
element.children.push(#el);
|
element.children.push(#el);
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
tx @ Node::Text(_) => {
|
tx @ Node::Text(_) => {
|
||||||
let tx = tx.into_token_stream();
|
let tx = tx.into_token_stream()?;
|
||||||
quote!(
|
Ok(quote!(
|
||||||
element.children.push(#tx);
|
element.children.push(#tx);
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
Node::Block(group) => {
|
Node::Block(group) => {
|
||||||
let group: TokenTree = group.into();
|
let group: TokenTree = group.into();
|
||||||
quote!(
|
Ok(quote!(
|
||||||
for child in #group.into_iter() {
|
for child in #group.into_iter() {
|
||||||
element.children.push(child);
|
element.children.push(child);
|
||||||
}
|
}
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,24 +115,22 @@ fn is_string_literal(literal: &Literal) -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Element {
|
impl Element {
|
||||||
fn into_token_stream(mut self) -> TokenStream {
|
fn into_token_stream(mut self) -> Result<TokenStream, TokenStream> {
|
||||||
let name = self.name;
|
let name = self.name;
|
||||||
let name_str = name.to_string();
|
let name_str = name.to_string();
|
||||||
let typename: TokenTree = Ident::new(&name_str, name.span()).into();
|
let typename: TokenTree = Ident::new(&name_str, name.span()).into();
|
||||||
let req_names = required_children(&name_str);
|
let req_names = required_children(&name_str);
|
||||||
if req_names.len() > self.children.len() {
|
if req_names.len() > self.children.len() {
|
||||||
Diagnostic::spanned(
|
let span = name.span();
|
||||||
name.span().unstable(),
|
let error = format!(
|
||||||
Level::Error,
|
|
||||||
format!(
|
|
||||||
"<{}> requires {} children but there are only {}",
|
"<{}> requires {} children but there are only {}",
|
||||||
name_str,
|
name_str,
|
||||||
req_names.len(),
|
req_names.len(),
|
||||||
self.children.len()
|
self.children.len()
|
||||||
),
|
);
|
||||||
)
|
return Err(quote_spanned! {span=>
|
||||||
.emit();
|
compile_error! { #error }
|
||||||
panic!();
|
});
|
||||||
}
|
}
|
||||||
let events = extract_event_handlers(&mut self.attributes);
|
let events = extract_event_handlers(&mut self.attributes);
|
||||||
let data_attrs = extract_data_attrs(&mut self.attributes);
|
let data_attrs = extract_data_attrs(&mut self.attributes);
|
||||||
|
@ -148,8 +145,13 @@ impl Element {
|
||||||
.children
|
.children
|
||||||
.split_off(req_names.len())
|
.split_off(req_names.len())
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(Node::into_child_stream);
|
.map(Node::into_child_stream)
|
||||||
let req_children = self.children.into_iter().map(Node::into_token_stream);
|
.collect::<Result<Vec<TokenStream>, TokenStream>>()?;
|
||||||
|
let req_children = self
|
||||||
|
.children
|
||||||
|
.into_iter()
|
||||||
|
.map(Node::into_token_stream)
|
||||||
|
.collect::<Result<Vec<TokenStream>, TokenStream>>()?;
|
||||||
|
|
||||||
let mut body = TokenStream::new();
|
let mut body = TokenStream::new();
|
||||||
for (attr_str, key, value) in attrs {
|
for (attr_str, key, value) in attrs {
|
||||||
|
@ -205,13 +207,13 @@ impl Element {
|
||||||
args.extend(quote!( #arg, ));
|
args.extend(quote!( #arg, ));
|
||||||
}
|
}
|
||||||
|
|
||||||
quote!(
|
Ok(quote!(
|
||||||
{
|
{
|
||||||
let mut element = typed_html::elements::#typename::new(#args);
|
let mut element = typed_html::elements::#typename::new(#args);
|
||||||
#body
|
#body
|
||||||
Box::new(element)
|
Box::new(element)
|
||||||
}
|
}
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#![recursion_limit = "128"]
|
#![recursion_limit = "128"]
|
||||||
#![feature(proc_macro_hygiene)]
|
#![feature(proc_macro_hygiene)]
|
||||||
#![feature(proc_macro_span)]
|
#![feature(proc_macro_span)]
|
||||||
#![feature(proc_macro_diagnostic)]
|
|
||||||
|
|
||||||
extern crate ansi_term;
|
extern crate ansi_term;
|
||||||
extern crate lalrpop_util;
|
extern crate lalrpop_util;
|
||||||
|
@ -10,7 +9,6 @@ extern crate proc_macro2;
|
||||||
extern crate quote;
|
extern crate quote;
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::quote;
|
|
||||||
|
|
||||||
mod config;
|
mod config;
|
||||||
mod declare;
|
mod declare;
|
||||||
|
@ -32,11 +30,11 @@ pub fn html(input: TokenStream) -> TokenStream {
|
||||||
let stream = lexer::unroll_stream(input.into(), false);
|
let stream = lexer::unroll_stream(input.into(), false);
|
||||||
let result = html::expand_html(&stream);
|
let result = html::expand_html(&stream);
|
||||||
TokenStream::from(match result {
|
TokenStream::from(match result {
|
||||||
Err(err) => {
|
Err(err) => error::parse_error(&stream, &err),
|
||||||
error::parse_error(&stream, &err).emit();
|
Ok(node) => match node.into_token_stream() {
|
||||||
quote!(panic!())
|
Err(err) => err,
|
||||||
}
|
Ok(success) => success,
|
||||||
Ok(node) => node.into_token_stream(),
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,10 +45,7 @@ pub fn declare_elements(input: TokenStream) -> TokenStream {
|
||||||
let stream = lexer::keywordise(lexer::unroll_stream(input.into(), true));
|
let stream = lexer::keywordise(lexer::unroll_stream(input.into(), true));
|
||||||
let result = declare::expand_declare(&stream);
|
let result = declare::expand_declare(&stream);
|
||||||
TokenStream::from(match result {
|
TokenStream::from(match result {
|
||||||
Err(err) => {
|
Err(err) => error::parse_error(&stream, &err),
|
||||||
error::parse_error(&stream, &err).emit();
|
|
||||||
quote!(panic!())
|
|
||||||
}
|
|
||||||
Ok(decls) => {
|
Ok(decls) => {
|
||||||
let mut out = proc_macro2::TokenStream::new();
|
let mut out = proc_macro2::TokenStream::new();
|
||||||
for decl in decls {
|
for decl in decls {
|
||||||
|
|
Loading…
Reference in New Issue