From 4199bc7f617e387fb03fc06939cd17366dc15c5e Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 9 Apr 2017 05:30:45 -0400 Subject: [PATCH] Fix Python 3.5 CALL_FUNCTION_VAR_KW Fixes Issue #95 --- test/bytecode_3.3/10_kw+pos_args-bug.pyc | Bin 823 -> 1063 bytes test/bytecode_3.5/10_kw+pos_args-bug.pyc | Bin 0 -> 695 bytes test/simple_source/def/10_kw+pos_args-bug.py | 6 ++++ uncompyle6/parsers/parse3.py | 28 +++++++++++++++---- 4 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 test/bytecode_3.5/10_kw+pos_args-bug.pyc diff --git a/test/bytecode_3.3/10_kw+pos_args-bug.pyc b/test/bytecode_3.3/10_kw+pos_args-bug.pyc index f491014200a719a21c9b131f1061d8dff82766f4..1893246e473be538036eedbf7db0211d90c842ab 100644 GIT binary patch delta 346 zcmY*TJ5B>J6dZelcUg9`flyFVp*;aL5;Y$wDUygT&oq33>{tjXQVLSjY)?x~1&84R zxd9Cl;~)^R{YLh9=FNLEFWLOLDD(HP<=|5TWBglP-j7)Rj37K6NCMf07)S+4Av=(4 zg`2P%lEYF^!L}e>$QGo)B1uQomyk9Vz=*C2y?U2DLr!@0OEv$?IT4WjKUX~U&`U_J0!CpKM_jPV`j`IKCA#&d8)UU!_%u2tLoaLm><>$4j(1nS@ z&AKvPI!wJT@-Wgl>6L|9^EGWzYaOxynIM~yIS$rEip4jG2chNAY?AI@Dwp&WNlL#f zF&VFoDYh~%t_3Y~SblGr)pi+r41ESxvBLxGA3B|t2Bj-1o8mF?A3r^j7u!c=;pEz$ zyT_lZ^C#slbS1TMtup>|A!c1pmS*ZQKq#|_KMwn;!fS70Od+sQ~C zM$gkq25;x5Z_eJWmh;&viR9U0IbYQ+)I2w|>hZ8(=)TAbRT+F$cg^ug4C^lvljskz CkfgZ) literal 0 HcmV?d00001 diff --git a/test/simple_source/def/10_kw+pos_args-bug.py b/test/simple_source/def/10_kw+pos_args-bug.py index 88eb30ef..b89a390c 100644 --- a/test/simple_source/def/10_kw+pos_args-bug.py +++ b/test/simple_source/def/10_kw+pos_args-bug.py @@ -8,3 +8,9 @@ def __init__(self, defaults=None, dict_type=_default_dict, default_section=DEFAULTSECT, interpolation=_UNSET): pass + +# From 3.5 sqlalchemy/orm/__init__.py +# Python 3.5 changes the stack position of where * args are (furthest down the stack) +# Python 3.6+ replaces CALL_FUNCTION_VAR_KW with CALL_FUNCTION_EX +def deferred(*columns, **kw): + return ColumnProperty(deferred=True, *columns, **kw) diff --git a/uncompyle6/parsers/parse3.py b/uncompyle6/parsers/parse3.py index a13b2517..e31ce341 100644 --- a/uncompyle6/parsers/parse3.py +++ b/uncompyle6/parsers/parse3.py @@ -1,4 +1,4 @@ -# Copyright (c) 2015, 2016 Rocky Bernstein +# Copyright (c) 2015-2017 Rocky Bernstein # Copyright (c) 2005 by Dan Pascu # Copyright (c) 2000-2002 by hartmut Goebel # Copyright (c) 1999 John Aycock @@ -462,9 +462,9 @@ class Python3Parser(PythonParser): def custom_classfunc_rule(self, opname, token, customize): """ call_function ::= expr {expr}^n CALL_FUNCTION_n - call_function ::= expr {expr}^n CALL_FUNCTION_VAR_n POP_TOP - call_function ::= expr {expr}^n CALL_FUNCTION_VAR_KW_n POP_TOP - call_function ::= expr {expr}^n CALL_FUNCTION_KW_n POP_TOP + call_function ::= expr {expr}^n CALL_FUNCTION_VAR_n + call_function ::= expr {expr}^n CALL_FUNCTION_VAR_KW_n + call_function ::= expr {expr}^n CALL_FUNCTION_KW_n classdefdeco2 ::= LOAD_BUILD_CLASS mkfunc {expr}^n-1 CALL_FUNCTION_n """ @@ -472,15 +472,31 @@ class Python3Parser(PythonParser): # high byte number of positional parameters args_pos = token.attr & 0xff args_kw = (token.attr >> 8) & 0xff + + # Additional exprs for * and ** args: + # 0 if neither + # 1 for CALL_FUNCTION_VAR or CALL_FUNCTION_KW + # 2 for * and ** args (CALL_FUNCTION_VAR_KW). + # Yes, this computation based on instruction name is a little bit hoaky. nak = ( len(opname)-len('CALL_FUNCTION') ) // 3 + token.type = self.call_fn_name(token) + uniq_param = args_kw + args_pos + if self.version == 3.5 and opname.startswith('CALL_FUNCTION_VAR_KW'): + # Python 3.5 changes the stack position of where * args, the + # first LOAD_FAST, below are located. + # Python 3.6+ replaces CALL_FUNCTION_VAR_KW with CALL_FUNCTION_EX + rule = ('call_function ::= LOAD_GLOBAL LOAD_FAST ' + + ('pos_arg ' * args_pos) + + ('kwarg ' * args_kw) + 'LOAD_FAST ' + + token.type) + self.add_unique_rule(rule, token.type, uniq_param, customize) + rule = ('call_function ::= expr ' + ('pos_arg ' * args_pos) + ('kwarg ' * args_kw) + 'expr ' * nak + token.type) - uniq_param = args_kw + args_pos - self.add_unique_rule(rule, token.type, uniq_param, customize) if self.version >= 3.5: rule = ('async_call_function ::= expr ' +