bind-gen: Introduce a new SequenceNode

Introduces a new SequenceNode and replaces existing use cases of
SymbolScopeNode with the SequenceNode if appropriate.

The implementation of SequenceNode and SymbolScopeNode is
incomplete, and the follow-up patches will complete the two
classes.

Bug: 839389
Change-Id: I6d578ffe94c386757e76764a4d02221ef0847f51
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1946176
Commit-Queue: Yuki Shiino <yukishiino@chromium.org>
Reviewed-by: Hitoshi Yoshida <peria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#720790}
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py b/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py
index 4e9f398..d9fd164 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/code_node.py
@@ -208,7 +208,7 @@
         """
         if self.prev is not None:
             prev = self.prev
-            while isinstance(prev, SymbolScopeNode) and prev:
+            while isinstance(prev, SequenceNode) and prev:
                 prev = prev[-1]
             return prev
         else:
@@ -458,12 +458,10 @@
         node.reset_prev(None)
 
 
-class SymbolScopeNode(ListNode):
+class SequenceNode(ListNode):
     """
-    Represents a sequence of nodes.
-
-    If SymbolNodes are rendered inside this node, this node will attempt to
-    insert corresponding SymbolDefinitionNodes appropriately.
+    Represents a sequence of generated code without introducing any new scope,
+    and provides the points where SymbolDefinitionNodes can be inserted.
     """
 
     def __init__(self, code_nodes=None, separator="\n", separator_last=""):
@@ -473,8 +471,6 @@
             separator=separator,
             separator_last=separator_last)
 
-        self._registered_code_symbols = set()
-
     def _render(self, renderer, last_render_state):
         duplicates = []
         for element_node in self:
@@ -484,6 +480,28 @@
         for element_node in duplicates:
             self.remove(element_node)
 
+        return super(SequenceNode, self)._render(
+            renderer=renderer, last_render_state=last_render_state)
+
+
+class SymbolScopeNode(SequenceNode):
+    """
+    Represents a scope of generated code.
+
+    If SymbolNodes are rendered inside this node, this node will attempt to
+    insert corresponding SymbolDefinitionNodes appropriately.
+    """
+
+    def __init__(self, code_nodes=None, separator="\n", separator_last=""):
+        SequenceNode.__init__(
+            self,
+            code_nodes=code_nodes,
+            separator=separator,
+            separator_last=separator_last)
+
+        self._registered_code_symbols = set()
+
+    def _render(self, renderer, last_render_state):
         for symbol_node in last_render_state.undefined_code_symbols:
             if (self.is_code_symbol_registered(symbol_node)
                     and not self.is_code_symbol_defined(symbol_node)):
@@ -525,7 +543,7 @@
 
         def insert_right_before_first_use(symbol_scope_node):
             for index, node in enumerate(symbol_scope_node):
-                if isinstance(node, SymbolScopeNode):
+                if isinstance(node, SequenceNode):
                     did_insert = insert_right_before_first_use(node)
                     if did_insert:
                         return True
@@ -634,7 +652,7 @@
         return node
 
 
-class SymbolDefinitionNode(SymbolScopeNode):
+class SymbolDefinitionNode(SequenceNode):
     """
     Represents a definition of a code symbol.
 
@@ -645,7 +663,7 @@
     def __init__(self, symbol_node, code_nodes=None):
         assert isinstance(symbol_node, SymbolNode)
 
-        SymbolScopeNode.__init__(self, code_nodes)
+        SequenceNode.__init__(self, code_nodes)
 
         self._symbol_node = symbol_node
 
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py b/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py
index 9b6e100..2635adb 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/codegen_utils.py
@@ -7,7 +7,7 @@
 from .clang_format import clang_format
 from .code_node import CodeNode
 from .code_node import LiteralNode
-from .code_node import SymbolScopeNode
+from .code_node import SequenceNode
 from .codegen_accumulator import CodeGenAccumulator
 from .path_manager import PathManager
 
@@ -40,7 +40,7 @@
     assert isinstance(code_node, CodeNode)
     assert isinstance(header_guard, str)
 
