Skip to content

Commit 014f317

Browse files
committed
Allow generic args when calling a rule
Fixes #396
1 parent 4928a1e commit 014f317

File tree

6 files changed

+218
-12
lines changed

6 files changed

+218
-12
lines changed

peg-macros/analysis.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ impl<'a> LeftRecursionVisitor<'a> {
8686
fn walk_expr(&mut self, this_expr: &SpannedExpr) -> bool {
8787
use self::Expr::*;
8888
match this_expr.expr {
89-
RuleExpr(ref rule_ident, _) => {
89+
RuleExpr(ref rule_ident, _, _) => {
9090
let name = rule_ident.to_string();
9191

9292
if let Some(rule) = self.rules.get(&name) {
@@ -221,7 +221,7 @@ impl<'a> LoopNullabilityVisitor<'a> {
221221
fn walk_expr(&mut self, this_expr: &SpannedExpr) -> bool {
222222
use self::Expr::*;
223223
match this_expr.expr {
224-
RuleExpr(ref rule_ident, _) => {
224+
RuleExpr(ref rule_ident, _, _) => {
225225
let name = rule_ident.to_string();
226226
*self.rule_nullability.get(&name).unwrap_or(&false)
227227
}

peg-macros/ast.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub struct SpannedExpr {
7474
pub enum Expr {
7575
LiteralExpr(Literal),
7676
PatternExpr(Group),
77-
RuleExpr(Ident, Vec<RuleArg>),
77+
RuleExpr(Ident, Option<TokenStream>, Vec<RuleArg>),
7878
MethodExpr(Ident, TokenStream),
7979
CustomExpr(Group),
8080
ChoiceExpr(Vec<SpannedExpr>),

peg-macros/grammar.rs

+188-2
Large diffs are not rendered by default.

peg-macros/grammar.rustpeg

+6-3
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ rule rust_type()
6565
/ ("<" rust_type() ("as" rust_ty_path())? ">")? rust_ty_path()
6666

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

7070
rule rust_ty_params() -> Vec<TokenStream>
7171
= "<" p:($(rust_generic_param()) ++ ",") ","? ">" { p }
@@ -88,6 +88,9 @@ rule rust_ty_param_bound()
8888
/ "?"? rust_for_lifetimes()? rust_ty_path()
8989
/ "(" "?"? rust_for_lifetimes()? rust_ty_path() ")"
9090

91+
rule rust_generic_args()
92+
= "<" (LIFETIME() / rust_type() / BRACE_GROUP() / LITERAL()) ++ "," ","? ">"
93+
9194
rule expression() -> SpannedExpr = choice()
9295

9396
rule choice() -> SpannedExpr = sp:sp() s:sequence() ++ "/" {
@@ -140,8 +143,8 @@ rule primary() -> SpannedExpr
140143
/ sp:sp() "position" "!" "(" ")" { PositionExpr.at(sp) }
141144
/ sp:sp() "quiet" "!" "{" e:expression() "}" { QuietExpr(Box::new(e)).at(sp) }
142145
/ sp:sp() "expected" "!" s:PAREN_GROUP() { FailExpr(s).at(sp) }
143-
/ &("_" / "__" / "___") sp:sp() name:IDENT() { RuleExpr(name, Vec::new()).at(sp) }
144-
/ sp:sp() name:IDENT() "(" args:(rule_arg() ** ",") ")" { RuleExpr(name, args).at(sp) }
146+
/ &("_" / "__" / "___") sp:sp() name:IDENT() { RuleExpr(name, None, Vec::new()).at(sp) }
147+
/ sp:sp() name:IDENT() generics:$("::" rust_generic_args())? "(" args:(rule_arg() ** ",") ")" { RuleExpr(name, generics, args).at(sp) }
145148
/ sp:sp() l:LITERAL() { LiteralExpr(l).at(sp) }
146149
/ sp:sp() p:BRACKET_GROUP() { PatternExpr(p).at(sp) }
147150
/ "(" sp:sp() "@" ")" { MarkerExpr(true).at(sp) }

peg-macros/translate.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ fn compile_expr(context: &Context, e: &SpannedExpr, result_used: bool) -> TokenS
552552
)
553553
}
554554

555-
RuleExpr(ref rule_name, ref rule_args)
555+
RuleExpr(ref rule_name, ref generics, ref rule_args)
556556
if context.rules_from_args.contains(&rule_name.to_string()) =>
557557
{
558558
if !rule_args.is_empty() {
@@ -562,10 +562,17 @@ fn compile_expr(context: &Context, e: &SpannedExpr, result_used: bool) -> TokenS
562562
);
563563
}
564564

565+
if generics.is_some() {
566+
return report_error_expr(
567+
rule_name.span(),
568+
"rule closure cannot have generics".to_string()
569+
);
570+
}
571+
565572
quote_spanned! { span=> #rule_name(__input, __state, __err_state, __pos) }
566573
}
567574

568-
RuleExpr(ref rule_name, ref rule_args) => {
575+
RuleExpr(ref rule_name, ref generics, ref rule_args) => {
569576
let rule_name_str = rule_name.to_string();
570577

571578
let rule_def = if let Some(rule_def) = context.rules.get(&rule_name_str) {
@@ -611,10 +618,10 @@ fn compile_expr(context: &Context, e: &SpannedExpr, result_used: bool) -> TokenS
611618
.collect();
612619

613620
if result_used {
614-
quote_spanned! { span=> #func(__input, __state, __err_state, __pos #extra_args_call #(, #rule_args_call)*) }
621+
quote_spanned! { span=> #func #generics (__input, __state, __err_state, __pos #extra_args_call #(, #rule_args_call)*) }
615622
} else {
616623
quote_spanned! { span=>
617-
match #func(__input, __state, __err_state, __pos #extra_args_call #(, #rule_args_call)*){
624+
match #func #generics (__input, __state, __err_state, __pos #extra_args_call #(, #rule_args_call)*){
618625
::peg::RuleResult::Matched(pos, _) => ::peg::RuleResult::Matched(pos, ()),
619626
::peg::RuleResult::Failed => ::peg::RuleResult::Failed,
620627
}

tests/run-pass/rule_generic.rs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
peg::parser!( grammar test() for str {
2+
rule number<T: std::str::FromStr>() -> T = s:$(['0'..='9']+) {? s.parse().or(Err("number")) }
3+
4+
pub rule numbers() -> (u8, i32)
5+
= n1:number::<u8>() "," n2:number::<i32>() { (n1, n2) }
6+
});
7+
8+
fn main() {
9+
assert_eq!(test::numbers("42,1234"), Ok((42, 1234)));
10+
}

0 commit comments

Comments
 (0)