Index: third_party/cython/src/Cython/CodeWriter.py |
diff --git a/third_party/cython/src/Cython/CodeWriter.py b/third_party/cython/src/Cython/CodeWriter.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..704ef7437a4bfcd6a155e06071bbeecd9518a709 |
--- /dev/null |
+++ b/third_party/cython/src/Cython/CodeWriter.py |
@@ -0,0 +1,512 @@ |
+""" |
+Serializes a Cython code tree to Cython code. This is primarily useful for |
+debugging and testing purposes. |
+ |
+The output is in a strict format, no whitespace or comments from the input |
+is preserved (and it could not be as it is not present in the code tree). |
+""" |
+ |
+from Cython.Compiler.Visitor import TreeVisitor |
+from Cython.Compiler.ExprNodes import * |
+ |
+class LinesResult(object): |
+ def __init__(self): |
+ self.lines = [] |
+ self.s = u"" |
+ |
+ def put(self, s): |
+ self.s += s |
+ |
+ def newline(self): |
+ self.lines.append(self.s) |
+ self.s = u"" |
+ |
+ def putline(self, s): |
+ self.put(s) |
+ self.newline() |
+ |
+class DeclarationWriter(TreeVisitor): |
+ |
+ indent_string = u" " |
+ |
+ def __init__(self, result = None): |
+ super(DeclarationWriter, self).__init__() |
+ if result is None: |
+ result = LinesResult() |
+ self.result = result |
+ self.numindents = 0 |
+ self.tempnames = {} |
+ self.tempblockindex = 0 |
+ |
+ def write(self, tree): |
+ self.visit(tree) |
+ return self.result |
+ |
+ def indent(self): |
+ self.numindents += 1 |
+ |
+ def dedent(self): |
+ self.numindents -= 1 |
+ |
+ def startline(self, s = u""): |
+ self.result.put(self.indent_string * self.numindents + s) |
+ |
+ def put(self, s): |
+ self.result.put(s) |
+ |
+ def putline(self, s): |
+ self.result.putline(self.indent_string * self.numindents + s) |
+ |
+ def endline(self, s = u""): |
+ self.result.putline(s) |
+ |
+ def line(self, s): |
+ self.startline(s) |
+ self.endline() |
+ |
+ def comma_separated_list(self, items, output_rhs=False): |
+ if len(items) > 0: |
+ for item in items[:-1]: |
+ self.visit(item) |
+ if output_rhs and item.default is not None: |
+ self.put(u" = ") |
+ self.visit(item.default) |
+ self.put(u", ") |
+ self.visit(items[-1]) |
+ |
+ def visit_Node(self, node): |
+ raise AssertionError("Node not handled by serializer: %r" % node) |
+ |
+ def visit_ModuleNode(self, node): |
+ self.visitchildren(node) |
+ |
+ def visit_StatListNode(self, node): |
+ self.visitchildren(node) |
+ |
+ def visit_CDefExternNode(self, node): |
+ if node.include_file is None: |
+ file = u'*' |
+ else: |
+ file = u'"%s"' % node.include_file |
+ self.putline(u"cdef extern from %s:" % file) |
+ self.indent() |
+ self.visit(node.body) |
+ self.dedent() |
+ |
+ def visit_CPtrDeclaratorNode(self, node): |
+ self.put('*') |
+ self.visit(node.base) |
+ |
+ def visit_CReferenceDeclaratorNode(self, node): |
+ self.put('&') |
+ self.visit(node.base) |
+ |
+ def visit_CArrayDeclaratorNode(self, node): |
+ self.visit(node.base) |
+ self.put(u'[') |
+ if node.dimension is not None: |
+ self.visit(node.dimension) |
+ self.put(u']') |
+ |
+ def visit_CArrayDeclaratorNode(self, node): |
+ self.visit(node.base) |
+ self.put(u'[') |
+ if node.dimension is not None: |
+ self.visit(node.dimension) |
+ self.put(u']') |
+ |
+ def visit_CFuncDeclaratorNode(self, node): |
+ # TODO: except, gil, etc. |
+ self.visit(node.base) |
+ self.put(u'(') |
+ self.comma_separated_list(node.args) |
+ self.endline(u')') |
+ |
+ def visit_CNameDeclaratorNode(self, node): |
+ self.put(node.name) |
+ |
+ def visit_CSimpleBaseTypeNode(self, node): |
+ # See Parsing.p_sign_and_longness |
+ if node.is_basic_c_type: |
+ self.put(("unsigned ", "", "signed ")[node.signed]) |
+ if node.longness < 0: |
+ self.put("short " * -node.longness) |
+ elif node.longness > 0: |
+ self.put("long " * node.longness) |
+ self.put(node.name) |
+ |
+ def visit_CComplexBaseTypeNode(self, node): |
+ self.put(u'(') |
+ self.visit(node.base_type) |
+ self.visit(node.declarator) |
+ self.put(u')') |
+ |
+ def visit_CNestedBaseTypeNode(self, node): |
+ self.visit(node.base_type) |
+ self.put(u'.') |
+ self.put(node.name) |
+ |
+ def visit_TemplatedTypeNode(self, node): |
+ self.visit(node.base_type_node) |
+ self.put(u'[') |
+ self.comma_separated_list(node.positional_args + node.keyword_args.key_value_pairs) |
+ self.put(u']') |
+ |
+ def visit_CVarDefNode(self, node): |
+ self.startline(u"cdef ") |
+ self.visit(node.base_type) |
+ self.put(u" ") |
+ self.comma_separated_list(node.declarators, output_rhs=True) |
+ self.endline() |
+ |
+ def visit_container_node(self, node, decl, extras, attributes): |
+ # TODO: visibility |
+ self.startline(decl) |
+ if node.name: |
+ self.put(u' ') |
+ self.put(node.name) |
+ if node.cname is not None: |
+ self.put(u' "%s"' % node.cname) |
+ if extras: |
+ self.put(extras) |
+ self.endline(':') |
+ self.indent() |
+ if not attributes: |
+ self.putline('pass') |
+ else: |
+ for attribute in attributes: |
+ self.visit(attribute) |
+ self.dedent() |
+ |
+ def visit_CStructOrUnionDefNode(self, node): |
+ if node.typedef_flag: |
+ decl = u'ctypedef ' |
+ else: |
+ decl = u'cdef ' |
+ if node.visibility == 'public': |
+ decl += u'public ' |
+ if node.packed: |
+ decl += u'packed ' |
+ decl += node.kind |
+ self.visit_container_node(node, decl, None, node.attributes) |
+ |
+ def visit_CppClassNode(self, node): |
+ extras = "" |
+ if node.templates: |
+ extras = u"[%s]" % ", ".join(node.templates) |
+ if node.base_classes: |
+ extras += "(%s)" % ", ".join(node.base_classes) |
+ self.visit_container_node(node, u"cdef cppclass", extras, node.attributes) |
+ |
+ def visit_CEnumDefNode(self, node): |
+ self.visit_container_node(node, u"cdef enum", None, node.items) |
+ |
+ def visit_CEnumDefItemNode(self, node): |
+ self.startline(node.name) |
+ if node.cname: |
+ self.put(u' "%s"' % node.cname) |
+ if node.value: |
+ self.put(u" = ") |
+ self.visit(node.value) |
+ self.endline() |
+ |
+ def visit_CClassDefNode(self, node): |
+ assert not node.module_name |
+ if node.decorators: |
+ for decorator in node.decorators: |
+ self.visit(decorator) |
+ self.startline(u"cdef class ") |
+ self.put(node.class_name) |
+ if node.base_class_name: |
+ self.put(u"(") |
+ if node.base_class_module: |
+ self.put(node.base_class_module) |
+ self.put(u".") |
+ self.put(node.base_class_name) |
+ self.put(u")") |
+ self.endline(u":") |
+ self.indent() |
+ self.visit(node.body) |
+ self.dedent() |
+ |
+ def visit_CTypeDefNode(self, node): |
+ self.startline(u"ctypedef ") |
+ self.visit(node.base_type) |
+ self.put(u" ") |
+ self.visit(node.declarator) |
+ self.endline() |
+ |
+ def visit_FuncDefNode(self, node): |
+ self.startline(u"def %s(" % node.name) |
+ self.comma_separated_list(node.args) |
+ self.endline(u"):") |
+ self.indent() |
+ self.visit(node.body) |
+ self.dedent() |
+ |
+ def visit_CArgDeclNode(self, node): |
+ if node.base_type.name is not None: |
+ self.visit(node.base_type) |
+ self.put(u" ") |
+ self.visit(node.declarator) |
+ if node.default is not None: |
+ self.put(u" = ") |
+ self.visit(node.default) |
+ |
+ def visit_CImportStatNode(self, node): |
+ self.startline(u"cimport ") |
+ self.put(node.module_name) |
+ if node.as_name: |
+ self.put(u" as ") |
+ self.put(node.as_name) |
+ self.endline() |
+ |
+ def visit_FromCImportStatNode(self, node): |
+ self.startline(u"from ") |
+ self.put(node.module_name) |
+ self.put(u" cimport ") |
+ first = True |
+ for pos, name, as_name, kind in node.imported_names: |
+ assert kind is None |
+ if first: |
+ first = False |
+ else: |
+ self.put(u", ") |
+ self.put(name) |
+ if as_name: |
+ self.put(u" as ") |
+ self.put(as_name) |
+ self.endline() |
+ |
+ def visit_NameNode(self, node): |
+ self.put(node.name) |
+ |
+ def visit_IntNode(self, node): |
+ self.put(node.value) |
+ |
+ def visit_NoneNode(self, node): |
+ self.put(u"None") |
+ |
+ def visit_NotNode(self, node): |
+ self.put(u"(not ") |
+ self.visit(node.operand) |
+ self.put(u")") |
+ |
+ def visit_DecoratorNode(self, node): |
+ self.startline("@") |
+ self.visit(node.decorator) |
+ self.endline() |
+ |
+ def visit_BinopNode(self, node): |
+ self.visit(node.operand1) |
+ self.put(u" %s " % node.operator) |
+ self.visit(node.operand2) |
+ |
+ def visit_AttributeNode(self, node): |
+ self.visit(node.obj) |
+ self.put(u".%s" % node.attribute) |
+ |
+ def visit_BoolNode(self, node): |
+ self.put(str(node.value)) |
+ |
+ # FIXME: represent string nodes correctly |
+ def visit_StringNode(self, node): |
+ value = node.value |
+ if value.encoding is not None: |
+ value = value.encode(value.encoding) |
+ self.put(repr(value)) |
+ |
+ def visit_PassStatNode(self, node): |
+ self.startline(u"pass") |
+ self.endline() |
+ |
+class CodeWriter(DeclarationWriter): |
+ |
+ def visit_SingleAssignmentNode(self, node): |
+ self.startline() |
+ self.visit(node.lhs) |
+ self.put(u" = ") |
+ self.visit(node.rhs) |
+ self.endline() |
+ |
+ def visit_CascadedAssignmentNode(self, node): |
+ self.startline() |
+ for lhs in node.lhs_list: |
+ self.visit(lhs) |
+ self.put(u" = ") |
+ self.visit(node.rhs) |
+ self.endline() |
+ |
+ def visit_PrintStatNode(self, node): |
+ self.startline(u"print ") |
+ self.comma_separated_list(node.arg_tuple.args) |
+ if not node.append_newline: |
+ self.put(u",") |
+ self.endline() |
+ |
+ def visit_ForInStatNode(self, node): |
+ self.startline(u"for ") |
+ self.visit(node.target) |
+ self.put(u" in ") |
+ self.visit(node.iterator.sequence) |
+ self.endline(u":") |
+ self.indent() |
+ self.visit(node.body) |
+ self.dedent() |
+ if node.else_clause is not None: |
+ self.line(u"else:") |
+ self.indent() |
+ self.visit(node.else_clause) |
+ self.dedent() |
+ |
+ def visit_IfStatNode(self, node): |
+ # The IfClauseNode is handled directly without a seperate match |
+ # for clariy. |
+ self.startline(u"if ") |
+ self.visit(node.if_clauses[0].condition) |
+ self.endline(":") |
+ self.indent() |
+ self.visit(node.if_clauses[0].body) |
+ self.dedent() |
+ for clause in node.if_clauses[1:]: |
+ self.startline("elif ") |
+ self.visit(clause.condition) |
+ self.endline(":") |
+ self.indent() |
+ self.visit(clause.body) |
+ self.dedent() |
+ if node.else_clause is not None: |
+ self.line("else:") |
+ self.indent() |
+ self.visit(node.else_clause) |
+ self.dedent() |
+ |
+ def visit_SequenceNode(self, node): |
+ self.comma_separated_list(node.args) # Might need to discover whether we need () around tuples...hmm... |
+ |
+ def visit_SimpleCallNode(self, node): |
+ self.visit(node.function) |
+ self.put(u"(") |
+ self.comma_separated_list(node.args) |
+ self.put(")") |
+ |
+ def visit_GeneralCallNode(self, node): |
+ self.visit(node.function) |
+ self.put(u"(") |
+ posarg = node.positional_args |
+ if isinstance(posarg, AsTupleNode): |
+ self.visit(posarg.arg) |
+ else: |
+ self.comma_separated_list(posarg) |
+ if node.keyword_args is not None or node.starstar_arg is not None: |
+ raise Exception("Not implemented yet") |
+ self.put(u")") |
+ |
+ def visit_ExprStatNode(self, node): |
+ self.startline() |
+ self.visit(node.expr) |
+ self.endline() |
+ |
+ def visit_InPlaceAssignmentNode(self, node): |
+ self.startline() |
+ self.visit(node.lhs) |
+ self.put(u" %s= " % node.operator) |
+ self.visit(node.rhs) |
+ self.endline() |
+ |
+ def visit_WithStatNode(self, node): |
+ self.startline() |
+ self.put(u"with ") |
+ self.visit(node.manager) |
+ if node.target is not None: |
+ self.put(u" as ") |
+ self.visit(node.target) |
+ self.endline(u":") |
+ self.indent() |
+ self.visit(node.body) |
+ self.dedent() |
+ |
+ def visit_TryFinallyStatNode(self, node): |
+ self.line(u"try:") |
+ self.indent() |
+ self.visit(node.body) |
+ self.dedent() |
+ self.line(u"finally:") |
+ self.indent() |
+ self.visit(node.finally_clause) |
+ self.dedent() |
+ |
+ def visit_TryExceptStatNode(self, node): |
+ self.line(u"try:") |
+ self.indent() |
+ self.visit(node.body) |
+ self.dedent() |
+ for x in node.except_clauses: |
+ self.visit(x) |
+ if node.else_clause is not None: |
+ self.visit(node.else_clause) |
+ |
+ def visit_ExceptClauseNode(self, node): |
+ self.startline(u"except") |
+ if node.pattern is not None: |
+ self.put(u" ") |
+ self.visit(node.pattern) |
+ if node.target is not None: |
+ self.put(u", ") |
+ self.visit(node.target) |
+ self.endline(":") |
+ self.indent() |
+ self.visit(node.body) |
+ self.dedent() |
+ |
+ def visit_ReturnStatNode(self, node): |
+ self.startline("return ") |
+ self.visit(node.value) |
+ self.endline() |
+ |
+ def visit_ReraiseStatNode(self, node): |
+ self.line("raise") |
+ |
+ def visit_ImportNode(self, node): |
+ self.put(u"(import %s)" % node.module_name.value) |
+ |
+ def visit_TempsBlockNode(self, node): |
+ """ |
+ Temporaries are output like $1_1', where the first number is |
+ an index of the TempsBlockNode and the second number is an index |
+ of the temporary which that block allocates. |
+ """ |
+ idx = 0 |
+ for handle in node.temps: |
+ self.tempnames[handle] = "$%d_%d" % (self.tempblockindex, idx) |
+ idx += 1 |
+ self.tempblockindex += 1 |
+ self.visit(node.body) |
+ |
+ def visit_TempRefNode(self, node): |
+ self.put(self.tempnames[node.handle]) |
+ |
+ |
+class PxdWriter(DeclarationWriter): |
+ def __call__(self, node): |
+ print u'\n'.join(self.write(node).lines) |
+ return node |
+ |
+ def visit_CFuncDefNode(self, node): |
+ if 'inline' in node.modifiers: |
+ return |
+ if node.overridable: |
+ self.startline(u'cpdef ') |
+ else: |
+ self.startline(u'cdef ') |
+ if node.visibility != 'private': |
+ self.put(node.visibility) |
+ self.put(u' ') |
+ if node.api: |
+ self.put(u'api ') |
+ self.visit(node.declarator) |
+ |
+ def visit_StatNode(self, node): |
+ pass |
+ |
+ |