1 from Cython.Compiler.Visitor import TreeVisitor
2 from Cython.Compiler.Nodes import *
3 from Cython.Compiler.ExprNodes import *
6 Serializes a Cython code tree to Cython code. This is primarily useful for
7 debugging and testing purposes.
9 The output is in a strict format, no whitespace or comments from the input
10 is preserved (and it could not be as it is not present in the code tree).
13 class LinesResult(object):
22 self.lines.append(self.s)
29 class DeclarationWriter(TreeVisitor):
33 def __init__(self, result = None):
34 super(DeclarationWriter, self).__init__()
36 result = LinesResult()
40 self.tempblockindex = 0
42 def write(self, tree):
52 def startline(self, s = u""):
53 self.result.put(self.indent_string * self.numindents + s)
59 self.result.putline(self.indent_string * self.numindents + s)
61 def endline(self, s = u""):
62 self.result.putline(s)
68 def comma_separated_list(self, items, output_rhs=False):
70 for item in items[:-1]:
72 if output_rhs and item.default is not None:
74 self.visit(item.default)
78 def visit_Node(self, node):
79 raise AssertionError("Node not handled by serializer: %r" % node)
81 def visit_ModuleNode(self, node):
82 self.visitchildren(node)
84 def visit_StatListNode(self, node):
85 self.visitchildren(node)
87 def visit_CDefExternNode(self, node):
88 if node.include_file is None:
91 file = u'"%s"' % node.include_file
92 self.putline(u"cdef extern from %s:" % file)
97 def visit_CPtrDeclaratorNode(self, node):
101 def visit_CReferenceDeclaratorNode(self, node):
103 self.visit(node.base)
105 def visit_CArrayDeclaratorNode(self, node):
106 self.visit(node.base)
108 if node.dimension is not None:
109 self.visit(node.dimension)
112 def visit_CArrayDeclaratorNode(self, node):
113 self.visit(node.base)
115 if node.dimension is not None:
116 self.visit(node.dimension)
119 def visit_CFuncDeclaratorNode(self, node):
120 # TODO: except, gil, etc.
121 self.visit(node.base)
123 self.comma_separated_list(node.args)
126 def visit_CNameDeclaratorNode(self, node):
129 def visit_CSimpleBaseTypeNode(self, node):
130 # See Parsing.p_sign_and_longness
131 if node.is_basic_c_type:
132 self.put(("unsigned ", "", "signed ")[node.signed])
133 if node.longness < 0:
134 self.put("short " * -node.longness)
135 elif node.longness > 0:
136 self.put("long " * node.longness)
139 def visit_CComplexBaseTypeNode(self, node):
141 self.visit(node.base_type)
142 self.visit(node.declarator)
145 def visit_CNestedBaseTypeNode(self, node):
146 self.visit(node.base_type)
150 def visit_TemplatedTypeNode(self, node):
151 self.visit(node.base_type_node)
153 self.comma_separated_list(node.positional_args + node.keyword_args.key_value_pairs)
156 def visit_CVarDefNode(self, node):
157 self.startline(u"cdef ")
158 self.visit(node.base_type)
160 self.comma_separated_list(node.declarators, output_rhs=True)
163 def visit_container_node(self, node, decl, extras, attributes):
169 if node.cname is not None:
170 self.put(u' "%s"' % node.cname)
178 for attribute in attributes:
179 self.visit(attribute)
182 def visit_CStructOrUnionDefNode(self, node):
183 if node.typedef_flag:
187 if node.visibility == 'public':
192 self.visit_container_node(node, decl, None, node.attributes)
194 def visit_CppClassNode(self, node):
197 extras = u"[%s]" % ", ".join(node.templates)
198 if node.base_classes:
199 extras += "(%s)" % ", ".join(node.base_classes)
200 self.visit_container_node(node, u"cdef cppclass", extras, node.attributes)
202 def visit_CEnumDefNode(self, node):
203 self.visit_container_node(node, u"cdef enum", None, node.items)
205 def visit_CEnumDefItemNode(self, node):
206 self.startline(node.name)
208 self.put(u' "%s"' % node.cname)
211 self.visit(node.value)
214 def visit_CClassDefNode(self, node):
215 assert not node.module_name
217 for decorator in node.decorators:
218 self.visit(decorator)
219 self.startline(u"cdef class ")
220 self.put(node.class_name)
221 if node.base_class_name:
223 if node.base_class_module:
224 self.put(node.base_class_module)
226 self.put(node.base_class_name)
230 self.visit(node.body)
233 def visit_CTypeDefNode(self, node):
234 self.startline(u"ctypedef ")
235 self.visit(node.base_type)
237 self.visit(node.declarator)
240 def visit_FuncDefNode(self, node):
241 self.startline(u"def %s(" % node.name)
242 self.comma_separated_list(node.args)
245 self.visit(node.body)
248 def visit_CArgDeclNode(self, node):
249 if node.base_type.name is not None:
250 self.visit(node.base_type)
252 self.visit(node.declarator)
253 if node.default is not None:
255 self.visit(node.default)
257 def visit_CImportStatNode(self, node):
258 self.startline(u"cimport ")
259 self.put(node.module_name)
262 self.put(node.as_name)
265 def visit_FromCImportStatNode(self, node):
266 self.startline(u"from ")
267 self.put(node.module_name)
268 self.put(u" cimport ")
270 for pos, name, as_name, kind in node.imported_names:
282 def visit_NameNode(self, node):
285 def visit_IntNode(self, node):
288 def visit_NoneNode(self, node):
291 def visit_NotNode(self, node):
293 self.visit(node.operand)
296 def visit_DecoratorNode(self, node):
298 self.visit(node.decorator)
301 def visit_BinopNode(self, node):
302 self.visit(node.operand1)
303 self.put(u" %s " % node.operator)
304 self.visit(node.operand2)
306 def visit_AttributeNode(self, node):
308 self.put(u".%s" % node.attribute)
310 def visit_BoolNode(self, node):
311 self.put(str(node.value))
313 # FIXME: represent string nodes correctly
314 def visit_StringNode(self, node):
316 if value.encoding is not None:
317 value = value.encode(value.encoding)
318 self.put(repr(value))
320 def visit_PassStatNode(self, node):
321 self.startline(u"pass")
324 class CodeWriter(DeclarationWriter):
326 def visit_SingleAssignmentNode(self, node):
333 def visit_CascadedAssignmentNode(self, node):
335 for lhs in node.lhs_list:
341 def visit_PrintStatNode(self, node):
342 self.startline(u"print ")
343 self.comma_separated_list(node.arg_tuple.args)
344 if not node.append_newline:
348 def visit_ForInStatNode(self, node):
349 self.startline(u"for ")
350 self.visit(node.target)
352 self.visit(node.iterator.sequence)
355 self.visit(node.body)
357 if node.else_clause is not None:
360 self.visit(node.else_clause)
363 def visit_IfStatNode(self, node):
364 # The IfClauseNode is handled directly without a seperate match
366 self.startline(u"if ")
367 self.visit(node.if_clauses[0].condition)
370 self.visit(node.if_clauses[0].body)
372 for clause in node.if_clauses[1:]:
373 self.startline("elif ")
374 self.visit(clause.condition)
377 self.visit(clause.body)
379 if node.else_clause is not None:
382 self.visit(node.else_clause)
385 def visit_SequenceNode(self, node):
386 self.comma_separated_list(node.args) # Might need to discover whether we need () around tuples...hmm...
388 def visit_SimpleCallNode(self, node):
389 self.visit(node.function)
391 self.comma_separated_list(node.args)
394 def visit_GeneralCallNode(self, node):
395 self.visit(node.function)
397 posarg = node.positional_args
398 if isinstance(posarg, AsTupleNode):
399 self.visit(posarg.arg)
401 self.comma_separated_list(posarg)
402 if node.keyword_args is not None or node.starstar_arg is not None:
403 raise Exception("Not implemented yet")
406 def visit_ExprStatNode(self, node):
408 self.visit(node.expr)
411 def visit_InPlaceAssignmentNode(self, node):
414 self.put(u" %s= " % node.operator)
418 def visit_WithStatNode(self, node):
421 self.visit(node.manager)
422 if node.target is not None:
424 self.visit(node.target)
427 self.visit(node.body)
430 def visit_TryFinallyStatNode(self, node):
433 self.visit(node.body)
435 self.line(u"finally:")
437 self.visit(node.finally_clause)
440 def visit_TryExceptStatNode(self, node):
443 self.visit(node.body)
445 for x in node.except_clauses:
447 if node.else_clause is not None:
448 self.visit(node.else_clause)
450 def visit_ExceptClauseNode(self, node):
451 self.startline(u"except")
452 if node.pattern is not None:
454 self.visit(node.pattern)
455 if node.target is not None:
457 self.visit(node.target)
460 self.visit(node.body)
463 def visit_ReturnStatNode(self, node):
464 self.startline("return ")
465 self.visit(node.value)
468 def visit_ReraiseStatNode(self, node):
471 def visit_ImportNode(self, node):
472 self.put(u"(import %s)" % node.module_name.value)
474 def visit_TempsBlockNode(self, node):
476 Temporaries are output like $1_1', where the first number is
477 an index of the TempsBlockNode and the second number is an index
478 of the temporary which that block allocates.
481 for handle in node.temps:
482 self.tempnames[handle] = "$%d_%d" % (self.tempblockindex, idx)
484 self.tempblockindex += 1
485 self.visit(node.body)
487 def visit_TempRefNode(self, node):
488 self.put(self.tempnames[node.handle])
491 class PxdWriter(DeclarationWriter):
492 def __call__(self, node):
493 print u'\n'.join(self.write(node).lines)
496 def visit_CFuncDefNode(self, node):
497 if 'inline' in node.modifiers:
500 self.startline(u'cpdef ')
502 self.startline(u'cdef ')
503 if node.visibility != 'private':
504 self.put(node.visibility)
508 self.visit(node.declarator)
510 def visit_StatNode(self, node):