From e381c02ef304fdeafde1c94afd1a10c2085ab716 Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Thu, 30 Jul 2020 14:06:04 +0200
Subject: Add comma list to use tree

---
 xtask/src/codegen/gen_syntax.rs | 35 +++++++++++++++++++++++++++++++++++
 xtask/src/codegen/rust.ungram   | 25 +++++++++++++------------
 2 files changed, 48 insertions(+), 12 deletions(-)

(limited to 'xtask')

diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs
index 9b49712c1..c77fc8a8d 100644
--- a/xtask/src/codegen/gen_syntax.rs
+++ b/xtask/src/codegen/gen_syntax.rs
@@ -543,6 +543,10 @@ fn lower_enum(grammar: &Grammar, rule: &Rule) -> Option<Vec<String>> {
 }
 
 fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, rule: &Rule) {
+    if lower_comma_list(acc, grammar, rule) {
+        return;
+    }
+
     match rule {
         Rule::Node(node) => {
             let field = Field::Node { name: grammar[*node].name.clone(), src: FieldSrc::Shorthand };
@@ -595,6 +599,37 @@ fn lower_rule(acc: &mut Vec<Field>, grammar: &Grammar, rule: &Rule) {
     }
 }
 
+// (T (',' T)* ','?)?
+fn lower_comma_list(acc: &mut Vec<Field>, grammar: &Grammar, rule: &Rule) -> bool {
+    let rule = match rule {
+        Rule::Opt(it) => it,
+        _ => return false,
+    };
+    let rule = match &**rule {
+        Rule::Seq(it) => it,
+        _ => return false,
+    };
+    let (node, repeat, trailing_comma) = match rule.as_slice() {
+        [Rule::Node(node), Rule::Rep(repeat), Rule::Opt(trailing_comma)] => {
+            (node, repeat, trailing_comma)
+        }
+        _ => return false,
+    };
+    let repeat = match &**repeat {
+        Rule::Seq(it) => it,
+        _ => return false,
+    };
+    match repeat.as_slice() {
+        [comma, Rule::Node(n)] if comma == &**trailing_comma && n == node => (),
+        _ => return false,
+    }
+    let name = grammar[*node].name.clone();
+    let label = pluralize(&to_lower_snake_case(&name));
+    let field = Field::Node { name: label.clone(), src: FieldSrc::Many(name) };
+    acc.push(field);
+    true
+}
+
 fn deduplicate_fields(ast: &mut AstSrc) {
     for node in &mut ast.nodes {
         let mut i = 0;
diff --git a/xtask/src/codegen/rust.ungram b/xtask/src/codegen/rust.ungram
index e6e7c7518..2ba68457f 100644
--- a/xtask/src/codegen/rust.ungram
+++ b/xtask/src/codegen/rust.ungram
@@ -29,6 +29,19 @@ ItemList =
 ExternCrate =
   Attr* Visibility? 'extern' 'crate' (NameRef | 'self') Rename? ';'
 
+Rename =
+  'as' (Name | '_')
+
+UseItem =
+  Attr* Visibility? 'use' UseTree ';'
+
+UseTree =
+  (Path? '::')? ('*' | UseTreeList )
+| Path Rename?
+
+UseTreeList =
+  '{' (UseTree (',' UseTree)* ','?)? '}'
+
 FnDef =
  Attr* Visibility? Abi? 'const' 'default' 'async' 'unsafe' 'fn' Name TypeParamList?
  ParamList RetType?
@@ -395,18 +408,6 @@ Param =
   Attr* Pat (':' ascribed_type:TypeRef)
 | '...'
 
-UseItem =
-  Attr* Visibility? 'use' UseTree ';'
-
-UseTree =
-  Path ('::' ('*' | UseTreeList))  Rename?
-
-UseTreeList =
-  '{' UseTree* '}'
-
-Rename =
-  'as' Name
-
 Path =
   (qualifier:Path '::')? segment:PathSegment
 
-- 
cgit v1.2.3