macro: improve error output

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2019-07-31 15:42:05 +02:00
parent 3a36ff78df
commit ef13b38632
2 changed files with 49 additions and 29 deletions

View File

@ -50,33 +50,38 @@ pub fn optional_visibility(tokens: &mut TokenIter) -> Result<syn::Visibility, Er
return Ok(parser.parse2(visibility)?);
}
pub fn match_keyword(tokens: &mut TokenIter, keyword: &'static str) -> Result<(), Error> {
pub fn match_keyword(
span: Span,
tokens: &mut TokenIter,
keyword: &'static str,
) -> Result<Span, Error> {
if let Some(tt) = tokens.next() {
if let TokenTree::Ident(ident) = tt {
if ident.to_string() == keyword {
return Ok(());
return Ok(ident.span());
}
}
}
bail!("expected `{}` keyword", keyword);
c_bail!(span, "expected `{}` keyword", keyword);
}
pub fn need_ident(tokens: &mut TokenIter) -> Result<Ident, Error> {
pub fn need_ident(before: Span, tokens: &mut TokenIter) -> Result<Ident, Error> {
match tokens.next() {
Some(TokenTree::Ident(ident)) => Ok(ident),
other => bail!("expected ident: {:?}", other),
Some(other) => c_bail!(other.span(), "expected ident"),
None => c_bail!(before, "expected ident after this expression"),
}
}
pub fn match_punct(tokens: &mut TokenIter, punct: char) -> Result<(), Error> {
pub fn match_punct(span: Span, tokens: &mut TokenIter, punct: char) -> Result<Span, Error> {
if let Some(tt) = tokens.next() {
if let TokenTree::Punct(p) = tt {
if p.as_char() == punct {
return Ok(());
return Ok(p.span());
}
}
}
bail!("expected `{}`", punct);
c_bail!(span, "expected `{}` after this expression", punct);
}
pub fn need_group(tokens: &mut TokenIter, delimiter: Delimiter) -> Result<Group, Error> {
@ -91,11 +96,19 @@ pub fn need_group(tokens: &mut TokenIter, delimiter: Delimiter) -> Result<Group,
pub fn match_colon(tokens: &mut TokenIter) -> Result<(), Error> {
match tokens.next() {
Some(TokenTree::Punct(ref punct)) if punct.as_char() == ':' => Ok(()),
Some(other) => bail!("expected colon at {:?}", other.span()),
Some(other) => c_bail!(other.span(), "expected colon"),
None => bail!("colon expected"),
}
}
pub fn match_colon2(span: Span, tokens: &mut TokenIter) -> Result<Span, Error> {
match tokens.next() {
Some(TokenTree::Punct(ref punct)) if punct.as_char() == ':' => Ok(punct.span()),
Some(other) => c_bail!(other.span(), "expected colon"),
None => c_bail!(span, "colon expected following this expression"),
}
}
pub fn maybe_comma(tokens: &mut TokenIter) -> Result<bool, Error> {
match tokens.next() {
Some(TokenTree::Punct(ref punct)) if punct.as_char() == ',' => Ok(true),
@ -119,8 +132,8 @@ pub fn comma_or_end(tokens: &mut TokenIter) -> Result<(), Error> {
Ok(())
}
pub fn need_hyphenated_name(tokens: &mut TokenIter) -> Result<syn::LitStr, Error> {
let start = need_ident(&mut *tokens)?;
pub fn need_hyphenated_name(span: Span, tokens: &mut TokenIter) -> Result<syn::LitStr, Error> {
let start = need_ident(span, &mut *tokens)?;
finish_hyphenated_name(&mut *tokens, start)
}
@ -313,12 +326,13 @@ pub fn parse_object(tokens: TokenStream) -> Result<Object, Error> {
}
fn parse_object_key(tokens: &mut TokenIter) -> Result<Option<Name>, Error> {
if tokens.peek().is_none() {
return Ok(None);
}
let span = match tokens.peek() {
Some(ref val) => val.span(),
None => return Ok(None),
};
let key = need_ident_or_string(&mut *tokens)?;
match_colon(&mut *tokens)?;
match_colon2(span, &mut *tokens)?;
Ok(Some(key))
}

View File

@ -14,23 +14,26 @@ pub fn router_macro(input: TokenStream) -> Result<TokenStream, Error> {
let mut out = TokenStream::new();
loop {
if input.peek().is_none() {
break;
}
let mut at_span = match input.peek() {
Some(ref val) => val.span(),
None => break,
};
let public = optional_visibility(&mut input)?;
match_keyword(&mut input, "static")?;
let router_name = need_ident(&mut input)?;
at_span = match_keyword(at_span, &mut input, "static")?;
let router_name = need_ident(at_span, &mut input)?;
match_colon(&mut input)?;
match_keyword(&mut input, "Router")?;
match_punct(&mut input, '<')?;
let body_type = need_ident(&mut input)?;
match_punct(&mut input, '>')?;
at_span = match_colon2(router_name.span(), &mut input)?;
at_span = match_keyword(at_span, &mut input, "Router")?;
at_span = match_punct(at_span, &mut input, '<')?;
let body_type = need_ident(at_span, &mut input)?;
at_span = match_punct(body_type.span(), &mut input, '>')?;
match_punct(&mut input, '=')?;
at_span = match_punct(at_span, &mut input, '=')?;
let content = need_group(&mut input, Delimiter::Brace)?;
let _ = at_span;
at_span = content.span();
let router = parse_router(content.stream().into_iter().peekable())?;
let router = router.into_token_stream(&body_type, Some((router_name, public)));
@ -39,7 +42,7 @@ pub fn router_macro(input: TokenStream) -> Result<TokenStream, Error> {
out.extend(router);
match_punct(&mut input, ';')?;
match_punct(at_span, &mut input, ';')?;
}
Ok(out)
@ -270,7 +273,7 @@ fn parse_router(mut input: TokenIter) -> Result<Router, Error> {
loop {
match parse_entry_key(&mut input)? {
Some(Entry::Method(name)) => {
let function = need_ident(&mut input)?;
let function = need_ident(name.span(), &mut input)?;
let method_ptr = match name.to_string().as_str() {
"GET" => &mut router.get,
@ -334,7 +337,10 @@ fn parse_path_name(tokens: &mut TokenIter) -> Result<Path, Error> {
if group.delimiter() != Delimiter::Brace {
bail!("invalid path component: {:?}", group);
}
let name = need_hyphenated_name(&mut group.stream().into_iter().peekable())?;
let name = need_hyphenated_name(
group.span(),
&mut group.stream().into_iter().peekable(),
)?;
push_component(&mut path, &mut component, &mut span);
path.push(Component::Match(name));