code_gen.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901
  1. # -*- coding: utf-8 -*-
  2. """
  3. Part of the astor library for Python AST manipulation.
  4. License: 3-clause BSD
  5. Copyright (c) 2008 Armin Ronacher
  6. Copyright (c) 2012-2017 Patrick Maupin
  7. Copyright (c) 2013-2017 Berker Peksag
  8. This module converts an AST into Python source code.
  9. Before being version-controlled as part of astor,
  10. this code came from here (in 2012):
  11. https://gist.github.com/1250562
  12. """
  13. import ast
  14. import inspect
  15. import math
  16. import sys
  17. from .op_util import get_op_symbol, get_op_precedence, Precedence
  18. from .node_util import ExplicitNodeVisitor
  19. from .string_repr import pretty_string
  20. from .source_repr import pretty_source
  21. def to_source(node, indent_with=' ' * 4, add_line_information=False,
  22. pretty_string=pretty_string, pretty_source=pretty_source,
  23. source_generator_class=None):
  24. """This function can convert a node tree back into python sourcecode.
  25. This is useful for debugging purposes, especially if you're dealing with
  26. custom asts not generated by python itself.
  27. It could be that the sourcecode is evaluable when the AST itself is not
  28. compilable / evaluable. The reason for this is that the AST contains some
  29. more data than regular sourcecode does, which is dropped during
  30. conversion.
  31. Each level of indentation is replaced with `indent_with`. Per default this
  32. parameter is equal to four spaces as suggested by PEP 8, but it might be
  33. adjusted to match the application's styleguide.
  34. If `add_line_information` is set to `True` comments for the line numbers
  35. of the nodes are added to the output. This can be used to spot wrong line
  36. number information of statement nodes.
  37. `source_generator_class` defaults to `SourceGenerator`, and specifies the
  38. class that will be instantiated and used to generate the source code.
  39. """
  40. if source_generator_class is None:
  41. source_generator_class = SourceGenerator
  42. elif not inspect.isclass(source_generator_class):
  43. raise TypeError('source_generator_class should be a class')
  44. elif not issubclass(source_generator_class, SourceGenerator):
  45. raise TypeError('source_generator_class should be a subclass of SourceGenerator')
  46. generator = source_generator_class(
  47. indent_with, add_line_information, pretty_string)
  48. generator.visit(node)
  49. generator.result.append('\n')
  50. if set(generator.result[0]) == set('\n'):
  51. generator.result[0] = ''
  52. return pretty_source(generator.result)
  53. def precedence_setter(AST=ast.AST, get_op_precedence=get_op_precedence,
  54. isinstance=isinstance, list=list):
  55. """ This only uses a closure for performance reasons,
  56. to reduce the number of attribute lookups. (set_precedence
  57. is called a lot of times.)
  58. """
  59. def set_precedence(value, *nodes):
  60. """Set the precedence (of the parent) into the children.
  61. """
  62. if isinstance(value, AST):
  63. value = get_op_precedence(value)
  64. for node in nodes:
  65. if isinstance(node, AST):
  66. node._pp = value
  67. elif isinstance(node, list):
  68. set_precedence(value, *node)
  69. else:
  70. assert node is None, node
  71. return set_precedence
  72. set_precedence = precedence_setter()
  73. class Delimit(object):
  74. """A context manager that can add enclosing
  75. delimiters around the output of a
  76. SourceGenerator method. By default, the
  77. parentheses are added, but the enclosed code
  78. may set discard=True to get rid of them.
  79. """
  80. discard = False
  81. def __init__(self, tree, *args):
  82. """ use write instead of using result directly
  83. for initial data, because it may flush
  84. preceding data into result.
  85. """
  86. delimiters = '()'
  87. node = None
  88. op = None
  89. for arg in args:
  90. if isinstance(arg, ast.AST):
  91. if node is None:
  92. node = arg
  93. else:
  94. op = arg
  95. else:
  96. delimiters = arg
  97. tree.write(delimiters[0])
  98. result = self.result = tree.result
  99. self.index = len(result)
  100. self.closing = delimiters[1]
  101. if node is not None:
  102. self.p = p = get_op_precedence(op or node)
  103. self.pp = pp = tree.get__pp(node)
  104. self.discard = p >= pp
  105. def __enter__(self):
  106. return self
  107. def __exit__(self, *exc_info):
  108. result = self.result
  109. start = self.index - 1
  110. if self.discard:
  111. result[start] = ''
  112. else:
  113. result.append(self.closing)
  114. class SourceGenerator(ExplicitNodeVisitor):
  115. """This visitor is able to transform a well formed syntax tree into Python
  116. sourcecode.
  117. For more details have a look at the docstring of the `node_to_source`
  118. function.
  119. """
  120. using_unicode_literals = False
  121. def __init__(self, indent_with, add_line_information=False,
  122. pretty_string=pretty_string,
  123. # constants
  124. len=len, isinstance=isinstance, callable=callable):
  125. self.result = []
  126. self.indent_with = indent_with
  127. self.add_line_information = add_line_information
  128. self.indentation = 0 # Current indentation level
  129. self.new_lines = 0 # Number of lines to insert before next code
  130. self.colinfo = 0, 0 # index in result of string containing linefeed, and
  131. # position of last linefeed in that string
  132. self.pretty_string = pretty_string
  133. AST = ast.AST
  134. visit = self.visit
  135. result = self.result
  136. append = result.append
  137. def write(*params):
  138. """ self.write is a closure for performance (to reduce the number
  139. of attribute lookups).
  140. """
  141. for item in params:
  142. if isinstance(item, AST):
  143. visit(item)
  144. elif callable(item):
  145. item()
  146. else:
  147. if self.new_lines:
  148. append('\n' * self.new_lines)
  149. self.colinfo = len(result), 0
  150. append(self.indent_with * self.indentation)
  151. self.new_lines = 0
  152. if item:
  153. append(item)
  154. self.write = write
  155. def __getattr__(self, name, defaults=dict(keywords=(),
  156. _pp=Precedence.highest).get):
  157. """ Get an attribute of the node.
  158. like dict.get (returns None if doesn't exist)
  159. """
  160. if not name.startswith('get_'):
  161. raise AttributeError
  162. geta = getattr
  163. shortname = name[4:]
  164. default = defaults(shortname)
  165. def getter(node):
  166. return geta(node, shortname, default)
  167. setattr(self, name, getter)
  168. return getter
  169. def delimit(self, *args):
  170. return Delimit(self, *args)
  171. def conditional_write(self, *stuff):
  172. if stuff[-1] is not None:
  173. self.write(*stuff)
  174. # Inform the caller that we wrote
  175. return True
  176. def newline(self, node=None, extra=0):
  177. self.new_lines = max(self.new_lines, 1 + extra)
  178. if node is not None and self.add_line_information:
  179. self.write('# line: %s' % node.lineno)
  180. self.new_lines = 1
  181. def body(self, statements):
  182. self.indentation += 1
  183. self.write(*statements)
  184. self.indentation -= 1
  185. def else_body(self, elsewhat):
  186. if elsewhat:
  187. self.write(self.newline, 'else:')
  188. self.body(elsewhat)
  189. def body_or_else(self, node):
  190. self.body(node.body)
  191. self.else_body(node.orelse)
  192. def visit_arguments(self, node):
  193. want_comma = []
  194. def write_comma():
  195. if want_comma:
  196. self.write(', ')
  197. else:
  198. want_comma.append(True)
  199. def loop_args(args, defaults):
  200. set_precedence(Precedence.Comma, defaults)
  201. padding = [None] * (len(args) - len(defaults))
  202. for arg, default in zip(args, padding + defaults):
  203. self.write(write_comma, arg)
  204. self.conditional_write('=', default)
  205. posonlyargs = getattr(node, 'posonlyargs', [])
  206. offset = 0
  207. if posonlyargs:
  208. offset += len(node.defaults) - len(node.args)
  209. loop_args(posonlyargs, node.defaults[:offset])
  210. self.write(write_comma, '/')
  211. loop_args(node.args, node.defaults[offset:])
  212. self.conditional_write(write_comma, '*', node.vararg)
  213. kwonlyargs = self.get_kwonlyargs(node)
  214. if kwonlyargs:
  215. if node.vararg is None:
  216. self.write(write_comma, '*')
  217. loop_args(kwonlyargs, node.kw_defaults)
  218. self.conditional_write(write_comma, '**', node.kwarg)
  219. def statement(self, node, *params, **kw):
  220. self.newline(node)
  221. self.write(*params)
  222. def decorators(self, node, extra):
  223. self.newline(extra=extra)
  224. for decorator in node.decorator_list:
  225. self.statement(decorator, '@', decorator)
  226. def comma_list(self, items, trailing=False):
  227. set_precedence(Precedence.Comma, *items)
  228. for idx, item in enumerate(items):
  229. self.write(', ' if idx else '', item)
  230. self.write(',' if trailing else '')
  231. # Statements
  232. def visit_Assign(self, node):
  233. set_precedence(node, node.value, *node.targets)
  234. self.newline(node)
  235. for target in node.targets:
  236. self.write(target, ' = ')
  237. self.visit(node.value)
  238. def visit_AugAssign(self, node):
  239. set_precedence(node, node.value, node.target)
  240. self.statement(node, node.target, get_op_symbol(node.op, ' %s= '),
  241. node.value)
  242. def visit_AnnAssign(self, node):
  243. set_precedence(node, node.target, node.annotation)
  244. set_precedence(Precedence.Comma, node.value)
  245. need_parens = isinstance(node.target, ast.Name) and not node.simple
  246. begin = '(' if need_parens else ''
  247. end = ')' if need_parens else ''
  248. self.statement(node, begin, node.target, end, ': ', node.annotation)
  249. self.conditional_write(' = ', node.value)
  250. def visit_ImportFrom(self, node):
  251. self.statement(node, 'from ', node.level * '.',
  252. node.module or '', ' import ')
  253. self.comma_list(node.names)
  254. # Goofy stuff for Python 2.7 _pyio module
  255. if node.module == '__future__' and 'unicode_literals' in (
  256. x.name for x in node.names):
  257. self.using_unicode_literals = True
  258. def visit_Import(self, node):
  259. self.statement(node, 'import ')
  260. self.comma_list(node.names)
  261. def visit_Expr(self, node):
  262. set_precedence(node, node.value)
  263. self.statement(node)
  264. self.generic_visit(node)
  265. def visit_FunctionDef(self, node, is_async=False):
  266. prefix = 'async ' if is_async else ''
  267. self.decorators(node, 1 if self.indentation else 2)
  268. self.statement(node, '%sdef %s' % (prefix, node.name), '(')
  269. self.visit_arguments(node.args)
  270. self.write(')')
  271. self.conditional_write(' ->', self.get_returns(node))
  272. self.write(':')
  273. self.body(node.body)
  274. if not self.indentation:
  275. self.newline(extra=2)
  276. # introduced in Python 3.5
  277. def visit_AsyncFunctionDef(self, node):
  278. self.visit_FunctionDef(node, is_async=True)
  279. def visit_ClassDef(self, node):
  280. have_args = []
  281. def paren_or_comma():
  282. if have_args:
  283. self.write(', ')
  284. else:
  285. have_args.append(True)
  286. self.write('(')
  287. self.decorators(node, 2)
  288. self.statement(node, 'class %s' % node.name)
  289. for base in node.bases:
  290. self.write(paren_or_comma, base)
  291. # keywords not available in early version
  292. for keyword in self.get_keywords(node):
  293. self.write(paren_or_comma, keyword.arg or '',
  294. '=' if keyword.arg else '**', keyword.value)
  295. self.conditional_write(paren_or_comma, '*', self.get_starargs(node))
  296. self.conditional_write(paren_or_comma, '**', self.get_kwargs(node))
  297. self.write(have_args and '):' or ':')
  298. self.body(node.body)
  299. if not self.indentation:
  300. self.newline(extra=2)
  301. def visit_If(self, node):
  302. set_precedence(node, node.test)
  303. self.statement(node, 'if ', node.test, ':')
  304. self.body(node.body)
  305. while True:
  306. else_ = node.orelse
  307. if len(else_) == 1 and isinstance(else_[0], ast.If):
  308. node = else_[0]
  309. set_precedence(node, node.test)
  310. self.write(self.newline, 'elif ', node.test, ':')
  311. self.body(node.body)
  312. else:
  313. self.else_body(else_)
  314. break
  315. def visit_For(self, node, is_async=False):
  316. set_precedence(node, node.target)
  317. prefix = 'async ' if is_async else ''
  318. self.statement(node, '%sfor ' % prefix,
  319. node.target, ' in ', node.iter, ':')
  320. self.body_or_else(node)
  321. # introduced in Python 3.5
  322. def visit_AsyncFor(self, node):
  323. self.visit_For(node, is_async=True)
  324. def visit_While(self, node):
  325. set_precedence(node, node.test)
  326. self.statement(node, 'while ', node.test, ':')
  327. self.body_or_else(node)
  328. def visit_With(self, node, is_async=False):
  329. prefix = 'async ' if is_async else ''
  330. self.statement(node, '%swith ' % prefix)
  331. if hasattr(node, "context_expr"): # Python < 3.3
  332. self.visit_withitem(node)
  333. else: # Python >= 3.3
  334. self.comma_list(node.items)
  335. self.write(':')
  336. self.body(node.body)
  337. # new for Python 3.5
  338. def visit_AsyncWith(self, node):
  339. self.visit_With(node, is_async=True)
  340. # new for Python 3.3
  341. def visit_withitem(self, node):
  342. self.write(node.context_expr)
  343. self.conditional_write(' as ', node.optional_vars)
  344. # deprecated in Python 3.8
  345. def visit_NameConstant(self, node):
  346. self.write(repr(node.value))
  347. def visit_Pass(self, node):
  348. self.statement(node, 'pass')
  349. def visit_Print(self, node):
  350. # XXX: python 2.6 only
  351. self.statement(node, 'print ')
  352. values = node.values
  353. if node.dest is not None:
  354. self.write(' >> ')
  355. values = [node.dest] + node.values
  356. self.comma_list(values, not node.nl)
  357. def visit_Delete(self, node):
  358. self.statement(node, 'del ')
  359. self.comma_list(node.targets)
  360. def visit_TryExcept(self, node):
  361. self.statement(node, 'try:')
  362. self.body(node.body)
  363. self.write(*node.handlers)
  364. self.else_body(node.orelse)
  365. # new for Python 3.3
  366. def visit_Try(self, node):
  367. self.statement(node, 'try:')
  368. self.body(node.body)
  369. self.write(*node.handlers)
  370. self.else_body(node.orelse)
  371. if node.finalbody:
  372. self.statement(node, 'finally:')
  373. self.body(node.finalbody)
  374. def visit_ExceptHandler(self, node):
  375. self.statement(node, 'except')
  376. if self.conditional_write(' ', node.type):
  377. self.conditional_write(' as ', node.name)
  378. self.write(':')
  379. self.body(node.body)
  380. def visit_TryFinally(self, node):
  381. self.statement(node, 'try:')
  382. self.body(node.body)
  383. self.statement(node, 'finally:')
  384. self.body(node.finalbody)
  385. def visit_Exec(self, node):
  386. dicts = node.globals, node.locals
  387. dicts = dicts[::-1] if dicts[0] is None else dicts
  388. self.statement(node, 'exec ', node.body)
  389. self.conditional_write(' in ', dicts[0])
  390. self.conditional_write(', ', dicts[1])
  391. def visit_Assert(self, node):
  392. set_precedence(node, node.test, node.msg)
  393. self.statement(node, 'assert ', node.test)
  394. self.conditional_write(', ', node.msg)
  395. def visit_Global(self, node):
  396. self.statement(node, 'global ', ', '.join(node.names))
  397. def visit_Nonlocal(self, node):
  398. self.statement(node, 'nonlocal ', ', '.join(node.names))
  399. def visit_Return(self, node):
  400. set_precedence(node, node.value)
  401. self.statement(node, 'return')
  402. self.conditional_write(' ', node.value)
  403. def visit_Break(self, node):
  404. self.statement(node, 'break')
  405. def visit_Continue(self, node):
  406. self.statement(node, 'continue')
  407. def visit_Raise(self, node):
  408. # XXX: Python 2.6 / 3.0 compatibility
  409. self.statement(node, 'raise')
  410. if self.conditional_write(' ', self.get_exc(node)):
  411. self.conditional_write(' from ', node.cause)
  412. elif self.conditional_write(' ', self.get_type(node)):
  413. set_precedence(node, node.inst)
  414. self.conditional_write(', ', node.inst)
  415. self.conditional_write(', ', node.tback)
  416. # Expressions
  417. def visit_Attribute(self, node):
  418. self.write(node.value, '.', node.attr)
  419. def visit_Call(self, node, len=len):
  420. write = self.write
  421. want_comma = []
  422. def write_comma():
  423. if want_comma:
  424. write(', ')
  425. else:
  426. want_comma.append(True)
  427. args = node.args
  428. keywords = node.keywords
  429. starargs = self.get_starargs(node)
  430. kwargs = self.get_kwargs(node)
  431. numargs = len(args) + len(keywords)
  432. numargs += starargs is not None
  433. numargs += kwargs is not None
  434. p = Precedence.Comma if numargs > 1 else Precedence.call_one_arg
  435. set_precedence(p, *args)
  436. self.visit(node.func)
  437. write('(')
  438. for arg in args:
  439. write(write_comma, arg)
  440. set_precedence(Precedence.Comma, *(x.value for x in keywords))
  441. for keyword in keywords:
  442. # a keyword.arg of None indicates dictionary unpacking
  443. # (Python >= 3.5)
  444. arg = keyword.arg or ''
  445. write(write_comma, arg, '=' if arg else '**', keyword.value)
  446. # 3.5 no longer has these
  447. self.conditional_write(write_comma, '*', starargs)
  448. self.conditional_write(write_comma, '**', kwargs)
  449. write(')')
  450. def visit_Name(self, node):
  451. self.write(node.id)
  452. # ast.Constant is new in Python 3.6 and it replaces ast.Bytes,
  453. # ast.Ellipsis, ast.NameConstant, ast.Num, ast.Str in Python 3.8
  454. def visit_Constant(self, node):
  455. value = node.value
  456. if isinstance(value, (int, float, complex)):
  457. with self.delimit(node):
  458. self._handle_numeric_constant(value)
  459. elif isinstance(value, str):
  460. self._handle_string_constant(node, node.value)
  461. elif value is Ellipsis:
  462. self.write('...')
  463. else:
  464. self.write(repr(value))
  465. def visit_JoinedStr(self, node):
  466. self._handle_string_constant(node, None, is_joined=True)
  467. def _handle_string_constant(self, node, value, is_joined=False):
  468. # embedded is used to control when we might want
  469. # to use a triple-quoted string. We determine
  470. # if we are in an assignment and/or in an expression
  471. precedence = self.get__pp(node)
  472. embedded = ((precedence > Precedence.Expr) +
  473. (precedence >= Precedence.Assign))
  474. # Flush any pending newlines, because we're about
  475. # to severely abuse the result list.
  476. self.write('')
  477. result = self.result
  478. # Calculate the string representing the line
  479. # we are working on, up to but not including
  480. # the string we are adding.
  481. res_index, str_index = self.colinfo
  482. current_line = self.result[res_index:]
  483. if str_index:
  484. current_line[0] = current_line[0][str_index:]
  485. current_line = ''.join(current_line)
  486. has_ast_constant = sys.version_info >= (3, 6)
  487. if is_joined:
  488. # Handle new f-strings. This is a bit complicated, because
  489. # the tree can contain subnodes that recurse back to JoinedStr
  490. # subnodes...
  491. def recurse(node):
  492. for value in node.values:
  493. if isinstance(value, ast.Str):
  494. # Double up braces to escape them.
  495. self.write(value.s.replace('{', '{{').replace('}', '}}'))
  496. elif isinstance(value, ast.FormattedValue):
  497. with self.delimit('{}'):
  498. # expr_text used for f-string debugging syntax.
  499. if getattr(value, 'expr_text', None):
  500. self.write(value.expr_text)
  501. else:
  502. set_precedence(value, value.value)
  503. self.visit(value.value)
  504. if value.conversion != -1:
  505. self.write('!%s' % chr(value.conversion))
  506. if value.format_spec is not None:
  507. self.write(':')
  508. recurse(value.format_spec)
  509. elif has_ast_constant and isinstance(value, ast.Constant):
  510. self.write(value.value)
  511. else:
  512. kind = type(value).__name__
  513. assert False, 'Invalid node %s inside JoinedStr' % kind
  514. index = len(result)
  515. recurse(node)
  516. # Flush trailing newlines (so that they are part of mystr)
  517. self.write('')
  518. mystr = ''.join(result[index:])
  519. del result[index:]
  520. self.colinfo = res_index, str_index # Put it back like we found it
  521. uni_lit = False # No formatted byte strings
  522. else:
  523. assert value is not None, "Node value cannot be None"
  524. mystr = value
  525. uni_lit = self.using_unicode_literals
  526. mystr = self.pretty_string(mystr, embedded, current_line, uni_lit)
  527. if is_joined:
  528. mystr = 'f' + mystr
  529. elif getattr(node, 'kind', False):
  530. # Constant.kind is a Python 3.8 addition.
  531. mystr = node.kind + mystr
  532. self.write(mystr)
  533. lf = mystr.rfind('\n') + 1
  534. if lf:
  535. self.colinfo = len(result) - 1, lf
  536. # deprecated in Python 3.8
  537. def visit_Str(self, node):
  538. self._handle_string_constant(node, node.s)
  539. # deprecated in Python 3.8
  540. def visit_Bytes(self, node):
  541. self.write(repr(node.s))
  542. def _handle_numeric_constant(self, value):
  543. x = value
  544. def part(p, imaginary):
  545. # Represent infinity as 1e1000 and NaN as 1e1000-1e1000.
  546. s = 'j' if imaginary else ''
  547. try:
  548. if math.isinf(p):
  549. if p < 0:
  550. return '-1e1000' + s
  551. return '1e1000' + s
  552. if math.isnan(p):
  553. return '(1e1000%s-1e1000%s)' % (s, s)
  554. except OverflowError:
  555. # math.isinf will raise this when given an integer
  556. # that's too large to convert to a float.
  557. pass
  558. return repr(p) + s
  559. real = part(x.real if isinstance(x, complex) else x, imaginary=False)
  560. if isinstance(x, complex):
  561. imag = part(x.imag, imaginary=True)
  562. if x.real == 0:
  563. s = imag
  564. elif x.imag == 0:
  565. s = '(%s+0j)' % real
  566. else:
  567. # x has nonzero real and imaginary parts.
  568. s = '(%s%s%s)' % (real, ['+', ''][imag.startswith('-')], imag)
  569. else:
  570. s = real
  571. self.write(s)
  572. def visit_Num(self, node,
  573. # constants
  574. new=sys.version_info >= (3, 0)):
  575. with self.delimit(node) as delimiters:
  576. self._handle_numeric_constant(node.n)
  577. # We can leave the delimiters handling in visit_Num
  578. # since this is meant to handle a Python 2.x specific
  579. # issue and ast.Constant exists only in 3.6+
  580. # The Python 2.x compiler merges a unary minus
  581. # with a number. This is a premature optimization
  582. # that we deal with here...
  583. if not new and delimiters.discard:
  584. if not isinstance(node.n, complex) and node.n < 0:
  585. pow_lhs = Precedence.Pow + 1
  586. delimiters.discard = delimiters.pp != pow_lhs
  587. else:
  588. op = self.get__p_op(node)
  589. delimiters.discard = not isinstance(op, ast.USub)
  590. def visit_Tuple(self, node):
  591. with self.delimit(node) as delimiters:
  592. # Two things are special about tuples:
  593. # 1) We cannot discard the enclosing parentheses if empty
  594. # 2) We need the trailing comma if only one item
  595. elts = node.elts
  596. delimiters.discard = delimiters.discard and elts
  597. self.comma_list(elts, len(elts) == 1)
  598. def visit_List(self, node):
  599. with self.delimit('[]'):
  600. self.comma_list(node.elts)
  601. def visit_Set(self, node):
  602. if node.elts:
  603. with self.delimit('{}'):
  604. self.comma_list(node.elts)
  605. else:
  606. # If we tried to use "{}" to represent an empty set, it would be
  607. # interpreted as an empty dictionary. We can't use "set()" either
  608. # because the name "set" might be rebound.
  609. self.write('{1}.__class__()')
  610. def visit_Dict(self, node):
  611. set_precedence(Precedence.Comma, *node.values)
  612. with self.delimit('{}'):
  613. for idx, (key, value) in enumerate(zip(node.keys, node.values)):
  614. self.write(', ' if idx else '',
  615. key if key else '',
  616. ': ' if key else '**', value)
  617. def visit_BinOp(self, node):
  618. op, left, right = node.op, node.left, node.right
  619. with self.delimit(node, op) as delimiters:
  620. ispow = isinstance(op, ast.Pow)
  621. p = delimiters.p
  622. set_precedence((Precedence.Pow + 1) if ispow else p, left)
  623. set_precedence(Precedence.PowRHS if ispow else (p + 1), right)
  624. self.write(left, get_op_symbol(op, ' %s '), right)
  625. def visit_BoolOp(self, node):
  626. with self.delimit(node, node.op) as delimiters:
  627. op = get_op_symbol(node.op, ' %s ')
  628. set_precedence(delimiters.p + 1, *node.values)
  629. for idx, value in enumerate(node.values):
  630. self.write(idx and op or '', value)
  631. def visit_Compare(self, node):
  632. with self.delimit(node, node.ops[0]) as delimiters:
  633. set_precedence(delimiters.p + 1, node.left, *node.comparators)
  634. self.visit(node.left)
  635. for op, right in zip(node.ops, node.comparators):
  636. self.write(get_op_symbol(op, ' %s '), right)
  637. # assignment expressions; new for Python 3.8
  638. def visit_NamedExpr(self, node):
  639. with self.delimit(node) as delimiters:
  640. p = delimiters.p
  641. set_precedence(p, node.target)
  642. set_precedence(p + 1, node.value)
  643. # Python is picky about delimiters for assignment
  644. # expressions: it requires at least one pair in any
  645. # statement that uses an assignment expression, even
  646. # when not necessary according to the precedence
  647. # rules. We address this with the kludge of forcing a
  648. # pair of parentheses around every assignment
  649. # expression.
  650. delimiters.discard = False
  651. self.write(node.target, ' := ', node.value)
  652. def visit_UnaryOp(self, node):
  653. with self.delimit(node, node.op) as delimiters:
  654. set_precedence(delimiters.p, node.operand)
  655. # In Python 2.x, a unary negative of a literal
  656. # number is merged into the number itself. This
  657. # bit of ugliness means it is useful to know
  658. # what the parent operation was...
  659. node.operand._p_op = node.op
  660. sym = get_op_symbol(node.op)
  661. self.write(sym, ' ' if sym.isalpha() else '', node.operand)
  662. def visit_Subscript(self, node):
  663. set_precedence(node, node.slice)
  664. self.write(node.value, '[', node.slice, ']')
  665. def visit_Slice(self, node):
  666. set_precedence(node, node.lower, node.upper, node.step)
  667. self.conditional_write(node.lower)
  668. self.write(':')
  669. self.conditional_write(node.upper)
  670. if node.step is not None:
  671. self.write(':')
  672. if not (isinstance(node.step, ast.Name) and
  673. node.step.id == 'None'):
  674. self.visit(node.step)
  675. def visit_Index(self, node):
  676. with self.delimit(node) as delimiters:
  677. set_precedence(delimiters.p, node.value)
  678. self.visit(node.value)
  679. def visit_ExtSlice(self, node):
  680. dims = node.dims
  681. set_precedence(node, *dims)
  682. self.comma_list(dims, len(dims) == 1)
  683. def visit_Yield(self, node):
  684. with self.delimit(node):
  685. set_precedence(get_op_precedence(node) + 1, node.value)
  686. self.write('yield')
  687. self.conditional_write(' ', node.value)
  688. # new for Python 3.3
  689. def visit_YieldFrom(self, node):
  690. with self.delimit(node):
  691. self.write('yield from ', node.value)
  692. # new for Python 3.5
  693. def visit_Await(self, node):
  694. with self.delimit(node):
  695. self.write('await ', node.value)
  696. def visit_Lambda(self, node):
  697. with self.delimit(node) as delimiters:
  698. set_precedence(delimiters.p, node.body)
  699. self.write('lambda ')
  700. self.visit_arguments(node.args)
  701. self.write(': ', node.body)
  702. def visit_Ellipsis(self, node):
  703. self.write('...')
  704. def visit_ListComp(self, node):
  705. with self.delimit('[]'):
  706. self.write(node.elt, *node.generators)
  707. def visit_GeneratorExp(self, node):
  708. with self.delimit(node) as delimiters:
  709. if delimiters.pp == Precedence.call_one_arg:
  710. delimiters.discard = True
  711. set_precedence(Precedence.Comma, node.elt)
  712. self.write(node.elt, *node.generators)
  713. def visit_SetComp(self, node):
  714. with self.delimit('{}'):
  715. self.write(node.elt, *node.generators)
  716. def visit_DictComp(self, node):
  717. with self.delimit('{}'):
  718. self.write(node.key, ': ', node.value, *node.generators)
  719. def visit_IfExp(self, node):
  720. with self.delimit(node) as delimiters:
  721. set_precedence(delimiters.p + 1, node.body, node.test)
  722. set_precedence(delimiters.p, node.orelse)
  723. self.write(node.body, ' if ', node.test, ' else ', node.orelse)
  724. def visit_Starred(self, node):
  725. self.write('*', node.value)
  726. def visit_Repr(self, node):
  727. # XXX: python 2.6 only
  728. with self.delimit('``'):
  729. self.visit(node.value)
  730. def visit_Module(self, node):
  731. self.write(*node.body)
  732. visit_Interactive = visit_Module
  733. def visit_Expression(self, node):
  734. self.visit(node.body)
  735. # Helper Nodes
  736. def visit_arg(self, node):
  737. self.write(node.arg)
  738. self.conditional_write(': ', node.annotation)
  739. def visit_alias(self, node):
  740. self.write(node.name)
  741. self.conditional_write(' as ', node.asname)
  742. def visit_comprehension(self, node):
  743. set_precedence(node, node.iter, *node.ifs)
  744. set_precedence(Precedence.comprehension_target, node.target)
  745. stmt = ' async for ' if self.get_is_async(node) else ' for '
  746. self.write(stmt, node.target, ' in ', node.iter)
  747. for if_ in node.ifs:
  748. self.write(' if ', if_)