diff --git a/test/bytecode_3.6/01_named_and_kwargs.pyc b/test/bytecode_3.6/01_named_and_kwargs.pyc new file mode 100644 index 00000000..4fa92e31 Binary files /dev/null and b/test/bytecode_3.6/01_named_and_kwargs.pyc differ diff --git a/test/bytecode_3.6/04_withas.pyc b/test/bytecode_3.6/04_withas.pyc index 1d9b0dd7..2691fde2 100644 Binary files a/test/bytecode_3.6/04_withas.pyc and b/test/bytecode_3.6/04_withas.pyc differ diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index def0a6b3..2912d23c 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -496,17 +496,11 @@ class Python3Parser(PythonParser): ('pos_arg ' * args_pos) + ('kwarg ' * args_kw) + kw + token.kind) self.add_unique_rule(rule, token.kind, uniq_param, customize) - if self.version >= 3.6 and opname == 'CALL_FUNCTION_EX_KW': - rule = ('call36 ::= ' - 'expr build_tuple_unpack_with_call build_map_unpack_with_call ' - 'CALL_FUNCTION_EX_KW_1') - self.add_unique_rule(rule, token.kind, uniq_param, customize) - rule = 'call ::= call36' - else: - rule = ('call ::= expr ' + - ('pos_arg ' * args_pos) + - ('kwarg ' * args_kw) + - 'expr ' * nak + token.kind) + + rule = ('call ::= expr ' + + ('pos_arg ' * args_pos) + + ('kwarg ' * args_kw) + + 'expr ' * nak + token.kind) self.add_unique_rule(rule, token.kind, uniq_param, customize) if self.version >= 3.5 and seen_GET_AWAITABLE_YIELD_FROM: diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index a79e9c64..2f5cfae0 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -119,6 +119,8 @@ class Python36Parser(Python35Parser): rules_str = """ withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY + withstmt ::= expr SETUP_WITH POP_TOP suite_stmts_opt COME_FROM_WITH + WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY # Removes POP_BLOCK LOAD_CONST from 3.6- withasstmt ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH @@ -139,12 +141,17 @@ class Python36Parser(Python35Parser): elif opname == 'CALL_FUNCTION_EX_KW': self.addRule("""expr ::= call_ex_kw expr ::= call_ex_kw2 + expr ::= call_ex_kw3 call_ex_kw ::= expr expr build_map_unpack_with_call CALL_FUNCTION_EX_KW call_ex_kw2 ::= expr build_tuple_unpack_with_call build_map_unpack_with_call CALL_FUNCTION_EX_KW + call_ex_kw3 ::= expr + tuple + expr + CALL_FUNCTION_EX_KW """, nop_func) elif opname == 'CALL_FUNCTION_EX': diff --git a/uncompyle6/semantics/make_function.py b/uncompyle6/semantics/make_function.py index f64c8d09..e15049f4 100644 --- a/uncompyle6/semantics/make_function.py +++ b/uncompyle6/semantics/make_function.py @@ -479,8 +479,9 @@ def make_function3(self, node, is_lambda, nested=1, codeNode=None): else: if self.version < 3.6: defparams = node[:args_node.attr] + kw_args = 0 else: - default, kw, annotate, closure = args_node.attr + default, kw_args, annotate, closure = args_node.attr if default: assert node[0] == 'expr', "expecting mkfunc default node to be an expr" expr_node = node[0] @@ -492,8 +493,6 @@ def make_function3(self, node, is_lambda, nested=1, codeNode=None): else: defparams = [] # FIXME: handle kw, annotate and closure - - kw_args = 0 pass if 3.0 <= self.version <= 3.2: @@ -619,16 +618,9 @@ def make_function3(self, node, is_lambda, nested=1, codeNode=None): else: self.write(", ") - if not 3.0 <= self.version <= 3.2: - for n in node: - if n == 'pos_arg': - continue - elif self.version >= 3.4 and not (n.kind in ('kwargs', 'kwargs1', 'kwarg')): - continue - else: - self.preorder(n) - break - else: + # FIXME: this is not correct for 3.5. or 3.6 (which works different) + # and 3.7? + if 3.0 <= self.version <= 3.2: kwargs = node[0] last = len(kwargs)-1 i = 0 @@ -638,10 +630,37 @@ def make_function3(self, node, is_lambda, nested=1, codeNode=None): self.preorder(n[1]) if i < last: self.write(', ') + pass i += 1 pass pass pass + elif self.version <= 3.5: + # FIXME this is not qute right for 3.5 + for n in node: + if n == 'pos_arg': + continue + elif self.version >= 3.4 and not (n.kind in ('kwargs', 'kwargs1', 'kwarg')): + continue + else: + self.preorder(n) + break + elif self.version >= 3.6: + d = node[1] + if d == 'expr': + d = d[0] + assert d == 'dict' + defaults = [self.traverse(n, indent='') for n in d[:-2]] + names = eval(self.traverse(d[-2])) + assert len(defaults) == len(names) + sep = '' + # FIXME: possibly handle line breaks + for i, n in enumerate(names): + self.write(sep) + self.write("%s=%s" % (n, defaults[i])) + sep = ', ' + pass + pass pass if code_has_star_star_arg(code): diff --git a/uncompyle6/semantics/pysource.py b/uncompyle6/semantics/pysource.py index 4b209f3d..a097a276 100644 --- a/uncompyle6/semantics/pysource.py +++ b/uncompyle6/semantics/pysource.py @@ -568,8 +568,17 @@ class SourceWalker(GenericASTTraversal, object): self.n_build_tuple_unpack_with_call = build_unpack_tuple_with_call def build_unpack_map_with_call(node): - sep = '**' - for n in node[:-1]: + 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 = ', **' @@ -612,6 +621,23 @@ class SourceWalker(GenericASTTraversal, object): self.prune() self.n_call_ex_kw2 = call_ex_kw2 + def call_ex_kw3(node): + self.preorder(node[0]) + self.write('(') + tup = node[1] + assert tup == 'tuple' + self.call36_tuple(tup) + expr = node[2] + if len(tup) > 0: + # if tup[0].attr > 0: + self.write(', ') + self.write('**') + self.preorder(expr) + self.write(')') + self.prune() + self.n_call_ex_kw3 = call_ex_kw3 + + def call36_tuple(node): """ A tuple used in a call, these are like normal tuples but they