Merge pull request #319 from Ace314159/add-set-ops
Implement BUILD_SET and SET_UPDATE
This commit is contained in:
15
ASTNode.h
15
ASTNode.h
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "pyc_module.h"
|
||||
#include <list>
|
||||
#include <deque>
|
||||
|
||||
/* Similar interface to PycObject, so PycRef can work on it... *
|
||||
* However, this does *NOT* mean the two are interchangeable! */
|
||||
@@ -12,7 +13,7 @@ public:
|
||||
NODE_INVALID, NODE_NODELIST, NODE_OBJECT, NODE_UNARY, NODE_BINARY,
|
||||
NODE_COMPARE, NODE_SLICE, NODE_STORE, NODE_RETURN, NODE_NAME,
|
||||
NODE_DELETE, NODE_FUNCTION, NODE_CLASS, NODE_CALL, NODE_IMPORT,
|
||||
NODE_TUPLE, NODE_LIST, NODE_MAP, NODE_SUBSCR, NODE_PRINT,
|
||||
NODE_TUPLE, NODE_LIST, NODE_SET, NODE_MAP, NODE_SUBSCR, NODE_PRINT,
|
||||
NODE_CONVERT, NODE_KEYWORD, NODE_RAISE, NODE_EXEC, NODE_BLOCK,
|
||||
NODE_COMPREHENSION, NODE_LOADBUILDCLASS, NODE_AWAITABLE,
|
||||
NODE_FORMATTEDVALUE, NODE_JOINEDSTR, NODE_CONST_MAP,
|
||||
@@ -358,6 +359,18 @@ private:
|
||||
value_t m_values;
|
||||
};
|
||||
|
||||
class ASTSet : public ASTNode {
|
||||
public:
|
||||
typedef std::deque<PycRef<ASTNode>> value_t;
|
||||
|
||||
ASTSet(value_t values)
|
||||
: ASTNode(NODE_SET), m_values(std::move(values)) { }
|
||||
|
||||
const value_t& values() const { return m_values; }
|
||||
|
||||
private:
|
||||
value_t m_values;
|
||||
};
|
||||
|
||||
class ASTMap : public ASTNode {
|
||||
public:
|
||||
|
55
ASTree.cpp
55
ASTree.cpp
@@ -322,6 +322,16 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
stack.push(new ASTList(values));
|
||||
}
|
||||
break;
|
||||
case Pyc::BUILD_SET_A:
|
||||
{
|
||||
ASTSet::value_t values;
|
||||
for (int i=0; i<operand; i++) {
|
||||
values.push_front(stack.top());
|
||||
stack.pop();
|
||||
}
|
||||
stack.push(new ASTSet(values));
|
||||
}
|
||||
break;
|
||||
case Pyc::BUILD_MAP_A:
|
||||
if (mod->verCompare(3, 5) >= 0) {
|
||||
auto map = new ASTMap;
|
||||
@@ -1547,6 +1557,33 @@ PycRef<ASTNode> BuildFromCode(PycRef<PycCode> code, PycModule* mod)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Pyc::SET_UPDATE_A:
|
||||
{
|
||||
PycRef<ASTNode> rhs = stack.top();
|
||||
stack.pop();
|
||||
PycRef<ASTSet> lhs = stack.top().cast<ASTSet>();
|
||||
stack.pop();
|
||||
|
||||
if (rhs.type() != ASTNode::NODE_OBJECT) {
|
||||
fprintf(stderr, "Unsupported argument found for SET_UPDATE\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// I've only ever seen this be a TYPE_FROZENSET, but let's be careful...
|
||||
PycRef<PycObject> obj = rhs.cast<ASTObject>()->object();
|
||||
if (obj->type() != PycObject::TYPE_FROZENSET) {
|
||||
fprintf(stderr, "Unsupported argument type found for SET_UPDATE\n");
|
||||
break;
|
||||
}
|
||||
|
||||
ASTSet::value_t result = lhs->values();
|
||||
for (const auto& it : obj.cast<PycSet>()->values()) {
|
||||
result.push_back(new ASTObject(it));
|
||||
}
|
||||
|
||||
stack.push(new ASTSet(result));
|
||||
}
|
||||
break;
|
||||
case Pyc::LIST_EXTEND_A:
|
||||
{
|
||||
PycRef<ASTNode> rhs = stack.top();
|
||||
@@ -2838,6 +2875,24 @@ void print_src(PycRef<ASTNode> node, PycModule* mod)
|
||||
fputs("]", pyc_output);
|
||||
}
|
||||
break;
|
||||
case ASTNode::NODE_SET:
|
||||
{
|
||||
fputs("{", pyc_output);
|
||||
bool first = true;
|
||||
cur_indent++;
|
||||
for (const auto& val : node.cast<ASTSet>()->values()) {
|
||||
if (first)
|
||||
fputs("\n", pyc_output);
|
||||
else
|
||||
fputs(",\n", pyc_output);
|
||||
start_line(cur_indent);
|
||||
print_src(val, mod);
|
||||
first = false;
|
||||
}
|
||||
cur_indent--;
|
||||
fputs("}", pyc_output);
|
||||
}
|
||||
break;
|
||||
case ASTNode::NODE_COMPREHENSION:
|
||||
{
|
||||
PycRef<ASTComprehension> comp = node.cast<ASTComprehension>();
|
||||
|
17
bytecode.cpp
17
bytecode.cpp
@@ -257,6 +257,21 @@ void print_const(PycRef<PycObject> obj, PycModule* mod, const char* parent_f_str
|
||||
fputs("}", pyc_output);
|
||||
}
|
||||
break;
|
||||
case PycObject::TYPE_FROZENSET:
|
||||
{
|
||||
fputs("frozenset({", pyc_output);
|
||||
PycSet::value_t values = obj.cast<PycSet>()->values();
|
||||
auto it = values.cbegin();
|
||||
if (it != values.cend()) {
|
||||
print_const(*it, mod);
|
||||
while (++it != values.cend()) {
|
||||
fputs(", ", pyc_output);
|
||||
print_const(*it, mod);
|
||||
}
|
||||
}
|
||||
fputs("})", pyc_output);
|
||||
}
|
||||
break;
|
||||
case PycObject::TYPE_NONE:
|
||||
fputs("None", pyc_output);
|
||||
break;
|
||||
@@ -312,6 +327,8 @@ void print_const(PycRef<PycObject> obj, PycModule* mod, const char* parent_f_str
|
||||
case PycObject::TYPE_CODE2:
|
||||
fprintf(pyc_output, "<CODE> %s", obj.cast<PycCode>()->name()->value());
|
||||
break;
|
||||
default:
|
||||
fprintf(pyc_output, "<TYPE: %d>\n", obj->type());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -211,6 +211,14 @@ void output_object(PycRef<PycObject> obj, PycModule* mod, int indent,
|
||||
iputs(indent, "}\n");
|
||||
}
|
||||
break;
|
||||
case PycObject::TYPE_FROZENSET:
|
||||
{
|
||||
iputs(indent, "frozenset({\n");
|
||||
for (const auto& val : obj.cast<PycSet>()->values())
|
||||
output_object(val, mod, indent + 1, flags);
|
||||
iputs(indent, "})\n");
|
||||
}
|
||||
break;
|
||||
case PycObject::TYPE_NONE:
|
||||
iputs(indent, "None\n");
|
||||
break;
|
||||
|
BIN
tests/compiled/test_sets.3.10.pyc
Normal file
BIN
tests/compiled/test_sets.3.10.pyc
Normal file
Binary file not shown.
5
tests/input/test_sets.py
Normal file
5
tests/input/test_sets.py
Normal file
@@ -0,0 +1,5 @@
|
||||
a = set()
|
||||
b = {1, 2}
|
||||
c = {"AB", "CD"}
|
||||
# Below uses SET_UPDATE
|
||||
d = {1, 2, 3, 4}
|
4
tests/tokenized/test_sets.txt
Normal file
4
tests/tokenized/test_sets.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
a = set ( ) <EOL>
|
||||
b = { 1 , 2 } <EOL>
|
||||
c = { 'AB' , 'CD' } <EOL>
|
||||
d = { 2 , 1 , 3 , 4 } <EOL>
|
Reference in New Issue
Block a user