Bug 1454744 - Part 1: Allow BinSource generator to place code after parsing interface sum branches. (r=Yoric)
authorEric Faust <efaustbmo@gmail.com>
Mon, 30 Apr 2018 20:45:34 -0700
changeset 472507 42c4d4acfba5d5c07e9f95c61c737b626d37c994
parent 472506 9bf70e179625ca212595e8fe8cd51b237fe99039
child 472508 02e7d188fd568150be6629adf95a06363dfd6560
push id1728
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:12:27 +0000
treeherdermozilla-release@c296fde26f5f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersYoric
bugs1454744
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1454744 - Part 1: Allow BinSource generator to place code after parsing interface sum branches. (r=Yoric)
js/src/frontend/binsource/src/main.rs
--- a/js/src/frontend/binsource/src/main.rs
+++ b/js/src/frontend/binsource/src/main.rs
@@ -41,16 +41,22 @@ struct FieldRules {
     /// putting guard values on the stack.
     block_before_field: Option<String>,
 
     /// Things to add before the field, as part of a block, typically for
     /// cleanup.
     block_after_field: Option<String>,
 }
 
+#[derive(Clone, Default)]
+struct SumRules {
+    after_arm: Option<String>,
+}
+
+
 /// Rules for generating the code for parsing a full node
 /// of a node.
 ///
 /// Extracted from the yaml file.
 #[derive(Clone, Default)]
 struct NodeRules {
     /// This node inherits from another node.
     inherits: Option<NodeName>,
@@ -62,16 +68,18 @@ struct NodeRules {
     init: Option<String>,
 
     /// How to append to a list. Used only for lists.
     append: Option<String>,
 
     /// Custom per-field treatment. Used only for interfaces.
     by_field: HashMap<FieldName, FieldRules>,
 
+    by_sum: HashMap<NodeName, SumRules>,
+
     /// How to build the result, eventually.
     build_result: Option<String>,
 }
 
 /// Rules for generating entire files.
 ///
 /// Extracted from the yaml file.
 #[derive(Default)]
@@ -231,16 +239,45 @@ impl GlobalRules {
                                     _ => {
                                         panic!("Unexpected {}.fields.{}.{}", node_key, field_key, field_config_key)
                                     }
                                 }
                             }
                             node_rule.by_field.insert(field_name.clone(), field_rule);
                         }
                     }
