Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / third_party / cython / src / Cython / CodeWriter.py
blob704ef7437a4bfcd6a155e06071bbeecd9518a709
1 """
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).
7 """
9 from Cython.Compiler.Visitor import TreeVisitor
10 from Cython.Compiler.ExprNodes import *
12 class LinesResult(object):
13 def __init__(self):
14 self.lines = []
15 self.s = u""
17 def put(self, s):
18 self.s += s
20 def newline(self):
21 self.lines.append(self.s)
22 self.s = u""
24 def putline(self, s):
25 self.put(s)
26 self.newline()
28 class DeclarationWriter(TreeVisitor):
30 indent_string = u" "
32 def __init__(self, result = None):
33 super(DeclarationWriter, self).__init__()
34 if result is None:
35 result = LinesResult()
36 self.result = result
37 self.numindents = 0
38 self.tempnames = {}
39 self.tempblockindex = 0
41 def write(self, tree):
42 self.visit(tree)
43 return self.result
45 def indent(self):
46 self.numindents += 1
48 def dedent(self):
49 self.numindents -= 1
51 def startline(self, s = u""):
52 self.result.put(self.indent_string * self.numindents + s)
54 def put(self, s):
55 self.result.put(s)
57 def putline(self, s):
58 self.result.putline(self.indent_string * self.numindents + s)
60 def endline(self, s = u""):
61 self.result.putline(s)
63 def line(self, s):
64 self.startline(s)
65 self.endline()
67 def comma_separated_list(self, items, output_rhs=False):
68 if len(items) > 0:
69 for item in items[:-1]:
70 self.visit(item)
71 if output_rhs and item.default is not None:
72 self.put(u" = ")
73 self.visit(item.default)
74 self.put(u", ")
75 self.visit(items[-1])
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:
88 file = u'*'
89 else:
90 file = u'"%s"' % node.include_file
91 self.putline(u"cdef extern from %s:" % file)
92 self.indent()
93 self.visit(node.body)
94 self.dedent()
96 def visit_CPtrDeclaratorNode(self, node):
97 self.put('*')
98 self.visit(node.base)
100 def visit_CReferenceDeclaratorNode(self, node):
101 self.put('&')
102 self.visit(node.base)
104 def visit_CArrayDeclaratorNode(self, node):
105 self.visit(node.base)
106 self.put(u'[')
107 if node.dimension is not None:
108 self.visit(node.dimension)
109 self.put(u']')
111 def visit_CArrayDeclaratorNode(self, node):
112 self.visit(node.base)
113 self.put(u'[')
114 if node.dimension is not None:
115 self.visit(node.dimension)
116 self.put(u']')
118 def visit_CFuncDeclaratorNode(self, node):
119 # TODO: except, gil, etc.
120 self.visit(node.base)
121 self.put(u'(')
122 self.comma_separated_list(node.args)
123 self.endline(u')')
125 def visit_CNameDeclaratorNode(self, node):
126 self.put(node.name)
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)
136 self.put(node.name)
138 def visit_CComplexBaseTypeNode(self, node):
139 self.put(u'(')
140 self.visit(node.base_type)
141 self.visit(node.declarator)
142 self.put(u')')
144 def visit_CNestedBaseTypeNode(self, node):
145 self.visit(node.base_type)
146 self.put(u'.')
147 self.put(node.name)
149 def visit_TemplatedTypeNode(self, node):
150 self.visit(node.base_type_node)
151 self.put(u'[')
152 self.comma_separated_list(node.positional_args + node.keyword_args.key_value_pairs)
153 self.put(u']')
155 def visit_CVarDefNode(self, node):
156 self.startline(u"cdef ")
157 self.visit(node.base_type)
158 self.put(u" ")
159 self.comma_separated_list(node.declarators, output_rhs=True)
160 self.endline()
162 def visit_container_node(self, node, decl, extras, attributes):
163 # TODO: visibility
164 self.startline(decl)
165 if node.name:
166 self.put(u' ')
167 self.put(node.name)
168 if node.cname is not None:
169 self.put(u' "%s"' % node.cname)
170 if extras:
171 self.put(extras)
172 self.endline(':')
173 self.indent()
174 if not attributes:
175 self.putline('pass')
176 else:
177 for attribute in attributes:
178 self.visit(attribute)
179 self.dedent()
181 def visit_CStructOrUnionDefNode(self, node):
182 if node.typedef_flag:
183 decl = u'ctypedef '
184 else:
185 decl = u'cdef '
186 if node.visibility == 'public':
187 decl += u'public '
188 if node.packed:
189 decl += u'packed '
190 decl += node.kind
191 self.visit_container_node(node, decl, None, node.attributes)
193 def visit_CppClassNode(self, node):
194 extras = ""
195 if node.templates:
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)
206 if node.cname:
207 self.put(u' "%s"' % node.cname)
208 if node.value:
209 self.put(u" = ")
210 self.visit(node.value)
211 self.endline()
213 def visit_CClassDefNode(self, node):
214 assert not node.module_name
215 if node.decorators:
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:
221 self.put(u"(")
222 if node.base_class_module:
223 self.put(node.base_class_module)
224 self.put(u".")
225 self.put(node.base_class_name)
226 self.put(u")")
227 self.endline(u":")
228 self.indent()
229 self.visit(node.body)
230 self.dedent()
232 def visit_CTypeDefNode(self, node):
233 self.startline(u"ctypedef ")
234 self.visit(node.base_type)
235 self.put(u" ")
236 self.visit(node.declarator)
237 self.endline()
239 def visit_FuncDefNode(self, node):
240 self.startline(u"def %s(" % node.name)
241 self.comma_separated_list(node.args)
242 self.endline(u"):")
243 self.indent()
244 self.visit(node.body)
245 self.dedent()
247 def visit_CArgDeclNode(self, node):
248 if node.base_type.name is not None:
249 self.visit(node.base_type)
250 self.put(u" ")
251 self.visit(node.declarator)
252 if node.default is not None:
253 self.put(u" = ")
254 self.visit(node.default)
256 def visit_CImportStatNode(self, node):
257 self.startline(u"cimport ")
258 self.put(node.module_name)
259 if node.as_name:
260 self.put(u" as ")
261 self.put(node.as_name)
262 self.endline()
264 def visit_FromCImportStatNode(self, node):
265 self.startline(u"from ")
266 self.put(node.module_name)
267 self.put(u" cimport ")
268 first = True
269 for pos, name, as_name, kind in node.imported_names:
270 assert kind is None
271 if first:
272 first = False
273 else:
274 self.put(u", ")
275 self.put(name)
276 if as_name:
277 self.put(u" as ")
278 self.put(as_name)
279 self.endline()
281 def visit_NameNode(self, node):
282 self.put(node.name)
284 def visit_IntNode(self, node):
285 self.put(node.value)
287 def visit_NoneNode(self, node):
288 self.put(u"None")
290 def visit_NotNode(self, node):
291 self.put(u"(not ")
292 self.visit(node.operand)
293 self.put(u")")
295 def visit_DecoratorNode(self, node):
296 self.startline("@")
297 self.visit(node.decorator)
298 self.endline()
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):
306 self.visit(node.obj)
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):
314 value = node.value
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")
321 self.endline()
323 class CodeWriter(DeclarationWriter):
325 def visit_SingleAssignmentNode(self, node):
326 self.startline()
327 self.visit(node.lhs)
328 self.put(u" = ")
329 self.visit(node.rhs)
330 self.endline()
332 def visit_CascadedAssignmentNode(self, node):
333 self.startline()
334 for lhs in node.lhs_list:
335 self.visit(lhs)
336 self.put(u" = ")
337 self.visit(node.rhs)
338 self.endline()
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:
344 self.put(u",")
345 self.endline()
347 def visit_ForInStatNode(self, node):
348 self.startline(u"for ")
349 self.visit(node.target)
350 self.put(u" in ")
351 self.visit(node.iterator.sequence)
352 self.endline(u":")
353 self.indent()
354 self.visit(node.body)
355 self.dedent()
356 if node.else_clause is not None:
357 self.line(u"else:")
358 self.indent()
359 self.visit(node.else_clause)
360 self.dedent()
362 def visit_IfStatNode(self, node):
363 # The IfClauseNode is handled directly without a seperate match
364 # for clariy.
365 self.startline(u"if ")
366 self.visit(node.if_clauses[0].condition)
367 self.endline(":")
368 self.indent()
369 self.visit(node.if_clauses[0].body)
370 self.dedent()
371 for clause in node.if_clauses[1:]:
372 self.startline("elif ")
373 self.visit(clause.condition)
374 self.endline(":")
375 self.indent()
376 self.visit(clause.body)
377 self.dedent()
378 if node.else_clause is not None:
379 self.line("else:")
380 self.indent()
381 self.visit(node.else_clause)
382 self.dedent()
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)
389 self.put(u"(")
390 self.comma_separated_list(node.args)
391 self.put(")")
393 def visit_GeneralCallNode(self, node):
394 self.visit(node.function)
395 self.put(u"(")
396 posarg = node.positional_args
397 if isinstance(posarg, AsTupleNode):
398 self.visit(posarg.arg)
399 else:
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")
403 self.put(u")")
405 def visit_ExprStatNode(self, node):
406 self.startline()
407 self.visit(node.expr)
408 self.endline()
410 def visit_InPlaceAssignmentNode(self, node):
411 self.startline()
412 self.visit(node.lhs)
413 self.put(u" %s= " % node.operator)
414 self.visit(node.rhs)
415 self.endline()
417 def visit_WithStatNode(self, node):
418 self.startline()
419 self.put(u"with ")
420 self.visit(node.manager)
421 if node.target is not None:
422 self.put(u" as ")
423 self.visit(node.target)
424 self.endline(u":")
425 self.indent()
426 self.visit(node.body)
427 self.dedent()
429 def visit_TryFinallyStatNode(self, node):
430 self.line(u"try:")
431 self.indent()
432 self.visit(node.body)
433 self.dedent()
434 self.line(u"finally:")
435 self.indent()
436 self.visit(node.finally_clause)
437 self.dedent()
439 def visit_TryExceptStatNode(self, node):
440 self.line(u"try:")
441 self.indent()
442 self.visit(node.body)
443 self.dedent()
444 for x in node.except_clauses:
445 self.visit(x)
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:
452 self.put(u" ")
453 self.visit(node.pattern)
454 if node.target is not None:
455 self.put(u", ")
456 self.visit(node.target)
457 self.endline(":")
458 self.indent()
459 self.visit(node.body)
460 self.dedent()
462 def visit_ReturnStatNode(self, node):
463 self.startline("return ")
464 self.visit(node.value)
465 self.endline()
467 def visit_ReraiseStatNode(self, node):
468 self.line("raise")
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.
479 idx = 0
480 for handle in node.temps:
481 self.tempnames[handle] = "$%d_%d" % (self.tempblockindex, idx)
482 idx += 1
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)
493 return node
495 def visit_CFuncDefNode(self, node):
496 if 'inline' in node.modifiers:
497 return
498 if node.overridable:
499 self.startline(u'cpdef ')
500 else:
501 self.startline(u'cdef ')
502 if node.visibility != 'private':
503 self.put(node.visibility)
504 self.put(u' ')
505 if node.api:
506 self.put(u'api ')
507 self.visit(node.declarator)
509 def visit_StatNode(self, node):
510 pass