7 from Visitor
import CythonTransform
8 from Errors
import CompileError
, InternalError
, AbortError
12 # Really small pipeline stages
15 # For quick debugging in pipelines
19 def abort_on_errors(node
):
20 # Stop the pipeline if there are any errors.
21 if Errors
.num_errors
!= 0:
22 raise AbortError("pipeline break")
25 def parse_stage_factory(context
):
27 source_desc
= compsrc
.source_desc
28 full_module_name
= compsrc
.full_module_name
29 initial_pos
= (source_desc
, 1, 0)
30 saved_cimport_from_pyx
, Options
.cimport_from_pyx
= Options
.cimport_from_pyx
, False
31 scope
= context
.find_module(full_module_name
, pos
= initial_pos
, need_pxd
= 0,
32 check_module_name
= not Options
.embed
)
33 Options
.cimport_from_pyx
= saved_cimport_from_pyx
34 tree
= context
.parse(source_desc
, scope
, pxd
= 0, full_module_name
= full_module_name
)
35 tree
.compilation_source
= compsrc
41 def parse_pxd_stage_factory(context
, scope
, module_name
):
42 def parse(source_desc
):
43 tree
= context
.parse(source_desc
, scope
, pxd
=True,
44 full_module_name
=module_name
)
50 def generate_pyx_code_stage_factory(options
, result
):
51 def generate_pyx_code_stage(module_node
):
52 module_node
.process_implementation(options
, result
)
53 result
.compilation_source
= module_node
.compilation_source
55 return generate_pyx_code_stage
57 def inject_pxd_code_stage_factory(context
):
58 def inject_pxd_code_stage(module_node
):
59 from textwrap
import dedent
60 stats
= module_node
.body
.stats
61 for name
, (statlistnode
, scope
) in context
.pxds
.iteritems():
62 module_node
.merge_in(statlistnode
, scope
)
64 return inject_pxd_code_stage
66 def use_utility_code_definitions(scope
, target
, seen
=None):
70 for entry
in scope
.entries
.itervalues():
75 if entry
.used
and entry
.utility_code_definition
:
76 target
.use_utility_code(entry
.utility_code_definition
)
77 for required_utility
in entry
.utility_code_definition
.requires
:
78 target
.use_utility_code(required_utility
)
80 use_utility_code_definitions(entry
.as_module
, target
, seen
)
82 def inject_utility_code_stage_factory(context
):
83 def inject_utility_code_stage(module_node
):
84 use_utility_code_definitions(context
.cython_scope
, module_node
.scope
)
86 # Note: the list might be extended inside the loop (if some utility code
87 # pulls in other utility code, explicitly or implicitly)
88 for utilcode
in module_node
.scope
.utility_code_list
:
89 if utilcode
in added
: continue
90 added
.append(utilcode
)
92 for dep
in utilcode
.requires
:
93 if not dep
in added
and not dep
in module_node
.scope
.utility_code_list
:
94 module_node
.scope
.utility_code_list
.append(dep
)
95 tree
= utilcode
.get_tree()
97 module_node
.merge_in(tree
.body
, tree
.scope
, merge_scope
=True)
99 return inject_utility_code_stage
101 class UseUtilityCodeDefinitions(CythonTransform
):
102 # Temporary hack to use any utility code in nodes' "utility_code_definitions".
103 # This should be moved to the code generation phase of the relevant nodes once
104 # it is safe to generate CythonUtilityCode at code generation time.
105 def __call__(self
, node
):
106 self
.scope
= node
.scope
107 return super(UseUtilityCodeDefinitions
, self
).__call
__(node
)
109 def process_entry(self
, entry
):
111 for utility_code
in (entry
.utility_code
, entry
.utility_code_definition
):
113 self
.scope
.use_utility_code(utility_code
)
115 def visit_AttributeNode(self
, node
):
116 self
.process_entry(node
.entry
)
119 def visit_NameNode(self
, node
):
120 self
.process_entry(node
.entry
)
121 self
.process_entry(node
.type_entry
)
128 def create_pipeline(context
, mode
, exclude_classes
=()):
129 assert mode
in ('pyx', 'py', 'pxd')
130 from Visitor
import PrintTree
131 from ParseTreeTransforms
import WithTransform
, NormalizeTree
, PostParse
, PxdPostParse
132 from ParseTreeTransforms
import ForwardDeclareTypes
, AnalyseDeclarationsTransform
133 from ParseTreeTransforms
import AnalyseExpressionsTransform
, FindInvalidUseOfFusedTypes
134 from ParseTreeTransforms
import CreateClosureClasses
, MarkClosureVisitor
, DecoratorTransform
135 from ParseTreeTransforms
import InterpretCompilerDirectives
, TransformBuiltinMethods
136 from ParseTreeTransforms
import ExpandInplaceOperators
, ParallelRangeTransform
137 from ParseTreeTransforms
import CalculateQualifiedNamesTransform
138 from TypeInference
import MarkParallelAssignments
, MarkOverflowingArithmetic
139 from ParseTreeTransforms
import AdjustDefByDirectives
, AlignFunctionDefinitions
140 from ParseTreeTransforms
import RemoveUnreachableCode
, GilCheck
141 from FlowControl
import ControlFlowAnalysis
142 from AnalysedTreeTransforms
import AutoTestDictTransform
143 from AutoDocTransforms
import EmbedSignature
144 from Optimize
import FlattenInListTransform
, SwitchTransform
, IterationTransform
145 from Optimize
import EarlyReplaceBuiltinCalls
, OptimizeBuiltinCalls
146 from Optimize
import InlineDefNodeCalls
147 from Optimize
import ConstantFolding
, FinalOptimizePhase
148 from Optimize
import DropRefcountingTransform
149 from Optimize
import ConsolidateOverflowCheck
150 from Buffer
import IntroduceBufferAuxiliaryVars
151 from ModuleNode
import check_c_declarations
, check_c_declarations_pxd
155 _check_c_declarations
= check_c_declarations_pxd
156 _specific_post_parse
= PxdPostParse(context
)
158 _check_c_declarations
= check_c_declarations
159 _specific_post_parse
= None
162 _align_function_definitions
= AlignFunctionDefinitions(context
)
164 _align_function_definitions
= None
166 # NOTE: This is the "common" parts of the pipeline, which is also
167 # code in pxd files. So it will be run multiple times in a
170 NormalizeTree(context
),
172 _specific_post_parse
,
173 InterpretCompilerDirectives(context
, context
.compiler_directives
),
174 ParallelRangeTransform(context
),
175 AdjustDefByDirectives(context
),
176 MarkClosureVisitor(context
),
177 _align_function_definitions
,
178 RemoveUnreachableCode(context
),
180 FlattenInListTransform(),
181 WithTransform(context
),
182 DecoratorTransform(context
),
183 ForwardDeclareTypes(context
),
184 AnalyseDeclarationsTransform(context
),
185 AutoTestDictTransform(context
),
186 EmbedSignature(context
),
187 EarlyReplaceBuiltinCalls(context
), ## Necessary?
188 TransformBuiltinMethods(context
), ## Necessary?
189 MarkParallelAssignments(context
),
190 ControlFlowAnalysis(context
),
191 RemoveUnreachableCode(context
),
192 # MarkParallelAssignments(context),
193 MarkOverflowingArithmetic(context
),
194 IntroduceBufferAuxiliaryVars(context
),
195 _check_c_declarations
,
196 InlineDefNodeCalls(context
),
197 AnalyseExpressionsTransform(context
),
198 FindInvalidUseOfFusedTypes(context
),
199 ExpandInplaceOperators(context
),
200 OptimizeBuiltinCalls(context
), ## Necessary?
201 CreateClosureClasses(context
), ## After all lookups and type inference
202 CalculateQualifiedNamesTransform(context
),
203 ConsolidateOverflowCheck(context
),
204 IterationTransform(context
),
206 DropRefcountingTransform(),
207 FinalOptimizePhase(context
),
209 UseUtilityCodeDefinitions(context
),
213 if s
.__class
__ not in exclude_classes
:
214 filtered_stages
.append(s
)
215 return filtered_stages
217 def create_pyx_pipeline(context
, options
, result
, py
=False, exclude_classes
=()):
223 if options
.evaluate_tree_assertions
:
224 from Cython
.TestUtils
import TreeAssertVisitor
225 test_support
.append(TreeAssertVisitor())
227 if options
.gdb_debug
:
228 from Cython
.Debugger
import DebugWriter
# requires Py2.5+
229 from ParseTreeTransforms
import DebugTransform
230 context
.gdb_debug_outputwriter
= DebugWriter
.CythonDebugWriter(
232 debug_transform
= [DebugTransform(context
, options
, result
)]
236 return list(itertools
.chain(
237 [parse_stage_factory(context
)],
238 create_pipeline(context
, mode
, exclude_classes
=exclude_classes
),
240 [inject_pxd_code_stage_factory(context
),
241 inject_utility_code_stage_factory(context
),
244 [generate_pyx_code_stage_factory(options
, result
)]))
246 def create_pxd_pipeline(context
, scope
, module_name
):
247 from CodeGeneration
import ExtractPxdCode
249 # The pxd pipeline ends up with a CCodeWriter containing the
250 # code of the pxd, as well as a pxd scope.
252 parse_pxd_stage_factory(context
, scope
, module_name
)
253 ] + create_pipeline(context
, 'pxd') + [
257 def create_py_pipeline(context
, options
, result
):
258 return create_pyx_pipeline(context
, options
, result
, py
=True)
260 def create_pyx_as_pxd_pipeline(context
, result
):
261 from ParseTreeTransforms
import AlignFunctionDefinitions
, \
262 MarkClosureVisitor
, WithTransform
, AnalyseDeclarationsTransform
263 from Optimize
import ConstantFolding
, FlattenInListTransform
264 from Nodes
import StatListNode
266 pyx_pipeline
= create_pyx_pipeline(context
, context
.options
, result
,
268 AlignFunctionDefinitions
,
271 FlattenInListTransform
,
274 for stage
in pyx_pipeline
:
275 pipeline
.append(stage
)
276 if isinstance(stage
, AnalyseDeclarationsTransform
):
277 # This is the last stage we need.
280 for entry
in root
.scope
.entries
.values():
281 if not entry
.in_cinclude
:
282 entry
.defined_in_pxd
= 1
283 if entry
.name
== entry
.cname
and entry
.visibility
!= 'extern':
284 # Always mangle non-extern cimported entries.
285 entry
.cname
= entry
.scope
.mangle(Naming
.func_prefix
, entry
.name
)
286 return StatListNode(root
.pos
, stats
=[]), root
.scope
287 pipeline
.append(fake_pxd
)
290 def insert_into_pipeline(pipeline
, transform
, before
=None, after
=None):
292 Insert a new transform into the pipeline after or before an instance of
293 the given class. e.g.
295 pipeline = insert_into_pipeline(pipeline, transform,
296 after=AnalyseDeclarationsTransform)
298 assert before
or after
300 cls
= before
or after
301 for i
, t
in enumerate(pipeline
):
302 if isinstance(t
, cls
):
308 return pipeline
[:i
] + [transform
] + pipeline
[i
:]
314 def run_pipeline(pipeline
, source
, printtree
=True):
315 from Cython
.Compiler
.Visitor
import PrintTree
321 for phase
in pipeline
:
322 if phase
is not None:
323 if DebugFlags
.debug_verbose_pipeline
:
325 print "Entering pipeline phase %r" % phase
326 if not printtree
and isinstance(phase
, PrintTree
):
329 if DebugFlags
.debug_verbose_pipeline
:
330 print " %.3f seconds" % (time() - t
)
331 except CompileError
, err
:
333 Errors
.report_error(err
)
335 except InternalError
, err
:
336 # Only raise if there was not an earlier error
337 if Errors
.num_errors
== 0:
340 except AbortError
, err
: