Cython has moved to github.

cython-devel

view Cython/Compiler/UtilNodes.py @ 2746:9e88d3a5d085

'type inference' for special temp nodes
author Stefan Behnel <scoder@users.berlios.de>
date Sun Dec 06 00:09:54 2009 +0100 (2 years ago)
parents d98ebaf99b15
children 6866d26ea6ef
line source
1 #
2 # Nodes used as utilities and support for transforms etc.
3 # These often make up sets including both Nodes and ExprNodes
4 # so it is convenient to have them in a seperate module.
5 #
7 import Nodes
8 import ExprNodes
9 from Nodes import Node
10 from ExprNodes import AtomicExprNode
12 class TempHandle(object):
13 # THIS IS DEPRECATED, USE LetRefNode instead
14 temp = None
15 needs_xdecref = False
16 def __init__(self, type):
17 self.type = type
18 self.needs_cleanup = type.is_pyobject
20 def ref(self, pos):
21 return TempRefNode(pos, handle=self, type=self.type)
23 def cleanup_ref(self, pos):
24 return CleanupTempRefNode(pos, handle=self, type=self.type)
26 class TempRefNode(AtomicExprNode):
27 # THIS IS DEPRECATED, USE LetRefNode instead
28 # handle TempHandle
30 def analyse_types(self, env):
31 assert self.type == self.handle.type
33 def analyse_target_types(self, env):
34 assert self.type == self.handle.type
36 def analyse_target_declaration(self, env):
37 pass
39 def calculate_result_code(self):
40 result = self.handle.temp
41 if result is None: result = "<error>" # might be called and overwritten
42 return result
44 def generate_result_code(self, code):
45 pass
47 def generate_assignment_code(self, rhs, code):
48 if self.type.is_pyobject:
49 rhs.make_owned_reference(code)
50 # TODO: analyse control flow to see if this is necessary
51 code.put_xdecref(self.result(), self.ctype())
52 code.putln('%s = %s;' % (self.result(), rhs.result_as(self.ctype())))
53 rhs.generate_post_assignment_code(code)
54 rhs.free_temps(code)
56 class CleanupTempRefNode(TempRefNode):
57 # THIS IS DEPRECATED, USE LetRefNode instead
58 # handle TempHandle
60 def generate_assignment_code(self, rhs, code):
61 pass
63 def generate_execution_code(self, code):
64 if self.type.is_pyobject:
65 code.put_decref_clear(self.result(), self.type)
66 self.handle.needs_cleanup = False
68 class TempsBlockNode(Node):
69 # THIS IS DEPRECATED, USE LetNode instead
71 """
72 Creates a block which allocates temporary variables.
73 This is used by transforms to output constructs that need
74 to make use of a temporary variable. Simply pass the types
75 of the needed temporaries to the constructor.
77 The variables can be referred to using a TempRefNode
78 (which can be constructed by calling get_ref_node).
79 """
81 # temps [TempHandle]
82 # body StatNode
84 child_attrs = ["body"]
86 def generate_execution_code(self, code):
87 for handle in self.temps:
88 handle.temp = code.funcstate.allocate_temp(
89 handle.type, manage_ref=handle.needs_cleanup)
90 self.body.generate_execution_code(code)
91 for handle in self.temps:
92 if handle.needs_cleanup:
93 if handle.needs_xdecref:
94 code.put_xdecref_clear(handle.temp, handle.type)
95 else:
96 code.put_decref_clear(handle.temp, handle.type)
97 code.funcstate.release_temp(handle.temp)
99 def analyse_control_flow(self, env):
100 self.body.analyse_control_flow(env)
102 def analyse_declarations(self, env):
103 self.body.analyse_declarations(env)
105 def analyse_expressions(self, env):
106 self.body.analyse_expressions(env)
108 def generate_function_definitions(self, env, code):
109 self.body.generate_function_definitions(env, code)
111 def annotate(self, code):
112 self.body.annotate(code)
115 class ResultRefNode(AtomicExprNode):
116 # A reference to the result of an expression. The result_code
117 # must be set externally (usually a temp name).
119 subexprs = []
121 def __init__(self, expression):
122 self.pos = expression.pos
123 self.expression = expression
124 if hasattr(expression, "type"):
125 self.type = expression.type
127 def analyse_types(self, env):
128 self.type = self.expression.type
130 def infer_type(self, env):
131 return self.expression.infer_type(env)
133 def result(self):
134 return self.result_code
136 def generate_evaluation_code(self, code):
137 pass
139 def generate_result_code(self, code):
140 pass
142 def generate_disposal_code(self, code):
143 pass
145 def generate_assignment_code(self, rhs, code):
146 if self.type.is_pyobject:
147 rhs.make_owned_reference(code)
148 code.put_decref(self.result(), self.ctype())
149 code.putln('%s = %s;' % (self.result(), rhs.result_as(self.ctype())))
150 rhs.generate_post_assignment_code(code)
151 rhs.free_temps(code)
153 def allocate_temps(self, env):
154 pass
156 def release_temp(self, env):
157 pass
159 def free_temps(self, code):
160 pass
163 class LetNodeMixin:
164 def set_temp_expr(self, lazy_temp):
165 self.lazy_temp = lazy_temp
166 self.temp_expression = lazy_temp.expression
168 def setup_temp_expr(self, code):
169 self.temp_expression.generate_evaluation_code(code)
170 self._result_in_temp = self.temp_expression.result_in_temp()
171 self.temp_type = self.temp_expression.type
172 if self._result_in_temp:
173 self.temp = self.temp_expression.result()
174 else:
175 self.temp_expression.make_owned_reference(code)
176 self.temp = code.funcstate.allocate_temp(
177 self.temp_type, manage_ref=True)
178 code.putln("%s = %s;" % (self.temp, self.temp_expression.result()))
179 self.lazy_temp.result_code = self.temp
181 def teardown_temp_expr(self, code):
182 if not self._result_in_temp:
183 if self.temp_type.is_pyobject:
184 code.put_decref_clear(self.temp, self.temp_type)
185 code.funcstate.release_temp(self.temp)
187 class EvalWithTempExprNode(ExprNodes.ExprNode, LetNodeMixin):
188 # A wrapper around a subexpression that moves an expression into a
189 # temp variable and provides it to the subexpression.
191 subexprs = ['temp_expression', 'subexpression']
193 def __init__(self, lazy_temp, subexpression):
194 self.set_temp_expr(lazy_temp)
195 self.pos = subexpression.pos
196 self.subexpression = subexpression
198 def infer_type(self, env):
199 return self.subexpression.infer_type(env)
201 def result(self):
202 return self.subexpression.result()
204 def analyse_types(self, env):
205 self.temp_expression.analyse_types(env)
206 self.subexpression.analyse_types(env)
207 self.type = self.subexpression.type
209 def generate_evaluation_code(self, code):
210 self.setup_temp_expr(code)
211 self.subexpression.generate_evaluation_code(code)
212 self.teardown_temp_expr(code)
214 LetRefNode = ResultRefNode
216 class LetNode(Nodes.StatNode, LetNodeMixin):
217 # Implements a local temporary variable scope. Imagine this
218 # syntax being present:
219 # let temp = VALUE:
220 # BLOCK (can modify temp)
221 # if temp is an object, decref
222 #
223 # To be used after analysis phase, does no analysis.
225 child_attrs = ['temp_expression', 'body']
227 def __init__(self, lazy_temp, body):
228 self.set_temp_expr(lazy_temp)
229 self.pos = body.pos
230 self.body = body
232 def generate_execution_code(self, code):
233 self.setup_temp_expr(code)
234 self.body.generate_execution_code(code)
235 self.teardown_temp_expr(code)