Buffer type checking cleanup/rewrite (now uses use_utility_code)
[cython.git] / Cython / CodeWriter.py
1 from Cython.Compiler.Visitor import TreeVisitor, get_temp_name_handle_desc
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     
41     def write(self, tree):
42         self.visit(tree)
43     
44     def indent(self):
45         self.numindents += 1
46     
47     def dedent(self):
48         self.numindents -= 1
49     
50     def startline(self, s = u""):
51         self.result.put(self.indent_string * self.numindents + s)
52     
53     def put(self, s):
54         self.result.put(s)
55     
56     def endline(self, s = u""):
57         self.result.putline(s)
58
59     def line(self, s):
60         self.startline(s)
61         self.endline()
62
63     def putname(self, name):
64         tmpdesc = get_temp_name_handle_desc(name)
65         if tmpdesc is not None:
66             name = self.tempnames.setdefault(tmpdesc, u"$" +tmpdesc)
67         self.put(name)
68     
69     def comma_seperated_list(self, items, output_rhs=False):
70         if len(items) > 0:
71             for item in items[:-1]:
72                 self.visit(item)
73                 if output_rhs and item.default is not None:
74                     self.put(u" = ")
75                     self.visit(item.default)
76                 self.put(u", ")
77             self.visit(items[-1])
78     
79     def visit_Node(self, node):
80         raise AssertionError("Node not handled by serializer: %r" % node)
81     
82     def visit_ModuleNode(self, node):
83         self.visitchildren(node)
84     
85     def visit_StatListNode(self, node):
86         self.visitchildren(node)
87
88     def visit_FuncDefNode(self, node):
89         self.startline(u"def %s(" % node.name)
90         self.comma_seperated_list(node.args)
91         self.endline(u"):")
92         self.indent()
93         self.visit(node.body)
94         self.dedent()
95     
96     def visit_CArgDeclNode(self, node):
97         if node.base_type.name is not None:
98             self.visit(node.base_type)
99             self.put(u" ")
100         self.visit(node.declarator)
101         if node.default is not None:
102             self.put(u" = ")
103             self.visit(node.default)
104     
105     def visit_CNameDeclaratorNode(self, node):
106         self.put(node.name)
107     
108     def visit_CSimpleBaseTypeNode(self, node):
109         # See Parsing.p_sign_and_longness
110         if node.is_basic_c_type:
111             self.put(("unsigned ", "", "signed ")[node.signed])
112             if node.longness < 0:
113                 self.put("short " * -node.longness)
114             elif node.longness > 0:
115                 self.put("long " * node.longness)
116             
117         self.put(node.name)
118     
119     def visit_SingleAssignmentNode(self, node):
120         self.startline()
121         self.visit(node.lhs)
122         self.put(u" = ")
123         self.visit(node.rhs)
124         self.endline()
125     
126     def visit_CascadedAssignmentNode(self, node):
127         self.startline()
128         for lhs in node.lhs_list:
129             self.visit(lhs)
130             self.put(u" = ")
131         self.visit(node.rhs)
132         self.endline()
133     
134     def visit_NameNode(self, node):
135         self.putname(node.name)
136     
137     def visit_IntNode(self, node):
138         self.put(node.value)
139
140     def visit_StringNode(self, node):
141         value = node.value
142         if value.encoding is not None:
143             value = value.encode(value.encoding)
144         self.put(repr(value))
145
146     def visit_IfStatNode(self, node):
147         # The IfClauseNode is handled directly without a seperate match
148         # for clariy.
149         self.startline(u"if ")
150         self.visit(node.if_clauses[0].condition)
151         self.endline(":")
152         self.indent()
153         self.visit(node.if_clauses[0].body)
154         self.dedent()
155         for clause in node.if_clauses[1:]:
156             self.startline("elif ")
157             self.visit(clause.condition)
158             self.endline(":")
159             self.indent()
160             self.visit(clause.body)
161             self.dedent()
162         if node.else_clause is not None:
163             self.line("else:")
164             self.indent()
165             self.visit(node.else_clause)
166             self.dedent()
167
168     def visit_PassStatNode(self, node):
169         self.startline(u"pass")
170         self.endline()
171     
172     def visit_PrintStatNode(self, node):
173         self.startline(u"print ")
174         self.comma_seperated_list(node.arg_tuple.args)
175         if not node.append_newline:
176             self.put(u",")
177         self.endline()
178
179     def visit_BinopNode(self, node):
180         self.visit(node.operand1)
181         self.put(u" %s " % node.operator)
182         self.visit(node.operand2)
183     
184     def visit_CVarDefNode(self, node):
185         self.startline(u"cdef ")
186         self.visit(node.base_type)
187         self.put(u" ")
188         self.comma_seperated_list(node.declarators, output_rhs=True)
189         self.endline()
190
191     def visit_ForInStatNode(self, node):
192         self.startline(u"for ")
193         self.visit(node.target)
194         self.put(u" in ")
195         self.visit(node.iterator.sequence)
196         self.endline(u":")
197         self.indent()
198         self.visit(node.body)
199         self.dedent()
200         if node.else_clause is not None:
201             self.line(u"else:")
202             self.indent()
203             self.visit(node.else_clause)
204             self.dedent()
205
206     def visit_SequenceNode(self, node):
207         self.comma_seperated_list(node.args) # Might need to discover whether we need () around tuples...hmm...
208     
209     def visit_SimpleCallNode(self, node):
210         self.visit(node.function)
211         self.put(u"(")
212         self.comma_seperated_list(node.args)
213         self.put(")")
214
215     def visit_GeneralCallNode(self, node):
216         self.visit(node.function)
217         self.put(u"(")
218         posarg = node.positional_args
219         if isinstance(posarg, AsTupleNode):
220             self.visit(posarg.arg)
221         else:
222             self.comma_seperated_list(posarg)
223         if node.keyword_args is not None or node.starstar_arg is not None:
224             raise Exception("Not implemented yet")
225         self.put(u")")
226
227     def visit_ExprStatNode(self, node):
228         self.startline()
229         self.visit(node.expr)
230         self.endline()
231     
232     def visit_InPlaceAssignmentNode(self, node):
233         self.startline()
234         self.visit(node.lhs)
235         self.put(u" %s= " % node.operator)
236         self.visit(node.rhs)
237         self.endline()
238         
239     def visit_WithStatNode(self, node):
240         self.startline()
241         self.put(u"with ")
242         self.visit(node.manager)
243         if node.target is not None:
244             self.put(u" as ")
245             self.visit(node.target)
246         self.endline(u":")
247         self.indent()
248         self.visit(node.body)
249         self.dedent()
250         
251     def visit_AttributeNode(self, node):
252         self.visit(node.obj)
253         self.put(u".%s" % node.attribute)
254
255     def visit_BoolNode(self, node):
256         self.put(str(node.value))
257
258     def visit_TryFinallyStatNode(self, node):
259         self.line(u"try:")
260         self.indent()
261         self.visit(node.body)
262         self.dedent()
263         self.line(u"finally:")
264         self.indent()
265         self.visit(node.finally_clause)
266         self.dedent()
267
268     def visit_TryExceptStatNode(self, node):
269         self.line(u"try:")
270         self.indent()
271         self.visit(node.body)
272         self.dedent()
273         for x in node.except_clauses:
274             self.visit(x)
275         if node.else_clause is not None:
276             self.visit(node.else_clause)
277
278     def visit_ExceptClauseNode(self, node):
279         self.startline(u"except")
280         if node.pattern is not None:
281             self.put(u" ")
282             self.visit(node.pattern)
283         if node.target is not None:
284             self.put(u", ")
285             self.visit(node.target)
286         self.endline(":")
287         self.indent()
288         self.visit(node.body)
289         self.dedent()
290
291     def visit_ReturnStatNode(self, node):
292         self.startline("return ")
293         self.visit(node.value)
294         self.endline()
295
296     def visit_DecoratorNode(self, node):
297         self.startline("@")
298         self.visit(node.decorator)
299         self.endline()
300
301     def visit_ReraiseStatNode(self, node):
302         self.line("raise")
303
304     def visit_NoneNode(self, node):
305         self.put(u"None")
306
307     def visit_ImportNode(self, node):
308         self.put(u"(import %s)" % node.module_name.value)
309
310     def visit_NotNode(self, node):
311         self.put(u"(not ")
312         self.visit(node.operand)
313         self.put(u")")
314