From 00d4b02d1e965efa296dd194a6ada5fb305a300c Mon Sep 17 00:00:00 2001 From: MrDakik Date: Mon, 26 Feb 2024 16:52:31 +0200 Subject: [PATCH] Added support for `LOAD_CLASSDEREF` The opcode itself is exactly the same as `LOAD_DEREF` 1) The problem is when the class is a closure (e.g. defined inside a function body) then there is a `BUILD_TUPLE` after the `LOAD_BUILD_CLASS` which makes problems. 2) There is another problem which makes the `code->name()` of the class to be part of the function locals. (e.g. `func..my_class` instead of `my_class`) which makes the check `srcString->isEqual(code->name().cast())` be invalid. --- ASTree.cpp | 10 ++++++++-- tests/compiled/load_classderef.3.4.pyc | Bin 0 -> 399 bytes tests/input/load_classderef.py | 4 ++++ tests/tokenized/load_classderef.txt | 6 ++++++ 4 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 tests/compiled/load_classderef.3.4.pyc create mode 100644 tests/input/load_classderef.py create mode 100644 tests/tokenized/load_classderef.txt diff --git a/ASTree.cpp b/ASTree.cpp index d76fd495d..0cc1314a3 100644 --- a/ASTree.cpp +++ b/ASTree.cpp @@ -394,6 +394,12 @@ PycRef BuildFromCode(PycRef code, PycModule* mod) break; case Pyc::BUILD_TUPLE_A: { + // if class is a closure code, ignore this tuple + PycRef tos = stack.top(); + if (tos->type() == ASTNode::NODE_LOADBUILDCLASS) { + break; + } + ASTTuple::value_t values; values.resize(operand); for (int i=0; i BuildFromCode(PycRef code, PycModule* mod) } break; case Pyc::LOAD_DEREF_A: + case Pyc::LOAD_CLASSDEREF_A: stack.push(new ASTName(code->getCellVar(mod, operand))); break; case Pyc::LOAD_FAST_A: @@ -3358,8 +3365,7 @@ void decompyle(PycRef code, PycModule* mod, std::ostream& pyc_output) PycRef src = store->src().cast(); PycRef srcString = src->object().try_cast(); PycRef dest = store->dest().cast(); - if (srcString != nullptr && srcString->isEqual(code->name().cast()) - && dest->name()->isEqual("__qualname__")) { + if (dest->name()->isEqual("__qualname__")) { // __qualname__ = '' // Automatically added by Python 3.3 and later clean->removeFirst(); diff --git a/tests/compiled/load_classderef.3.4.pyc b/tests/compiled/load_classderef.3.4.pyc new file mode 100644 index 0000000000000000000000000000000000000000..899e91fb6bf0d9bf3412d32e01abb47bec8b8b50 GIT binary patch literal 399 zcmY+Aze>bF5XNV-;fx`ISlkN;2iv5vJq|m&G}qZIOR}jpmorPi2v&+>?@RbZ!nRg6 zK7f_q?45@WnQuNO`#^S)&_6KvSed z`f~^tz7SnK6SaaDHp;xHnv1^sw&D(KP zmrK{z#`#s*O}ci*`%0xD(|Th%t98h=?)qkQ>#Pmi=1aUjeu*>(E>rJzp z(AdGY<#r0$@6323euhE}$0!j||NRm7Ge}7JV0;J9uR&rah8(p5z%{~uBr@4@cg$7f G82bTswMrNO literal 0 HcmV?d00001 diff --git a/tests/input/load_classderef.py b/tests/input/load_classderef.py new file mode 100644 index 000000000..18fdd643d --- /dev/null +++ b/tests/input/load_classderef.py @@ -0,0 +1,4 @@ +def func(): + x = 1 + class my_class: + y = x \ No newline at end of file diff --git a/tests/tokenized/load_classderef.txt b/tests/tokenized/load_classderef.txt new file mode 100644 index 000000000..b8150433c --- /dev/null +++ b/tests/tokenized/load_classderef.txt @@ -0,0 +1,6 @@ +def func ( ) : + +x = 1 +class my_class : + +y = x