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 CodeWriter(TreeVisitor):
33 def __init__(self, result = None):
34 super(CodeWriter, self).__init__()
36 result = LinesResult()
40 self.tempblockindex = 0
42 def write(self, tree):
51 def startline(self, s = u""):
52 self.result.put(self.indent_string * self.numindents + s)
57 def endline(self, s = u""):
58 self.result.putline(s)
64 def comma_separated_list(self, items, output_rhs=False):
66 for item in items[:-1]:
68 if output_rhs and item.default is not None:
70 self.visit(item.default)
74 def visit_Node(self, node):
75 raise AssertionError("Node not handled by serializer: %r" % node)
77 def visit_ModuleNode(self, node):
78 self.visitchildren(node)
80 def visit_StatListNode(self, node):
81 self.visitchildren(node)
83 def visit_FuncDefNode(self, node):
84 self.startline(u"def %s(" % node.name)
85 self.comma_separated_list(node.args)
91 def visit_CArgDeclNode(self, node):
92 if node.base_type.name is not None:
93 self.visit(node.base_type)
95 self.visit(node.declarator)
96 if node.default is not None:
98 self.visit(node.default)
100 def visit_CNameDeclaratorNode(self, node):
103 def visit_CSimpleBaseTypeNode(self, node):
104 # See Parsing.p_sign_and_longness
105 if node.is_basic_c_type:
106 self.put(("unsigned ", "", "signed ")[node.signed])
107 if node.longness < 0:
108 self.put("short " * -node.longness)
109 elif node.longness > 0:
110 self.put("long " * node.longness)
114 def visit_SingleAssignmentNode(self, node):
121 def visit_CascadedAssignmentNode(self, node):
123 for lhs in node.lhs_list:
129 def visit_NameNode(self, node):
132 def visit_IntNode(self, node):
135 # FIXME: represent string nodes correctly
136 def visit_StringNode(self, node):
138 if value.encoding is not None:
139 value = value.encode(value.encoding)
140 self.put(repr(value))
142 def visit_IfStatNode(self, node):
143 # The IfClauseNode is handled directly without a seperate match
145 self.startline(u"if ")
146 self.visit(node.if_clauses[0].condition)
149 self.visit(node.if_clauses[0].body)
151 for clause in node.if_clauses[1:]:
152 self.startline("elif ")
153 self.visit(clause.condition)
156 self.visit(clause.body)
158 if node.else_clause is not None:
161 self.visit(node.else_clause)
164 def visit_PassStatNode(self, node):
165 self.startline(u"pass")
168 def visit_PrintStatNode(self, node):
169 self.startline(u"print ")
170 self.comma_separated_list(node.arg_tuple.args)
171 if not node.append_newline:
175 def visit_BinopNode(self, node):
176 self.visit(node.operand1)
177 self.put(u" %s " % node.operator)
178 self.visit(node.operand2)
180 def visit_CVarDefNode(self, node):
181 self.startline(u"cdef ")
182 self.visit(node.base_type)
184 self.comma_separated_list(node.declarators, output_rhs=True)
187 def visit_ForInStatNode(self, node):
188 self.startline(u"for ")
189 self.visit(node.target)
191 self.visit(node.iterator.sequence)
194 self.visit(node.body)
196 if node.else_clause is not None:
199 self.visit(node.else_clause)
202 def visit_SequenceNode(self, node):
203 self.comma_separated_list(node.args) # Might need to discover whether we need () around tuples...hmm...
205 def visit_SimpleCallNode(self, node):
206 self.visit(node.function)
208 self.comma_separated_list(node.args)
211 def visit_GeneralCallNode(self, node):
212 self.visit(node.function)
214 posarg = node.positional_args
215 if isinstance(posarg, AsTupleNode):
216 self.visit(posarg.arg)
218 self.comma_separated_list(posarg)
219 if node.keyword_args is not None or node.starstar_arg is not None:
220 raise Exception("Not implemented yet")
223 def visit_ExprStatNode(self, node):
225 self.visit(node.expr)
228 def visit_InPlaceAssignmentNode(self, node):
231 self.put(u" %s= " % node.operator)
235 def visit_WithStatNode(self, node):
238 self.visit(node.manager)
239 if node.target is not None:
241 self.visit(node.target)
244 self.visit(node.body)
247 def visit_AttributeNode(self, node):
249 self.put(u".%s" % node.attribute)
251 def visit_BoolNode(self, node):
252 self.put(str(node.value))
254 def visit_TryFinallyStatNode(self, node):
257 self.visit(node.body)
259 self.line(u"finally:")
261 self.visit(node.finally_clause)
264 def visit_TryExceptStatNode(self, node):
267 self.visit(node.body)
269 for x in node.except_clauses:
271 if node.else_clause is not None:
272 self.visit(node.else_clause)
274 def visit_ExceptClauseNode(self, node):
275 self.startline(u"except")
276 if node.pattern is not None:
278 self.visit(node.pattern)
279 if node.target is not None:
281 self.visit(node.target)
284 self.visit(node.body)
287 def visit_ReturnStatNode(self, node):
288 self.startline("return ")
289 self.visit(node.value)
292 def visit_DecoratorNode(self, node):
294 self.visit(node.decorator)
297 def visit_ReraiseStatNode(self, node):
300 def visit_NoneNode(self, node):
303 def visit_ImportNode(self, node):
304 self.put(u"(import %s)" % node.module_name.value)
306 def visit_NotNode(self, node):
308 self.visit(node.operand)
311 def visit_TempsBlockNode(self, node):
313 Temporaries are output like $1_1', where the first number is
314 an index of the TempsBlockNode and the second number is an index
315 of the temporary which that block allocates.
318 for handle in node.temps:
319 self.tempnames[handle] = "$%d_%d" % (self.tempblockindex, idx)
321 self.tempblockindex += 1
322 self.visit(node.body)
324 def visit_TempRefNode(self, node):
325 self.put(self.tempnames[node.handle])