From c88d9de3163b8a5eb02b992b460979f04f666e97 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 20 Apr 2022 20:03:28 -0400 Subject: [PATCH] Correct 3.7 "impor"t and "from .. import" --- test/bytecode_3.7_run/00_import.pyc | Bin 0 -> 401 bytes test/bytecode_3.8_run/00_import.pyc | Bin 0 -> 405 bytes test/simple_source/stmts/00_import.py | 20 ++++++++-- uncompyle6/parsers/parse37.py | 52 +++++++++++++++++--------- uncompyle6/parsers/parse37base.py | 7 ++++ uncompyle6/semantics/customize37.py | 15 ++++++-- uncompyle6/semantics/n_actions.py | 12 +++++- 7 files changed, 80 insertions(+), 26 deletions(-) create mode 100644 test/bytecode_3.7_run/00_import.pyc create mode 100644 test/bytecode_3.8_run/00_import.pyc diff --git a/test/bytecode_3.7_run/00_import.pyc b/test/bytecode_3.7_run/00_import.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8c349eba0eed39f4213f6269408c6b3887f98bf4 GIT binary patch literal 401 zcmXwzJ5s|i5QcXpJ2Al_rh*w7+EC=#G7Q53XrNMK9#$p}Qsl7|hSc1Hfs)H`0JT(H zfr_;pR-^yhUHvQRs^9Mc#nIc{!xsX4H^qN&N-k;JXOaR6R3I8Mg_;S5P0khGwr5;K z!Gj_W?2xA$Jdx_?MC>8Rp4@-M0-jjC44zc?86fC`paU@=54>jud>~EY4GiNSdK<2X z=%ec1Es1#66f0A%hlifqt@X^SdIQqyZU#f+kU?X6i07&4_^rI-6a2mQ*ue$K9dwspaRj5Db!3bY|dQaO?$^h z6g(*6zz%u3!4s*DPQ)I9?8*ICEZ~XN%iu|Mp8Nn_{EnMe`GzktCR6!m>E!wAeBG0~c6hg8%>k literal 0 HcmV?d00001 diff --git a/test/simple_source/stmts/00_import.py b/test/simple_source/stmts/00_import.py index a3f58355..2d0e17c9 100644 --- a/test/simple_source/stmts/00_import.py +++ b/test/simple_source/stmts/00_import.py @@ -1,11 +1,23 @@ # Tests all the different kinds of imports +"""This program is self-checking!""" + import sys from os import path -from os import * +from os import * # NOQA + import time as time1, os as os1 -import http.client as httpclient -from sys import stdin, stdout, stderr + +assert isinstance(os1.pathsep, str) + +assert time1.time() > 0 +import os.path as osp + +assert osp == path +from os.path import join as jj +assert path.join == jj + if len(__file__) == 0: # a.b.c should force consecutive LOAD_ATTRs - import a.b.c as d import stuff0.stuff1.stuff2.stuff3 as stuff3 + +sys.exit(0) diff --git a/uncompyle6/parsers/parse37.py b/uncompyle6/parsers/parse37.py index f131e6ef..ce8dedc8 100644 --- a/uncompyle6/parsers/parse37.py +++ b/uncompyle6/parsers/parse37.py @@ -152,7 +152,10 @@ class Python37Parser(Python37BaseParser): expr ::= LOAD_NAME expr ::= LOAD_STR expr ::= _lambda_body + expr ::= and + expr ::= attribute37 + expr ::= bin_op expr ::= call expr ::= compare @@ -346,28 +349,43 @@ class Python37Parser(Python37BaseParser): def p_import37(self, args): """ - stmt ::= import_as37 - import_as37 ::= LOAD_CONST LOAD_CONST importlist37 store POP_TOP - - importlist37 ::= importlist37 ROT_TWO IMPORT_FROM - importlist37 ::= importlist37 ROT_TWO POP_TOP IMPORT_FROM - importlist37 ::= importattr37 - importattr37 ::= IMPORT_NAME_ATTR IMPORT_FROM - # The 3.7base scanner adds IMPORT_NAME_ATTR - alias ::= IMPORT_NAME_ATTR attributes store - alias ::= IMPORT_NAME_ATTR store + alias ::= IMPORT_NAME_ATTR attributes store + alias ::= IMPORT_NAME_ATTR store + + alias37 ::= IMPORT_NAME store + alias37 ::= IMPORT_FROM store + + attribute37 ::= expr LOAD_METHOD + + import_as37 ::= LOAD_CONST LOAD_CONST importlist37 store POP_TOP import_from ::= LOAD_CONST LOAD_CONST importlist POP_TOP + import_from37 ::= LOAD_CONST LOAD_CONST IMPORT_NAME_ATTR importlist37 POP_TOP + import_from_as37 ::= LOAD_CONST LOAD_CONST import_from_attr37 store POP_TOP - expr ::= attribute37 - attribute37 ::= expr LOAD_METHOD + # A single entry in a dotted import a.b.c.d + import_one ::= importlists ROT_TWO IMPORT_FROM + import_one ::= importlists ROT_TWO POP_TOP IMPORT_FROM + + # Semantic checks distinguish importattr37 from import_from_attr37 + # in the former the "from" slot in a prior LOAD_CONST is null. + + # Used in: import .. as .. + importattr37 ::= IMPORT_NAME_ATTR IMPORT_FROM + + # Used in: from xx import .. as .. + import_from_attr37 ::= IMPORT_NAME_ATTR IMPORT_FROM + + importlist37 ::= import_one + importlist37 ::= importattr37 + importlist37 ::= alias37+ + + importlists ::= importlist37+ + + stmt ::= import_as37 stmt ::= import_from37 - importlist37 ::= importlist37 alias37 - importlist37 ::= alias37 - alias37 ::= IMPORT_NAME store - alias37 ::= IMPORT_FROM store - import_from37 ::= LOAD_CONST LOAD_CONST IMPORT_NAME_ATTR importlist37 POP_TOP + stmt ::= import_from_as37 """ diff --git a/uncompyle6/parsers/parse37base.py b/uncompyle6/parsers/parse37base.py index 94d7b463..9119bbec 100644 --- a/uncompyle6/parsers/parse37base.py +++ b/uncompyle6/parsers/parse37base.py @@ -1134,6 +1134,9 @@ class Python37BaseParser(PythonParser): self.check_reduce["while1stmt"] = "noAST" self.check_reduce["while1elsestmt"] = "noAST" self.check_reduce["_ifstmts_jump"] = "AST" + self.check_reduce["import_as37"] = "tokens" + self.check_reduce["import_from_as37"] = "tokens" + self.check_reduce["import_from_as37"] = "tokens" self.check_reduce["ifelsestmt"] = "AST" self.check_reduce["ifelsestmtl"] = "AST" self.check_reduce["iflaststmt"] = "AST" @@ -1263,5 +1266,9 @@ class Python37BaseParser(PythonParser): assert store == "store" return alias37[0].attr != store[0].attr return False + elif lhs == "import_as37": + return tokens[first + 1].pattr is not None + elif lhs == "import_from_as37": + return tokens[first + 1].pattr is None return False diff --git a/uncompyle6/semantics/customize37.py b/uncompyle6/semantics/customize37.py index 38341785..976c340b 100644 --- a/uncompyle6/semantics/customize37.py +++ b/uncompyle6/semantics/customize37.py @@ -146,11 +146,18 @@ def customize_for_version37(self, version): ), "ifstmtl": ("%|if %c:\n%+%c%-", (0, "testexpr"), (1, "_ifstmts_jumpl")), 'import_as37': ( '%|import %c as %c\n', 2, -2), - 'import_from37': ( '%|from %[2]{pattr} import %c\n', - (3, 'importlist37') ), - + "import_from_as37": ( + "%|from %c as %c\n", + (2, "import_from_attr37"), + (3, "store"), + ), + "import_one": ("%c", (0, "importlists"),), "importattr37": ("%c", (0, "IMPORT_NAME_ATTR")), - + "import_from_attr37": ( + "%c import %c", + (0, "IMPORT_NAME_ATTR"), + (1, "IMPORT_FROM"), + ), "list_afor": ( " async for %[1]{%c} in %c%[1]{%c}", (1, "store"), (0, "get_aiter"), (3, "list_iter"), diff --git a/uncompyle6/semantics/n_actions.py b/uncompyle6/semantics/n_actions.py index 9506c21d..fe3053eb 100644 --- a/uncompyle6/semantics/n_actions.py +++ b/uncompyle6/semantics/n_actions.py @@ -13,7 +13,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . """ -Custom Nonterminal action functions +Custom Nonterminal action functions. See NonterminalActions docstring. """ from uncompyle6.semantics.consts import ( @@ -33,6 +33,16 @@ from uncompyle6.semantics.helper import ( ) class NonterminalActions: + """ + Methods here all start with n_ and the remaining portion should be a nonterminal + name defined by some rule. + + These methods take priority over names defined in table constants. + All of the methods should have the same signature: (self, node) and return None. + + node is the subtree of the parse tree the that nonterminal name as the root. + """ + def n_alias(self, node): if self.version <= (2, 1): if len(node) == 2: