123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- #
- # 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)
|