| Index: third_party/cython/src/Cython/Compiler/UtilNodes.py
|
| diff --git a/third_party/cython/src/Cython/Compiler/UtilNodes.py b/third_party/cython/src/Cython/Compiler/UtilNodes.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..abd7a5c91c723cd3daef05ad4617a2884490488a
|
| --- /dev/null
|
| +++ b/third_party/cython/src/Cython/Compiler/UtilNodes.py
|
| @@ -0,0 +1,349 @@
|
| +#
|
| +# 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 seperate module.
|
| +#
|
| +
|
| +import Nodes
|
| +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)
|
| +
|
| + def cleanup_ref(self, pos):
|
| + return CleanupTempRefNode(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):
|
| + 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_as(self.ctype())))
|
| + rhs.generate_post_assignment_code(code)
|
| + rhs.free_temps(code)
|
| +
|
| +class CleanupTempRefNode(TempRefNode):
|
| + # THIS IS DEPRECATED, USE LetRefNode instead
|
| + # handle TempHandle
|
| +
|
| + def generate_assignment_code(self, rhs, code):
|
| + pass
|
| +
|
| + def generate_execution_code(self, code):
|
| + if self.type.is_pyobject:
|
| + code.put_decref_clear(self.result(), self.type)
|
| + self.handle.needs_cleanup = False
|
| +
|
| +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 analyse_types(self, env):
|
| + if self.expression is not None:
|
| + 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):
|
| + 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_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 result(self):
|
| + return self.subexpression.result()
|
| +
|
| + def analyse_types(self, env):
|
| + self.temp_expression = self.temp_expression.analyse_types(env)
|
| + 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)
|
|
|