Commit ddcff1e4 authored by Yuki Shiino's avatar Yuki Shiino Committed by Commit Bot

bind-gen: Support complex cases of symbol definitions

It turned out that some of SymbolDefinitionNodes need to be
followed by UnlikelyExitNode just like the following example,
so this patch makes SymbolDefinitionNode inherits from
SymbolScopeNode so that a definition can consist from
multiple CodeNodes.

Example:

  const auto& return_value = F(exception_state);
  if (exception_state.HadException()) {
    return;
  }

A symbol definition of |return_value| needs to be followed by
UnlikelyExitNode to return early if an exception is thrown.

Note that SymbolNode is just moved and should have no code
change.  SymbolDefinitionNode is updated accordingly.

Bug: 839389
Change-Id: I65e2f730084ad5018c2521ea0826c058910d153b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1882253
Commit-Queue: Yuki Shiino <yukishiino@chromium.org>
Reviewed-by: default avatarHitoshi Yoshida <peria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#709868}
parent bedb4f4b
...@@ -118,21 +118,17 @@ class CodeNode(object): ...@@ -118,21 +118,17 @@ class CodeNode(object):
return "gensym{}".format(cls._gensym_seq_id) return "gensym{}".format(cls._gensym_seq_id)
def __init__(self, def __init__(self,
outer=None,
prev=None,
template_text=None, template_text=None,
template_vars=None, template_vars=None,
renderer=None): renderer=None):
assert outer is None or isinstance(outer, CodeNode)
assert prev is None or isinstance(prev, CodeNode)
assert template_text is None or isinstance(template_text, str) assert template_text is None or isinstance(template_text, str)
assert template_vars is None or isinstance(template_vars, dict) assert template_vars is None or isinstance(template_vars, dict)
assert renderer is None or isinstance(renderer, MakoRenderer) assert renderer is None or isinstance(renderer, MakoRenderer)
# The outer CodeNode or None iff this is a top-level node # The outer CodeNode or None iff this is a top-level node
self._outer = outer self._outer = None
# The previous CodeNode if this is a Sequence or None # The previous CodeNode if this is a Sequence or None
self._prev = prev self._prev = None
# Mako's template text, bindings dict, and the renderer object # Mako's template text, bindings dict, and the renderer object
self._template_text = template_text self._template_text = template_text
...@@ -255,7 +251,8 @@ class CodeNode(object): ...@@ -255,7 +251,8 @@ class CodeNode(object):
return binds return binds
def add_template_var(self, name, value): def add_template_var(self, name, value):
assert name not in self._template_vars assert name not in self._template_vars, (
"Duplicated template variable binding: {}".format(name))
if isinstance(value, CodeNode): if isinstance(value, CodeNode):
value.set_outer(self) value.set_outer(self)
self._template_vars[name] = value self._template_vars[name] = value
...@@ -449,105 +446,6 @@ ${node | trim}\\ ...@@ -449,105 +446,6 @@ ${node | trim}\\
node.reset_prev(None) node.reset_prev(None)
class SymbolNode(CodeNode):
"""
Represents a code symbol such as a local variable of generated code.
Using a SymbolNode combined with SymbolScopeNode, SymbolDefinitionNode(s)
will be automatically inserted iff this symbol is referenced.
"""
def __init__(self,
name,
template_text=None,
definition_node_constructor=None):
"""
Args:
name: The name of this code symbol.
template_text: Template text to be used to define the code symbol.
definition_node_constructor: A callable that creates and returns a
new definition node. This SymbolNode will be passed as the
argument.
Either of |template_text| or |definition_node_constructor| must
be given.
"""
assert isinstance(name, str) and name
assert (template_text is not None
or definition_node_constructor is not None)
assert template_text is None or definition_node_constructor is None
if template_text is not None:
assert isinstance(template_text, str)
if definition_node_constructor is not None:
assert callable(definition_node_constructor)
CodeNode.__init__(self)
self._name = name
if template_text is not None:
def constructor(symbol_node):
return SymbolDefinitionNode(
symbol_node=symbol_node, template_text=template_text)
self._definition_node_constructor = constructor
else:
self._definition_node_constructor = definition_node_constructor
def _render(self, renderer, last_render_state):
for caller in renderer.callers:
assert isinstance(caller, CodeNode)
if caller.is_code_symbol_defined(self):
break
caller.on_undefined_code_symbol_found(self)
return self.name
@property
def name(self):
return self._name
def create_definition_node(self):
"""Creates a new definition node."""
node = self._definition_node_constructor(self)
assert isinstance(node, SymbolDefinitionNode)
return node
class SymbolDefinitionNode(CodeNode):
"""
Represents a definition of a code symbol.
It's allowed to define the same code symbol multiple times, and most
upstream definition(s) are effective.
"""
def __init__(self, symbol_node, template_text, template_vars=None):
assert isinstance(symbol_node, SymbolNode)
CodeNode.__init__(
self, template_text=template_text, template_vars=template_vars)
self._symbol_node = symbol_node
def _render(self, renderer, last_render_state):
if self.is_duplicated():
return ""
return super(SymbolDefinitionNode, self)._render(
renderer=renderer, last_render_state=last_render_state)
def is_code_symbol_defined(self, symbol_node):
if symbol_node is self._symbol_node:
return True
return super(SymbolDefinitionNode,
self).is_code_symbol_defined(symbol_node)
def is_duplicated(self):
return (self.upstream is not None
and self.upstream.is_code_symbol_defined(self._symbol_node))
class SymbolScopeNode(SequenceNode): class SymbolScopeNode(SequenceNode):
""" """
Represents a sequence of nodes. Represents a sequence of nodes.
...@@ -661,6 +559,103 @@ class SymbolScopeNode(SequenceNode): ...@@ -661,6 +559,103 @@ class SymbolScopeNode(SequenceNode):
self.register_code_symbol(symbol_node) self.register_code_symbol(symbol_node)
class SymbolNode(CodeNode):
"""
Represents a code symbol such as a local variable of generated code.
Using a SymbolNode combined with SymbolScopeNode, SymbolDefinitionNode(s)
will be automatically inserted iff this symbol is referenced.
"""
def __init__(self, name, template_text=None, definition_constructor=None):
"""
Args:
name: The name of this code symbol.
template_text: Template text to be used to define the code symbol.
definition_constructor: A callable that creates and returns a new
definition node. This SymbolNode will be passed as the
argument.
Either of |template_text| or |definition_constructor| must be
given.
"""
assert isinstance(name, str) and name
assert (template_text is not None
or definition_constructor is not None)
assert template_text is None or definition_constructor is None
if template_text is not None:
assert isinstance(template_text, str)
if definition_constructor is not None:
assert callable(definition_constructor)
CodeNode.__init__(self)
self._name = name
if template_text is not None:
def constructor(symbol_node):
return SymbolDefinitionNode(
symbol_node=symbol_node,
code_nodes=[TextNode(template_text)])
self._definition_constructor = constructor
else:
self._definition_constructor = definition_constructor
def _render(self, renderer, last_render_state):
for caller in renderer.callers:
assert isinstance(caller, CodeNode)
if caller.is_code_symbol_defined(self):
break
caller.on_undefined_code_symbol_found(self)
return self.name
@property
def name(self):
return self._name
def create_definition_node(self):
"""Creates a new definition node."""
node = self._definition_constructor(self)
assert isinstance(node, SymbolDefinitionNode)
assert node.is_code_symbol_defined(self)
return node
class SymbolDefinitionNode(SymbolScopeNode):
"""
Represents a definition of a code symbol.
It's allowed to define the same code symbol multiple times, and most
upstream definition(s) are effective.
"""
def __init__(self, symbol_node, code_nodes=None):
assert isinstance(symbol_node, SymbolNode)
SymbolScopeNode.__init__(self, code_nodes)
self._symbol_node = symbol_node
def _render(self, renderer, last_render_state):
if self.is_duplicated():
return ""
return super(SymbolDefinitionNode, self)._render(
renderer=renderer, last_render_state=last_render_state)
def is_code_symbol_defined(self, symbol_node):
if symbol_node is self._symbol_node:
return True
return super(SymbolDefinitionNode,
self).is_code_symbol_defined(symbol_node)
def is_duplicated(self):
return (self.upstream is not None
and self.upstream.is_code_symbol_defined(self._symbol_node))
class ConditionalNode(CodeNode): class ConditionalNode(CodeNode):
""" """
This is the base class of code nodes that directly contain conditional This is the base class of code nodes that directly contain conditional
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment