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.<locals>.my_class` instead of `my_class`) which makes the check `srcString->isEqual(code->name().cast<PycObject>())` be invalid.
This commit is contained in:
10
ASTree.cpp
10
ASTree.cpp
@@ -394,6 +394,12 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
break;
|
break;
|
||||||
case Pyc::BUILD_TUPLE_A:
|
case Pyc::BUILD_TUPLE_A:
|
||||||
{
|
{
|
||||||
|
// if class is a closure code, ignore this tuple
|
||||||
|
PycRef<ASTNode> tos = stack.top();
|
||||||
|
if (tos->type() == ASTNode::NODE_LOADBUILDCLASS) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ASTTuple::value_t values;
|
ASTTuple::value_t values;
|
||||||
values.resize(operand);
|
values.resize(operand);
|
||||||
for (int i=0; i<operand; i++) {
|
for (int i=0; i<operand; i++) {
|
||||||
@@ -1501,6 +1507,7 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Pyc::LOAD_DEREF_A:
|
case Pyc::LOAD_DEREF_A:
|
||||||
|
case Pyc::LOAD_CLASSDEREF_A:
|
||||||
stack.push(new ASTName(code->getCellVar(mod, operand)));
|
stack.push(new ASTName(code->getCellVar(mod, operand)));
|
||||||
break;
|
break;
|
||||||
case Pyc::LOAD_FAST_A:
|
case Pyc::LOAD_FAST_A:
|
||||||
@@ -3358,8 +3365,7 @@ void decompyle(PycRef<PycCode> code, PycModule* mod, std::ostream& pyc_output)
|
|||||||
PycRef<ASTObject> src = store->src().cast<ASTObject>();
|
PycRef<ASTObject> src = store->src().cast<ASTObject>();
|
||||||
PycRef<PycString> srcString = src->object().try_cast<PycString>();
|
PycRef<PycString> srcString = src->object().try_cast<PycString>();
|
||||||
PycRef<ASTName> dest = store->dest().cast<ASTName>();
|
PycRef<ASTName> dest = store->dest().cast<ASTName>();
|
||||||
if (srcString != nullptr && srcString->isEqual(code->name().cast<PycObject>())
|
if (dest->name()->isEqual("__qualname__")) {
|
||||||
&& dest->name()->isEqual("__qualname__")) {
|
|
||||||
// __qualname__ = '<Class Name>'
|
// __qualname__ = '<Class Name>'
|
||||||
// Automatically added by Python 3.3 and later
|
// Automatically added by Python 3.3 and later
|
||||||
clean->removeFirst();
|
clean->removeFirst();
|
||||||
|
BIN
tests/compiled/load_classderef.3.4.pyc
Normal file
BIN
tests/compiled/load_classderef.3.4.pyc
Normal file
Binary file not shown.
4
tests/input/load_classderef.py
Normal file
4
tests/input/load_classderef.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
def func():
|
||||||
|
x = 1
|
||||||
|
class my_class:
|
||||||
|
y = x
|
6
tests/tokenized/load_classderef.txt
Normal file
6
tests/tokenized/load_classderef.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
def func ( ) : <EOL>
|
||||||
|
<INDENT>
|
||||||
|
x = 1 <EOL>
|
||||||
|
class my_class : <EOL>
|
||||||
|
<INDENT>
|
||||||
|
y = x <EOL>
|
Reference in New Issue
Block a user