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 = "<" 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" "]" {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 = "(" 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 = $(("#" "[" "doc" "=" LITERAL() "]")*)? rule rust_visibility() -> Option = $("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 = "<" 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() }