You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

816 lines
23 KiB

4 years ago
  1. """
  2. Serializes a Cython code tree to Cython code. This is primarily useful for
  3. debugging and testing purposes.
  4. The output is in a strict format, no whitespace or comments from the input
  5. is preserved (and it could not be as it is not present in the code tree).
  6. """
  7. from __future__ import absolute_import, print_function
  8. from .Compiler.Visitor import TreeVisitor
  9. from .Compiler.ExprNodes import *
  10. class LinesResult(object):
  11. def __init__(self):
  12. self.lines = []
  13. self.s = u""
  14. def put(self, s):
  15. self.s += s
  16. def newline(self):
  17. self.lines.append(self.s)
  18. self.s = u""
  19. def putline(self, s):
  20. self.put(s)
  21. self.newline()
  22. class DeclarationWriter(TreeVisitor):
  23. indent_string = u" "
  24. def __init__(self, result=None):
  25. super(DeclarationWriter, self).__init__()
  26. if result is None:
  27. result = LinesResult()
  28. self.result = result
  29. self.numindents = 0
  30. self.tempnames = {}
  31. self.tempblockindex = 0
  32. def write(self, tree):
  33. self.visit(tree)
  34. return self.result
  35. def indent(self):
  36. self.numindents += 1
  37. def dedent(self):
  38. self.numindents -= 1
  39. def startline(self, s=u""):
  40. self.result.put(self.indent_string * self.numindents + s)
  41. def put(self, s):
  42. self.result.put(s)
  43. def putline(self, s):
  44. self.result.putline(self.indent_string * self.numindents + s)
  45. def endline(self, s=u""):
  46. self.result.putline(s)
  47. def line(self, s):
  48. self.startline(s)
  49. self.endline()
  50. def comma_separated_list(self, items, output_rhs=False):
  51. if len(items) > 0:
  52. for item in items[:-1]:
  53. self.visit(item)
  54. if output_rhs and item.default is not None:
  55. self.put(u" = ")
  56. self.visit(item.default)
  57. self.put(u", ")
  58. self.visit(items[-1])
  59. def visit_Node(self, node):
  60. raise AssertionError("Node not handled by serializer: %r" % node)
  61. def visit_ModuleNode(self, node):
  62. self.visitchildren(node)
  63. def visit_StatListNode(self, node):
  64. self.visitchildren(node)
  65. def visit_CDefExternNode(self, node):
  66. if node.include_file is None:
  67. file = u'*'
  68. else:
  69. file = u'"%s"' % node.include_file
  70. self.putline(u"cdef extern from %s:" % file)
  71. self.indent()
  72. self.visit(node.body)
  73. self.dedent()
  74. def visit_CPtrDeclaratorNode(self, node):
  75. self.put('*')
  76. self.visit(node.base)
  77. def visit_CReferenceDeclaratorNode(self, node):
  78. self.put('&')
  79. self.visit(node.base)
  80. def visit_CArrayDeclaratorNode(self, node):
  81. self.visit(node.base)
  82. self.put(u'[')
  83. if node.dimension is not None:
  84. self.visit(node.dimension)
  85. self.put(u']')
  86. def visit_CArrayDeclaratorNode(self, node):
  87. self.visit(node.base)
  88. self.put(u'[')
  89. if node.dimension is not None:
  90. self.visit(node.dimension)
  91. self.put(u']')
  92. def visit_CFuncDeclaratorNode(self, node):
  93. # TODO: except, gil, etc.
  94. self.visit(node.base)
  95. self.put(u'(')
  96. self.comma_separated_list(node.args)
  97. self.endline(u')')
  98. def visit_CNameDeclaratorNode(self, node):
  99. self.put(node.name)
  100. def visit_CSimpleBaseTypeNode(self, node):
  101. # See Parsing.p_sign_and_longness
  102. if node.is_basic_c_type:
  103. self.put(("unsigned ", "", "signed ")[node.signed])
  104. if node.longness < 0:
  105. self.put("short " * -node.longness)
  106. elif node.longness > 0:
  107. self.put("long " * node.longness)
  108. self.put(node.name)
  109. def visit_CComplexBaseTypeNode(self, node):
  110. self.put(u'(')
  111. self.visit(node.base_type)
  112. self.visit(node.declarator)
  113. self.put(u')')
  114. def visit_CNestedBaseTypeNode(self, node):
  115. self.visit(node.base_type)
  116. self.put(u'.')
  117. self.put(node.name)
  118. def visit_TemplatedTypeNode(self, node):
  119. self.visit(node.base_type_node)
  120. self.put(u'[')
  121. self.comma_separated_list(node.positional_args + node.keyword_args.key_value_pairs)
  122. self.put(u']')
  123. def visit_CVarDefNode(self, node):
  124. self.startline(u"cdef ")
  125. self.visit(node.base_type)
  126. self.put(u" ")
  127. self.comma_separated_list(node.declarators, output_rhs=True)
  128. self.endline()
  129. def visit_container_node(self, node, decl, extras, attributes):
  130. # TODO: visibility
  131. self.startline(decl)
  132. if node.name:
  133. self.put(u' ')
  134. self.put(node.name)
  135. if node.cname is not None:
  136. self.put(u' "%s"' % node.cname)
  137. if extras:
  138. self.put(extras)
  139. self.endline(':')
  140. self.indent()
  141. if not attributes:
  142. self.putline('pass')
  143. else:
  144. for attribute in attributes:
  145. self.visit(attribute)
  146. self.dedent()
  147. def visit_CStructOrUnionDefNode(self, node):
  148. if node.typedef_flag:
  149. decl = u'ctypedef '
  150. else:
  151. decl = u'cdef '
  152. if node.visibility == 'public':
  153. decl += u'public '
  154. if node.packed:
  155. decl += u'packed '
  156. decl += node.kind
  157. self.visit_container_node(node, decl, None, node.attributes)
  158. def visit_CppClassNode(self, node):
  159. extras = ""
  160. if node.templates:
  161. extras = u"[%s]" % ", ".join(node.templates)
  162. if node.base_classes:
  163. extras += "(%s)" % ", ".join(node.base_classes)
  164. self.visit_container_node(node, u"cdef cppclass", extras, node.attributes)
  165. def visit_CEnumDefNode(self, node):
  166. self.visit_container_node(node, u"cdef enum", None, node.items)
  167. def visit_CEnumDefItemNode(self, node):
  168. self.startline(node.name)
  169. if node.cname:
  170. self.put(u' "%s"' % node.cname)
  171. if node.value:
  172. self.put(u" = ")
  173. self.visit(node.value)
  174. self.endline()
  175. def visit_CClassDefNode(self, node):
  176. assert not node.module_name
  177. if node.decorators:
  178. for decorator in node.decorators:
  179. self.visit(decorator)
  180. self.startline(u"cdef class ")
  181. self.put(node.class_name)
  182. if node.base_class_name:
  183. self.put(u"(")
  184. if node.base_class_module:
  185. self.put(node.base_class_module)
  186. self.put(u".")
  187. self.put(node.base_class_name)
  188. self.put(u")")
  189. self.endline(u":")
  190. self.indent()
  191. self.visit(node.body)
  192. self.dedent()
  193. def visit_CTypeDefNode(self, node):
  194. self.startline(u"ctypedef ")
  195. self.visit(node.base_type)
  196. self.put(u" ")
  197. self.visit(node.declarator)
  198. self.endline()
  199. def visit_FuncDefNode(self, node):
  200. self.startline(u"def %s(" % node.name)
  201. self.comma_separated_list(node.args)
  202. self.endline(u"):")
  203. self.indent()
  204. self.visit(node.body)
  205. self.dedent()
  206. def visit_CArgDeclNode(self, node):
  207. if node.base_type.name is not None:
  208. self.visit(node.base_type)
  209. self.put(u" ")
  210. self.visit(node.declarator)
  211. if node.default is not None:
  212. self.put(u" = ")
  213. self.visit(node.default)
  214. def visit_CImportStatNode(self, node):
  215. self.startline(u"cimport ")
  216. self.put(node.module_name)
  217. if node.as_name:
  218. self.put(u" as ")
  219. self.put(node.as_name)
  220. self.endline()
  221. def visit_FromCImportStatNode(self, node):
  222. self.startline(u"from ")
  223. self.put(node.module_name)
  224. self.put(u" cimport ")
  225. first = True
  226. for pos, name, as_name, kind in node.imported_names:
  227. assert kind is None
  228. if first:
  229. first = False
  230. else:
  231. self.put(u", ")
  232. self.put(name)
  233. if as_name:
  234. self.put(u" as ")
  235. self.put(as_name)
  236. self.endline()
  237. def visit_NameNode(self, node):
  238. self.put(node.name)
  239. def visit_IntNode(self, node):
  240. self.put(node.value)
  241. def visit_NoneNode(self, node):
  242. self.put(u"None")
  243. def visit_NotNode(self, node):
  244. self.put(u"(not ")
  245. self.visit(node.operand)
  246. self.put(u")")
  247. def visit_DecoratorNode(self, node):
  248. self.startline("@")
  249. self.visit(node.decorator)
  250. self.endline()
  251. def visit_BinopNode(self, node):
  252. self.visit(node.operand1)
  253. self.put(u" %s " % node.operator)
  254. self.visit(node.operand2)
  255. def visit_AttributeNode(self, node):
  256. self.visit(node.obj)
  257. self.put(u".%s" % node.attribute)
  258. def visit_BoolNode(self, node):
  259. self.put(str(node.value))
  260. # FIXME: represent string nodes correctly
  261. def visit_StringNode(self, node):
  262. value = node.value
  263. if value.encoding is not None:
  264. value = value.encode(value.encoding)
  265. self.put(repr(value))
  266. def visit_PassStatNode(self, node):
  267. self.startline(u"pass")
  268. self.endline()
  269. class CodeWriter(DeclarationWriter):
  270. def visit_SingleAssignmentNode(self, node):
  271. self.startline()
  272. self.visit(node.lhs)
  273. self.put(u" = ")
  274. self.visit(node.rhs)
  275. self.endline()
  276. def visit_CascadedAssignmentNode(self, node):
  277. self.startline()
  278. for lhs in node.lhs_list:
  279. self.visit(lhs)
  280. self.put(u" = ")
  281. self.visit(node.rhs)
  282. self.endline()
  283. def visit_PrintStatNode(self, node):
  284. self.startline(u"print ")
  285. self.comma_separated_list(node.arg_tuple.args)
  286. if not node.append_newline:
  287. self.put(u",")
  288. self.endline()
  289. def visit_ForInStatNode(self, node):
  290. self.startline(u"for ")
  291. self.visit(node.target)
  292. self.put(u" in ")
  293. self.visit(node.iterator.sequence)
  294. self.endline(u":")
  295. self.indent()
  296. self.visit(node.body)
  297. self.dedent()
  298. if node.else_clause is not None:
  299. self.line(u"else:")
  300. self.indent()
  301. self.visit(node.else_clause)
  302. self.dedent()
  303. def visit_IfStatNode(self, node):
  304. # The IfClauseNode is handled directly without a separate match
  305. # for clariy.
  306. self.startline(u"if ")
  307. self.visit(node.if_clauses[0].condition)
  308. self.endline(":")
  309. self.indent()
  310. self.visit(node.if_clauses[0].body)
  311. self.dedent()
  312. for clause in node.if_clauses[1:]:
  313. self.startline("elif ")
  314. self.visit(clause.condition)
  315. self.endline(":")
  316. self.indent()
  317. self.visit(clause.body)
  318. self.dedent()
  319. if node.else_clause is not None:
  320. self.line("else:")
  321. self.indent()
  322. self.visit(node.else_clause)
  323. self.dedent()
  324. def visit_SequenceNode(self, node):
  325. self.comma_separated_list(node.args) # Might need to discover whether we need () around tuples...hmm...
  326. def visit_SimpleCallNode(self, node):
  327. self.visit(node.function)
  328. self.put(u"(")
  329. self.comma_separated_list(node.args)
  330. self.put(")")
  331. def visit_GeneralCallNode(self, node):
  332. self.visit(node.function)
  333. self.put(u"(")
  334. posarg = node.positional_args
  335. if isinstance(posarg, AsTupleNode):
  336. self.visit(posarg.arg)
  337. else:
  338. self.comma_separated_list(posarg.args) # TupleNode.args
  339. if node.keyword_args:
  340. if isinstance(node.keyword_args, DictNode):
  341. for i, (name, value) in enumerate(node.keyword_args.key_value_pairs):
  342. if i > 0:
  343. self.put(', ')
  344. self.visit(name)
  345. self.put('=')
  346. self.visit(value)
  347. else:
  348. raise Exception("Not implemented yet")
  349. self.put(u")")
  350. def visit_ExprStatNode(self, node):
  351. self.startline()
  352. self.visit(node.expr)
  353. self.endline()
  354. def visit_InPlaceAssignmentNode(self, node):
  355. self.startline()
  356. self.visit(node.lhs)
  357. self.put(u" %s= " % node.operator)
  358. self.visit(node.rhs)
  359. self.endline()
  360. def visit_WithStatNode(self, node):
  361. self.startline()
  362. self.put(u"with ")
  363. self.visit(node.manager)
  364. if node.target is not None:
  365. self.put(u" as ")
  366. self.visit(node.target)
  367. self.endline(u":")
  368. self.indent()
  369. self.visit(node.body)
  370. self.dedent()
  371. def visit_TryFinallyStatNode(self, node):
  372. self.line(u"try:")
  373. self.indent()
  374. self.visit(node.body)
  375. self.dedent()
  376. self.line(u"finally:")
  377. self.indent()
  378. self.visit(node.finally_clause)
  379. self.dedent()
  380. def visit_TryExceptStatNode(self, node):
  381. self.line(u"try:")
  382. self.indent()
  383. self.visit(node.body)
  384. self.dedent()
  385. for x in node.except_clauses:
  386. self.visit(x)
  387. if node.else_clause is not None:
  388. self.visit(node.else_clause)
  389. def visit_ExceptClauseNode(self, node):
  390. self.startline(u"except")
  391. if node.pattern is not None:
  392. self.put(u" ")
  393. self.visit(node.pattern)
  394. if node.target is not None:
  395. self.put(u", ")
  396. self.visit(node.target)
  397. self.endline(":")
  398. self.indent()
  399. self.visit(node.body)
  400. self.dedent()
  401. def visit_ReturnStatNode(self, node):
  402. self.startline("return ")
  403. self.visit(node.value)
  404. self.endline()
  405. def visit_ReraiseStatNode(self, node):
  406. self.line("raise")
  407. def visit_ImportNode(self, node):
  408. self.put(u"(import %s)" % node.module_name.value)
  409. def visit_TempsBlockNode(self, node):
  410. """
  411. Temporaries are output like $1_1', where the first number is
  412. an index of the TempsBlockNode and the second number is an index
  413. of the temporary which that block allocates.
  414. """
  415. idx = 0
  416. for handle in node.temps:
  417. self.tempnames[handle] = "$%d_%d" % (self.tempblockindex, idx)
  418. idx += 1
  419. self.tempblockindex += 1
  420. self.visit(node.body)
  421. def visit_TempRefNode(self, node):
  422. self.put(self.tempnames[node.handle])
  423. class PxdWriter(DeclarationWriter):
  424. def __call__(self, node):
  425. print(u'\n'.join(self.write(node).lines))
  426. return node
  427. def visit_CFuncDefNode(self, node):
  428. if 'inline' in node.modifiers:
  429. return
  430. if node.overridable:
  431. self.startline(u'cpdef ')
  432. else:
  433. self.startline(u'cdef ')
  434. if node.visibility != 'private':
  435. self.put(node.visibility)
  436. self.put(u' ')
  437. if node.api:
  438. self.put(u'api ')
  439. self.visit(node.declarator)
  440. def visit_StatNode(self, node):
  441. pass
  442. class ExpressionWriter(TreeVisitor):
  443. def __init__(self, result=None):
  444. super(ExpressionWriter, self).__init__()
  445. if result is None:
  446. result = u""
  447. self.result = result
  448. self.precedence = [0]
  449. def write(self, tree):
  450. self.visit(tree)
  451. return self.result
  452. def put(self, s):
  453. self.result += s
  454. def remove(self, s):
  455. if self.result.endswith(s):
  456. self.result = self.result[:-len(s)]
  457. def comma_separated_list(self, items):
  458. if len(items) > 0:
  459. for item in items[:-1]:
  460. self.visit(item)
  461. self.put(u", ")
  462. self.visit(items[-1])
  463. def visit_Node(self, node):
  464. raise AssertionError("Node not handled by serializer: %r" % node)
  465. def visit_NameNode(self, node):
  466. self.put(node.name)
  467. def visit_NoneNode(self, node):
  468. self.put(u"None")
  469. def visit_EllipsisNode(self, node):
  470. self.put(u"...")
  471. def visit_BoolNode(self, node):
  472. self.put(str(node.value))
  473. def visit_ConstNode(self, node):
  474. self.put(str(node.value))
  475. def visit_ImagNode(self, node):
  476. self.put(node.value)
  477. self.put(u"j")
  478. def emit_string(self, node, prefix=u""):
  479. repr_val = repr(node.value)
  480. if repr_val[0] in 'ub':
  481. repr_val = repr_val[1:]
  482. self.put(u"%s%s" % (prefix, repr_val))
  483. def visit_BytesNode(self, node):
  484. self.emit_string(node, u"b")
  485. def visit_StringNode(self, node):
  486. self.emit_string(node)
  487. def visit_UnicodeNode(self, node):
  488. self.emit_string(node, u"u")
  489. def emit_sequence(self, node, parens=(u"", u"")):
  490. open_paren, close_paren = parens
  491. items = node.subexpr_nodes()
  492. self.put(open_paren)
  493. self.comma_separated_list(items)
  494. self.put(close_paren)
  495. def visit_ListNode(self, node):
  496. self.emit_sequence(node, u"[]")
  497. def visit_TupleNode(self, node):
  498. self.emit_sequence(node, u"()")
  499. def visit_SetNode(self, node):
  500. if len(node.subexpr_nodes()) > 0:
  501. self.emit_sequence(node, u"{}")
  502. else:
  503. self.put(u"set()")
  504. def visit_DictNode(self, node):
  505. self.emit_sequence(node, u"{}")
  506. def visit_DictItemNode(self, node):
  507. self.visit(node.key)
  508. self.put(u": ")
  509. self.visit(node.value)
  510. unop_precedence = {
  511. 'not': 3, '!': 3,
  512. '+': 11, '-': 11, '~': 11,
  513. }
  514. binop_precedence = {
  515. 'or': 1,
  516. 'and': 2,
  517. # unary: 'not': 3, '!': 3,
  518. 'in': 4, 'not_in': 4, 'is': 4, 'is_not': 4, '<': 4, '<=': 4, '>': 4, '>=': 4, '!=': 4, '==': 4,
  519. '|': 5,
  520. '^': 6,
  521. '&': 7,
  522. '<<': 8, '>>': 8,
  523. '+': 9, '-': 9,
  524. '*': 10, '@': 10, '/': 10, '//': 10, '%': 10,
  525. # unary: '+': 11, '-': 11, '~': 11
  526. '**': 12,
  527. }
  528. def operator_enter(self, new_prec):
  529. old_prec = self.precedence[-1]
  530. if old_prec > new_prec:
  531. self.put(u"(")
  532. self.precedence.append(new_prec)
  533. def operator_exit(self):
  534. old_prec, new_prec = self.precedence[-2:]
  535. if old_prec > new_prec:
  536. self.put(u")")
  537. self.precedence.pop()
  538. def visit_NotNode(self, node):
  539. op = 'not'
  540. prec = self.unop_precedence[op]
  541. self.operator_enter(prec)
  542. self.put(u"not ")
  543. self.visit(node.operand)
  544. self.operator_exit()
  545. def visit_UnopNode(self, node):
  546. op = node.operator
  547. prec = self.unop_precedence[op]
  548. self.operator_enter(prec)
  549. self.put(u"%s" % node.operator)
  550. self.visit(node.operand)
  551. self.operator_exit()
  552. def visit_BinopNode(self, node):
  553. op = node.operator
  554. prec = self.binop_precedence.get(op, 0)
  555. self.operator_enter(prec)
  556. self.visit(node.operand1)
  557. self.put(u" %s " % op.replace('_', ' '))
  558. self.visit(node.operand2)
  559. self.operator_exit()
  560. def visit_BoolBinopNode(self, node):
  561. self.visit_BinopNode(node)
  562. def visit_PrimaryCmpNode(self, node):
  563. self.visit_BinopNode(node)
  564. def visit_IndexNode(self, node):
  565. self.visit(node.base)
  566. self.put(u"[")
  567. if isinstance(node.index, TupleNode):
  568. self.emit_sequence(node.index)
  569. else:
  570. self.visit(node.index)
  571. self.put(u"]")
  572. def visit_SliceIndexNode(self, node):
  573. self.visit(node.base)
  574. self.put(u"[")
  575. if node.start:
  576. self.visit(node.start)
  577. self.put(u":")
  578. if node.stop:
  579. self.visit(node.stop)
  580. if node.slice:
  581. self.put(u":")
  582. self.visit(node.slice)
  583. self.put(u"]")
  584. def visit_SliceNode(self, node):
  585. if not node.start.is_none:
  586. self.visit(node.start)
  587. self.put(u":")
  588. if not node.stop.is_none:
  589. self.visit(node.stop)
  590. if not node.step.is_none:
  591. self.put(u":")
  592. self.visit(node.step)
  593. def visit_CondExprNode(self, node):
  594. self.visit(node.true_val)
  595. self.put(u" if ")
  596. self.visit(node.test)
  597. self.put(u" else ")
  598. self.visit(node.false_val)
  599. def visit_AttributeNode(self, node):
  600. self.visit(node.obj)
  601. self.put(u".%s" % node.attribute)
  602. def visit_SimpleCallNode(self, node):
  603. self.visit(node.function)
  604. self.put(u"(")
  605. self.comma_separated_list(node.args)
  606. self.put(")")
  607. def emit_pos_args(self, node):
  608. if node is None:
  609. return
  610. if isinstance(node, AddNode):
  611. self.emit_pos_args(node.operand1)
  612. self.emit_pos_args(node.operand2)
  613. elif isinstance(node, TupleNode):
  614. for expr in node.subexpr_nodes():
  615. self.visit(expr)
  616. self.put(u", ")
  617. elif isinstance(node, AsTupleNode):
  618. self.put("*")
  619. self.visit(node.arg)
  620. self.put(u", ")
  621. else:
  622. self.visit(node)
  623. self.put(u", ")
  624. def emit_kwd_args(self, node):
  625. if node is None:
  626. return
  627. if isinstance(node, MergedDictNode):
  628. for expr in node.subexpr_nodes():
  629. self.emit_kwd_args(expr)
  630. elif isinstance(node, DictNode):
  631. for expr in node.subexpr_nodes():
  632. self.put(u"%s=" % expr.key.value)
  633. self.visit(expr.value)
  634. self.put(u", ")
  635. else:
  636. self.put(u"**")
  637. self.visit(node)
  638. self.put(u", ")
  639. def visit_GeneralCallNode(self, node):
  640. self.visit(node.function)
  641. self.put(u"(")
  642. self.emit_pos_args(node.positional_args)
  643. self.emit_kwd_args(node.keyword_args)
  644. self.remove(u", ")
  645. self.put(")")
  646. def emit_comprehension(self, body, target,
  647. sequence, condition,
  648. parens=(u"", u"")):
  649. open_paren, close_paren = parens
  650. self.put(open_paren)
  651. self.visit(body)
  652. self.put(u" for ")
  653. self.visit(target)
  654. self.put(u" in ")
  655. self.visit(sequence)
  656. if condition:
  657. self.put(u" if ")
  658. self.visit(condition)
  659. self.put(close_paren)
  660. def visit_ComprehensionAppendNode(self, node):
  661. self.visit(node.expr)
  662. def visit_DictComprehensionAppendNode(self, node):
  663. self.visit(node.key_expr)
  664. self.put(u": ")
  665. self.visit(node.value_expr)
  666. def visit_ComprehensionNode(self, node):
  667. tpmap = {'list': u"[]", 'dict': u"{}", 'set': u"{}"}
  668. parens = tpmap[node.type.py_type_name()]
  669. body = node.loop.body
  670. target = node.loop.target
  671. sequence = node.loop.iterator.sequence
  672. condition = None
  673. if hasattr(body, 'if_clauses'):
  674. # type(body) is Nodes.IfStatNode
  675. condition = body.if_clauses[0].condition
  676. body = body.if_clauses[0].body
  677. self.emit_comprehension(body, target, sequence, condition, parens)
  678. def visit_GeneratorExpressionNode(self, node):
  679. body = node.loop.body
  680. target = node.loop.target
  681. sequence = node.loop.iterator.sequence
  682. condition = None
  683. if hasattr(body, 'if_clauses'):
  684. # type(body) is Nodes.IfStatNode
  685. condition = body.if_clauses[0].condition
  686. body = body.if_clauses[0].body.expr.arg
  687. elif hasattr(body, 'expr'):
  688. # type(body) is Nodes.ExprStatNode
  689. body = body.expr.arg
  690. self.emit_comprehension(body, target, sequence, condition, u"()")