result_ctype = None
type = None
+ temp_code = None
+ old_temp = None # error checker for multiple frees etc.
# The Analyse Expressions phase for expressions is split
# into two sub-phases:
return nodes
def result(self):
- if not self.is_temp or self.is_target:
+ if self.is_temp:
+ return self.temp_code
+ else:
return self.calculate_result_code()
- else: # i.e. self.is_temp:
- return self.result_code
def result_as(self, type = None):
# Return the result code cast to the specified C type.
return self.is_temp
def allocate_target_temps(self, env, rhs):
- # Perform temp allocation for the LHS of an assignment.
- if debug_temp_alloc:
- print("%s Allocating target temps" % self)
self.allocate_subexpr_temps(env)
self.is_target = True
if rhs:
rhs.release_temp(env)
self.release_subexpr_temps(env)
-
+
+ def allocate_temps(self, env, result = None):
+ assert result is None, "deprecated, contact dagss if this triggers"
+ self.allocate_subexpr_temps(env)
+ if self.is_temp:
+ self.release_subexpr_temps(env)
+
def allocate_temps(self, env, result = None):
# Allocate temporary variables for this node and
# all its sub-expressions. If a result is specified,
node.allocate_temps(env)
def allocate_temp(self, env, result = None):
- # If this node requires a temporary variable for its
- # result, allocate one, otherwise set the result to
- # a C code fragment. If a result is specified,
- # this must be a temp node and the specified variable
- # is used as the result instead of allocating a new
- # one.
- if debug_temp_alloc:
- print("%s Allocating temp" % self)
- if result:
- if not self.is_temp:
- raise InternalError("Result forced on non-temp node")
- self.result_code = result
- elif self.is_temp:
- type = self.type
- if not type.is_void:
- if type.is_pyobject:
- type = PyrexTypes.py_object_type
- self.result_code = env.allocate_temp(type)
- else:
- self.result_code = None
- if debug_temp_alloc:
- print("%s Allocated result %s" % (self, self.result_code))
+ assert result is None
def target_code(self):
# Return code fragment for use as LHS of a C assignment.
# # Release temporaries used by LHS of an assignment.
# self.release_subexpr_temps(env)
+
def release_temp(self, env):
- # If this node owns a temporary result, release it,
- # otherwise release results of its sub-expressions.
if self.is_temp:
- if debug_temp_alloc:
- print("%s Releasing result %s" % (self, self.result_code))
- env.release_temp(self.result_code)
+ pass
else:
self.release_subexpr_temps(env)
if node:
node.release_temp(env)
+ def allocate_temp_result(self, code):
+ if self.temp_code:
+ raise RuntimeError("Temp allocated multiple times")
+ type = self.type
+ if not type.is_void:
+ if type.is_pyobject:
+ type = PyrexTypes.py_object_type
+ self.temp_code = code.funcstate.allocate_temp(
+ type, manage_ref=True)
+ else:
+ self.temp_code = None
+
+ def release_temp_result(self, code):
+ if not self.temp_code:
+ if self.old_temp:
+ raise RuntimeError("temp %s released multiple times in %s" % (
+ self.old_temp, self.__class__.__name__))
+ else:
+ raise RuntimeError("no temp, but release requested in %s" % (
+ self.__class__.__name__))
+ code.funcstate.release_temp(self.temp_code)
+ self.old_temp = self.temp_code
+ self.temp_code = None
+
# ---------------- Code Generation -----------------
def make_owned_reference(self, code):
def generate_evaluation_code(self, code):
code.mark_pos(self.pos)
+
# Generate code to evaluate this node and
# its sub-expressions, and dispose of any
# temporary results of its sub-expressions.
self.generate_subexpr_evaluation_code(code)
+
+ if self.is_temp:
+ self.allocate_temp_result(code)
+
self.generate_result_code(code)
if self.is_temp:
+ # If we are temp we do not need to wait until this node is disposed
+ # before disposing children.
self.generate_subexpr_disposal_code(code)
self.free_subexpr_temps(code)
self.not_implemented("generate_result_code")
def generate_disposal_code(self, code):
- # If necessary, generate code to dispose of
- # temporary Python reference.
if self.is_temp:
if self.type.is_pyobject:
code.put_decref_clear(self.result(), self.ctype())
else:
+ # Already done if self.is_temp
self.generate_subexpr_disposal_code(code)
-
+
def generate_subexpr_disposal_code(self, code):
# Generate code to dispose of temporary results
# of all sub-expressions.
node.generate_disposal_code(code)
def generate_post_assignment_code(self, code):
- # Same as generate_disposal_code except that
- # assignment will have absorbed a reference to
- # the result if it is a Python object.
if self.is_temp:
if self.type.is_pyobject:
code.putln("%s = 0;" % self.result())
else:
self.generate_subexpr_disposal_code(code)
-
+
def generate_assignment_code(self, rhs, code):
# Stub method for nodes which are not legal as
# the LHS of an assignment. An error will have
pass
def free_temps(self, code):
- if not self.is_temp:
+ if self.is_temp:
+ if not self.type.is_void:
+ self.release_temp_result(code)
+ else:
self.free_subexpr_temps(code)
- # otherwise, already freed in generate_evaluation_code
def free_subexpr_temps(self, code):
for sub in self.subexpr_nodes():
def as_cython_attribute(self):
return None
-
-class RemoveAllocateTemps(type):
- def __init__(cls, name, bases, dct):
- super(RemoveAllocateTemps, cls).__init__(name, bases, dct)
- def noop(self, env): pass
- setattr(cls, 'allocate_temps', noop)
- setattr(cls, 'allocate_temp', noop)
- setattr(cls, 'release_temp', noop)
-
-class NewTempExprNode(ExprNode):
- temp_code = None
- old_temp = None # error checker for multiple frees etc.
-
-# Do not enable this unless you are trying to make all ExprNodes
-# NewTempExprNodes (child nodes reached via recursion may not have
-# transferred).
-# __metaclass__ = RemoveAllocateTemps
-
- def result(self):
- if self.is_temp:
- return self.temp_code
- else:
- return self.calculate_result_code()
-
- def allocate_target_temps(self, env, rhs):
- self.allocate_subexpr_temps(env)
- self.is_target = True
- if rhs:
- rhs.release_temp(env)
- self.release_subexpr_temps(env)
-
- def allocate_temps(self, env, result = None):
- assert result is None, "deprecated, contact dagss if this triggers"
- self.allocate_subexpr_temps(env)
- if self.is_temp:
- self.release_subexpr_temps(env)
-
- def allocate_temp(self, env, result = None):
- assert result is None
-
- def release_temp(self, env):
- if self.is_temp:
- pass
- else:
- self.release_subexpr_temps(env)
-
- def allocate_temp_result(self, code):
- if self.temp_code:
- raise RuntimeError("Temp allocated multiple times")
- type = self.type
- if not type.is_void:
- if type.is_pyobject:
- type = PyrexTypes.py_object_type
- self.temp_code = code.funcstate.allocate_temp(
- type, manage_ref=True)
- else:
- self.temp_code = None
-
- def release_temp_result(self, code):
- if not self.temp_code:
- if self.old_temp:
- raise RuntimeError("temp %s released multiple times in %s" % (
- self.old_temp, self.__class__.__name__))
- else:
- raise RuntimeError("no temp, but release requested in %s" % (
- self.__class__.__name__))
- code.funcstate.release_temp(self.temp_code)
- self.old_temp = self.temp_code
- self.temp_code = None
-
- def generate_evaluation_code(self, code):
- code.mark_pos(self.pos)
-
- # Generate code to evaluate this node and
- # its sub-expressions, and dispose of any
- # temporary results of its sub-expressions.
- self.generate_subexpr_evaluation_code(code)
-
- if self.is_temp:
- self.allocate_temp_result(code)
-
- self.generate_result_code(code)
- if self.is_temp:
- # If we are temp we do not need to wait until this node is disposed
- # before disposing children.
- self.generate_subexpr_disposal_code(code)
- self.free_subexpr_temps(code)
-
- def generate_disposal_code(self, code):
- if self.is_temp:
- if self.type.is_pyobject:
- code.put_decref_clear(self.result(), self.ctype())
- else:
- # Already done if self.is_temp
- self.generate_subexpr_disposal_code(code)
-
- def generate_post_assignment_code(self, code):
- if self.is_temp:
- if self.type.is_pyobject:
- code.putln("%s = 0;" % self.result())
- else:
- self.generate_subexpr_disposal_code(code)
-
- def free_temps(self, code):
- if self.is_temp:
- if not self.type.is_void:
- self.release_temp_result(code)
- else:
- self.free_subexpr_temps(code)
-
-# ExprNode = NewTempExprNode
-
class AtomicExprNode(ExprNode):
- # Abstract base class for expression nodes which have
- # no sub-expressions.
-
- subexprs = []
-
-class AtomicNewTempExprNode(NewTempExprNode):
# I do not dare to convert NameNode yet. This is now
# ancestor of all former AtomicExprNode except
# NameNode. Should be renamed to AtomicExprNode
def generate_subexpr_disposal_code(self, code):
pass
-class PyConstNode(AtomicNewTempExprNode):
+class PyConstNode(AtomicExprNode):
# Abstract base class for constant Python values.
is_literal = 1
return Ellipsis
-class ConstNode(AtomicNewTempExprNode):
+class ConstNode(AtomicExprNode):
# Abstract base type for literal constant nodes.
#
# value string C code fragment
return self.result_code
-class LongNode(AtomicNewTempExprNode):
+class LongNode(AtomicExprNode):
# Python long integer literal
#
# value string
code.put_gotref(self.py_result())
-class ImagNode(AtomicNewTempExprNode):
+class ImagNode(AtomicExprNode):
# Imaginary number literal
#
# value float imaginary part
-class NameNode(AtomicNewTempExprNode):
+class NameNode(AtomicExprNode):
# Reference to a local or global variable name.
#
# name string Python name of the variable
else:
code.annotate(pos, AnnotationItem('c_call', 'c function', size=len(self.name)))
-class BackquoteNode(NewTempExprNode):
+class BackquoteNode(ExprNode):
# `expr`
#
# arg ExprNode
-class ImportNode(NewTempExprNode):
+class ImportNode(ExprNode):
# Used as part of import statement implementation.
# Implements result =
# __import__(module_name, globals(), None, name_list)
code.put_gotref(self.py_result())
-class IteratorNode(NewTempExprNode):
+class IteratorNode(ExprNode):
# Used as part of for statement implementation.
#
# allocate_counter_temp/release_counter_temp needs to be called
code.putln("}")
-class NextNode(AtomicNewTempExprNode):
+class NextNode(AtomicExprNode):
# Used as part of for statement implementation.
# Implements result = iterator.next()
# Created during analyse_types phase.
code.putln("}")
-class ExcValueNode(AtomicNewTempExprNode):
+class ExcValueNode(AtomicExprNode):
# Node created during analyse_types phase
# of an ExceptClauseNode to fetch the current
# exception value.
pass
-class TempNode(NewTempExprNode):
+class TempNode(ExprNode):
# Node created during analyse_types phase
# of some nodes to hold a temporary value.
#
#
#-------------------------------------------------------------------
-class IndexNode(NewTempExprNode):
+class IndexNode(ExprNode):
# Sequence indexing.
#
# base ExprNode
code.putln(code.error_goto(self.pos))
code.putln("}")
-class SliceIndexNode(NewTempExprNode):
+class SliceIndexNode(ExprNode):
# 2-element slice indexing
#
# base ExprNode
return "<unused>"
-class SliceNode(NewTempExprNode):
+class SliceNode(ExprNode):
# start:stop:step in subscript list
#
# start ExprNode
code.put_gotref(self.py_result())
-class CallNode(NewTempExprNode):
+class CallNode(ExprNode):
def analyse_as_type_constructor(self, env):
type = self.function.analyse_as_type(env)
if type and type.is_struct_or_union:
code.put_gotref(self.py_result())
-class AsTupleNode(NewTempExprNode):
+class AsTupleNode(ExprNode):
# Convert argument to tuple. Used for normalising
# the * argument of a function call.
#
code.put_gotref(self.py_result())
-class AttributeNode(NewTempExprNode):
+class AttributeNode(ExprNode):
# obj.attribute
#
# obj ExprNode
#
#-------------------------------------------------------------------
-class SequenceNode(NewTempExprNode):
+class SequenceNode(ExprNode):
# Base class for list and tuple constructor nodes.
# Contains common code for performing sequence unpacking.
#
# generate_evaluation_code which will do that.
-class ComprehensionNode(NewTempExprNode):
+class ComprehensionNode(ExprNode):
subexprs = ["target"]
child_attrs = ["loop", "append"]
self.loop.annotate(code)
-class ComprehensionAppendNode(NewTempExprNode):
+class ComprehensionAppendNode(ExprNode):
# Need to be careful to avoid infinite recursion:
# target must not be in child_attrs/subexprs
subexprs = ['expr']
code.error_goto_if(self.result(), self.pos)))
-class SetNode(NewTempExprNode):
+class SetNode(ExprNode):
# Set constructor.
subexprs = ['args']
arg.free_temps(code)
-class DictNode(NewTempExprNode):
+class DictNode(ExprNode):
# Dictionary constructor.
#
# key_value_pairs [DictItemNode]
for item in self.key_value_pairs:
item.annotate(code)
-class DictItemNode(NewTempExprNode):
+class DictItemNode(ExprNode):
# Represents a single item in a DictNode
#
# key ExprNode
return iter([self.key, self.value])
-class ClassNode(NewTempExprNode):
+class ClassNode(ExprNode):
# Helper class used in the implementation of Python
# class definitions. Constructs a class object given
# a name, tuple of bases and class dictionary.
code.put_gotref(self.py_result())
-class UnboundMethodNode(NewTempExprNode):
+class UnboundMethodNode(ExprNode):
# Helper class used in the implementation of Python
# class definitions. Constructs an unbound method
# object from a class and a function.
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
-class PyCFunctionNode(AtomicNewTempExprNode):
+class PyCFunctionNode(AtomicExprNode):
# Helper class used in the implementation of Python
# class definitions. Constructs a PyCFunction object
# from a PyMethodDef struct.
'+': operator.pos,
}
-class UnopNode(NewTempExprNode):
+class UnopNode(ExprNode):
# operator string
# operand ExprNode
#
self.type = PyrexTypes.error_type
-class NotNode(NewTempExprNode):
+class NotNode(ExprNode):
# 'not' operator
#
# operand ExprNode
return "(~%s)" % self.operand.result()
-class AmpersandNode(NewTempExprNode):
+class AmpersandNode(ExprNode):
# The C address-of operator.
#
# operand ExprNode
operand = operand)
-class TypecastNode(NewTempExprNode):
+class TypecastNode(ExprNode):
# C type cast
#
# operand ExprNode
code.put_incref(self.result(), self.ctype())
-class SizeofNode(NewTempExprNode):
+class SizeofNode(ExprNode):
# Abstract base class for sizeof(x) expression nodes.
type = PyrexTypes.c_size_t_type
% node.operator)
return func
-class BinopNode(NewTempExprNode):
+class BinopNode(ExprNode):
# operator string
# operand1 ExprNode
# operand2 ExprNode
# one could have a look at adding this again after /all/ classes
# are converted to the new temp scheme. (The temp juggling cannot work
# otherwise).
-class BoolBinopNode(NewTempExprNode):
+class BoolBinopNode(ExprNode):
# Short-circuiting boolean operation.
#
# operator string
return (test_result, self.type.is_pyobject)
-class CondExprNode(NewTempExprNode):
+class CondExprNode(ExprNode):
# Short-circuiting conditional expression.
#
# test ExprNode
return op
-class PrimaryCmpNode(NewTempExprNode, CmpNode):
+class PrimaryCmpNode(ExprNode, CmpNode):
# Non-cascaded comparison or first comparison of
# a cascaded sequence.
#
#
#-------------------------------------------------------------------
-class CoercionNode(NewTempExprNode):
+class CoercionNode(ExprNode):
# Abstract base class for coercion nodes.
#
# arg ExprNode node being coerced