aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/cython/Cython/Compiler/UtilNodes.py
diff options
context:
space:
mode:
authoralexv-smirnov <alex@ydb.tech>2023-06-13 11:05:01 +0300
committeralexv-smirnov <alex@ydb.tech>2023-06-13 11:05:01 +0300
commitbf0f13dd39ee3e65092ba3572bb5b1fcd125dcd0 (patch)
tree1d1df72c0541a59a81439842f46d95396d3e7189 /contrib/tools/cython/Cython/Compiler/UtilNodes.py
parent8bfdfa9a9bd19bddbc58d888e180fbd1218681be (diff)
downloadydb-bf0f13dd39ee3e65092ba3572bb5b1fcd125dcd0.tar.gz
add ymake export to ydb
Diffstat (limited to 'contrib/tools/cython/Cython/Compiler/UtilNodes.py')
-rw-r--r--contrib/tools/cython/Cython/Compiler/UtilNodes.py359
1 files changed, 359 insertions, 0 deletions
diff --git a/contrib/tools/cython/Cython/Compiler/UtilNodes.py b/contrib/tools/cython/Cython/Compiler/UtilNodes.py
new file mode 100644
index 0000000000..c41748ace0
--- /dev/null
+++ b/contrib/tools/cython/Cython/Compiler/UtilNodes.py
@@ -0,0 +1,359 @@
+#
+# Nodes used as utilities and support for transforms etc.
+# These often make up sets including both Nodes and ExprNodes
+# so it is convenient to have them in a separate module.
+#
+
+from __future__ import absolute_import
+
+from . import Nodes
+from . import ExprNodes
+from .Nodes import Node
+from .ExprNodes import AtomicExprNode
+from .PyrexTypes import c_ptr_type
+
+
+class TempHandle(object):
+ # THIS IS DEPRECATED, USE LetRefNode instead
+ temp = None
+ needs_xdecref = False
+ def __init__(self, type, needs_cleanup=None):
+ self.type = type
+ if needs_cleanup is None:
+ self.needs_cleanup = type.is_pyobject
+ else:
+ self.needs_cleanup = needs_cleanup
+
+ def ref(self, pos):
+ return TempRefNode(pos, handle=self, type=self.type)
+
+
+class TempRefNode(AtomicExprNode):
+ # THIS IS DEPRECATED, USE LetRefNode instead
+ # handle TempHandle
+
+ def analyse_types(self, env):
+ assert self.type == self.handle.type
+ return self
+
+ def analyse_target_types(self, env):
+ assert self.type == self.handle.type
+ return self
+
+ def analyse_target_declaration(self, env):
+ pass
+
+ def calculate_result_code(self):
+ result = self.handle.temp
+ if result is None: result = "<error>" # might be called and overwritten
+ return result
+
+ def generate_result_code(self, code):
+ pass
+
+ def generate_assignment_code(self, rhs, code, overloaded_assignment=False):
+ if self.type.is_pyobject:
+ rhs.make_owned_reference(code)
+ # TODO: analyse control flow to see if this is necessary
+ code.put_xdecref(self.result(), self.ctype())
+ code.putln('%s = %s;' % (
+ self.result(),
+ rhs.result() if overloaded_assignment else rhs.result_as(self.ctype()),
+ ))
+ rhs.generate_post_assignment_code(code)
+ rhs.free_temps(code)
+
+
+class TempsBlockNode(Node):
+ # THIS IS DEPRECATED, USE LetNode instead
+
+ """
+ Creates a block which allocates temporary variables.
+ This is used by transforms to output constructs that need
+ to make use of a temporary variable. Simply pass the types
+ of the needed temporaries to the constructor.
+
+ The variables can be referred to using a TempRefNode
+ (which can be constructed by calling get_ref_node).
+ """
+
+ # temps [TempHandle]
+ # body StatNode
+
+ child_attrs = ["body"]
+
+ def generate_execution_code(self, code):
+ for handle in self.temps:
+ handle.temp = code.funcstate.allocate_temp(
+ handle.type, manage_ref=handle.needs_cleanup)
+ self.body.generate_execution_code(code)
+ for handle in self.temps:
+ if handle.needs_cleanup:
+ if handle.needs_xdecref:
+ code.put_xdecref_clear(handle.temp, handle.type)
+ else:
+ code.put_decref_clear(handle.temp, handle.type)
+ code.funcstate.release_temp(handle.temp)
+
+ def analyse_declarations(self, env):
+ self.body.analyse_declarations(env)
+
+ def analyse_expressions(self, env):
+ self.body = self.body.analyse_expressions(env)
+ return self
+
+ def generate_function_definitions(self, env, code):
+ self.body.generate_function_definitions(env, code)
+
+ def annotate(self, code):
+ self.body.annotate(code)
+
+
+class ResultRefNode(AtomicExprNode):
+ # A reference to the result of an expression. The result_code
+ # must be set externally (usually a temp name).
+
+ subexprs = []
+ lhs_of_first_assignment = False
+
+ def __init__(self, expression=None, pos=None, type=None, may_hold_none=True, is_temp=False):
+ self.expression = expression
+ self.pos = None
+ self.may_hold_none = may_hold_none
+ if expression is not None:
+ self.pos = expression.pos
+ if hasattr(expression, "type"):
+ self.type = expression.type
+ if pos is not None:
+ self.pos = pos
+ if type is not None:
+ self.type = type
+ if is_temp:
+ self.is_temp = True
+ assert self.pos is not None
+
+ def clone_node(self):
+ # nothing to do here
+ return self
+
+ def type_dependencies(self, env):
+ if self.expression:
+ return self.expression.type_dependencies(env)
+ else:
+ return ()
+
+ def update_expression(self, expression):
+ self.expression = expression
+ if hasattr(expression, "type"):
+ self.type = expression.type
+
+ def analyse_types(self, env):
+ if self.expression is not None:
+ if not self.expression.type:
+ self.expression = self.expression.analyse_types(env)
+ self.type = self.expression.type
+ return self
+
+ def infer_type(self, env):
+ if self.type is not None:
+ return self.type
+ if self.expression is not None:
+ if self.expression.type is not None:
+ return self.expression.type
+ return self.expression.infer_type(env)
+ assert False, "cannot infer type of ResultRefNode"
+
+ def may_be_none(self):
+ if not self.type.is_pyobject:
+ return False
+ return self.may_hold_none
+
+ def _DISABLED_may_be_none(self):
+ # not sure if this is safe - the expression may not be the
+ # only value that gets assigned
+ if self.expression is not None:
+ return self.expression.may_be_none()
+ if self.type is not None:
+ return self.type.is_pyobject
+ return True # play safe
+
+ def is_simple(self):
+ return True
+
+ def result(self):
+ try:
+ return self.result_code
+ except AttributeError:
+ if self.expression is not None:
+ self.result_code = self.expression.result()
+ return self.result_code
+
+ def generate_evaluation_code(self, code):
+ pass
+
+ def generate_result_code(self, code):
+ pass
+
+ def generate_disposal_code(self, code):
+ pass
+
+ def generate_assignment_code(self, rhs, code, overloaded_assignment=False):
+ if self.type.is_pyobject:
+ rhs.make_owned_reference(code)
+ if not self.lhs_of_first_assignment:
+ code.put_decref(self.result(), self.ctype())
+ code.putln('%s = %s;' % (
+ self.result(),
+ rhs.result() if overloaded_assignment else rhs.result_as(self.ctype()),
+ ))
+ rhs.generate_post_assignment_code(code)
+ rhs.free_temps(code)
+
+ def allocate_temps(self, env):
+ pass
+
+ def release_temp(self, env):
+ pass
+
+ def free_temps(self, code):
+ pass
+
+
+class LetNodeMixin:
+ def set_temp_expr(self, lazy_temp):
+ self.lazy_temp = lazy_temp
+ self.temp_expression = lazy_temp.expression
+
+ def setup_temp_expr(self, code):
+ self.temp_expression.generate_evaluation_code(code)
+ self.temp_type = self.temp_expression.type
+ if self.temp_type.is_array:
+ self.temp_type = c_ptr_type(self.temp_type.base_type)
+ self._result_in_temp = self.temp_expression.result_in_temp()
+ if self._result_in_temp:
+ self.temp = self.temp_expression.result()
+ else:
+ self.temp_expression.make_owned_reference(code)
+ self.temp = code.funcstate.allocate_temp(
+ self.temp_type, manage_ref=True)
+ code.putln("%s = %s;" % (self.temp, self.temp_expression.result()))
+ self.temp_expression.generate_disposal_code(code)
+ self.temp_expression.free_temps(code)
+ self.lazy_temp.result_code = self.temp
+
+ def teardown_temp_expr(self, code):
+ if self._result_in_temp:
+ self.temp_expression.generate_disposal_code(code)
+ self.temp_expression.free_temps(code)
+ else:
+ if self.temp_type.is_pyobject:
+ code.put_decref_clear(self.temp, self.temp_type)
+ code.funcstate.release_temp(self.temp)
+
+
+class EvalWithTempExprNode(ExprNodes.ExprNode, LetNodeMixin):
+ # A wrapper around a subexpression that moves an expression into a
+ # temp variable and provides it to the subexpression.
+
+ subexprs = ['temp_expression', 'subexpression']
+
+ def __init__(self, lazy_temp, subexpression):
+ self.set_temp_expr(lazy_temp)
+ self.pos = subexpression.pos
+ self.subexpression = subexpression
+ # if called after type analysis, we already know the type here
+ self.type = self.subexpression.type
+
+ def infer_type(self, env):
+ return self.subexpression.infer_type(env)
+
+ def may_be_none(self):
+ return self.subexpression.may_be_none()
+
+ def result(self):
+ return self.subexpression.result()
+
+ def analyse_types(self, env):
+ self.temp_expression = self.temp_expression.analyse_types(env)
+ self.lazy_temp.update_expression(self.temp_expression) # overwrite in case it changed
+ self.subexpression = self.subexpression.analyse_types(env)
+ self.type = self.subexpression.type
+ return self
+
+ def free_subexpr_temps(self, code):
+ self.subexpression.free_temps(code)
+
+ def generate_subexpr_disposal_code(self, code):
+ self.subexpression.generate_disposal_code(code)
+
+ def generate_evaluation_code(self, code):
+ self.setup_temp_expr(code)
+ self.subexpression.generate_evaluation_code(code)
+ self.teardown_temp_expr(code)
+
+
+LetRefNode = ResultRefNode
+
+
+class LetNode(Nodes.StatNode, LetNodeMixin):
+ # Implements a local temporary variable scope. Imagine this
+ # syntax being present:
+ # let temp = VALUE:
+ # BLOCK (can modify temp)
+ # if temp is an object, decref
+ #
+ # Usually used after analysis phase, but forwards analysis methods
+ # to its children
+
+ child_attrs = ['temp_expression', 'body']
+
+ def __init__(self, lazy_temp, body):
+ self.set_temp_expr(lazy_temp)
+ self.pos = body.pos
+ self.body = body
+
+ def analyse_declarations(self, env):
+ self.temp_expression.analyse_declarations(env)
+ self.body.analyse_declarations(env)
+
+ def analyse_expressions(self, env):
+ self.temp_expression = self.temp_expression.analyse_expressions(env)
+ self.body = self.body.analyse_expressions(env)
+ return self
+
+ def generate_execution_code(self, code):
+ self.setup_temp_expr(code)
+ self.body.generate_execution_code(code)
+ self.teardown_temp_expr(code)
+
+ def generate_function_definitions(self, env, code):
+ self.temp_expression.generate_function_definitions(env, code)
+ self.body.generate_function_definitions(env, code)
+
+
+class TempResultFromStatNode(ExprNodes.ExprNode):
+ # An ExprNode wrapper around a StatNode that executes the StatNode
+ # body. Requires a ResultRefNode that it sets up to refer to its
+ # own temp result. The StatNode must assign a value to the result
+ # node, which then becomes the result of this node.
+
+ subexprs = []
+ child_attrs = ['body']
+
+ def __init__(self, result_ref, body):
+ self.result_ref = result_ref
+ self.pos = body.pos
+ self.body = body
+ self.type = result_ref.type
+ self.is_temp = 1
+
+ def analyse_declarations(self, env):
+ self.body.analyse_declarations(env)
+
+ def analyse_types(self, env):
+ self.body = self.body.analyse_expressions(env)
+ return self
+
+ def generate_result_code(self, code):
+ self.result_ref.result_code = self.result()
+ self.body.generate_execution_code(code)