From 755c16fc4678df9264103122ccff014d18cb48bc Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 7 Mar 2024 17:42:09 -0500 Subject: [PATCH 1/2] Handle degenerate "with_as: pass" --- decompyle3/parsers/p37/base.py | 2 ++ decompyle3/parsers/p38/full_custom.py | 7 +++++++ decompyle3/semantics/consts.py | 9 ++++++--- decompyle3/semantics/customize38.py | 14 ++++++++++---- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/decompyle3/parsers/p37/base.py b/decompyle3/parsers/p37/base.py index 416c7d68..2069419b 100644 --- a/decompyle3/parsers/p37/base.py +++ b/decompyle3/parsers/p37/base.py @@ -1003,6 +1003,7 @@ def customize_grammar_rules37(self, tokens, customize): elif opname == "SETUP_WITH": rules_str = """ stmt ::= with + stmt ::= with_as_pass stmt ::= withasstmt c_stmt ::= c_with @@ -1040,6 +1041,7 @@ def customize_grammar_rules37(self, tokens, customize): SETUP_WITH store suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix + """ if self.version < (3, 8): rules_str += """ diff --git a/decompyle3/parsers/p38/full_custom.py b/decompyle3/parsers/p38/full_custom.py index 3258c35c..da498c02 100644 --- a/decompyle3/parsers/p38/full_custom.py +++ b/decompyle3/parsers/p38/full_custom.py @@ -660,7 +660,9 @@ def customize_grammar_rules_full38(self, tokens, customize): elif opname == "SETUP_WITH": rules_str = """ stmt ::= with + stmt ::= with_as_pass stmt ::= withasstmt + c_stmt ::= c_with c_with ::= expr SETUP_WITH POP_TOP @@ -697,6 +699,11 @@ def customize_grammar_rules_full38(self, tokens, customize): SETUP_WITH store suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix + + with_as_pass ::= expr + SETUP_WITH store pass + POP_BLOCK BEGIN_FINALLY COME_FROM_WITH + with_suffix """ if self.version < (3, 8): rules_str += """ diff --git a/decompyle3/semantics/consts.py b/decompyle3/semantics/consts.py index 3c84bbe3..466d9876 100644 --- a/decompyle3/semantics/consts.py +++ b/decompyle3/semantics/consts.py @@ -271,8 +271,6 @@ (2, NO_PARENTHESIS_EVER) ), - "IMPORT_FROM": ("%{pattr}",), - "IMPORT_NAME_ATTR": ("%{pattr}",), "attribute": ("%c.%[1]{pattr}", (0, "expr")), "delete_subscript": ( "%|del %p[%c]\n", @@ -580,7 +578,12 @@ # If there are situations where we need "with ... as ()" # We may need to customize this in n_withasstmt - "withasstmt": ("%|with %c as %c:\n%+%c%-", 0, 2, 3), + "withasstmt": ( + "%|with %c as %c:\n%+%c%-", + (0, "expr"), + (2, "store"), + (3, "suite_stmts_opt"), + ), } # fmt: on diff --git a/decompyle3/semantics/customize38.py b/decompyle3/semantics/customize38.py index e5ee05f9..5e11db8b 100644 --- a/decompyle3/semantics/customize38.py +++ b/decompyle3/semantics/customize38.py @@ -1,4 +1,4 @@ -# Copyright (c) 2019-2023 by Rocky Bernstein +# Copyright (c) 2019-2024 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 @@ -153,6 +153,11 @@ def customize_for_version38(self, version): -2, ), "list_if_not38": (" if not %c", (2, "expr", PRECEDENCE["unary_not"])), + "named_expr": ( # AKA "walrus operator" + "%c := %p", + (2, "store"), + (0, "expr", PRECEDENCE["named_expr"] - 1), + ), "or_in_ifexp": ( "%c or %c", (0, ("or_in_ifexp", "expr_pjit")), @@ -315,10 +320,11 @@ def customize_for_version38(self, version): (2, "suite_stmts_opt"), (8, "suite_stmts_opt"), ), - "named_expr": ( # AKA "walrus operator" - "%c := %p", + "with_as_pass": ( + "%|with %c as %c:\n%+%c%-", + (0, "expr"), (2, "store"), - (0, "expr", PRECEDENCE["named_expr"] - 1), + (3, "pass"), ), } ) From 190c068f4bfef140797bf7ff1b619d64d0bf902a Mon Sep 17 00:00:00 2001 From: rocky Date: Thu, 7 Mar 2024 18:22:58 -0500 Subject: [PATCH 2/2] withasstmt -> with_as Matches AST a little closer and is not as confusing a name --- decompyle3/parsers/p37/base.py | 14 +++---- decompyle3/parsers/p37/lambda_custom.py | 2 +- decompyle3/parsers/p38/full_custom.py | 36 +++++++++--------- decompyle3/parsers/p38/lambda_custom.py | 4 +- decompyle3/parsers/p38pypy/full_custom.py | 36 +++++++++--------- decompyle3/parsers/p38pypy/lambda_custom.py | 2 +- decompyle3/semantics/consts.py | 6 +-- decompyle3/semantics/transform.py | 2 +- .../run/08_test_contextmanager.pyc | Bin 0 -> 843 bytes .../run/08_test_contextmanager.pyc | Bin 0 -> 852 bytes .../stmts/08_test_contextmanager.py | 21 ++++++++++ 11 files changed, 73 insertions(+), 50 deletions(-) create mode 100644 test/bytecode_3.7/run/08_test_contextmanager.pyc create mode 100644 test/bytecode_3.8/run/08_test_contextmanager.pyc create mode 100644 test/simple_source/stmts/08_test_contextmanager.py diff --git a/decompyle3/parsers/p37/base.py b/decompyle3/parsers/p37/base.py index 2069419b..2bb7594a 100644 --- a/decompyle3/parsers/p37/base.py +++ b/decompyle3/parsers/p37/base.py @@ -1004,7 +1004,7 @@ def customize_grammar_rules37(self, tokens, customize): rules_str = """ stmt ::= with stmt ::= with_as_pass - stmt ::= withasstmt + stmt ::= with_as c_stmt ::= c_with c_with ::= expr SETUP_WITH POP_TOP @@ -1021,14 +1021,14 @@ def customize_grammar_rules37(self, tokens, customize): COME_FROM_WITH with_suffix - withasstmt ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH + with_as ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH with_suffix with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix @@ -1037,7 +1037,7 @@ def customize_grammar_rules37(self, tokens, customize): SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix @@ -1067,16 +1067,16 @@ def customize_grammar_rules37(self, tokens, customize): with_suffix - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts POP_BLOCK LOAD_CONST COME_FROM_WITH - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts POP_BLOCK BEGIN_FINALLY COME_FROM_WITH with_suffix - # withasstmt ::= expr SETUP_WITH store suite_stmts + # with_as ::= expr SETUP_WITH store suite_stmts # COME_FROM expr COME_FROM POP_BLOCK ROT_TWO # BEGIN_FINALLY WITH_CLEANUP_START WITH_CLEANUP_FINISH # POP_FINALLY RETURN_VALUE COME_FROM_WITH diff --git a/decompyle3/parsers/p37/lambda_custom.py b/decompyle3/parsers/p37/lambda_custom.py index 2ff1ee06..617cb8da 100644 --- a/decompyle3/parsers/p37/lambda_custom.py +++ b/decompyle3/parsers/p37/lambda_custom.py @@ -542,7 +542,7 @@ def customize_grammar_rules_lambda37(self, tokens, customize): 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 + with_as ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY """ if self.version < (3, 8): diff --git a/decompyle3/parsers/p38/full_custom.py b/decompyle3/parsers/p38/full_custom.py index da498c02..359a3057 100644 --- a/decompyle3/parsers/p38/full_custom.py +++ b/decompyle3/parsers/p38/full_custom.py @@ -661,7 +661,7 @@ def customize_grammar_rules_full38(self, tokens, customize): rules_str = """ stmt ::= with stmt ::= with_as_pass - stmt ::= withasstmt + stmt ::= with_as c_stmt ::= c_with @@ -679,23 +679,25 @@ def customize_grammar_rules_full38(self, tokens, customize): COME_FROM_WITH with_suffix - withasstmt ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH + with ::= expr + SETUP_WITH POP_TOP suite_stmts_opt + POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix - withasstmt ::= expr + + with_as ::= expr SETUP_WITH store suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix - with ::= expr - SETUP_WITH POP_TOP suite_stmts_opt - POP_BLOCK LOAD_CONST COME_FROM_WITH + with_as ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH with_suffix - withasstmt ::= expr + + with_as ::= expr SETUP_WITH store suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix @@ -729,16 +731,16 @@ def customize_grammar_rules_full38(self, tokens, customize): with_suffix - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts POP_BLOCK LOAD_CONST COME_FROM_WITH - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts POP_BLOCK BEGIN_FINALLY COME_FROM_WITH with_suffix - # withasstmt ::= expr SETUP_WITH store suite_stmts + # with_as ::= expr SETUP_WITH store suite_stmts # COME_FROM expr COME_FROM POP_BLOCK ROT_TWO # BEGIN_FINALLY WITH_CLEANUP_START WITH_CLEANUP_FINISH # POP_FINALLY RETURN_VALUE COME_FROM_WITH @@ -1229,7 +1231,7 @@ def customize_grammar_rules38(self, tokens, customize): elif opname == "SETUP_WITH": rules_str = """ stmt ::= with - stmt ::= withasstmt + stmt ::= with_as c_stmt ::= c_with c_with ::= expr SETUP_WITH POP_TOP @@ -1246,14 +1248,14 @@ def customize_grammar_rules38(self, tokens, customize): COME_FROM_WITH with_suffix - withasstmt ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH + with_as ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH with_suffix with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix @@ -1262,7 +1264,7 @@ def customize_grammar_rules38(self, tokens, customize): SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix @@ -1291,16 +1293,16 @@ def customize_grammar_rules38(self, tokens, customize): with_suffix - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts POP_BLOCK LOAD_CONST COME_FROM_WITH - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts POP_BLOCK BEGIN_FINALLY COME_FROM_WITH with_suffix - # withasstmt ::= expr SETUP_WITH store suite_stmts + # with_as ::= expr SETUP_WITH store suite_stmts # COME_FROM expr COME_FROM POP_BLOCK ROT_TWO # BEGIN_FINALLY WITH_CLEANUP_START WITH_CLEANUP_FINISH # POP_FINALLY RETURN_VALUE COME_FROM_WITH diff --git a/decompyle3/parsers/p38/lambda_custom.py b/decompyle3/parsers/p38/lambda_custom.py index c646c909..717eea1b 100644 --- a/decompyle3/parsers/p38/lambda_custom.py +++ b/decompyle3/parsers/p38/lambda_custom.py @@ -612,8 +612,8 @@ def customize_grammar_rules_lambda38(self, tokens, customize): 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 - WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY + with_as ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH +a WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY """ if self.version < (3, 8): rules_str += """ diff --git a/decompyle3/parsers/p38pypy/full_custom.py b/decompyle3/parsers/p38pypy/full_custom.py index a0f54c01..c1a4084b 100644 --- a/decompyle3/parsers/p38pypy/full_custom.py +++ b/decompyle3/parsers/p38pypy/full_custom.py @@ -660,7 +660,7 @@ def customize_grammar_rules_full38(self, tokens, customize): elif opname == "SETUP_WITH": rules_str = """ stmt ::= with - stmt ::= withasstmt + stmt ::= with_as c_stmt ::= c_with c_with ::= expr SETUP_WITH POP_TOP @@ -677,14 +677,14 @@ def customize_grammar_rules_full38(self, tokens, customize): COME_FROM_WITH with_suffix - withasstmt ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH + with_as ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH with_suffix with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix @@ -693,7 +693,7 @@ def customize_grammar_rules_full38(self, tokens, customize): SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix @@ -722,16 +722,16 @@ def customize_grammar_rules_full38(self, tokens, customize): with_suffix - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts POP_BLOCK LOAD_CONST COME_FROM_WITH - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts POP_BLOCK BEGIN_FINALLY COME_FROM_WITH with_suffix - # withasstmt ::= expr SETUP_WITH store suite_stmts + # with_as ::= expr SETUP_WITH store suite_stmts # COME_FROM expr COME_FROM POP_BLOCK ROT_TWO # BEGIN_FINALLY WITH_CLEANUP_START WITH_CLEANUP_FINISH # POP_FINALLY RETURN_VALUE COME_FROM_WITH @@ -1222,7 +1222,7 @@ def customize_grammar_rules38(self, tokens, customize): elif opname == "SETUP_WITH": rules_str = """ stmt ::= with - stmt ::= withasstmt + stmt ::= with_as c_stmt ::= c_with c_with ::= expr SETUP_WITH POP_TOP @@ -1239,14 +1239,14 @@ def customize_grammar_rules38(self, tokens, customize): COME_FROM_WITH with_suffix - withasstmt ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH + with_as ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH with_suffix with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix @@ -1255,7 +1255,7 @@ def customize_grammar_rules38(self, tokens, customize): SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts_opt POP_BLOCK LOAD_CONST COME_FROM_WITH with_suffix @@ -1284,20 +1284,20 @@ def customize_grammar_rules38(self, tokens, customize): with_suffix - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts POP_BLOCK LOAD_CONST COME_FROM_WITH - withasstmt ::= expr + with_as ::= expr SETUP_WITH store suite_stmts POP_BLOCK BEGIN_FINALLY COME_FROM_WITH with_suffix - # withasstmt ::= expr SETUP_WITH store suite_stmts - # COME_FROM expr COME_FROM POP_BLOCK ROT_TWO - # BEGIN_FINALLY WITH_CLEANUP_START WITH_CLEANUP_FINISH - # POP_FINALLY RETURN_VALUE COME_FROM_WITH - # WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY + # with_as ::= expr SETUP_WITH store suite_stmts + # COME_FROM expr COME_FROM POP_BLOCK ROT_TWO + # BEGIN_FINALLY WITH_CLEANUP_START WITH_CLEANUP_FINISH + # POP_FINALLY RETURN_VALUE COME_FROM_WITH + # WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK BEGIN_FINALLY COME_FROM_WITH diff --git a/decompyle3/parsers/p38pypy/lambda_custom.py b/decompyle3/parsers/p38pypy/lambda_custom.py index 9c58a512..ee337ade 100644 --- a/decompyle3/parsers/p38pypy/lambda_custom.py +++ b/decompyle3/parsers/p38pypy/lambda_custom.py @@ -623,7 +623,7 @@ def customize_grammar_rules_lambda38(self, tokens, customize): 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 + with_as ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY """ if self.version < (3, 8): diff --git a/decompyle3/semantics/consts.py b/decompyle3/semantics/consts.py index 466d9876..429dedf8 100644 --- a/decompyle3/semantics/consts.py +++ b/decompyle3/semantics/consts.py @@ -577,12 +577,12 @@ "import_from_star": ("%|from %[2]{pattr} import *\n",), # If there are situations where we need "with ... as ()" - # We may need to customize this in n_withasstmt - "withasstmt": ( + # We may need to customize this in n_with_as + "with_as": ( "%|with %c as %c:\n%+%c%-", (0, "expr"), (2, "store"), - (3, "suite_stmts_opt"), + (3, ("suite_stmts_opt", "_stmts")), ), } diff --git a/decompyle3/semantics/transform.py b/decompyle3/semantics/transform.py index d1032dae..5a04dc4d 100644 --- a/decompyle3/semantics/transform.py +++ b/decompyle3/semantics/transform.py @@ -67,7 +67,7 @@ # "return_expr", # "set_comp_func", "tryfinallystmt", - "withasstmt", + "with_as", ) diff --git a/test/bytecode_3.7/run/08_test_contextmanager.pyc b/test/bytecode_3.7/run/08_test_contextmanager.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e3f7b00eaf2dea34b0c05cfcd01f60490bd35ecc GIT binary patch literal 843 zcmZ`%J#Q015Z&EdpD!kH5g`glVI+jOf`l>!LV*ZTAS?k9ple2#+p%NCcV~9b$cbFx z6m;e%gp$9sEmimlRLtBF10swxZ|8PC-rLbV+1Tg^vg-MF{49m|#vhl)nLToMPGCeL zo(Ut3Iuk}MR3cGfu#n4cqEWj$RqLaCD@^cGyb|xkuiQ4}nyQ;gi2A(!MPSHytlXQw zJO1dE3$eUQo#FC^6iDYl8BHCZ{?}oG*CKA6_BsbgBiEbQa%j`MN1?;ufVV`Yk>J#x22fFhCfLe;!42~1%0nMky0(d5u?9-yoC%c8mW8p{vDnxa}P!} wpG1gh5Z>L}vo9ub5k(Y`!bk|=0*59N1wug)qCi*z!jG<5U2ezDDZV?iyN;a5 z6;45C9wC%@rERIgBTzAOM@%BZNHaG(voqf}v-f^&t;JB>tDo?VGxmcHSB0`WsP+tv zW-)uoG}q#kX)zZu2LZvHFWRvLY45x63;)Qr*&FtjePVxdJn8e|WJ z{cyeFN-dwW#RIHtEN*iK_#FrxV8z$}RcQH+b;FZRYwsYlov|s0CdoVKS{MyF=>epN zSuwoVN^y>BBJi|>YB$jUi#bjy>KWre2U?!8Sn3eFH~jh@Shrgi4yNvPQY1q#DQ;~k zygd!@d%VHCnkk0>vCte9zRhI@l;v^ z<~3k%eC$`00wiISYGMmZZ5cn={FhyCc`+qAmqI>i#d8&%8JqE$m<0pcBJWqEy3#Z- z31XFR7#hrQdQK;atsB5 y4zdb}C%*mMS}-mvixvZT=g^jlzon literal 0 HcmV?d00001 diff --git a/test/simple_source/stmts/08_test_contextmanager.py b/test/simple_source/stmts/08_test_contextmanager.py new file mode 100644 index 00000000..9a6ea5f9 --- /dev/null +++ b/test/simple_source/stmts/08_test_contextmanager.py @@ -0,0 +1,21 @@ +""" +This program is self checking! +""" + + +class TestContextManager: + def __enter__(self): + return 1, 2 + + def __exit__(self, exc_type, exc_value, exc_tb): + return self, exc_type, exc_value, exc_tb + + +with open(__file__) as a: + assert a + +with open(__file__) as a, open(__file__) as b: + assert a.read() == b.read() + +with TestContextManager() as a, b: + assert (a, b) == (1, 2)