Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Spans

When parsing malformed input, simply stating what is wrong without indicating its location is not very helpful for debugging.

To provide precise error locations, we use Spans. A Span is an opaque value representing a specific range of source code. While they cannot be modified, they can be created or retrieved. Their primary purpose is error reporting, and every token carries an associated Span.

Example with Coarse-grained Spans

use syn::{
    parse::{Parse, ParseStream},
    *,
};

struct HtmlNode;
impl Parse for HtmlNode {
    fn parse(input: ParseStream) -> Result<Self> {
        input.parse::<Token![<]>()?;
        input.parse::<Ident>()?;
        input.parse::<Token![>]>()?;
        input.parse::<LitStr>()?;
        input.parse::<Token![<]>()?;
        input.parse::<Token![/]>()?;
        input.parse::<Ident>()?;
        input.parse::<Token![>]>()?;
        Ok(HtmlNode)
    }
}
fn main() {
    // `quote!` assigns the same span to all tokens inside the block.
    let input = quote::quote! {<div>"Hello World"<div>};
    if let Err(e) = syn::parse2::<HtmlNode>(input) {
        println!("Error: {} at {:?}", e, e.span());
    }
}

Example with Precise Spans

use std::str::FromStr;

use proc_macro2::TokenStream;
use syn::{
    parse::{Parse, ParseStream},
    *,
};

struct HtmlNode;
impl Parse for HtmlNode {
    fn parse(input: ParseStream) -> Result<Self> {
        input.parse::<Token![<]>()?;
        input.parse::<Ident>()?;
        input.parse::<Token![>]>()?;
        input.parse::<LitStr>()?;
        input.parse::<Token![<]>()?;
        input.parse::<Token![/]>()?;
        input.parse::<Ident>()?;
        input.parse::<Token![>]>()?;
        Ok(HtmlNode)
    }
}
fn main() {
    // `TokenStream::from_str` assigns a unique span to each individual token.
    let input = TokenStream::from_str(r#"<div>"Hello World"<div>"#).unwrap();
    if let Err(e) = syn::parse2::<HtmlNode>(input) {
        println!("Error: {} at {:?}", e, e.span());
    }
}