Macro gramma::define_rule

source ·
macro_rules! define_rule {
    ($(
        $(#$attr:tt)*
        $vis:vis struct $Name:ident {
            $(
                $(#$field_attr:tt)*
                $field_vis:vis $field:ident
            ),* $(,)?
        }
    )*) => { ... };
    ($(
        $(#$attr:tt)*
        $vis:vis enum $Name:ident {
            $(
                $(#$variant_attr:tt)*
                $Variant:ident {
                    $(
                        $(#$field_attr:tt)*
                        $field_vis:vis $field:ident
                    ),* $(,)?
                }
            ),* $(,)?
        }
    )*) => { ... };
    ($(
        $(#$attr:tt)*
        $vis:vis $kind:ident $Name:ident { $($x:tt)* }
    )*) => { ... };
}
Expand description

Define AST rules by declaring structs and enums.

§Basic Example

// Define Ident, LParen, RParen, Whitespace here:
gramma::define_token! {
    /* ... */
}
gramma::define_rule! {
 struct Group {
     l_paren: LParen,
     exprs: Vec<Expr>,
     r_paren: RParen,
 }
 // Enum rules may only have struct-like variants:
 #[transform(ignore_around<Whitespace>)]
 enum Expr {
     Group { group: Group },
     Ident { ident: Ident },
 }
}

let src = "
(list
    (add a b)
    (mul (sub c d) e)
)
";

let expr: Expr = gramma::parse_tree::<_, 1>(src).unwrap();

let display = format!("{:#}", gramma::display_tree(src, &expr));
assert_eq!(display, r#"Group -> {
    "(",
    [
        <Ident "list">,
        Group -> {
            "(",
            [
                <Ident "add">,
                <Ident "a">,
                <Ident "b">,
            ],
            ")",
        },
        Group -> {
            "(",
            [
                <Ident "mul">,
                Group -> {
                    "(",
                    [
                        <Ident "sub">,
                        <Ident "c">,
                        <Ident "d">,
                    ],
                    ")",
                },
                <Ident "e">,
            ],
            ")",
        },
    ],
    ")",
}"#);

§Transformations

In the example above, Expr was given the attribute #[transform(ignore_around<Whitespace>)]. Transformations, denoted by the #[transform(...)] attribute, modify the way a rule is parsed. All built-in transformations are declared as types in the ast::transform module. Some of the more common transformations are:

TransformationDescription

ignore_before<S>

Parse an optional S before the target rule and discard the result if found. Useful for ignoring optional whitespace before the target rule.

ignore_after<S>

Parse an optional S after the target rule and discard the result if found. Useful for ignoring optional whitespace after the target rule.

ignore_around<S1, S2 = S1>

Parse an optional S1 before and S2 after the target rule and discard the results if found. Useful for ignoring optional whitespace around the target rule.

discard_before<S>

Parse a required S before the target rule and discard the result. Useful for matching punctuation before the target rule.

discard_after<S>

Parse a required S after the target rule and discard the result. Useful for matching punctuation after the target rule.

discard_around<S1, S2 = S1>

Parse a required S1 before and S2 after the target rule and discard the results. Useful for matching punctuation around the target rule.

not<Invalid>

Rejects if the section matched by the target rule starts with Invalid.

for_each<X>

Apply the transformation X to each item in the target rule. Useful when matching a Vec of rules.

A #[transform(...)] can be applied to the entirety of a struct or enum rule, an enum variant, or an individual field.