-    return SymbolScopeNode([
+    return SequenceNode([
         LiteralNode("#ifndef {}".format(header_guard)),
         LiteralNode("#define {}".format(header_guard)),
         LiteralNode(""),
@@ -54,7 +54,7 @@
     assert isinstance(code_node, CodeNode)
     assert isinstance(namespace, str)
 
-    return SymbolScopeNode([
+    return SequenceNode([
         LiteralNode("namespace {} {{".format(namespace)),
         LiteralNode(""),
         code_node,
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py b/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py
index 06eb174..9821f27 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/dictionary.py
@@ -12,6 +12,7 @@
 from .blink_v8_bridge import make_v8_to_blink_value
 from .code_node import CodeNode
 from .code_node import FunctionDefinitionNode
+from .code_node import SequenceNode
 from .code_node import SymbolScopeNode
 from .code_node import TextNode
 from .codegen_context import CodeGenContext
@@ -394,7 +395,7 @@
 
     member_set_func = name_style.api_func("set", member.identifier)
 
-    node = SymbolScopeNode()
+    node = SequenceNode()
 
     pattern = """
 if (!v8_dictionary->Get(current_context, member_names[{_1}].Get(${isolate}))
@@ -471,7 +472,7 @@
     root_node = SymbolScopeNode(separator_last="\n")
     root_node.set_renderer(MakoRenderer())
 
-    code_node = SymbolScopeNode()
+    code_node = SequenceNode()
 
     code_node.extend([
         make_get_v8_dict_member_names_def(cg_context),
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
index 0efae48..e4ff770 100644
--- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
+++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
@@ -15,6 +15,7 @@
 from .code_node import CodeNode
 from .code_node import FunctionDefinitionNode
 from .code_node import LiteralNode
+from .code_node import SequenceNode
 from .code_node import SymbolDefinitionNode
 from .code_node import SymbolNode
 from .code_node import SymbolScopeNode
@@ -264,7 +265,7 @@
 
     if (cg_context.attribute
             and "LenientThis" in cg_context.attribute.extended_attributes):
-        return SymbolScopeNode([
+        return SequenceNode([
             T("// [LenientThis]"),
             UnlikelyExitNode(
                 cond=T("!${v8_class}::HasInstance(${receiver}, ${isolate})"),
@@ -272,7 +273,7 @@
         ])
 
     if cg_context.return_type.unwrap().is_promise:
-        return SymbolScopeNode([
+        return SequenceNode([
             T("// Promise returning function: "
               "Convert a TypeError to a reject promise."),
             UnlikelyExitNode(
@@ -311,7 +312,7 @@
         T("V8SetReturnValueNull(${info});\n"
           "return;"),
     ])
-    return SymbolScopeNode([
+    return SequenceNode([
         T("// [CheckSecurity=ReturnValue]"),
         UnlikelyExitNode(cond=cond, body=body),
     ])
@@ -392,7 +393,7 @@
     else:
         arg_index = None
     func_like = None
-    dispatcher_nodes = SymbolScopeNode()
+    dispatcher_nodes = SequenceNode()
 
     # True if there exists a case that overload resolution will fail.
     can_fail = True
@@ -580,7 +581,7 @@
     items_grouped_by_arg_size = itertools.groupby(
         sorted(items, key=args_size, reverse=True), key=args_size)
 
-    branches = SymbolScopeNode()
+    branches = SequenceNode()
     did_use_break = False
     for arg_size, items in items_grouped_by_arg_size:
         items = list(items)
@@ -622,7 +623,7 @@
     if not did_use_break and arg_size == 0 and conditional.is_always_true:
         return branches
 
-    return SymbolScopeNode([
+    return SequenceNode([
         branches,
         T(""),
         T("${exception_state}.ThrowTypeError"
@@ -681,7 +682,7 @@
             name_style.raw.upper_camel_case(cg_context.member_like.identifier),
             suffix)
 
-    node = SymbolScopeNode()
+    node = SequenceNode()
 
     pattern = ("// [Measure], [MeasureAs]\n"
                "UseCounter::Count(${execution_context}, WebFeature::{_1});")
@@ -893,7 +894,7 @@
         return make_operation_function_def(
             cg_context.make_copy(operation=operation_group[0]), function_name)
 
-    node = SymbolScopeNode()
+    node = SequenceNode()
     for operation in operation_group:
         node.append(
             make_operation_function_def(
@@ -997,7 +998,7 @@
     root_node.accumulator.add_include_headers(
         collect_include_headers(interface))
 
-    code_node = SymbolScopeNode()
+    code_node = SequenceNode()
 
     for attribute in interface.attributes:
         func_name = name_style.func(attribute.identifier,