diff options
Diffstat (limited to 'Cython/CodeWriter.py')
-rw-r--r-- | Cython/CodeWriter.py | 283 |
1 files changed, 142 insertions, 141 deletions
diff --git a/Cython/CodeWriter.py b/Cython/CodeWriter.py index a5453b90b..f386da21c 100644 --- a/Cython/CodeWriter.py +++ b/Cython/CodeWriter.py @@ -1,7 +1,6 @@ """ 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). """ @@ -10,6 +9,7 @@ from __future__ import absolute_import, print_function from .Compiler.Visitor import TreeVisitor from .Compiler.ExprNodes import * +from .Compiler.Nodes import CSimpleBaseTypeNode class LinesResult(object): @@ -28,7 +28,11 @@ class LinesResult(object): self.put(s) self.newline() + class DeclarationWriter(TreeVisitor): + """ + A Cython code writer that is limited to declarations nodes. + """ indent_string = u" " @@ -76,6 +80,14 @@ class DeclarationWriter(TreeVisitor): self.visit(item.default) self.put(u", ") self.visit(items[-1]) + if output_rhs and items[-1].default is not None: + self.put(u" = ") + self.visit(items[-1].default) + + def _visit_indented(self, node): + self.indent() + self.visit(node) + self.dedent() def visit_Node(self, node): raise AssertionError("Node not handled by serializer: %r" % node) @@ -92,9 +104,7 @@ class DeclarationWriter(TreeVisitor): else: file = u'"%s"' % node.include_file self.putline(u"cdef extern from %s:" % file) - self.indent() - self.visit(node.body) - self.dedent() + self._visit_indented(node.body) def visit_CPtrDeclaratorNode(self, node): self.put('*') @@ -111,13 +121,6 @@ class DeclarationWriter(TreeVisitor): 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) @@ -136,13 +139,12 @@ class DeclarationWriter(TreeVisitor): self.put("short " * -node.longness) elif node.longness > 0: self.put("long " * node.longness) - self.put(node.name) + if node.name is not None: + 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) @@ -162,7 +164,7 @@ class DeclarationWriter(TreeVisitor): self.comma_separated_list(node.declarators, output_rhs=True) self.endline() - def visit_container_node(self, node, decl, extras, attributes): + def _visit_container_node(self, node, decl, extras, attributes): # TODO: visibility self.startline(decl) if node.name: @@ -191,7 +193,7 @@ class DeclarationWriter(TreeVisitor): if node.packed: decl += u'packed ' decl += node.kind - self.visit_container_node(node, decl, None, node.attributes) + self._visit_container_node(node, decl, None, node.attributes) def visit_CppClassNode(self, node): extras = "" @@ -199,10 +201,10 @@ class DeclarationWriter(TreeVisitor): 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) + 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) + self._visit_container_node(node, u"cdef enum", None, node.items) def visit_CEnumDefItemNode(self, node): self.startline(node.name) @@ -228,9 +230,7 @@ class DeclarationWriter(TreeVisitor): self.put(node.base_class_name) self.put(u")") self.endline(u":") - self.indent() - self.visit(node.body) - self.dedent() + self._visit_indented(node.body) def visit_CTypeDefNode(self, node): self.startline(u"ctypedef ") @@ -240,17 +240,49 @@ class DeclarationWriter(TreeVisitor): self.endline() def visit_FuncDefNode(self, node): + # TODO: support cdef + cpdef functions self.startline(u"def %s(" % node.name) self.comma_separated_list(node.args) self.endline(u"):") - self.indent() - self.visit(node.body) - self.dedent() + self._visit_indented(node.body) + + def visit_CFuncDefNode(self, node): + self.startline(u'cpdef ' if node.overridable else u'cdef ') + if node.modifiers: + self.put(' '.join(node.modifiers)) + self.put(' ') + if node.visibility != 'private': + self.put(node.visibility) + self.put(u' ') + if node.api: + self.put(u'api ') + + if node.base_type: + self.visit(node.base_type) + if node.base_type.name is not None: + self.put(u' ') + + # visit the CFuncDeclaratorNode, but put a `:` at the end of line + self.visit(node.declarator.base) + self.put(u'(') + self.comma_separated_list(node.declarator.args) + self.endline(u'):') + + self._visit_indented(node.body) def visit_CArgDeclNode(self, node): - if node.base_type.name is not None: + # For "CSimpleBaseTypeNode", the variable type may have been parsed as type. + # For other node types, the "name" is always None. + if not isinstance(node.base_type, CSimpleBaseTypeNode) or \ + node.base_type.name is not None: self.visit(node.base_type) - self.put(u" ") + + # If we printed something for "node.base_type", we may need to print an extra ' '. + # + # Special case: if "node.declarator" is a "CNameDeclaratorNode", + # its "name" might be an empty string, for example, for "cdef f(x)". + if node.declarator.declared_name(): + self.put(u" ") self.visit(node.declarator) if node.default is not None: self.put(u" = ") @@ -284,46 +316,20 @@ class DeclarationWriter(TreeVisitor): 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): + +class StatementWriter(DeclarationWriter): + """ + A Cython code writer for most language statement features. + """ def visit_SingleAssignmentNode(self, node): self.startline() @@ -349,18 +355,17 @@ class CodeWriter(DeclarationWriter): def visit_ForInStatNode(self, node): self.startline(u"for ") - self.visit(node.target) + if node.target.is_sequence_constructor: + self.comma_separated_list(node.target.args) + else: + self.visit(node.target) self.put(u" in ") self.visit(node.iterator.sequence) self.endline(u":") - self.indent() - self.visit(node.body) - self.dedent() + self._visit_indented(node.body) if node.else_clause is not None: self.line(u"else:") - self.indent() - self.visit(node.else_clause) - self.dedent() + self._visit_indented(node.else_clause) def visit_IfStatNode(self, node): # The IfClauseNode is handled directly without a separate match @@ -368,50 +373,33 @@ class CodeWriter(DeclarationWriter): self.startline(u"if ") self.visit(node.if_clauses[0].condition) self.endline(":") - self.indent() - self.visit(node.if_clauses[0].body) - self.dedent() + self._visit_indented(node.if_clauses[0].body) for clause in node.if_clauses[1:]: self.startline("elif ") self.visit(clause.condition) self.endline(":") - self.indent() - self.visit(clause.body) - self.dedent() + self._visit_indented(clause.body) if node.else_clause is not None: self.line("else:") - self.indent() - self.visit(node.else_clause) - self.dedent() + self._visit_indented(node.else_clause) - def visit_SequenceNode(self, node): - self.comma_separated_list(node.args) # Might need to discover whether we need () around tuples...hmm... + def visit_WhileStatNode(self, node): + self.startline(u"while ") + self.visit(node.condition) + self.endline(u":") + self._visit_indented(node.body) + if node.else_clause is not None: + self.line("else:") + self._visit_indented(node.else_clause) - def visit_SimpleCallNode(self, node): - self.visit(node.function) - self.put(u"(") - self.comma_separated_list(node.args) - self.put(")") + def visit_ContinueStatNode(self, node): + self.line(u"continue") - 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.args) # TupleNode.args - if node.keyword_args: - if isinstance(node.keyword_args, DictNode): - for i, (name, value) in enumerate(node.keyword_args.key_value_pairs): - if i > 0: - self.put(', ') - self.visit(name) - self.put('=') - self.visit(value) - else: - raise Exception("Not implemented yet") - self.put(u")") + def visit_BreakStatNode(self, node): + self.line(u"break") + + def visit_SequenceNode(self, node): + self.comma_separated_list(node.args) # Might need to discover whether we need () around tuples...hmm... def visit_ExprStatNode(self, node): self.startline() @@ -433,25 +421,17 @@ class CodeWriter(DeclarationWriter): self.put(u" as ") self.visit(node.target) self.endline(u":") - self.indent() - self.visit(node.body) - self.dedent() + self._visit_indented(node.body) def visit_TryFinallyStatNode(self, node): self.line(u"try:") - self.indent() - self.visit(node.body) - self.dedent() + self._visit_indented(node.body) self.line(u"finally:") - self.indent() - self.visit(node.finally_clause) - self.dedent() + self._visit_indented(node.finally_clause) def visit_TryExceptStatNode(self, node): self.line(u"try:") - self.indent() - self.visit(node.body) - self.dedent() + self._visit_indented(node.body) for x in node.except_clauses: self.visit(x) if node.else_clause is not None: @@ -466,13 +446,13 @@ class CodeWriter(DeclarationWriter): self.put(u", ") self.visit(node.target) self.endline(":") - self.indent() - self.visit(node.body) - self.dedent() + self._visit_indented(node.body) def visit_ReturnStatNode(self, node): - self.startline("return ") - self.visit(node.value) + self.startline("return") + if node.value is not None: + self.put(u" ") + self.visit(node.value) self.endline() def visit_ReraiseStatNode(self, node): @@ -498,30 +478,10 @@ class CodeWriter(DeclarationWriter): 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 - - class ExpressionWriter(TreeVisitor): + """ + A Cython code writer that is intentionally limited to expressions. + """ def __init__(self, result=None): super(ExpressionWriter, self).__init__() @@ -551,12 +511,18 @@ class ExpressionWriter(TreeVisitor): def visit_Node(self, node): raise AssertionError("Node not handled by serializer: %r" % node) - def visit_NameNode(self, node): - self.put(node.name) + def visit_IntNode(self, node): + self.put(node.value) + + def visit_FloatNode(self, node): + self.put(node.value) def visit_NoneNode(self, node): self.put(u"None") + def visit_NameNode(self, node): + self.put(node.name) + def visit_EllipsisNode(self, node): self.put(u"...") @@ -817,3 +783,38 @@ class ExpressionWriter(TreeVisitor): # type(body) is Nodes.ExprStatNode body = body.expr.arg self.emit_comprehension(body, target, sequence, condition, u"()") + + +class PxdWriter(DeclarationWriter, ExpressionWriter): + """ + A Cython code writer for everything supported in pxd files. + (currently unused) + """ + + def __call__(self, node): + print(u'\n'.join(self.write(node).lines)) + return node + + def visit_CFuncDefNode(self, node): + if node.overridable: + self.startline(u'cpdef ') + else: + self.startline(u'cdef ') + if node.modifiers: + self.put(' '.join(node.modifiers)) + self.put(' ') + 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 + + +class CodeWriter(StatementWriter, ExpressionWriter): + """ + A complete Cython code writer. + """ |