+                    "sum-arms" => {
+                        let arms = node_item_entry.as_hash()
+                            .unwrap_or_else(|| panic!("Rule {}.sum-arms must be a hash, got {:?}", node_key, node_entries["sum-arms"]));
+                        for (sum_arm_key, sum_arm_entry) in arms {
+                            let sum_arm_key = sum_arm_key.as_str()
+                                .unwrap_or_else(|| panic!("In rule {}, sum arms must be interface names"));
+                            let sum_arm_name = syntax.get_node_name(&sum_arm_key)
+                                .unwrap_or_else(|| panic!("In rule {}. cannot find interface {}", node_key, sum_arm_key));
+
+                            let mut sum_rule = SumRules::default();
+                            for (arm_config_key, arm_config_entry) in sum_arm_entry.as_hash()
+                                .unwrap_or_else(|| panic!("Rule {}.sum-arms.{} must be a hash", node_key, sum_arm_key))
+                            {
+                                let arm_config_key = arm_config_key.as_str()
+                                    .expect("Expected a string as a key");
+                                match arm_config_key
+                                {
+                                    "after" => {
+                                        update_rule(&mut sum_rule.after_arm, arm_config_entry)
+                                            .unwrap_or_else(|()| panic!("Rule {}.sum-arms.{}.{} must be a string", node_key, sum_arm_key, arm_config_key));
+                                    }
+                                    _ => {
+                                        panic!("Unexpected {}.sum-arms.{}.{}", node_key, sum_arm_key, arm_config_key);
+                                    }
+                                }
+                            }
+                            node_rule.by_sum.insert(sum_arm_name.clone(), sum_rule);
+                        }
+                    }
                     _ => panic!("Unexpected node_item_key {}.{}", node_key, as_string)
                 }
             }
 
             per_node.insert(node_name.clone(), node_rule);
         }
 
         Self {
@@ -261,16 +298,17 @@ impl GlobalRules {
             .unwrap_or_default();
         if let Some(ref parent) = rules.inherits {
             let NodeRules {
                 inherits: _,
                 type_ok,
                 init,
                 append,
                 by_field,
+                by_sum,
                 build_result,
             } = self.get(parent);
             if rules.type_ok.is_none() {
                 rules.type_ok = type_ok;
             }
             if rules.init.is_none() {
                 rules.init = init;
             }
@@ -279,16 +317,20 @@ impl GlobalRules {
             }
             if rules.build_result.is_none() {
                 rules.build_result = build_result;
             }
             for (key, value) in by_field {
                 rules.by_field.entry(key)
                     .or_insert(value);
             }
+            for (key, value) in by_sum {
+                rules.by_sum.entry(key)
+                    .or_insert(value);
+            }
         }
         rules
     }
 }
 
 /// The inforamtion used to generate a list parser.
 struct ListParserData {
     /// Name of the node.
@@ -652,16 +694,17 @@ enum class BinVariant {
         buffer
     }
 }
 
 impl CPPExporter {
     /// Generate implementation of a single typesum.
     fn generate_implement_sum(&self, buffer: &mut String, name: &NodeName, nodes: &HashSet<NodeName>) {
         // Generate comments (FIXME: We should use the actual webidl, not the resolved sum)
+        let rules_for_this_sum = self.rules.get(name);
         let nodes = nodes.iter()
             .sorted();
         let kind = name.to_class_cases();
         let rendered_bnf = format!("/*\n{name} ::= {nodes}\n*/",
             nodes = nodes.iter()
                 .format("\n    "),
             name = name.to_str());
 
@@ -687,19 +730,23 @@ impl CPPExporter {
         ));
 
         // Generate inner method
         let mut buffer_cases = String::new();
         for node in nodes {
             buffer_cases.push_str(&format!("
       case BinKind::{variant_name}:
         MOZ_TRY_VAR(result, parseInterface{class_name}(start, kind, fields));
+{arm_after}
         break;",
                 class_name = node.to_class_cases(),
-                variant_name = node.to_cpp_enum_case()));
+                variant_name = node.to_cpp_enum_case(),
+                arm_after = rules_for_this_sum.by_sum.get(&node)
+                    .cloned()
+                    .unwrap_or_default().after_arm.reindent("        ")));
         }
         buffer.push_str(&format!("\n{first_line}
 {{
     {type_ok} result;
     switch(kind) {{{cases}
       default:
         return raiseInvalidKind(\"{kind}\", kind);
     }}
@@ -718,16 +765,17 @@ impl CPPExporter {
     fn generate_implement_list(&self, buffer: &mut String, parser: &ListParserData) {
         let rules_for_this_list = self.rules.get(&parser.name);
 
         // Warn if some rules are unused.
         for &(condition, name) in &[
             (rules_for_this_list.build_result.is_some(), "build:"),
             (rules_for_this_list.type_ok.is_some(), "type-ok:"),
             (rules_for_this_list.by_field.len() > 0, "fields:"),
+            (rules_for_this_list.by_sum.len() > 0, "sum-arms:"),
         ] {
             if condition {
                 warn!("In {}, rule `{}` was specified but is ignored.", parser.name, name);
             }
         }
 
         let kind = parser.name.to_class_cases();
         let first_line = self.get_method_definition_start(&parser.name, "ParseNode*", "", "");
@@ -791,16 +839,17 @@ impl CPPExporter {
 
         let rules_for_this_node = self.rules.get(&parser.name);
 
         // Warn if some rules are unused.
         for &(condition, name) in &[
             (rules_for_this_node.build_result.is_some(), "build:"),
             (rules_for_this_node.append.is_some(), "append:"),
             (rules_for_this_node.by_field.len() > 0, "fields:"),
+            (rules_for_this_node.by_sum.len() > 0, "sum-arms:"),
         ] {
             if condition {
                 warn!("In {}, rule `{}` was specified but is ignored.", parser.name, name);
             }
         }
 
         let type_ok = self.get_type_ok(&parser.name, "ParseNode*");
         let default_value =