diff --git a/uncompyle6/semantics/customize.py b/uncompyle6/semantics/customize.py
index 05dbf75c..56c5af85 100644
--- a/uncompyle6/semantics/customize.py
+++ b/uncompyle6/semantics/customize.py
@@ -17,18 +17,11 @@
"""
from uncompyle6.semantics.consts import (
- PRECEDENCE, INDENT_PER_LEVEL, TABLE_R, TABLE_DIRECT)
+ TABLE_R, TABLE_DIRECT)
-from uncompyle6.semantics.make_function import (
- make_function3_annotate,
- )
-
-from xdis.util import COMPILER_FLAG_BIT
-from xdis.code import iscode
from uncompyle6.parsers.astnode import AST
from uncompyle6.scanners.tok import Token
-from uncompyle6.semantics.helper import flatten_list
-from spark_parser.ast import GenericASTTraversalPruningException
+from uncompyle6.semantics.customize3 import customize_for_version3
def customize_for_version(self, is_pypy, version):
if is_pypy:
@@ -189,635 +182,5 @@ def customize_for_version(self, is_pypy, version):
})
if version >= 3.0:
- TABLE_DIRECT.update({
- 'function_def_annotate': ( '\n\n%|def %c%c\n', -1, 0),
- 'store_locals': ( '%|# inspect.currentframe().f_locals = __locals__\n', ),
- })
-
- if 3.2 <= version <= 3.4:
- def n_call(node):
- mapping = self._get_mapping(node)
- key = node
- for i in mapping[1:]:
- key = key[i]
- pass
- if key.kind.startswith('CALL_FUNCTION_VAR_KW'):
- # We may want to fill this in...
- # But it is distinct from CALL_FUNCTION_VAR below
- pass
- elif key.kind.startswith('CALL_FUNCTION_VAR'):
- # CALL_FUNCTION_VAR's top element of the stack contains
- # the variable argument list, then comes
- # annotation args, then keyword args.
- # In the most least-top-most stack entry, but position 1
- # in node order, the positional args.
- argc = node[-1].attr
- nargs = argc & 0xFF
- kwargs = (argc >> 8) & 0xFF
- # FIXME: handle annotation args
- if kwargs != 0:
- # kwargs == 0 is handled by the table entry
- # Should probably handle it here though.
- if nargs == 0:
- template = ('%c(*%c, %C)',
- 0, -2, (1, kwargs+1, ', '))
- else:
- template = ('%c(%C, *%c, %C)',
- 0, (1, nargs+1, ', '),
- -2, (-2-kwargs, -2, ', '))
- self.template_engine(template, node)
- self.prune()
-
- self.default(node)
- self.n_call = n_call
-
-
- def n_mkfunc_annotate(node):
-
- if self.version >= 3.3 or node[-2] == 'kwargs':
- # LOAD_CONST code object ..
- # LOAD_CONST 'x0' if >= 3.3
- # EXTENDED_ARG
- # MAKE_FUNCTION ..
- code = node[-4]
- elif node[-3] == 'expr':
- code = node[-3][0]
- else:
- # LOAD_CONST code object ..
- # MAKE_FUNCTION ..
- code = node[-3]
-
- self.indent_more()
- for annotate_last in range(len(node)-1, -1, -1):
- if node[annotate_last] == 'annotate_tuple':
- break
-
- # FIXME: the real situation is that when derived from
- # function_def_annotate we the name has been filled in.
- # But when derived from funcdefdeco it hasn't Would like a better
- # way to distinquish.
- if self.f.getvalue()[-4:] == 'def ':
- self.write(code.attr.co_name)
-
- # FIXME: handle and pass full annotate args
- make_function3_annotate(self, node, is_lambda=False,
- codeNode=code, annotate_last=annotate_last)
-
- if len(self.param_stack) > 1:
- self.write('\n\n')
- else:
- self.write('\n\n\n')
- self.indent_less()
- self.prune() # stop recursing
- self.n_mkfunc_annotate = n_mkfunc_annotate
-
- if version >= 3.4:
- ########################
- # Python 3.4+ Additions
- #######################
- TABLE_DIRECT.update({
- 'LOAD_CLASSDEREF': ( '%{pattr}', ),
- })
-
- ########################
- # Python 3.5+ Additions
- #######################
- if version >= 3.5:
- TABLE_DIRECT.update({
- 'await_expr': ( 'await %c', 0),
- 'await_stmt': ( '%|%c\n', 0),
- 'async_for_stmt': (
- '%|async for %c in %c:\n%+%c%-\n\n', 9, 1, 25 ),
- 'async_forelse_stmt': (
- '%|async for %c in %c:\n%+%c%-%|else:\n%+%c%-\n\n', 9, 1, 25, 28 ),
- 'async_with_stmt': (
- '%|async with %c:\n%+%c%-', 0, 7),
- 'async_with_as_stmt': (
- '%|async with %c as %c:\n%+%c%-', 0, 6, 7),
- 'unmap_dict': ( '{**%C}', (0, -1, ', **') ),
- # 'unmapexpr': ( '{**%c}', 0), # done by n_unmapexpr
-
- })
-
- def async_call(node):
- self.f.write('async ')
- node.kind == 'call'
- p = self.prec
- self.prec = 80
- self.template_engine(('%c(%P)', 0, (1, -4, ', ',
- 100)), node)
- self.prec = p
- node.kind == 'async_call'
- self.prune()
- self.n_async_call = async_call
- self.n_build_list_unpack = self.n_list
-
- if version == 3.5:
- def n_call(node):
- mapping = self._get_mapping(node)
- table = mapping[0]
- key = node
- for i in mapping[1:]:
- key = key[i]
- pass
- if key.kind.startswith('CALL_FUNCTION_VAR_KW'):
- # Python 3.5 changes the stack position of
- # *args: kwargs come after *args whereas
- # in earlier Pythons, *args is at the end
- # which simplifies things from our
- # perspective. Python 3.6+ replaces
- # CALL_FUNCTION_VAR_KW with
- # CALL_FUNCTION_EX We will just swap the
- # order to make it look like earlier
- # Python 3.
- entry = table[key.kind]
- kwarg_pos = entry[2][1]
- args_pos = kwarg_pos - 1
- # Put last node[args_pos] after subsequent kwargs
- while node[kwarg_pos] == 'kwarg' and kwarg_pos < len(node):
- # swap node[args_pos] with node[kwargs_pos]
- node[kwarg_pos], node[args_pos] = node[args_pos], node[kwarg_pos]
- args_pos = kwarg_pos
- kwarg_pos += 1
- elif key.kind.startswith('CALL_FUNCTION_VAR'):
- # CALL_FUNCTION_VAR's top element of the stack contains
- # the variable argument list, then comes
- # annotation args, then keyword args.
- # In the most least-top-most stack entry, but position 1
- # in node order, the positional args.
- argc = node[-1].attr
- nargs = argc & 0xFF
- kwargs = (argc >> 8) & 0xFF
- # FIXME: handle annotation args
- if nargs > 0:
- template = ('%c(%C, ', 0, (1, nargs+1, ', '))
- else:
- template = ('%c(', 0)
- self.template_engine(template, node)
-
- args_node = node[-2]
- if args_node in ('pos_arg', 'expr'):
- args_node = args_node[0]
- if args_node == 'build_list_unpack':
- template = ('*%P)', (0, len(args_node)-1, ', *', 100))
- self.template_engine(template, args_node)
- else:
- if len(node) - nargs > 3:
- template = ('*%c, %C)', nargs+1, (nargs+kwargs+1, -1, ', '))
- else:
- template = ('*%c)', nargs+1)
- self.template_engine(template, node)
- self.prune()
-
- self.default(node)
- self.n_call = n_call
-
- def n_function_def(node):
- if self.version == 3.6:
- code_node = node[0][0]
- else:
- code_node = node[0][1]
-
- is_code = hasattr(code_node, 'attr') and iscode(code_node.attr)
- if (is_code and
- (code_node.attr.co_flags & COMPILER_FLAG_BIT['COROUTINE'])):
- self.template_engine(('\n\n%|async def %c\n',
- -2), node)
- else:
- self.template_engine(('\n\n%|def %c\n', -2),
- node)
- self.prune()
- self.n_function_def = n_function_def
-
- def unmapexpr(node):
- last_n = node[0][-1]
- for n in node[0]:
- self.preorder(n)
- if n != last_n:
- self.f.write(', **')
- pass
- pass
- self.prune()
- pass
- self.n_unmapexpr = unmapexpr
-
- if version >= 3.6:
- ########################
- # Python 3.6+ Additions
- #######################
-
- # Value 100 is important; it is exactly
- # module/function precidence.
- PRECEDENCE['call_kw'] = 100
- PRECEDENCE['call_kw36'] = 100
- PRECEDENCE['call_ex'] = 100
- PRECEDENCE['call_ex_kw'] = 100
- PRECEDENCE['call_ex_kw2'] = 100
- PRECEDENCE['call_ex_kw3'] = 100
- PRECEDENCE['call_ex_kw4'] = 100
-
- TABLE_DIRECT.update({
- 'tryfinally36': ( '%|try:\n%+%c%-%|finally:\n%+%c%-\n\n',
- (1, 'returns'), 3 ),
- 'fstring_expr': ( "{%c%{conversion}}", 0),
- # FIXME: the below assumes the format strings
- # don't have ''' in them. Fix this properly
- 'fstring_single': ( "f'''{%c%{conversion}}'''", 0),
- 'fstring_multi': ( "f'''%c'''", 0),
- 'func_args36': ( "%c(**", 0),
- 'try_except36': ( '%|try:\n%+%c%-%c\n\n', 1, 2 ),
- 'except_return': ( '%|except:\n%+%c%-', 3 ),
- 'unpack_list': ( '*%c', (0, 'list') ),
- 'call_ex' : (
- '%c(%p)',
- (0, 'expr'), (1, 100)),
- 'call_ex_kw' : (
- '%c(%p)',
- (0, 'expr'), (2, 100)),
-
- })
-
- TABLE_R.update({
- 'CALL_FUNCTION_EX': ('%c(*%P)', 0, (1, 2, ', ', 100)),
- # Not quite right
- 'CALL_FUNCTION_EX_KW': ('%c(**%C)', 0, (2, 3, ',')),
- })
-
- def build_unpack_tuple_with_call(node):
-
- if node[0] == 'expr':
- tup = node[0][0]
- else:
- tup = node[0]
- pass
- assert tup == 'tuple'
- self.call36_tuple(tup)
-
- buwc = node[-1]
- assert buwc.kind.startswith('BUILD_TUPLE_UNPACK_WITH_CALL')
- for n in node[1:-1]:
- self.f.write(', *')
- self.preorder(n)
- pass
- self.prune()
- return
- self.n_build_tuple_unpack_with_call = build_unpack_tuple_with_call
-
- def build_unpack_map_with_call(node):
- n = node[0]
- if n == 'expr':
- n = n[0]
- if n == 'dict':
- self.call36_dict(n)
- first = 1
- sep = ', **'
- else:
- first = 0
- sep = '**'
- for n in node[first:-1]:
- self.f.write(sep)
- self.preorder(n)
- sep = ', **'
- pass
- self.prune()
- return
- self.n_build_map_unpack_with_call = build_unpack_map_with_call
-
- def call_ex_kw2(node):
- """Handle CALL_FUNCTION_EX 2 (have KW) but with
- BUILD_{MAP,TUPLE}_UNPACK_WITH_CALL"""
-
- # This is weird shit. Thanks Python!
- self.preorder(node[0])
- self.write('(')
-
- assert node[1] == 'build_tuple_unpack_with_call'
- btuwc = node[1]
- tup = btuwc[0]
- if tup == 'expr':
- tup = tup[0]
- assert tup == 'tuple'
- self.call36_tuple(tup)
- assert node[2] == 'build_map_unpack_with_call'
-
- self.write(', ')
- d = node[2][0]
- if d == 'expr':
- d = d[0]
- assert d == 'dict'
- self.call36_dict(d)
-
- args = btuwc[1]
- self.write(', *')
- self.preorder(args)
-
- self.write(', **')
- star_star_args = node[2][1]
- if star_star_args == 'expr':
- star_star_args = star_star_args[0]
- self.preorder(star_star_args)
- self.write(')')
- self.prune()
- self.n_call_ex_kw2 = call_ex_kw2
-
- def call_ex_kw3(node):
- """Handle CALL_FUNCTION_EX 1 (have KW) but without
- BUILD_MAP_UNPACK_WITH_CALL"""
- self.preorder(node[0])
- self.write('(')
- args = node[1][0]
- if args == 'expr':
- args = args[0]
- if args == 'tuple':
- if self.call36_tuple(args) > 0:
- self.write(', ')
- pass
- pass
-
- self.write('*')
- self.preorder(node[1][1])
- self.write(', ')
-
- kwargs = node[2]
- if kwargs == 'expr':
- kwargs = kwargs[0]
- if kwargs == 'dict':
- self.call36_dict(kwargs)
- else:
- self.write('**')
- self.preorder(kwargs)
- self.write(')')
- self.prune()
- self.n_call_ex_kw3 = call_ex_kw3
-
- def call_ex_kw4(node):
- """Handle CALL_FUNCTION_EX {1 or 2} but without
- BUILD_{MAP,TUPLE}_UNPACK_WITH_CALL"""
- self.preorder(node[0])
- self.write('(')
- args = node[1][0]
- if args == 'tuple':
- if self.call36_tuple(args) > 0:
- self.write(', ')
- pass
- pass
- else:
- self.write('*')
- self.preorder(args)
- self.write(', ')
- pass
-
- kwargs = node[2]
- if kwargs == 'expr':
- kwargs = kwargs[0]
- call_function_ex = node[-1]
- assert call_function_ex == 'CALL_FUNCTION_EX_KW'
- # FIXME: decide if the below test be on kwargs == 'dict'
- if (call_function_ex.attr & 1 and
- (not isinstance(kwargs, Token) and kwargs != 'attribute')
- and not kwargs[0].kind.startswith('kvlist')):
- self.call36_dict(kwargs)
- else:
- self.write('**')
- self.preorder(kwargs)
- self.write(')')
- self.prune()
- self.n_call_ex_kw4 = call_ex_kw4
-
- def call36_tuple(node):
- """
- A tuple used in a call, these are like normal tuples but they
- don't have the enclosing parenthesis.
- """
- assert node == 'tuple'
- # Note: don't iterate over last element which is a
- # BUILD_TUPLE...
- flat_elems = flatten_list(node[:-1])
-
- self.indent_more(INDENT_PER_LEVEL)
- sep = ''
-
- for elem in flat_elems:
- if elem in ('ROT_THREE', 'EXTENDED_ARG'):
- continue
- assert elem == 'expr'
- line_number = self.line_number
- value = self.traverse(elem)
- if line_number != self.line_number:
- sep += '\n' + self.indent + INDENT_PER_LEVEL[:-1]
- self.write(sep, value)
- sep = ', '
-
- self.indent_less(INDENT_PER_LEVEL)
- return len(flat_elems)
- self.call36_tuple = call36_tuple
-
- def call36_dict(node):
- """
- A dict used in a call_ex_kw2, which are a dictionary items expressed
- in a call. This should format to:
- a=1, b=2
- In other words, no braces, no quotes around keys and ":" becomes
- "=".
-
- We will source-code use line breaks to guide us when to break.
- """
- p = self.prec
- self.prec = 100
-
- self.indent_more(INDENT_PER_LEVEL)
- sep = INDENT_PER_LEVEL[:-1]
- line_number = self.line_number
-
- if node[0].kind.startswith('kvlist'):
- # Python 3.5+ style key/value list in dict
- kv_node = node[0]
- l = list(kv_node)
- i = 0
-
- length = len(l)
- # FIXME: Parser-speed improved grammars will have BUILD_MAP
- # at the end. So in the future when everything is
- # complete, we can do an "assert" instead of "if".
- if kv_node[-1].kind.startswith("BUILD_MAP"):
- length -= 1
-
- # Respect line breaks from source
- while i < length:
- self.write(sep)
- name = self.traverse(l[i], indent='')
- # Strip off beginning and trailing quotes in name
- name = name[1:-1]
- if i > 0:
- line_number = self.indent_if_source_nl(line_number,
- self.indent + INDENT_PER_LEVEL[:-1])
- line_number = self.line_number
- self.write(name, '=')
- value = self.traverse(l[i+1], indent=self.indent+(len(name)+2)*' ')
- self.write(value)
- sep = ", "
- if line_number != self.line_number:
- sep += "\n" + self.indent + INDENT_PER_LEVEL[:-1]
- line_number = self.line_number
- i += 2
- pass
- elif node[-1].kind.startswith('BUILD_CONST_KEY_MAP'):
- keys_node = node[-2]
- keys = keys_node.attr
- # from trepan.api import debug; debug()
- assert keys_node == 'LOAD_CONST' and isinstance(keys, tuple)
- for i in range(node[-1].attr):
- self.write(sep)
- self.write(keys[i], '=')
- value = self.traverse(node[i], indent='')
- self.write(value)
- sep = ", "
- if line_number != self.line_number:
- sep += "\n" + self.indent + INDENT_PER_LEVEL[:-1]
- line_number = self.line_number
- pass
- pass
- else:
- self.write("**")
- try:
- self.default(node)
- except GenericASTTraversalPruningException:
- pass
-
- self.prec = p
- self.indent_less(INDENT_PER_LEVEL)
- return
- self.call36_dict = call36_dict
-
-
- FSTRING_CONVERSION_MAP = {1: '!s', 2: '!r', 3: '!a'}
-
- def n_except_suite_finalize(node):
- if node[1] == 'returns' and self.hide_internal:
- # Process node[1] only.
- # The code after "returns", e.g. node[3], is dead code.
- # Adding it is wrong as it dedents and another
- # exception handler "except_stmt" afterwards.
- # Note it is also possible that the grammar is wrong here.
- # and this should not be "except_stmt".
- self.indent_more()
- self.preorder(node[1])
- self.indent_less()
- else:
- self.default(node)
- self.prune()
- self.n_except_suite_finalize = n_except_suite_finalize
-
- def n_formatted_value(node):
- if node[0] == 'LOAD_CONST':
- self.write(node[0].attr)
- self.prune()
- else:
- self.default(node)
- self.n_formatted_value = n_formatted_value
-
- def f_conversion(node):
- node.conversion = FSTRING_CONVERSION_MAP.get(node.data[1].attr, '')
-
- def fstring_expr(node):
- f_conversion(node)
- self.default(node)
- self.n_fstring_expr = fstring_expr
-
- def fstring_single(node):
- f_conversion(node)
- self.default(node)
- self.n_fstring_single = fstring_single
-
- # def kwargs_only_36(node):
- # keys = node[-1].attr
- # num_kwargs = len(keys)
- # values = node[:num_kwargs]
- # for i, (key, value) in enumerate(zip(keys, values)):
- # self.write(key + '=')
- # self.preorder(value)
- # if i < num_kwargs:
- # self.write(',')
- # self.prune()
- # return
- # self.n_kwargs_only_36 = kwargs_only_36
-
- def n_call_kw36(node):
- self.template_engine(("%c(", 0), node)
- keys = node[-2].attr
- num_kwargs = len(keys)
- num_posargs = len(node) - (num_kwargs + 2)
- n = len(node)
- assert n >= len(keys)+1, \
- 'not enough parameters keyword-tuple values'
- sep = ''
-
- line_number = self.line_number
- for i in range(1, num_posargs):
- self.write(sep)
- self.preorder(node[i])
- if line_number != self.line_number:
- sep = ",\n" + self.indent + " "
- else:
- sep = ", "
- line_number = self.line_number
-
- i = num_posargs
- j = 0
- # FIXME: adjust output for line breaks?
- while i < n-2:
- self.write(sep)
- self.write(keys[j] + '=')
- self.preorder(node[i])
- if line_number != self.line_number:
- sep = ",\n" + self.indent + " "
- else:
- sep = ", "
- i += 1
- j += 1
- self.write(')')
- self.prune()
- return
- self.n_call_kw36 = n_call_kw36
-
- def starred(node):
- l = len(node)
- assert l > 0
- pos_args = node[0]
- if pos_args == 'expr':
- pos_args = pos_args[0]
- if pos_args == 'tuple':
- build_tuple = pos_args[0]
- if build_tuple.kind.startswith('BUILD_TUPLE'):
- tuple_len = 0
- else:
- tuple_len = len(node) - 1
- star_start = 1
- template = '%C', (0, -1, ', ')
- self.template_engine(template, pos_args)
- if tuple_len == 0:
- self.write("*()")
- # That's it
- self.prune()
- self.write(', ')
- else:
- star_start = 0
- if l > 1:
- template = ( '*%C', (star_start, -1, ', *') )
- else:
- template = ( '*%c', (star_start, 'expr') )
-
- self.template_engine(template, node)
- self.prune()
-
- self.n_starred = starred
-
- def return_closure(node):
- # Nothing should be output here
- self.prune()
- return
- self.n_return_closure = return_closure
- pass # version >= 3.6
- pass # version >= 3.4
- pass # version >= 3.0
+ customize_for_version3(self, version)
return
diff --git a/uncompyle6/semantics/customize3.py b/uncompyle6/semantics/customize3.py
new file mode 100644
index 00000000..27871ac8
--- /dev/null
+++ b/uncompyle6/semantics/customize3.py
@@ -0,0 +1,675 @@
+# Copyright (c) 2018 by Rocky Bernstein
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+"""Isolate Python 3 version-specific semantic actions here.
+"""
+
+from uncompyle6.semantics.consts import (
+ INDENT_PER_LEVEL, PRECEDENCE, TABLE_DIRECT, TABLE_R)
+
+from xdis.code import iscode
+from xdis.util import COMPILER_FLAG_BIT
+from spark_parser.ast import GenericASTTraversalPruningException
+from uncompyle6.scanners.tok import Token
+from uncompyle6.semantics.helper import flatten_list
+from uncompyle6.semantics.make_function import make_function3_annotate
+
+def customize_for_version3(self, version):
+ TABLE_DIRECT.update({
+ 'function_def_annotate': ( '\n\n%|def %c%c\n', -1, 0),
+ 'store_locals': ( '%|# inspect.currentframe().f_locals = __locals__\n', ),
+ })
+
+ if version >= 3.3:
+ def n_yield_from(node):
+ self.write('yield from')
+ self.write(' ')
+ if 3.3 <= self.version <= 3.4:
+ self.preorder(node[0][0][0][0])
+ elif self.version >= 3.5:
+ self.preorder(node[0])
+ else:
+ assert False, "dunno about this python version"
+ self.prune() # stop recursing
+ self.n_yield_from = n_yield_from
+
+ if 3.2 <= version <= 3.4:
+
+ # In Python 3.3+ only
+ def n_call(node):
+ mapping = self._get_mapping(node)
+ key = node
+ for i in mapping[1:]:
+ key = key[i]
+ pass
+ if key.kind.startswith('CALL_FUNCTION_VAR_KW'):
+ # We may want to fill this in...
+ # But it is distinct from CALL_FUNCTION_VAR below
+ pass
+ elif key.kind.startswith('CALL_FUNCTION_VAR'):
+ # CALL_FUNCTION_VAR's top element of the stack contains
+ # the variable argument list, then comes
+ # annotation args, then keyword args.
+ # In the most least-top-most stack entry, but position 1
+ # in node order, the positional args.
+ argc = node[-1].attr
+ nargs = argc & 0xFF
+ kwargs = (argc >> 8) & 0xFF
+ # FIXME: handle annotation args
+ if kwargs != 0:
+ # kwargs == 0 is handled by the table entry
+ # Should probably handle it here though.
+ if nargs == 0:
+ template = ('%c(*%c, %C)',
+ 0, -2, (1, kwargs+1, ', '))
+ else:
+ template = ('%c(%C, *%c, %C)',
+ 0, (1, nargs+1, ', '),
+ -2, (-2-kwargs, -2, ', '))
+ self.template_engine(template, node)
+ self.prune()
+
+ self.default(node)
+ self.n_call = n_call
+
+
+ def n_mkfunc_annotate(node):
+
+ if self.version >= 3.3 or node[-2] == 'kwargs':
+ # LOAD_CONST code object ..
+ # LOAD_CONST 'x0' if >= 3.3
+ # EXTENDED_ARG
+ # MAKE_FUNCTION ..
+ code = node[-4]
+ elif node[-3] == 'expr':
+ code = node[-3][0]
+ else:
+ # LOAD_CONST code object ..
+ # MAKE_FUNCTION ..
+ code = node[-3]
+
+ self.indent_more()
+ for annotate_last in range(len(node)-1, -1, -1):
+ if node[annotate_last] == 'annotate_tuple':
+ break
+
+ # FIXME: the real situation is that when derived from
+ # function_def_annotate we the name has been filled in.
+ # But when derived from funcdefdeco it hasn't Would like a better
+ # way to distinquish.
+ if self.f.getvalue()[-4:] == 'def ':
+ self.write(code.attr.co_name)
+
+ # FIXME: handle and pass full annotate args
+ make_function3_annotate(self, node, is_lambda=False,
+ codeNode=code, annotate_last=annotate_last)
+
+ if len(self.param_stack) > 1:
+ self.write('\n\n')
+ else:
+ self.write('\n\n\n')
+ self.indent_less()
+ self.prune() # stop recursing
+ self.n_mkfunc_annotate = n_mkfunc_annotate
+
+ if version >= 3.4:
+ ########################
+ # Python 3.4+ Additions
+ #######################
+ TABLE_DIRECT.update({
+ 'LOAD_CLASSDEREF': ( '%{pattr}', ),
+ })
+
+ ########################
+ # Python 3.5+ Additions
+ #######################
+ if version >= 3.5:
+ TABLE_DIRECT.update({
+ 'await_expr': ( 'await %c', 0),
+ 'await_stmt': ( '%|%c\n', 0),
+ 'async_for_stmt': (
+ '%|async for %c in %c:\n%+%c%-\n\n', 9, 1, 25 ),
+ 'async_forelse_stmt': (
+ '%|async for %c in %c:\n%+%c%-%|else:\n%+%c%-\n\n', 9, 1, 25, 28 ),
+ 'async_with_stmt': (
+ '%|async with %c:\n%+%c%-', 0, 7),
+ 'async_with_as_stmt': (
+ '%|async with %c as %c:\n%+%c%-', 0, 6, 7),
+ 'unmap_dict': ( '{**%C}', (0, -1, ', **') ),
+ # 'unmapexpr': ( '{**%c}', 0), # done by n_unmapexpr
+
+ })
+
+ def async_call(node):
+ self.f.write('async ')
+ node.kind == 'call'
+ p = self.prec
+ self.prec = 80
+ self.template_engine(('%c(%P)', 0, (1, -4, ', ',
+ 100)), node)
+ self.prec = p
+ node.kind == 'async_call'
+ self.prune()
+ self.n_async_call = async_call
+ self.n_build_list_unpack = self.n_list
+
+ if version == 3.5:
+ def n_call(node):
+ mapping = self._get_mapping(node)
+ table = mapping[0]
+ key = node
+ for i in mapping[1:]:
+ key = key[i]
+ pass
+ if key.kind.startswith('CALL_FUNCTION_VAR_KW'):
+ # Python 3.5 changes the stack position of
+ # *args: kwargs come after *args whereas
+ # in earlier Pythons, *args is at the end
+ # which simplifies things from our
+ # perspective. Python 3.6+ replaces
+ # CALL_FUNCTION_VAR_KW with
+ # CALL_FUNCTION_EX We will just swap the
+ # order to make it look like earlier
+ # Python 3.
+ entry = table[key.kind]
+ kwarg_pos = entry[2][1]
+ args_pos = kwarg_pos - 1
+ # Put last node[args_pos] after subsequent kwargs
+ while node[kwarg_pos] == 'kwarg' and kwarg_pos < len(node):
+ # swap node[args_pos] with node[kwargs_pos]
+ node[kwarg_pos], node[args_pos] = node[args_pos], node[kwarg_pos]
+ args_pos = kwarg_pos
+ kwarg_pos += 1
+ elif key.kind.startswith('CALL_FUNCTION_VAR'):
+ # CALL_FUNCTION_VAR's top element of the stack contains
+ # the variable argument list, then comes
+ # annotation args, then keyword args.
+ # In the most least-top-most stack entry, but position 1
+ # in node order, the positional args.
+ argc = node[-1].attr
+ nargs = argc & 0xFF
+ kwargs = (argc >> 8) & 0xFF
+ # FIXME: handle annotation args
+ if nargs > 0:
+ template = ('%c(%C, ', 0, (1, nargs+1, ', '))
+ else:
+ template = ('%c(', 0)
+ self.template_engine(template, node)
+
+ args_node = node[-2]
+ if args_node in ('pos_arg', 'expr'):
+ args_node = args_node[0]
+ if args_node == 'build_list_unpack':
+ template = ('*%P)', (0, len(args_node)-1, ', *', 100))
+ self.template_engine(template, args_node)
+ else:
+ if len(node) - nargs > 3:
+ template = ('*%c, %C)', nargs+1, (nargs+kwargs+1, -1, ', '))
+ else:
+ template = ('*%c)', nargs+1)
+ self.template_engine(template, node)
+ self.prune()
+
+ self.default(node)
+ self.n_call = n_call
+
+ def n_function_def(node):
+ if self.version == 3.6:
+ code_node = node[0][0]
+ else:
+ code_node = node[0][1]
+
+ is_code = hasattr(code_node, 'attr') and iscode(code_node.attr)
+ if (is_code and
+ (code_node.attr.co_flags & COMPILER_FLAG_BIT['COROUTINE'])):
+ self.template_engine(('\n\n%|async def %c\n',
+ -2), node)
+ else:
+ self.template_engine(('\n\n%|def %c\n', -2),
+ node)
+ self.prune()
+ self.n_function_def = n_function_def
+
+ def unmapexpr(node):
+ last_n = node[0][-1]
+ for n in node[0]:
+ self.preorder(n)
+ if n != last_n:
+ self.f.write(', **')
+ pass
+ pass
+ self.prune()
+ pass
+ self.n_unmapexpr = unmapexpr
+
+ if version >= 3.6:
+ ########################
+ # Python 3.6+ Additions
+ #######################
+
+ # Value 100 is important; it is exactly
+ # module/function precidence.
+ PRECEDENCE['call_kw'] = 100
+ PRECEDENCE['call_kw36'] = 100
+ PRECEDENCE['call_ex'] = 100
+ PRECEDENCE['call_ex_kw'] = 100
+ PRECEDENCE['call_ex_kw2'] = 100
+ PRECEDENCE['call_ex_kw3'] = 100
+ PRECEDENCE['call_ex_kw4'] = 100
+
+ TABLE_DIRECT.update({
+ 'tryfinally36': ( '%|try:\n%+%c%-%|finally:\n%+%c%-\n\n',
+ (1, 'returns'), 3 ),
+ 'fstring_expr': ( "{%c%{conversion}}", 0),
+ # FIXME: the below assumes the format strings
+ # don't have ''' in them. Fix this properly
+ 'fstring_single': ( "f'''{%c%{conversion}}'''", 0),
+ 'fstring_multi': ( "f'''%c'''", 0),
+ 'func_args36': ( "%c(**", 0),
+ 'try_except36': ( '%|try:\n%+%c%-%c\n\n', 1, 2 ),
+ 'except_return': ( '%|except:\n%+%c%-', 3 ),
+ 'unpack_list': ( '*%c', (0, 'list') ),
+ 'call_ex' : (
+ '%c(%p)',
+ (0, 'expr'), (1, 100)),
+ 'call_ex_kw' : (
+ '%c(%p)',
+ (0, 'expr'), (2, 100)),
+
+ })
+
+ TABLE_R.update({
+ 'CALL_FUNCTION_EX': ('%c(*%P)', 0, (1, 2, ', ', 100)),
+ # Not quite right
+ 'CALL_FUNCTION_EX_KW': ('%c(**%C)', 0, (2, 3, ',')),
+ })
+
+ def build_unpack_tuple_with_call(node):
+
+ if node[0] == 'expr':
+ tup = node[0][0]
+ else:
+ tup = node[0]
+ pass
+ assert tup == 'tuple'
+ self.call36_tuple(tup)
+
+ buwc = node[-1]
+ assert buwc.kind.startswith('BUILD_TUPLE_UNPACK_WITH_CALL')
+ for n in node[1:-1]:
+ self.f.write(', *')
+ self.preorder(n)
+ pass
+ self.prune()
+ return
+ self.n_build_tuple_unpack_with_call = build_unpack_tuple_with_call
+
+ def build_unpack_map_with_call(node):
+ n = node[0]
+ if n == 'expr':
+ n = n[0]
+ if n == 'dict':
+ self.call36_dict(n)
+ first = 1
+ sep = ', **'
+ else:
+ first = 0
+ sep = '**'
+ for n in node[first:-1]:
+ self.f.write(sep)
+ self.preorder(n)
+ sep = ', **'
+ pass
+ self.prune()
+ return
+ self.n_build_map_unpack_with_call = build_unpack_map_with_call
+
+ def call_ex_kw2(node):
+ """Handle CALL_FUNCTION_EX 2 (have KW) but with
+ BUILD_{MAP,TUPLE}_UNPACK_WITH_CALL"""
+
+ # This is weird shit. Thanks Python!
+ self.preorder(node[0])
+ self.write('(')
+
+ assert node[1] == 'build_tuple_unpack_with_call'
+ btuwc = node[1]
+ tup = btuwc[0]
+ if tup == 'expr':
+ tup = tup[0]
+ assert tup == 'tuple'
+ self.call36_tuple(tup)
+ assert node[2] == 'build_map_unpack_with_call'
+
+ self.write(', ')
+ d = node[2][0]
+ if d == 'expr':
+ d = d[0]
+ assert d == 'dict'
+ self.call36_dict(d)
+
+ args = btuwc[1]
+ self.write(', *')
+ self.preorder(args)
+
+ self.write(', **')
+ star_star_args = node[2][1]
+ if star_star_args == 'expr':
+ star_star_args = star_star_args[0]
+ self.preorder(star_star_args)
+ self.write(')')
+ self.prune()
+ self.n_call_ex_kw2 = call_ex_kw2
+
+ def call_ex_kw3(node):
+ """Handle CALL_FUNCTION_EX 1 (have KW) but without
+ BUILD_MAP_UNPACK_WITH_CALL"""
+ self.preorder(node[0])
+ self.write('(')
+ args = node[1][0]
+ if args == 'expr':
+ args = args[0]
+ if args == 'tuple':
+ if self.call36_tuple(args) > 0:
+ self.write(', ')
+ pass
+ pass
+
+ self.write('*')
+ self.preorder(node[1][1])
+ self.write(', ')
+
+ kwargs = node[2]
+ if kwargs == 'expr':
+ kwargs = kwargs[0]
+ if kwargs == 'dict':
+ self.call36_dict(kwargs)
+ else:
+ self.write('**')
+ self.preorder(kwargs)
+ self.write(')')
+ self.prune()
+ self.n_call_ex_kw3 = call_ex_kw3
+
+ def call_ex_kw4(node):
+ """Handle CALL_FUNCTION_EX {1 or 2} but without
+ BUILD_{MAP,TUPLE}_UNPACK_WITH_CALL"""
+ self.preorder(node[0])
+ self.write('(')
+ args = node[1][0]
+ if args == 'tuple':
+ if self.call36_tuple(args) > 0:
+ self.write(', ')
+ pass
+ pass
+ else:
+ self.write('*')
+ self.preorder(args)
+ self.write(', ')
+ pass
+
+ kwargs = node[2]
+ if kwargs == 'expr':
+ kwargs = kwargs[0]
+ call_function_ex = node[-1]
+ assert call_function_ex == 'CALL_FUNCTION_EX_KW'
+ # FIXME: decide if the below test be on kwargs == 'dict'
+ if (call_function_ex.attr & 1 and
+ (not isinstance(kwargs, Token) and kwargs != 'attribute')
+ and not kwargs[0].kind.startswith('kvlist')):
+ self.call36_dict(kwargs)
+ else:
+ self.write('**')
+ self.preorder(kwargs)
+ self.write(')')
+ self.prune()
+ self.n_call_ex_kw4 = call_ex_kw4
+
+ def call36_tuple(node):
+ """
+ A tuple used in a call, these are like normal tuples but they
+ don't have the enclosing parenthesis.
+ """
+ assert node == 'tuple'
+ # Note: don't iterate over last element which is a
+ # BUILD_TUPLE...
+ flat_elems = flatten_list(node[:-1])
+
+ self.indent_more(INDENT_PER_LEVEL)
+ sep = ''
+
+ for elem in flat_elems:
+ if elem in ('ROT_THREE', 'EXTENDED_ARG'):
+ continue
+ assert elem == 'expr'
+ line_number = self.line_number
+ value = self.traverse(elem)
+ if line_number != self.line_number:
+ sep += '\n' + self.indent + INDENT_PER_LEVEL[:-1]
+ self.write(sep, value)
+ sep = ', '
+
+ self.indent_less(INDENT_PER_LEVEL)
+ return len(flat_elems)
+ self.call36_tuple = call36_tuple
+
+ def call36_dict(node):
+ """
+ A dict used in a call_ex_kw2, which are a dictionary items expressed
+ in a call. This should format to:
+ a=1, b=2
+ In other words, no braces, no quotes around keys and ":" becomes
+ "=".
+
+ We will source-code use line breaks to guide us when to break.
+ """
+ p = self.prec
+ self.prec = 100
+
+ self.indent_more(INDENT_PER_LEVEL)
+ sep = INDENT_PER_LEVEL[:-1]
+ line_number = self.line_number
+
+ if node[0].kind.startswith('kvlist'):
+ # Python 3.5+ style key/value list in dict
+ kv_node = node[0]
+ l = list(kv_node)
+ i = 0
+
+ length = len(l)
+ # FIXME: Parser-speed improved grammars will have BUILD_MAP
+ # at the end. So in the future when everything is
+ # complete, we can do an "assert" instead of "if".
+ if kv_node[-1].kind.startswith("BUILD_MAP"):
+ length -= 1
+
+ # Respect line breaks from source
+ while i < length:
+ self.write(sep)
+ name = self.traverse(l[i], indent='')
+ # Strip off beginning and trailing quotes in name
+ name = name[1:-1]
+ if i > 0:
+ line_number = self.indent_if_source_nl(line_number,
+ self.indent + INDENT_PER_LEVEL[:-1])
+ line_number = self.line_number
+ self.write(name, '=')
+ value = self.traverse(l[i+1], indent=self.indent+(len(name)+2)*' ')
+ self.write(value)
+ sep = ", "
+ if line_number != self.line_number:
+ sep += "\n" + self.indent + INDENT_PER_LEVEL[:-1]
+ line_number = self.line_number
+ i += 2
+ pass
+ elif node[-1].kind.startswith('BUILD_CONST_KEY_MAP'):
+ keys_node = node[-2]
+ keys = keys_node.attr
+ # from trepan.api import debug; debug()
+ assert keys_node == 'LOAD_CONST' and isinstance(keys, tuple)
+ for i in range(node[-1].attr):
+ self.write(sep)
+ self.write(keys[i], '=')
+ value = self.traverse(node[i], indent='')
+ self.write(value)
+ sep = ", "
+ if line_number != self.line_number:
+ sep += "\n" + self.indent + INDENT_PER_LEVEL[:-1]
+ line_number = self.line_number
+ pass
+ pass
+ else:
+ self.write("**")
+ try:
+ self.default(node)
+ except GenericASTTraversalPruningException:
+ pass
+
+ self.prec = p
+ self.indent_less(INDENT_PER_LEVEL)
+ return
+ self.call36_dict = call36_dict
+
+
+ FSTRING_CONVERSION_MAP = {1: '!s', 2: '!r', 3: '!a'}
+
+ def n_except_suite_finalize(node):
+ if node[1] == 'returns' and self.hide_internal:
+ # Process node[1] only.
+ # The code after "returns", e.g. node[3], is dead code.
+ # Adding it is wrong as it dedents and another
+ # exception handler "except_stmt" afterwards.
+ # Note it is also possible that the grammar is wrong here.
+ # and this should not be "except_stmt".
+ self.indent_more()
+ self.preorder(node[1])
+ self.indent_less()
+ else:
+ self.default(node)
+ self.prune()
+ self.n_except_suite_finalize = n_except_suite_finalize
+
+ def n_formatted_value(node):
+ if node[0] == 'LOAD_CONST':
+ self.write(node[0].attr)
+ self.prune()
+ else:
+ self.default(node)
+ self.n_formatted_value = n_formatted_value
+
+ def f_conversion(node):
+ node.conversion = FSTRING_CONVERSION_MAP.get(node.data[1].attr, '')
+
+ def fstring_expr(node):
+ f_conversion(node)
+ self.default(node)
+ self.n_fstring_expr = fstring_expr
+
+ def fstring_single(node):
+ f_conversion(node)
+ self.default(node)
+ self.n_fstring_single = fstring_single
+
+ # def kwargs_only_36(node):
+ # keys = node[-1].attr
+ # num_kwargs = len(keys)
+ # values = node[:num_kwargs]
+ # for i, (key, value) in enumerate(zip(keys, values)):
+ # self.write(key + '=')
+ # self.preorder(value)
+ # if i < num_kwargs:
+ # self.write(',')
+ # self.prune()
+ # return
+ # self.n_kwargs_only_36 = kwargs_only_36
+
+ def n_call_kw36(node):
+ self.template_engine(("%c(", 0), node)
+ keys = node[-2].attr
+ num_kwargs = len(keys)
+ num_posargs = len(node) - (num_kwargs + 2)
+ n = len(node)
+ assert n >= len(keys)+1, \
+ 'not enough parameters keyword-tuple values'
+ sep = ''
+
+ line_number = self.line_number
+ for i in range(1, num_posargs):
+ self.write(sep)
+ self.preorder(node[i])
+ if line_number != self.line_number:
+ sep = ",\n" + self.indent + " "
+ else:
+ sep = ", "
+ line_number = self.line_number
+
+ i = num_posargs
+ j = 0
+ # FIXME: adjust output for line breaks?
+ while i < n-2:
+ self.write(sep)
+ self.write(keys[j] + '=')
+ self.preorder(node[i])
+ if line_number != self.line_number:
+ sep = ",\n" + self.indent + " "
+ else:
+ sep = ", "
+ i += 1
+ j += 1
+ self.write(')')
+ self.prune()
+ return
+ self.n_call_kw36 = n_call_kw36
+
+ def starred(node):
+ l = len(node)
+ assert l > 0
+ pos_args = node[0]
+ if pos_args == 'expr':
+ pos_args = pos_args[0]
+ if pos_args == 'tuple':
+ build_tuple = pos_args[0]
+ if build_tuple.kind.startswith('BUILD_TUPLE'):
+ tuple_len = 0
+ else:
+ tuple_len = len(node) - 1
+ star_start = 1
+ template = '%C', (0, -1, ', ')
+ self.template_engine(template, pos_args)
+ if tuple_len == 0:
+ self.write("*()")
+ # That's it
+ self.prune()
+ self.write(', ')
+ else:
+ star_start = 0
+ if l > 1:
+ template = ( '*%C', (star_start, -1, ', *') )
+ else:
+ template = ( '*%c', (star_start, 'expr') )
+
+ self.template_engine(template, node)
+ self.prune()
+
+ self.n_starred = starred
+
+ def return_closure(node):
+ # Nothing should be output here
+ self.prune()
+ return
+ self.n_return_closure = return_closure
+ pass # version >= 3.6
+ pass # version >= 3.4
+ return
diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py
index 42496f8a..4b86ade5 100644
--- a/uncompyle6/semantics/pysource.py
+++ b/uncompyle6/semantics/pysource.py
@@ -256,223 +256,6 @@ class SourceWalker(GenericASTTraversal, object):
self.write("\n" + self.indent + INDENT_PER_LEVEL[:-1])
return self.line_number
- def customize_for_version(self, is_pypy, version):
- if is_pypy:
- ########################
- # PyPy changes
- #######################
- TABLE_DIRECT.update({
- 'assert_pypy': ( '%|assert %c\n' , 1 ),
- 'assert2_pypy': ( '%|assert %c, %c\n' , 1, 4 ),
- 'try_except_pypy': ( '%|try:\n%+%c%-%c\n\n', 1, 2 ),
- 'tryfinallystmt_pypy': ( '%|try:\n%+%c%-%|finally:\n%+%c%-\n\n', 1, 3 ),
- 'assign3_pypy': ( '%|%c, %c, %c = %c, %c, %c\n', 5, 4, 3, 0, 1, 2 ),
- 'assign2_pypy': ( '%|%c, %c = %c, %c\n', 3, 2, 0, 1),
- })
- else:
- ########################
- # Without PyPy
- #######################
- TABLE_DIRECT.update({
- 'assert': ( '%|assert %c\n' , 0 ),
- 'assert2': ( '%|assert %c, %c\n' , 0, 3 ),
- 'try_except': ( '%|try:\n%+%c%-%c\n\n', 1, 3 ),
- 'assign2': ( '%|%c, %c = %c, %c\n', 3, 4, 0, 1 ),
- 'assign3': ( '%|%c, %c, %c = %c, %c, %c\n', 5, 6, 7, 0, 1, 2 ),
- })
- if version < 3.0:
- TABLE_R.update({
- 'STORE_SLICE+0': ( '%c[:]', 0 ),
- 'STORE_SLICE+1': ( '%c[%p:]', 0, (1, 100) ),
- 'STORE_SLICE+2': ( '%c[:%p]', 0, (1, 100) ),
- 'STORE_SLICE+3': ( '%c[%p:%p]', 0, (1, 100), (2, 100) ),
- 'DELETE_SLICE+0': ( '%|del %c[:]\n', 0 ),
- 'DELETE_SLICE+1': ( '%|del %c[%c:]\n', 0, 1 ),
- 'DELETE_SLICE+2': ( '%|del %c[:%c]\n', 0, 1 ),
- 'DELETE_SLICE+3': ( '%|del %c[%c:%c]\n', 0, 1, 2 ),
- })
- TABLE_DIRECT.update({
- 'raise_stmt2': ( '%|raise %c, %c\n', 0, 1),
- })
- else:
- TABLE_DIRECT.update({
- # Gotta love Python for its futzing around with syntax like this
- 'raise_stmt2': ( '%|raise %c from %c\n', 0, 1),
- })
-
- if version >= 3.2:
- TABLE_DIRECT.update({
- 'del_deref_stmt': ( '%|del %c\n', 0),
- 'DELETE_DEREF': ( '%{pattr}', 0 ),
- })
-
- if version <= 2.4:
- TABLE_DIRECT.update({
- 'importmultiple': ( '%|import %c%c\n', 2, 3),
- 'import_cont' : ( ', %c', 2),
- 'tryfinallystmt': ( '%|try:\n%+%c%-%|finally:\n%+%c%-',
- (1, 'suite_stmts_opt') ,
- (5, 'suite_stmts_opt') )
- })
- if version == 2.3:
- TABLE_DIRECT.update({
- 'if1_stmt': ( '%|if 1\n%+%c%-', 5 )
- })
-
- global NAME_MODULE
- NAME_MODULE = AST('stmt',
- [ AST('assign',
- [ AST('expr',
- [Token('LOAD_GLOBAL', pattr='__name__',
- offset=0, has_arg=True)]),
- AST('store',
- [ Token('STORE_NAME', pattr='__module__',
- offset=3, has_arg=True)])
- ])])
- pass
- if version <= 2.3:
- if version <= 2.1:
- TABLE_DIRECT.update({
- 'importmultiple': ( '%c', 2 ),
- # FIXME: not quite right. We have indiividual imports
- # when there is in fact one: "import a, b, ..."
- 'imports_cont': ( '%C%,', (1, 100, '\n') ),
- })
- pass
- pass
- pass
- elif version >= 2.5:
- ########################
- # Import style for 2.5+
- ########################
- TABLE_DIRECT.update({
- 'importmultiple': ( '%|import %c%c\n', 2, 3 ),
- 'import_cont' : ( ', %c', 2 ),
- # With/as is allowed as "from future" thing in 2.5
- # Note: It is safe to put the variables after "as" in parenthesis,
- # and sometimes it is needed.
- 'withstmt': ( '%|with %c:\n%+%c%-', 0, 3),
- 'withasstmt': ( '%|with %c as (%c):\n%+%c%-', 0, 2, 3),
- })
-
- # In 2.5+ "except" handlers and the "finally" can appear in one
- # "try" statement. So the below has the effect of combining the
- # "tryfinally" with statement with the "try_except" statement
- def tryfinallystmt(node):
- if len(node[1][0]) == 1 and node[1][0][0] == 'stmt':
- if node[1][0][0][0] == 'try_except':
- node[1][0][0][0].kind = 'tf_try_except'
- if node[1][0][0][0] == 'tryelsestmt':
- node[1][0][0][0].kind = 'tf_tryelsestmt'
- self.default(node)
- self.n_tryfinallystmt = tryfinallystmt
-
- ########################################
- # Python 2.6+
- # except as
- # vs. older:
- # except ,
- #
- # For 2.6 we use the older syntax which
- # matches how we parse this in bytecode
- ########################################
- if version > 2.6:
- TABLE_DIRECT.update({
- 'except_cond2': ( '%|except %c as %c:\n', 1, 5 ),
- })
- else:
- TABLE_DIRECT.update({
- 'except_cond3': ( '%|except %c, %c:\n', 1, 6 ),
- 'testtrue_then': ( 'not %p', (0, 22) ),
-
- })
-
- if 2.4 <= version <= 2.6:
- TABLE_DIRECT.update({
- 'comp_for': ( ' for %c in %c', 3, 1 ),
- })
- else:
- TABLE_DIRECT.update({
- 'comp_for': ( ' for %c in %c%c', 2, 0, 3 ),
- })
-
- if version >= 3.0:
- TABLE_DIRECT.update({
- 'function_def_annotate': ( '\n\n%|def %c%c\n', -1, 0),
- 'store_locals': ( '%|# inspect.currentframe().f_locals = __locals__\n', ),
- })
-
- def n_mkfunc_annotate(node):
-
- if self.version >= 3.3 or node[-2] in ('kwargs', 'no_kwargs'):
- # LOAD_CONST code object ..
- # LOAD_CONST 'x0' if >= 3.3
- # EXTENDED_ARG
- # MAKE_FUNCTION ..
- code = node[-4]
- elif node[-3] == 'expr':
- code = node[-3][0]
- else:
- # LOAD_CONST code object ..
- # MAKE_FUNCTION ..
- code = node[-3]
-
- self.indent_more()
- for annotate_last in range(len(node)-1, -1, -1):
- if node[annotate_last] == 'annotate_tuple':
- break
-
- # FIXME: the real situation is that when derived from
- # function_def_annotate we the name has been filled in.
- # But when derived from funcdefdeco it hasn't Would like a better
- # way to distinquish.
- if self.f.getvalue()[-4:] == 'def ':
- self.write(code.attr.co_name)
-
- # FIXME: handle and pass full annotate args
- make_function3_annotate(self, node, is_lambda=False,
- codeNode=code, annotate_last=annotate_last)
-
- if len(self.param_stack) > 1:
- self.write('\n\n')
- else:
- self.write('\n\n\n')
- self.indent_less()
- self.prune() # stop recursing
- self.n_mkfunc_annotate = n_mkfunc_annotate
-
- if version >= 3.4:
- ########################
- # Python 3.4+ Additions
- #######################
- TABLE_DIRECT.update({
- 'LOAD_CLASSDEREF': ( '%{pattr}', ),
- })
- ########################
- # Python 3.5+ Additions
- #######################
- if version >= 3.5:
- TABLE_DIRECT.update({
- 'await_expr': ( 'await %c', 0),
- 'await_stmt': ( '%|%c\n', 0),
- 'async_for_stmt': (
- '%|async for %c in %c:\n%+%c%-\n\n', 9, 1, 25 ),
- 'async_forelse_stmt': (
- '%|async for %c in %c:\n%+%c%-%|else:\n%+%c%-\n\n', 9, 1, 25, 28 ),
- 'async_with_stmt': (
- '%|async with %c:\n%+%c%-', 0, 7),
- 'async_with_as_stmt': (
- '%|async with %c as %c:\n%+%c%-', 0, 6, 7),
- 'unmap_dict': ( '{**%C}', (0, -1, ', **') ),
- # 'unmapexpr': ( '{**%c}', 0), # done by n_unmapexpr
-
- })
-
-
- pass # version >= 3.4
- pass # version >= 3.0
- return
-
f = property(lambda s: s.params['f'],
lambda s, x: s.params.__setitem__('f', x),
lambda s: s.params.__delitem__('f'),
@@ -624,26 +407,14 @@ class SourceWalker(GenericASTTraversal, object):
self.prune() # stop recursing
def n_yield(self, node):
- self.write('yield')
if node != AST('yield', [NONE, Token('YIELD_VALUE')]):
- self.write(' ')
- self.preorder(node[0])
+ self.template_engine(( 'yield %c', 0), node)
elif self.version <= 2.4:
# Early versions of Python don't allow a plain "yield"
- self.write(' None')
-
- self.prune() # stop recursing
-
- # In Python 3.3+ only
- def n_yield_from(self, node):
- self.write('yield from')
- self.write(' ')
- if 3.3 <= self.version <= 3.4:
- self.preorder(node[0][0][0][0])
- elif self.version >= 3.5:
- self.preorder(node[0])
+ self.write('yield None')
else:
- assert False, "dunno about this python version"
+ self.write('yield')
+
self.prune() # stop recursing
def n_build_slice3(self, node):