aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/cython/Cython/CodeWriter.py
diff options
context:
space:
mode:
authoralexv-smirnov <alex@ydb.tech>2023-06-13 11:05:01 +0300
committeralexv-smirnov <alex@ydb.tech>2023-06-13 11:05:01 +0300
commitbf0f13dd39ee3e65092ba3572bb5b1fcd125dcd0 (patch)
tree1d1df72c0541a59a81439842f46d95396d3e7189 /contrib/tools/cython/Cython/CodeWriter.py
parent8bfdfa9a9bd19bddbc58d888e180fbd1218681be (diff)
downloadydb-bf0f13dd39ee3e65092ba3572bb5b1fcd125dcd0.tar.gz
add ymake export to ydb
Diffstat (limited to 'contrib/tools/cython/Cython/CodeWriter.py')
-rw-r--r--contrib/tools/cython/Cython/CodeWriter.py816
1 files changed, 816 insertions, 0 deletions
diff --git a/contrib/tools/cython/Cython/CodeWriter.py b/contrib/tools/cython/Cython/CodeWriter.py
new file mode 100644
index 0000000000..2e4646a654
--- /dev/null
+++ b/contrib/tools/cython/Cython/CodeWriter.py
@@ -0,0 +1,816 @@
+"""
+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 __future__ import absolute_import, print_function
+
+from .Compiler.Visitor import TreeVisitor
+from .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 separate 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.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_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
+
+
+class ExpressionWriter(TreeVisitor):
+
+ def __init__(self, result=None):
+ super(ExpressionWriter, self).__init__()
+ if result is None:
+ result = u""
+ self.result = result
+ self.precedence = [0]
+
+ def write(self, tree):
+ self.visit(tree)
+ return self.result
+
+ def put(self, s):
+ self.result += s
+
+ def remove(self, s):
+ if self.result.endswith(s):
+ self.result = self.result[:-len(s)]
+
+ def comma_separated_list(self, items):
+ if len(items) > 0:
+ for item in items[:-1]:
+ self.visit(item)
+ self.put(u", ")
+ self.visit(items[-1])
+
+ 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_NoneNode(self, node):
+ self.put(u"None")
+
+ def visit_EllipsisNode(self, node):
+ self.put(u"...")
+
+ def visit_BoolNode(self, node):
+ self.put(str(node.value))
+
+ def visit_ConstNode(self, node):
+ self.put(str(node.value))
+
+ def visit_ImagNode(self, node):
+ self.put(node.value)
+ self.put(u"j")
+
+ def emit_string(self, node, prefix=u""):
+ repr_val = repr(node.value)
+ if repr_val[0] in 'ub':
+ repr_val = repr_val[1:]
+ self.put(u"%s%s" % (prefix, repr_val))
+
+ def visit_BytesNode(self, node):
+ self.emit_string(node, u"b")
+
+ def visit_StringNode(self, node):
+ self.emit_string(node)
+
+ def visit_UnicodeNode(self, node):
+ self.emit_string(node, u"u")
+
+ def emit_sequence(self, node, parens=(u"", u"")):
+ open_paren, close_paren = parens
+ items = node.subexpr_nodes()
+ self.put(open_paren)
+ self.comma_separated_list(items)
+ self.put(close_paren)
+
+ def visit_ListNode(self, node):
+ self.emit_sequence(node, u"[]")
+
+ def visit_TupleNode(self, node):
+ self.emit_sequence(node, u"()")
+
+ def visit_SetNode(self, node):
+ if len(node.subexpr_nodes()) > 0:
+ self.emit_sequence(node, u"{}")
+ else:
+ self.put(u"set()")
+
+ def visit_DictNode(self, node):
+ self.emit_sequence(node, u"{}")
+
+ def visit_DictItemNode(self, node):
+ self.visit(node.key)
+ self.put(u": ")
+ self.visit(node.value)
+
+ unop_precedence = {
+ 'not': 3, '!': 3,
+ '+': 11, '-': 11, '~': 11,
+ }
+ binop_precedence = {
+ 'or': 1,
+ 'and': 2,
+ # unary: 'not': 3, '!': 3,
+ 'in': 4, 'not_in': 4, 'is': 4, 'is_not': 4, '<': 4, '<=': 4, '>': 4, '>=': 4, '!=': 4, '==': 4,
+ '|': 5,
+ '^': 6,
+ '&': 7,
+ '<<': 8, '>>': 8,
+ '+': 9, '-': 9,
+ '*': 10, '@': 10, '/': 10, '//': 10, '%': 10,
+ # unary: '+': 11, '-': 11, '~': 11
+ '**': 12,
+ }
+
+ def operator_enter(self, new_prec):
+ old_prec = self.precedence[-1]
+ if old_prec > new_prec:
+ self.put(u"(")
+ self.precedence.append(new_prec)
+
+ def operator_exit(self):
+ old_prec, new_prec = self.precedence[-2:]
+ if old_prec > new_prec:
+ self.put(u")")
+ self.precedence.pop()
+
+ def visit_NotNode(self, node):
+ op = 'not'
+ prec = self.unop_precedence[op]
+ self.operator_enter(prec)
+ self.put(u"not ")
+ self.visit(node.operand)
+ self.operator_exit()
+
+ def visit_UnopNode(self, node):
+ op = node.operator
+ prec = self.unop_precedence[op]
+ self.operator_enter(prec)
+ self.put(u"%s" % node.operator)
+ self.visit(node.operand)
+ self.operator_exit()
+
+ def visit_BinopNode(self, node):
+ op = node.operator
+ prec = self.binop_precedence.get(op, 0)
+ self.operator_enter(prec)
+ self.visit(node.operand1)
+ self.put(u" %s " % op.replace('_', ' '))
+ self.visit(node.operand2)
+ self.operator_exit()
+
+ def visit_BoolBinopNode(self, node):
+ self.visit_BinopNode(node)
+
+ def visit_PrimaryCmpNode(self, node):
+ self.visit_BinopNode(node)
+
+ def visit_IndexNode(self, node):
+ self.visit(node.base)
+ self.put(u"[")
+ if isinstance(node.index, TupleNode):
+ self.emit_sequence(node.index)
+ else:
+ self.visit(node.index)
+ self.put(u"]")
+
+ def visit_SliceIndexNode(self, node):
+ self.visit(node.base)
+ self.put(u"[")
+ if node.start:
+ self.visit(node.start)
+ self.put(u":")
+ if node.stop:
+ self.visit(node.stop)
+ if node.slice:
+ self.put(u":")
+ self.visit(node.slice)
+ self.put(u"]")
+
+ def visit_SliceNode(self, node):
+ if not node.start.is_none:
+ self.visit(node.start)
+ self.put(u":")
+ if not node.stop.is_none:
+ self.visit(node.stop)
+ if not node.step.is_none:
+ self.put(u":")
+ self.visit(node.step)
+
+ def visit_CondExprNode(self, node):
+ self.visit(node.true_val)
+ self.put(u" if ")
+ self.visit(node.test)
+ self.put(u" else ")
+ self.visit(node.false_val)
+
+ def visit_AttributeNode(self, node):
+ self.visit(node.obj)
+ self.put(u".%s" % node.attribute)
+
+ def visit_SimpleCallNode(self, node):
+ self.visit(node.function)
+ self.put(u"(")
+ self.comma_separated_list(node.args)
+ self.put(")")
+
+ def emit_pos_args(self, node):
+ if node is None:
+ return
+ if isinstance(node, AddNode):
+ self.emit_pos_args(node.operand1)
+ self.emit_pos_args(node.operand2)
+ elif isinstance(node, TupleNode):
+ for expr in node.subexpr_nodes():
+ self.visit(expr)
+ self.put(u", ")
+ elif isinstance(node, AsTupleNode):
+ self.put("*")
+ self.visit(node.arg)
+ self.put(u", ")
+ else:
+ self.visit(node)
+ self.put(u", ")
+
+ def emit_kwd_args(self, node):
+ if node is None:
+ return
+ if isinstance(node, MergedDictNode):
+ for expr in node.subexpr_nodes():
+ self.emit_kwd_args(expr)
+ elif isinstance(node, DictNode):
+ for expr in node.subexpr_nodes():
+ self.put(u"%s=" % expr.key.value)
+ self.visit(expr.value)
+ self.put(u", ")
+ else:
+ self.put(u"**")
+ self.visit(node)
+ self.put(u", ")
+
+ def visit_GeneralCallNode(self, node):
+ self.visit(node.function)
+ self.put(u"(")
+ self.emit_pos_args(node.positional_args)
+ self.emit_kwd_args(node.keyword_args)
+ self.remove(u", ")
+ self.put(")")
+
+ def emit_comprehension(self, body, target,
+ sequence, condition,
+ parens=(u"", u"")):
+ open_paren, close_paren = parens
+ self.put(open_paren)
+ self.visit(body)
+ self.put(u" for ")
+ self.visit(target)
+ self.put(u" in ")
+ self.visit(sequence)
+ if condition:
+ self.put(u" if ")
+ self.visit(condition)
+ self.put(close_paren)
+
+ def visit_ComprehensionAppendNode(self, node):
+ self.visit(node.expr)
+
+ def visit_DictComprehensionAppendNode(self, node):
+ self.visit(node.key_expr)
+ self.put(u": ")
+ self.visit(node.value_expr)
+
+ def visit_ComprehensionNode(self, node):
+ tpmap = {'list': u"[]", 'dict': u"{}", 'set': u"{}"}
+ parens = tpmap[node.type.py_type_name()]
+ body = node.loop.body
+ target = node.loop.target
+ sequence = node.loop.iterator.sequence
+ condition = None
+ if hasattr(body, 'if_clauses'):
+ # type(body) is Nodes.IfStatNode
+ condition = body.if_clauses[0].condition
+ body = body.if_clauses[0].body
+ self.emit_comprehension(body, target, sequence, condition, parens)
+
+ def visit_GeneratorExpressionNode(self, node):
+ body = node.loop.body
+ target = node.loop.target
+ sequence = node.loop.iterator.sequence
+ condition = None
+ if hasattr(body, 'if_clauses'):
+ # type(body) is Nodes.IfStatNode
+ condition = body.if_clauses[0].condition
+ body = body.if_clauses[0].body.expr.arg
+ elif hasattr(body, 'expr'):
+ # type(body) is Nodes.ExprStatNode
+ body = body.expr.arg
+ self.emit_comprehension(body, target, sequence, condition, u"()")