Added support for opcodes: (in DESC)
`KW_NAMES` `POP_JUMP_FORWARD_IF_FALSE` `POP_JUMP_FORWARD_IF_TRUE` `LOAD_GLOBAL`
This commit is contained in:
18
ASTNode.h
18
ASTNode.h
@@ -18,6 +18,7 @@ public:
|
|||||||
NODE_COMPREHENSION, NODE_LOADBUILDCLASS, NODE_AWAITABLE,
|
NODE_COMPREHENSION, NODE_LOADBUILDCLASS, NODE_AWAITABLE,
|
||||||
NODE_FORMATTEDVALUE, NODE_JOINEDSTR, NODE_CONST_MAP,
|
NODE_FORMATTEDVALUE, NODE_JOINEDSTR, NODE_CONST_MAP,
|
||||||
NODE_ANNOTATED_VAR, NODE_CHAINSTORE, NODE_TERNARY,
|
NODE_ANNOTATED_VAR, NODE_CHAINSTORE, NODE_TERNARY,
|
||||||
|
NODE_KW_NAMES_MAP,
|
||||||
|
|
||||||
// Empty node types
|
// Empty node types
|
||||||
NODE_LOCALS,
|
NODE_LOCALS,
|
||||||
@@ -394,6 +395,23 @@ private:
|
|||||||
map_t m_values;
|
map_t m_values;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ASTKwNamesMap : public ASTNode {
|
||||||
|
public:
|
||||||
|
typedef std::list<std::pair<PycRef<ASTNode>, PycRef<ASTNode>>> map_t;
|
||||||
|
|
||||||
|
ASTKwNamesMap() : ASTNode(NODE_KW_NAMES_MAP) { }
|
||||||
|
|
||||||
|
void add(PycRef<ASTNode> key, PycRef<ASTNode> value)
|
||||||
|
{
|
||||||
|
m_values.emplace_back(std::move(key), std::move(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
const map_t& values() const { return m_values; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
map_t m_values;
|
||||||
|
};
|
||||||
|
|
||||||
class ASTConstMap : public ASTNode {
|
class ASTConstMap : public ASTNode {
|
||||||
public:
|
public:
|
||||||
typedef std::vector<PycRef<ASTNode>> values_t;
|
typedef std::vector<PycRef<ASTNode>> values_t;
|
||||||
|
76
ASTree.cpp
76
ASTree.cpp
@@ -123,9 +123,11 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
&& opcode != Pyc::JUMP_IF_FALSE_A
|
&& opcode != Pyc::JUMP_IF_FALSE_A
|
||||||
&& opcode != Pyc::JUMP_IF_FALSE_OR_POP_A
|
&& opcode != Pyc::JUMP_IF_FALSE_OR_POP_A
|
||||||
&& opcode != Pyc::POP_JUMP_IF_FALSE_A
|
&& opcode != Pyc::POP_JUMP_IF_FALSE_A
|
||||||
|
&& opcode != Pyc::POP_JUMP_FORWARD_IF_FALSE_A
|
||||||
&& opcode != Pyc::JUMP_IF_TRUE_A
|
&& opcode != Pyc::JUMP_IF_TRUE_A
|
||||||
&& opcode != Pyc::JUMP_IF_TRUE_OR_POP_A
|
&& opcode != Pyc::JUMP_IF_TRUE_OR_POP_A
|
||||||
&& opcode != Pyc::POP_JUMP_IF_TRUE_A
|
&& opcode != Pyc::POP_JUMP_IF_TRUE_A
|
||||||
|
&& opcode != Pyc::POP_JUMP_FORWARD_IF_TRUE_A
|
||||||
&& opcode != Pyc::POP_BLOCK) {
|
&& opcode != Pyc::POP_BLOCK) {
|
||||||
else_pop = false;
|
else_pop = false;
|
||||||
|
|
||||||
@@ -401,6 +403,19 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
stack.push(new ASTTuple(values));
|
stack.push(new ASTTuple(values));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Pyc::KW_NAMES_A:
|
||||||
|
{
|
||||||
|
|
||||||
|
int kwparams = code->getConst(operand).cast<PycTuple>()->size();
|
||||||
|
ASTKwNamesMap kwparamList;
|
||||||
|
std::vector<PycRef<PycObject>> keys = code->getConst(operand).cast<PycSimpleSequence>()->values();
|
||||||
|
for (int i = 0; i < kwparams; i++) {
|
||||||
|
kwparamList.add(new ASTObject(keys[kwparams - i - 1]), stack.top());
|
||||||
|
stack.pop();
|
||||||
|
}
|
||||||
|
stack.push(new ASTKwNamesMap(kwparamList));
|
||||||
|
}
|
||||||
|
break;
|
||||||
case Pyc::CALL_A:
|
case Pyc::CALL_A:
|
||||||
case Pyc::CALL_FUNCTION_A:
|
case Pyc::CALL_FUNCTION_A:
|
||||||
{
|
{
|
||||||
@@ -445,12 +460,31 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
stack_hist.pop();
|
stack_hist.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<kwparams; i++) {
|
/*
|
||||||
PycRef<ASTNode> val = stack.top();
|
KW_NAMES(i)
|
||||||
stack.pop();
|
Stores a reference to co_consts[consti] into an internal variable for use by CALL.
|
||||||
PycRef<ASTNode> key = stack.top();
|
co_consts[consti] must be a tuple of strings.
|
||||||
stack.pop();
|
New in version 3.11.
|
||||||
kwparamList.push_front(std::make_pair(key, val));
|
*/
|
||||||
|
if (mod->verCompare(3, 11) >= 0) {
|
||||||
|
PycRef<ASTNode> object_or_map = stack.top();
|
||||||
|
if (object_or_map.type() == ASTNode::NODE_KW_NAMES_MAP) {
|
||||||
|
stack.pop();
|
||||||
|
PycRef<ASTKwNamesMap> kwparams_map = object_or_map.cast<ASTKwNamesMap>();
|
||||||
|
for (ASTKwNamesMap::map_t::const_iterator it = kwparams_map->values().begin(); it != kwparams_map->values().end(); it++) {
|
||||||
|
kwparamList.push_front(std::make_pair(it->first, it->second));
|
||||||
|
pparams -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (int i = 0; i < kwparams; i++) {
|
||||||
|
PycRef<ASTNode> val = stack.top();
|
||||||
|
stack.pop();
|
||||||
|
PycRef<ASTNode> key = stack.top();
|
||||||
|
stack.pop();
|
||||||
|
kwparamList.push_front(std::make_pair(key, val));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (int i=0; i<pparams; i++) {
|
for (int i=0; i<pparams; i++) {
|
||||||
PycRef<ASTNode> param = stack.top();
|
PycRef<ASTNode> param = stack.top();
|
||||||
@@ -1004,13 +1038,17 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
case Pyc::JUMP_IF_TRUE_OR_POP_A:
|
case Pyc::JUMP_IF_TRUE_OR_POP_A:
|
||||||
case Pyc::POP_JUMP_IF_FALSE_A:
|
case Pyc::POP_JUMP_IF_FALSE_A:
|
||||||
case Pyc::POP_JUMP_IF_TRUE_A:
|
case Pyc::POP_JUMP_IF_TRUE_A:
|
||||||
|
case Pyc::POP_JUMP_FORWARD_IF_FALSE_A:
|
||||||
|
case Pyc::POP_JUMP_FORWARD_IF_TRUE_A:
|
||||||
{
|
{
|
||||||
PycRef<ASTNode> cond = stack.top();
|
PycRef<ASTNode> cond = stack.top();
|
||||||
PycRef<ASTCondBlock> ifblk;
|
PycRef<ASTCondBlock> ifblk;
|
||||||
int popped = ASTCondBlock::UNINITED;
|
int popped = ASTCondBlock::UNINITED;
|
||||||
|
|
||||||
if (opcode == Pyc::POP_JUMP_IF_FALSE_A
|
if (opcode == Pyc::POP_JUMP_IF_FALSE_A
|
||||||
|| opcode == Pyc::POP_JUMP_IF_TRUE_A) {
|
|| opcode == Pyc::POP_JUMP_IF_TRUE_A
|
||||||
|
|| opcode == Pyc::POP_JUMP_FORWARD_IF_FALSE_A
|
||||||
|
|| opcode == Pyc::POP_JUMP_FORWARD_IF_TRUE_A) {
|
||||||
/* Pop condition before the jump */
|
/* Pop condition before the jump */
|
||||||
stack.pop();
|
stack.pop();
|
||||||
popped = ASTCondBlock::PRE_POPPED;
|
popped = ASTCondBlock::PRE_POPPED;
|
||||||
@@ -1029,15 +1067,18 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
/* "Jump if true" means "Jump if not false" */
|
/* "Jump if true" means "Jump if not false" */
|
||||||
bool neg = opcode == Pyc::JUMP_IF_TRUE_A
|
bool neg = opcode == Pyc::JUMP_IF_TRUE_A
|
||||||
|| opcode == Pyc::JUMP_IF_TRUE_OR_POP_A
|
|| opcode == Pyc::JUMP_IF_TRUE_OR_POP_A
|
||||||
|| opcode == Pyc::POP_JUMP_IF_TRUE_A;
|
|| opcode == Pyc::POP_JUMP_IF_TRUE_A
|
||||||
|
|| opcode == Pyc::POP_JUMP_FORWARD_IF_TRUE_A;
|
||||||
|
|
||||||
int offs = operand;
|
int offs = operand;
|
||||||
if (mod->verCompare(3, 10) >= 0)
|
if (mod->verCompare(3, 10) >= 0)
|
||||||
offs *= sizeof(uint16_t); // // BPO-27129
|
offs *= sizeof(uint16_t); // // BPO-27129
|
||||||
if (opcode == Pyc::JUMP_IF_FALSE_A
|
if (opcode == Pyc::JUMP_IF_FALSE_A
|
||||||
|| opcode == Pyc::JUMP_IF_TRUE_A) {
|
|| opcode == Pyc::JUMP_IF_TRUE_A
|
||||||
|
|| opcode == Pyc::POP_JUMP_FORWARD_IF_TRUE_A
|
||||||
|
|| opcode == Pyc::POP_JUMP_FORWARD_IF_FALSE_A) {
|
||||||
/* Offset is relative in these cases */
|
/* Offset is relative in these cases */
|
||||||
offs = pos + operand;
|
offs += pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cond.type() == ASTNode::NODE_COMPARE
|
if (cond.type() == ASTNode::NODE_COMPARE
|
||||||
@@ -1455,6 +1496,21 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
|||||||
stack.push(new ASTName(code->getLocal(operand)));
|
stack.push(new ASTName(code->getLocal(operand)));
|
||||||
break;
|
break;
|
||||||
case Pyc::LOAD_GLOBAL_A:
|
case Pyc::LOAD_GLOBAL_A:
|
||||||
|
if (mod->verCompare(3, 11) >= 0) {
|
||||||
|
if (operand & 1) {
|
||||||
|
/* Changed in version 3.11:
|
||||||
|
If the low bit of "NAMEI" (operand) is set,
|
||||||
|
then a NULL is pushed to the stack before the global variable. */
|
||||||
|
stack.push(nullptr);
|
||||||
|
/*
|
||||||
|
and thats because for some reason for example 3 global functions: input, int, print.
|
||||||
|
it tries to load: 1, 3, 5
|
||||||
|
all though we have only 3 names, so thats should be: (1-1)/2 = 0, (3-1)/2 = 1, (5-1)/2 = 2
|
||||||
|
i dont know why, maybe because of the null push, but thats a FIX for now.
|
||||||
|
*/
|
||||||
|
operand = (int)((operand - 1) / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
stack.push(new ASTName(code->getName(operand)));
|
stack.push(new ASTName(code->getName(operand)));
|
||||||
break;
|
break;
|
||||||
case Pyc::LOAD_LOCALS:
|
case Pyc::LOAD_LOCALS:
|
||||||
|
@@ -152,7 +152,8 @@ bool Pyc::IsJumpOffsetArg(int opcode)
|
|||||||
return (opcode == Pyc::JUMP_FORWARD_A) || (opcode == Pyc::JUMP_IF_FALSE_A) ||
|
return (opcode == Pyc::JUMP_FORWARD_A) || (opcode == Pyc::JUMP_IF_FALSE_A) ||
|
||||||
(opcode == Pyc::JUMP_IF_TRUE_A) || (opcode == Pyc::SETUP_LOOP_A) ||
|
(opcode == Pyc::JUMP_IF_TRUE_A) || (opcode == Pyc::SETUP_LOOP_A) ||
|
||||||
(opcode == Pyc::SETUP_FINALLY_A) || (opcode == Pyc::SETUP_EXCEPT_A) ||
|
(opcode == Pyc::SETUP_FINALLY_A) || (opcode == Pyc::SETUP_EXCEPT_A) ||
|
||||||
(opcode == Pyc::FOR_LOOP_A) || (opcode == Pyc::FOR_ITER_A);
|
(opcode == Pyc::FOR_LOOP_A) || (opcode == Pyc::FOR_ITER_A) ||
|
||||||
|
(opcode == Pyc::POP_JUMP_FORWARD_IF_FALSE_A) || (opcode == Pyc::POP_JUMP_FORWARD_IF_TRUE_A);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Pyc::IsCompareArg(int opcode)
|
bool Pyc::IsCompareArg(int opcode)
|
||||||
|
BIN
tests/compiled/test_kwnames.3.11.pyc
Normal file
BIN
tests/compiled/test_kwnames.3.11.pyc
Normal file
Binary file not shown.
BIN
tests/compiled/test_pop_jump_forward_if_false.3.11.pyc
Normal file
BIN
tests/compiled/test_pop_jump_forward_if_false.3.11.pyc
Normal file
Binary file not shown.
BIN
tests/compiled/test_pop_jump_forward_if_true.3.11.pyc
Normal file
BIN
tests/compiled/test_pop_jump_forward_if_true.3.11.pyc
Normal file
Binary file not shown.
3
tests/input/test_kwnames.py
Normal file
3
tests/input/test_kwnames.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
def foo(x):
|
||||||
|
print(x)
|
||||||
|
foo(x=1)
|
3
tests/input/test_pop_jump_forward_if_false.py
Normal file
3
tests/input/test_pop_jump_forward_if_false.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
if 1 == 0:
|
||||||
|
print('true')
|
||||||
|
print('false (so jumping forward)')
|
3
tests/input/test_pop_jump_forward_if_true.py
Normal file
3
tests/input/test_pop_jump_forward_if_true.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
if not 1 == 0:
|
||||||
|
print('not true')
|
||||||
|
print('true (so jumping forward)')
|
5
tests/tokenized/test_kwnames.txt
Normal file
5
tests/tokenized/test_kwnames.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
def foo ( x ) : <EOL>
|
||||||
|
<INDENT>
|
||||||
|
print ( x ) <EOL>
|
||||||
|
<OUTDENT>
|
||||||
|
foo ( x = 1 ) <EOL>
|
5
tests/tokenized/test_pop_jump_forward_if_false.txt
Normal file
5
tests/tokenized/test_pop_jump_forward_if_false.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
if 1 == 0 : <EOL>
|
||||||
|
<INDENT>
|
||||||
|
print ( 'true' ) <EOL>
|
||||||
|
<OUTDENT>
|
||||||
|
print ( 'false (so jumping forward)' ) <EOL>
|
5
tests/tokenized/test_pop_jump_forward_if_true.txt
Normal file
5
tests/tokenized/test_pop_jump_forward_if_true.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
if not 1 == 0 : <EOL>
|
||||||
|
<INDENT>
|
||||||
|
print ( 'not true' ) <EOL>
|
||||||
|
<OUTDENT>
|
||||||
|
print ( 'true (so jumping forward)' ) <EOL>
|
Reference in New Issue
Block a user