peg-macros 0.8.4

Procedural macros for rust-peg. To use rust-peg, see the `peg` crate.
Documentation
pub grammar peg() for FlatTokenStream {

use crate::ast::*;
use crate::ast::Expr::*;
use crate::tokens::FlatTokenStream;
use proc_macro2::{ TokenStream, Ident, Group, Literal, Delimiter, Span };

pub rule peg_grammar() -> Grammar
    = doc:rust_doc_comment() visibility:rust_visibility() "grammar" name:IDENT() lifetime_params:rust_lifetime_params()? args:grammar_args() "for" input_type:$(rust_type()) "{" items:item()* "}"
        { Grammar { doc, visibility, name, lifetime_params, args, input_type, items } }

    rule rust_lifetime_params() -> Vec<TokenStream>
        = "<" p:(($(LIFETIME())) ++ ",") ","? ">" { p }

rule grammar_args() -> Vec<(Ident, TokenStream)>
    = "(" args:((i:IDENT() ":" t:$(rust_type()) { (i, t) })**",") ","? ")" { args }

rule peg_rule() -> Rule
    = doc:rust_doc_comment() cache:cacheflag() no_eof:no_eof_flag() visibility:rust_visibility()
      span:sp() "rule"
      header:(
          &("_" / "__" / "___") name:IDENT() ("(" ")")? { (name, None, Vec::new()) }
        / name:IDENT() ty_params:rust_ty_params()? params:rule_params() { (name, ty_params, params) }
      )
      ret_type:("->" t:$(rust_type()) {t})?
      where_clause:$(rust_where_clause())?
      "=" expr:expression() ";"?
        { Rule { span, doc, name:header.0, ty_params:header.1, params:header.2, expr, ret_type, where_clause, visibility, no_eof, cache } }

    rule cacheflag() -> Option<Cache> = "#" "[" "cache" "]" {Some(Cache::Simple)} / "#" "[" "cache_left_rec" "]" {Some(Cache::Recursive)} / {None}

    rule no_eof_flag() -> bool = "#" "[" "no_eof" "]" {true} / {false}

    rule rule_param_ty() -> RuleParamTy
        = "rule" "<" r:$(rust_type()) ">" { RuleParamTy::Rule(r) }
        / t:$(rust_type()) { RuleParamTy::Rust(t) }

    rule rule_params() -> Vec<RuleParam>
        = "(" params:(x:(name:IDENT() ":" ty:rule_param_ty() { RuleParam { name, ty} }) ++ "," ","? {x})? ")" { params.unwrap_or_default() }

rule item() -> Item
    = u:rust_use()     { Item::Use(u) }
    / r:peg_rule()     { Item::Rule(r) }

rule rust_doc_comment() -> Option<TokenStream> = $(("#" "[" "doc" "=" LITERAL() "]")*)?

rule rust_visibility() -> Option<TokenStream> = $("pub" PAREN_GROUP()?)?

rule rust_use() -> TokenStream
    = v:$("use" rust_path() (
        "::" "*"
        / "::" "{" ((IDENT() ("as" IDENT())?) ++ "," ","?) "}"
        / ("as" IDENT())?
    ) ";") { v.to_owned() }

rule rust_path()
    = ("crate" "::")? IDENT() ++ "::"

rule rust_type()
    = BRACKET_GROUP()
    / "&" LIFETIME()? "mut"? rust_type()
    / "dyn" rust_type() ++ "+"
    / "impl" rust_type() ++ "+"
    / "(" (rust_type() ++ "," ","?)? ")"
    / ("<" rust_type() ("as" rust_ty_path())? ">")? rust_ty_path()

rule rust_ty_path()
    = "::"? (IDENT() ("::"? ("<" (LIFETIME() / rust_type() / BRACE_GROUP() / LITERAL()) ++ "," ","? ">" / PAREN_GROUP() ("->" rust_type())?))?) ++ "::"

rule rust_ty_params() -> Vec<TokenStream>
    = "<" p:($(rust_generic_param()) ++ ",") ","? ">" { p }

rule rust_where_clause()
    = "where" (
        LIFETIME() (":" LIFETIME() ++ "+")?
        / ("for" rust_ty_params())? rust_type() ":" (LIFETIME() / "?"? rust_ty_path()) ++ "+"
    ) ** "," ","?

rule rust_generic_param()
    = LIFETIME() (":" LIFETIME() ++ "+")?
    / IDENT() (":"(LIFETIME() / "?"? rust_ty_path()) ++ "+")?

rule expression() -> SpannedExpr = choice()

rule choice() -> SpannedExpr = sp:sp() s:sequence() ++ "/" {
    if s.len() == 1 {
        s.into_iter().next().unwrap()
    } else {
        ChoiceExpr(s).at(sp)
    }
}

rule sequence() -> SpannedExpr
    = sp:sp() elements:labeled()* code:BRACE_GROUP()? {
        if let Some(code) = code {
            ActionExpr(elements, Some(code)).at(sp)
        } else if elements.len() != 1 {
            ActionExpr(elements, None).at(sp)
        } else {
            elements.into_iter().next().unwrap().expr
        }
    }

rule labeled() -> TaggedExpr
    = label:(l:IDENT() ":" {l})? expression:suffixed()
        { TaggedExpr{ name: label, expr: expression } }

rule suffixed() -> SpannedExpr
    = e:prefixed() sp:sp() "?" { OptionalExpr(Box::new(e)).at(sp) }
    / e:prefixed() sp:sp() "**" count:repeatcount() sep:primary() { Repeat { inner: Box::new(e), bound: count, sep: Some(Box::new(sep)) }.at(sp) }
    / e:prefixed() sp:sp() "++" sep:primary() { Repeat { inner: Box::new(e), bound: BoundedRepeat::Plus, sep: Some(Box::new(sep)) }.at(sp )}
    / e:prefixed() sp:sp() "*" count:repeatcount() { Repeat { inner: Box::new(e), bound: count, sep: None }.at(sp) }
    / e:prefixed() sp:sp() "+" { Repeat { inner: Box::new(e), bound: BoundedRepeat::Plus, sep: None }.at(sp) }
    / prefixed()

rule repeatcount() -> BoundedRepeat
    = "<" n:repeatnum() ">" { BoundedRepeat::Exact(n) }
    / "<" min:repeatnum()? "," max:repeatnum()? ">" { BoundedRepeat::Both(min, max) }
    / { BoundedRepeat::None }

rule repeatnum() -> TokenStream = $(INTEGER() / BRACE_GROUP())

rule prefixed() -> SpannedExpr
    = sp:sp() "$" expression:primary() { MatchStrExpr(Box::new(expression)).at(sp) }
    / sp:sp() "&" expression:primary() { PosAssertExpr(Box::new(expression)).at(sp) }
    / sp:sp() "!" expression:primary() { NegAssertExpr(Box::new(expression)).at(sp) }
    / primary()

#[cache]
rule primary() -> SpannedExpr
  = sp:sp() "precedence" "!" "{" levels:precedence_level()**"--" "}" { PrecedenceExpr{ levels:levels }.at(sp) }
  / sp:sp() "position" "!" "(" ")" { PositionExpr.at(sp) }
  / sp:sp() "quiet" "!" "{" e:expression() "}" { QuietExpr(Box::new(e)).at(sp) }
  / sp:sp() "expected" "!" s:PAREN_GROUP() { FailExpr(s).at(sp) }
  / &("_" / "__" / "___") sp:sp() name:IDENT() { RuleExpr(name, Vec::new()).at(sp) }
  / sp:sp() name:IDENT() "(" args:(rule_arg() ** ",") ")" { RuleExpr(name, args).at(sp) }
  / sp:sp() l:LITERAL() { LiteralExpr(l).at(sp) }
  / sp:sp() p:BRACKET_GROUP() { PatternExpr(p).at(sp) }
  / "(" sp:sp() "@" ")" { MarkerExpr(true).at(sp) }
  / sp:sp() "@" { MarkerExpr(false).at(sp) }
  / sp:sp() "##" method:IDENT() args:PAREN_GROUP() { MethodExpr(method, args.stream()).at(sp) }
  / "(" expression:expression() ")" { expression }

    rule rule_arg() -> RuleArg
        = "<" e:expression() ">" { RuleArg::Peg(e) }
        / tt:$( ##eat_until(',')+ ) { RuleArg::Rust(tt) }

rule precedence_level() -> PrecedenceLevel
  = operators:precedence_op()+
  { PrecedenceLevel{ operators: operators } }

rule precedence_op() -> PrecedenceOperator
  = span:sp() elements:labeled()* action:BRACE_GROUP()
  { PrecedenceOperator{ span, elements, action } }

rule sp() -> Span = ##next_span()
rule KEYWORD() = "pub" / "rule" / "use" / "type" / "where"
rule IDENT() -> Ident = !KEYWORD() i:##ident() {i}
rule LITERAL() -> Literal = ##literal()
rule PAREN_GROUP()   -> Group = ##group(Delimiter::Parenthesis)
rule BRACE_GROUP()   -> Group = ##group(Delimiter::Brace)
rule BRACKET_GROUP() -> Group = ##group(Delimiter::Bracket)
rule LIFETIME() = "'" IDENT()
rule INTEGER() = LITERAL()

}