Remove trailing whitespace.
[cython.git] / Cython / CodeWriter.py
1 from Cython.Compiler.Visitor import TreeVisitor
2 from Cython.Compiler.Nodes import *
3 from Cython.Compiler.ExprNodes import *
4
5 """
6 Serializes a Cython code tree to Cython code. This is primarily useful for
7 debugging and testing purposes.
8
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).
11 """
12
13 class LinesResult(object):
14     def __init__(self):
15         self.lines = []
16         self.s = u""
17
18     def put(self, s):
19         self.s += s
20
21     def newline(self):
22         self.lines.append(self.s)
23         self.s = u""
24
25     def putline(self, s):
26         self.put(s)
27         self.newline()
28
29 class CodeWriter(TreeVisitor):
30
31     indent_string = u"    "
32
33     def __init__(self, result = None):
34         super(CodeWriter, self).__init__()
35         if result is None:
36             result = LinesResult()
37         self.result = result
38         self.numindents = 0
39         self.tempnames = {}
40         self.tempblockindex = 0
41
42     def write(self, tree):
43         self.visit(tree)
44
45     def indent(self):
46         self.numindents += 1
47
48     def dedent(self):
49         self.numindents -= 1
50
51     def startline(self, s = u""):
52         self.result.put(self.indent_string * self.numindents + s)
53
54     def put(self, s):
55         self.result.put(s)
56
57     def endline(self, s = u""):
58         self.result.putline(s)
59
60     def line(self, s):
61         self.startline(s)
62         self.endline()
63
64     def comma_separated_list(self, items, output_rhs=False):
65         if len(items) > 0:
66             for item in items[:-1]:
67                 self.visit(item)
68                 if output_rhs and item.default is not None:
69                     self.put(u" = ")
70                     self.visit(item.default)
71                 self.put(u", ")
72             self.visit(items[-1])
73
74     def visit_Node(self, node):
75         raise AssertionError("Node not handled by serializer: %r" % node)
76
77     def visit_ModuleNode(self, node):
78         self.visitchildren(node)
79
80     def visit_StatListNode(self, node):
81         self.visitchildren(node)
82
83     def visit_FuncDefNode(self, node):
84         self.startline(u"def %s(" % node.name)
85         self.comma_separated_list(node.args)
86         self.endline(u"):")
87         self.indent()
88         self.visit(node.body)
89         self.dedent()
90
91     def visit_CArgDeclNode(self, node):
92         if node.base_type.name is not None:
93             self.visit(node.base_type)
94             self.put(u" ")
95         self.visit(node.declarator)
96         if node.default is not None:
97             self.put(u" = ")
98             self.visit(node.default)
99
100     def visit_CNameDeclaratorNode(self, node):
101         self.put(node.name)
102
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)
111
112         self.put(node.name)
113
114     def visit_SingleAssignmentNode(self, node):
115         self.startline()
116         self.visit(node.lhs)
117         self.put(u" = ")
118         self.visit(node.rhs)
119         self.endline()
120
121     def visit_CascadedAssignmentNode(self, node):
122         self.startline()
123         for lhs in node.lhs_list:
124             self.visit(lhs)
125             self.put(u" = ")
126         self.visit(node.rhs)
127         self.endline()
128
129     def visit_NameNode(self, node):
130         self.put(node.name)
131
132     def visit_IntNode(self, node):
133         self.put(node.value)
134
135     # FIXME: represent string nodes correctly
136     def visit_StringNode(self, node):
137         value = node.value
138         if value.encoding is not None:
139             value = value.encode(value.encoding)
140         self.put(repr(value))
141
142     def visit_IfStatNode(self, node):
143         # The IfClauseNode is handled directly without a seperate match
144         # for clariy.
145         self.startline(u"if ")
146         self.visit(node.if_clauses[0].condition)
147         self.endline(":")
148         self.indent()
149         self.visit(node.if_clauses[0].body)
150         self.dedent()
151         for clause in node.if_clauses[1:]:
152             self.startline("elif ")
153             self.visit(clause.condition)
154             self.endline(":")
155             self.indent()
156             self.visit(clause.body)
157             self.dedent()
158         if node.else_clause is not None:
159             self.line("else:")
160             self.indent()
161             self.visit(node.else_clause)
162             self.dedent()
163
164     def visit_PassStatNode(self, node):
165         self.startline(u"pass")
166         self.endline()
167
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:
172             self.put(u",")
173         self.endline()
174
175     def visit_BinopNode(self, node):
176         self.visit(node.operand1)
177         self.put(u" %s " % node.operator)
178         self.visit(node.operand2)
179
180     def visit_CVarDefNode(self, node):
181         self.startline(u"cdef ")
182         self.visit(node.base_type)
183         self.put(u" ")
184         self.comma_separated_list(node.declarators, output_rhs=True)
185         self.endline()
186
187     def visit_ForInStatNode(self, node):
188         self.startline(u"for ")
189         self.visit(node.target)
190         self.put(u" in ")
191         self.visit(node.iterator.sequence)
192         self.endline(u":")
193         self.indent()
194         self.visit(node.body)
195         self.dedent()
196         if node.else_clause is not None:
197             self.line(u"else:")
198             self.indent()
199             self.visit(node.else_clause)
200             self.dedent()
201
202     def visit_SequenceNode(self, node):
203         self.comma_separated_list(node.args) # Might need to discover whether we need () around tuples...hmm...
204
205     def visit_SimpleCallNode(self, node):
206         self.visit(node.function)
207         self.put(u"(")
208         self.comma_separated_list(node.args)
209         self.put(")")
210
211     def visit_GeneralCallNode(self, node):
212         self.visit(node.function)
213         self.put(u"(")
214         posarg = node.positional_args
215         if isinstance(posarg, AsTupleNode):
216             self.visit(posarg.arg)
217         else:
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")
221         self.put(u")")
222
223     def visit_ExprStatNode(self, node):
224         self.startline()
225         self.visit(node.expr)
226         self.endline()
227
228     def visit_InPlaceAssignmentNode(self, node):
229         self.startline()
230         self.visit(node.lhs)
231         self.put(u" %s= " % node.operator)
232         self.visit(node.rhs)
233         self.endline()
234
235     def visit_WithStatNode(self, node):
236         self.startline()
237         self.put(u"with ")
238         self.visit(node.manager)
239         if node.target is not None:
240             self.put(u" as ")
241             self.visit(node.target)
242         self.endline(u":")
243         self.indent()
244         self.visit(node.body)
245         self.dedent()
246
247     def visit_AttributeNode(self, node):
248         self.visit(node.obj)
249         self.put(u".%s" % node.attribute)
250
251     def visit_BoolNode(self, node):
252         self.put(str(node.value))
253
254     def visit_TryFinallyStatNode(self, node):
255         self.line(u"try:")
256         self.indent()
257         self.visit(node.body)
258         self.dedent()
259         self.line(u"finally:")
260         self.indent()
261         self.visit(node.finally_clause)
262         self.dedent()
263
264     def visit_TryExceptStatNode(self, node):
265         self.line(u"try:")
266         self.indent()
267         self.visit(node.body)
268         self.dedent()
269         for x in node.except_clauses:
270             self.visit(x)
271         if node.else_clause is not None:
272             self.visit(node.else_clause)
273
274     def visit_ExceptClauseNode(self, node):
275         self.startline(u"except")
276         if node.pattern is not None:
277             self.put(u" ")
278             self.visit(node.pattern)
279         if node.target is not None:
280             self.put(u", ")
281             self.visit(node.target)
282         self.endline(":")
283         self.indent()
284         self.visit(node.body)
285         self.dedent()
286
287     def visit_ReturnStatNode(self, node):
288         self.startline("return ")
289         self.visit(node.value)
290         self.endline()
291
292     def visit_DecoratorNode(self, node):
293         self.startline("@")
294         self.visit(node.decorator)
295         self.endline()
296
297     def visit_ReraiseStatNode(self, node):
298         self.line("raise")
299
300     def visit_NoneNode(self, node):
301         self.put(u"None")
302
303     def visit_ImportNode(self, node):
304         self.put(u"(import %s)" % node.module_name.value)
305
306     def visit_NotNode(self, node):
307         self.put(u"(not ")
308         self.visit(node.operand)
309         self.put(u")")
310
311     def visit_TempsBlockNode(self, node):
312         """
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.
316         """
317         idx = 0
318         for handle in node.temps:
319             self.tempnames[handle] = "$%d_%d" % (self.tempblockindex, idx)
320             idx += 1
321         self.tempblockindex += 1
322         self.visit(node.body)
323
324     def visit_TempRefNode(self, node):
325         self.put(self.tempnames[node.handle])