summaryrefslogtreecommitdiff
path: root/Cython/CodeWriter.py
diff options
context:
space:
mode:
Diffstat (limited to 'Cython/CodeWriter.py')
-rw-r--r--Cython/CodeWriter.py283
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.
+ """