Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom keywords #481

Merged
merged 2 commits into from
Sep 6, 2018
Merged

Custom keywords #481

merged 2 commits into from
Sep 6, 2018

Conversation

dtolnay
Copy link
Owner

@dtolnay dtolnay commented Sep 6, 2018

This is just some additional design and polish atop @kureuil's work in #480. Copied from documentation:


macro_rules! custom_keyword {
    ($ident:ident) => { ... };
}

Define a type that supports parsing and printing a given identifier as if it were a keyword.

Usage

As a convention, it is recommended that this macro be invoked within a module called kw and that the resulting parser be invoked with a kw:: prefix.

mod kw {
    syn::custom_keyword!(whatever);
}

The generated syntax tree node supports the following operations just like any built-in keyword token.

  • Peekinginput.peek(kw::whatever)

  • Parsinginput.parse::<kw::whatever>()?

  • Printingquote!( ... #whatever_token ... )

  • Construction from a Spanlet whatever_token = kw::whatever(sp)

  • Field access to its span — let sp = whatever_token.span

Example

This example parses input that looks like bool = true or str = "value". The key must be either the identifier bool or the identifier str. If bool, the value may be either true or false. If str, the value may be any string literal.

The symbols bool and str are not reserved keywords in Rust so these are not considered keywords in the syn::token module. Like any other identifier that is not a keyword, these can be declared as custom keywords by crates that need to use them as such.

use syn::{LitBool, LitStr, Token};
use syn::parse::{Parse, ParseStream, Result};

mod kw {
    syn::custom_keyword!(bool);
    syn::custom_keyword!(str);
}

enum Argument {
    Bool {
        bool_token: kw::bool,
        eq_token: Token![=],
        value: LitBool,
    },
    Str {
        str_token: kw::str,
        eq_token: Token![=],
        value: LitStr,
    },
}

impl Parse for Argument {
    fn parse(input: ParseStream) -> Result<Self> {
        let lookahead = input.lookahead1();
        if lookahead.peek(kw::bool) {
            Ok(Argument::Bool {
                bool_token: input.parse::<kw::bool>()?,
                eq_token: input.parse()?,
                value: input.parse()?,
            })
        } else if lookahead.peek(kw::str) {
            Ok(Argument::Str {
                str_token: input.parse::<kw::str>()?,
                eq_token: input.parse()?,
                value: input.parse()?,
            })
        } else {
            Err(lookahead.error())
        }
    }
}

kureuil and others added 2 commits September 5, 2018 00:51
First prototype for support of custom keywords with syn's new parsing
API. Documentation and tests aren't present for now as I'm mainly
reaching for feedback.

This patch introduces a new Keyword trait, a new macro custom_keyword!
and exposes the existing TokenMarker enum. The Keyword trait
automatically implements the Token trait, making it possible to peek on
custom keywords (this is why I had to make TokenMarker public).

The custom macro generates a structure storing an Ident and implementing
the Keyword and Parse traits. A function with the same name as the
structure is also generated in order to use it like any predefined
keyword.
@dtolnay dtolnay merged commit 97cf49d into next Sep 6, 2018
@dtolnay dtolnay deleted the custom branch September 6, 2018 09:07
@dtolnay dtolnay mentioned this pull request Sep 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants