2 Serializes a Cython code tree to Cython code. This is primarily useful for
3 debugging and testing purposes.
5 The output is in a strict format, no whitespace or comments from the input
6 is preserved (and it could not be as it is not present in the code tree).
9 from Cython
.Compiler
.Visitor
import TreeVisitor
10 from Cython
.Compiler
.ExprNodes
import *
12 class LinesResult(object):
21 self
.lines
.append(self
.s
)
28 class DeclarationWriter(TreeVisitor
):
32 def __init__(self
, result
= None):
33 super(DeclarationWriter
, self
).__init
__()
35 result
= LinesResult()
39 self
.tempblockindex
= 0
41 def write(self
, tree
):
51 def startline(self
, s
= u
""):
52 self
.result
.put(self
.indent_string
* self
.numindents
+ s
)
58 self
.result
.putline(self
.indent_string
* self
.numindents
+ s
)
60 def endline(self
, s
= u
""):
61 self
.result
.putline(s
)
67 def comma_separated_list(self
, items
, output_rhs
=False):
69 for item
in items
[:-1]:
71 if output_rhs
and item
.default
is not None:
73 self
.visit(item
.default
)
77 def visit_Node(self
, node
):
78 raise AssertionError("Node not handled by serializer: %r" % node
)
80 def visit_ModuleNode(self
, node
):
81 self
.visitchildren(node
)
83 def visit_StatListNode(self
, node
):
84 self
.visitchildren(node
)
86 def visit_CDefExternNode(self
, node
):
87 if node
.include_file
is None:
90 file = u
'"%s"' % node
.include_file
91 self
.putline(u
"cdef extern from %s:" % file)
96 def visit_CPtrDeclaratorNode(self
, node
):
100 def visit_CReferenceDeclaratorNode(self
, node
):
102 self
.visit(node
.base
)
104 def visit_CArrayDeclaratorNode(self
, node
):
105 self
.visit(node
.base
)
107 if node
.dimension
is not None:
108 self
.visit(node
.dimension
)
111 def visit_CArrayDeclaratorNode(self
, node
):
112 self
.visit(node
.base
)
114 if node
.dimension
is not None:
115 self
.visit(node
.dimension
)
118 def visit_CFuncDeclaratorNode(self
, node
):
119 # TODO: except, gil, etc.
120 self
.visit(node
.base
)
122 self
.comma_separated_list(node
.args
)
125 def visit_CNameDeclaratorNode(self
, node
):
128 def visit_CSimpleBaseTypeNode(self
, node
):
129 # See Parsing.p_sign_and_longness
130 if node
.is_basic_c_type
:
131 self
.put(("unsigned ", "", "signed ")[node
.signed
])
132 if node
.longness
< 0:
133 self
.put("short " * -node
.longness
)
134 elif node
.longness
> 0:
135 self
.put("long " * node
.longness
)
138 def visit_CComplexBaseTypeNode(self
, node
):
140 self
.visit(node
.base_type
)
141 self
.visit(node
.declarator
)
144 def visit_CNestedBaseTypeNode(self
, node
):
145 self
.visit(node
.base_type
)
149 def visit_TemplatedTypeNode(self
, node
):
150 self
.visit(node
.base_type_node
)
152 self
.comma_separated_list(node
.positional_args
+ node
.keyword_args
.key_value_pairs
)
155 def visit_CVarDefNode(self
, node
):
156 self
.startline(u
"cdef ")
157 self
.visit(node
.base_type
)
159 self
.comma_separated_list(node
.declarators
, output_rhs
=True)
162 def visit_container_node(self
, node
, decl
, extras
, attributes
):
168 if node
.cname
is not None:
169 self
.put(u
' "%s"' % node
.cname
)
177 for attribute
in attributes
:
178 self
.visit(attribute
)
181 def visit_CStructOrUnionDefNode(self
, node
):
182 if node
.typedef_flag
:
186 if node
.visibility
== 'public':
191 self
.visit_container_node(node
, decl
, None, node
.attributes
)
193 def visit_CppClassNode(self
, node
):
196 extras
= u
"[%s]" % ", ".join(node
.templates
)
197 if node
.base_classes
:
198 extras
+= "(%s)" % ", ".join(node
.base_classes
)
199 self
.visit_container_node(node
, u
"cdef cppclass", extras
, node
.attributes
)
201 def visit_CEnumDefNode(self
, node
):
202 self
.visit_container_node(node
, u
"cdef enum", None, node
.items
)
204 def visit_CEnumDefItemNode(self
, node
):
205 self
.startline(node
.name
)
207 self
.put(u
' "%s"' % node
.cname
)
210 self
.visit(node
.value
)
213 def visit_CClassDefNode(self
, node
):
214 assert not node
.module_name
216 for decorator
in node
.decorators
:
217 self
.visit(decorator
)
218 self
.startline(u
"cdef class ")
219 self
.put(node
.class_name
)
220 if node
.base_class_name
:
222 if node
.base_class_module
:
223 self
.put(node
.base_class_module
)
225 self
.put(node
.base_class_name
)
229 self
.visit(node
.body
)
232 def visit_CTypeDefNode(self
, node
):
233 self
.startline(u
"ctypedef ")
234 self
.visit(node
.base_type
)
236 self
.visit(node
.declarator
)
239 def visit_FuncDefNode(self
, node
):
240 self
.startline(u
"def %s(" % node
.name
)
241 self
.comma_separated_list(node
.args
)
244 self
.visit(node
.body
)
247 def visit_CArgDeclNode(self
, node
):
248 if node
.base_type
.name
is not None:
249 self
.visit(node
.base_type
)
251 self
.visit(node
.declarator
)
252 if node
.default
is not None:
254 self
.visit(node
.default
)
256 def visit_CImportStatNode(self
, node
):
257 self
.startline(u
"cimport ")
258 self
.put(node
.module_name
)
261 self
.put(node
.as_name
)
264 def visit_FromCImportStatNode(self
, node
):
265 self
.startline(u
"from ")
266 self
.put(node
.module_name
)
267 self
.put(u
" cimport ")
269 for pos
, name
, as_name
, kind
in node
.imported_names
:
281 def visit_NameNode(self
, node
):
284 def visit_IntNode(self
, node
):
287 def visit_NoneNode(self
, node
):
290 def visit_NotNode(self
, node
):
292 self
.visit(node
.operand
)
295 def visit_DecoratorNode(self
, node
):
297 self
.visit(node
.decorator
)
300 def visit_BinopNode(self
, node
):
301 self
.visit(node
.operand1
)
302 self
.put(u
" %s " % node
.operator
)
303 self
.visit(node
.operand2
)
305 def visit_AttributeNode(self
, node
):
307 self
.put(u
".%s" % node
.attribute
)
309 def visit_BoolNode(self
, node
):
310 self
.put(str(node
.value
))
312 # FIXME: represent string nodes correctly
313 def visit_StringNode(self
, node
):
315 if value
.encoding
is not None:
316 value
= value
.encode(value
.encoding
)
317 self
.put(repr(value
))
319 def visit_PassStatNode(self
, node
):
320 self
.startline(u
"pass")
323 class CodeWriter(DeclarationWriter
):
325 def visit_SingleAssignmentNode(self
, node
):
332 def visit_CascadedAssignmentNode(self
, node
):
334 for lhs
in node
.lhs_list
:
340 def visit_PrintStatNode(self
, node
):
341 self
.startline(u
"print ")
342 self
.comma_separated_list(node
.arg_tuple
.args
)
343 if not node
.append_newline
:
347 def visit_ForInStatNode(self
, node
):
348 self
.startline(u
"for ")
349 self
.visit(node
.target
)
351 self
.visit(node
.iterator
.sequence
)
354 self
.visit(node
.body
)
356 if node
.else_clause
is not None:
359 self
.visit(node
.else_clause
)
362 def visit_IfStatNode(self
, node
):
363 # The IfClauseNode is handled directly without a seperate match
365 self
.startline(u
"if ")
366 self
.visit(node
.if_clauses
[0].condition
)
369 self
.visit(node
.if_clauses
[0].body
)
371 for clause
in node
.if_clauses
[1:]:
372 self
.startline("elif ")
373 self
.visit(clause
.condition
)
376 self
.visit(clause
.body
)
378 if node
.else_clause
is not None:
381 self
.visit(node
.else_clause
)
384 def visit_SequenceNode(self
, node
):
385 self
.comma_separated_list(node
.args
) # Might need to discover whether we need () around tuples...hmm...
387 def visit_SimpleCallNode(self
, node
):
388 self
.visit(node
.function
)
390 self
.comma_separated_list(node
.args
)
393 def visit_GeneralCallNode(self
, node
):
394 self
.visit(node
.function
)
396 posarg
= node
.positional_args
397 if isinstance(posarg
, AsTupleNode
):
398 self
.visit(posarg
.arg
)
400 self
.comma_separated_list(posarg
)
401 if node
.keyword_args
is not None or node
.starstar_arg
is not None:
402 raise Exception("Not implemented yet")
405 def visit_ExprStatNode(self
, node
):
407 self
.visit(node
.expr
)
410 def visit_InPlaceAssignmentNode(self
, node
):
413 self
.put(u
" %s= " % node
.operator
)
417 def visit_WithStatNode(self
, node
):
420 self
.visit(node
.manager
)
421 if node
.target
is not None:
423 self
.visit(node
.target
)
426 self
.visit(node
.body
)
429 def visit_TryFinallyStatNode(self
, node
):
432 self
.visit(node
.body
)
434 self
.line(u
"finally:")
436 self
.visit(node
.finally_clause
)
439 def visit_TryExceptStatNode(self
, node
):
442 self
.visit(node
.body
)
444 for x
in node
.except_clauses
:
446 if node
.else_clause
is not None:
447 self
.visit(node
.else_clause
)
449 def visit_ExceptClauseNode(self
, node
):
450 self
.startline(u
"except")
451 if node
.pattern
is not None:
453 self
.visit(node
.pattern
)
454 if node
.target
is not None:
456 self
.visit(node
.target
)
459 self
.visit(node
.body
)
462 def visit_ReturnStatNode(self
, node
):
463 self
.startline("return ")
464 self
.visit(node
.value
)
467 def visit_ReraiseStatNode(self
, node
):
470 def visit_ImportNode(self
, node
):
471 self
.put(u
"(import %s)" % node
.module_name
.value
)
473 def visit_TempsBlockNode(self
, node
):
475 Temporaries are output like $1_1', where the first number is
476 an index of the TempsBlockNode and the second number is an index
477 of the temporary which that block allocates.
480 for handle
in node
.temps
:
481 self
.tempnames
[handle
] = "$%d_%d" % (self
.tempblockindex
, idx
)
483 self
.tempblockindex
+= 1
484 self
.visit(node
.body
)
486 def visit_TempRefNode(self
, node
):
487 self
.put(self
.tempnames
[node
.handle
])
490 class PxdWriter(DeclarationWriter
):
491 def __call__(self
, node
):
492 print u
'\n'.join(self
.write(node
).lines
)
495 def visit_CFuncDefNode(self
, node
):
496 if 'inline' in node
.modifiers
:
499 self
.startline(u
'cpdef ')
501 self
.startline(u
'cdef ')
502 if node
.visibility
!= 'private':
503 self
.put(node
.visibility
)
507 self
.visit(node
.declarator
)
509 def visit_StatNode(self
, node
):