This commit is contained in:
blueloveTH 2024-01-19 19:13:10 +08:00
parent 19b2eda72a
commit 8d3bb6faa5
4 changed files with 82 additions and 100 deletions

View File

@ -144,6 +144,9 @@ public:
PyObject* _last_exception; // last exception
PyObject* _curr_class; // current class being defined
// this is for repr() recursion detection (no need to mark)
std::set<PyObject*> _repr_recursion_set;
// cached code objects for FSTRING_EVAL
std::map<std::string_view, CodeObject_> _cached_codes;

View File

@ -57,7 +57,6 @@ namespace pkpy
void insertObj(bool front, bool back, int index, PyObject *item); // insert at index, used purely for internal purposes: append, appendleft, insert methods
PyObject *popObj(bool front, bool back, PyObject *item, VM *vm); // pop at index, used purely for internal purposes: pop, popleft, remove methods
int findIndex(VM *vm, PyObject *obj, int start, int stop); // find the index of the given object in the deque
std::string getRepr(VM *vm, PyObject* thisObj); // get the string representation of the deque
// Special methods
static void _register(VM *vm, PyObject *mod, PyObject *type); // register the type
void _gc_mark() const; // needed for container types, mark all objects in the deque for gc
@ -74,80 +73,76 @@ namespace pkpy
});
// gets the item at the given index, if index is negative, it will be treated as index + len(deque)
// if the index is out of range, IndexError will be thrown --> required for [] operator
vm->bind(type, "__getitem__(self, index) -> PyObject",
[](VM *vm, ArgsView args)
{
PyDeque &self = _CAST(PyDeque &, args[0]);
int index = CAST(int, args[1]);
index = vm->normalized_index(index, self.dequeItems.size()); // error is handled by the vm->normalized_index
return self.dequeItems.at(index);
});
vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM *vm, PyObject* _0, PyObject* _1)
{
PyDeque &self = _CAST(PyDeque &, _0);
int index = CAST(int, _1);
index = vm->normalized_index(index, self.dequeItems.size()); // error is handled by the vm->normalized_index
return self.dequeItems.at(index);
});
// sets the item at the given index, if index is negative, it will be treated as index + len(deque)
// if the index is out of range, IndexError will be thrown --> required for [] operator
vm->bind(type, "__setitem__(self, index, newValue) -> None",
[](VM *vm, ArgsView args)
{
PyDeque &self = _CAST(PyDeque &, args[0]);
int index = CAST(int, args[1]);
PyObject *newValue = args[2];
index = vm->normalized_index(index, self.dequeItems.size()); // error is handled by the vm->normalized_index
self.dequeItems.at(index) = newValue;
return vm->None;
});
vm->bind__setitem__(PK_OBJ_GET(Type, type), [](VM *vm, PyObject* _0, PyObject* _1, PyObject* _2)
{
PyDeque &self = _CAST(PyDeque&, _0);
int index = CAST(int, _1);
index = vm->normalized_index(index, self.dequeItems.size()); // error is handled by the vm->normalized_index
self.dequeItems.at(index) = _2;
});
// erases the item at the given index, if index is negative, it will be treated as index + len(deque)
// if the index is out of range, IndexError will be thrown --> required for [] operator
vm->bind(type, "__delitem__(self, index) -> None",
[](VM *vm, ArgsView args)
{
PyDeque &self = _CAST(PyDeque &, args[0]);
int index = CAST(int, args[1]);
index = vm->normalized_index(index, self.dequeItems.size()); // error is handled by the vm->normalized_index
self.dequeItems.erase(self.dequeItems.begin() + index);
return vm->None;
});
// returns the length of the deque
vm->bind(type, "__len__(self) -> int",
[](VM *vm, ArgsView args)
{
PyDeque &self = _CAST(PyDeque &, args[0]);
return VAR(self.dequeItems.size());
});
// returns an iterator for the deque
vm->bind(type, "__iter__(self) -> deque_iterator",
[](VM *vm, ArgsView args)
{
PyDeque &self = _CAST(PyDeque &, args[0]);
return vm->heap.gcnew<PyDequeIter>(
PyDequeIter::_type(vm), args[0],
self.dequeItems.begin(), self.dequeItems.end());
});
// returns a string representation of the deque
vm->bind(type, "__repr__(self) -> str",
[](VM *vm, ArgsView args)
{
PyDeque &self = _CAST(PyDeque &, args[0]);
return VAR(self.getRepr(vm, args[0]));
});
// returns a string representation of the deque
vm->bind(type, "__str__(self) -> str",
[](VM *vm, ArgsView args)
{
PyDeque &self = _CAST(PyDeque &, args[0]);
return VAR(self.getRepr(vm, args[0]));
});
vm->bind__delitem__(PK_OBJ_GET(Type, type), [](VM *vm, PyObject* _0, PyObject* _1)
{
PyDeque &self = _CAST(PyDeque&, _0);
int index = CAST(int, _1);
index = vm->normalized_index(index, self.dequeItems.size()); // error is handled by the vm->normalized_index
self.dequeItems.erase(self.dequeItems.begin() + index);
});
vm->bind__len__(PK_OBJ_GET(Type, type), [](VM *vm, PyObject* _0)
{
PyDeque &self = _CAST(PyDeque&, _0);
return (i64)self.dequeItems.size();
});
vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM *vm, PyObject* _0)
{
PyDeque &self = _CAST(PyDeque &, _0);
return vm->heap.gcnew<PyDequeIter>(
PyDequeIter::_type(vm), _0,
self.dequeItems.begin(), self.dequeItems.end());
});
vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM *vm, PyObject* _0)
{
if(vm->_repr_recursion_set.count(_0)) return VAR("[...]");
const PyDeque &self = _CAST(PyDeque&, _0);
SStream ss;
ss << "deque([";
vm->_repr_recursion_set.insert(_0);
for (auto it = self.dequeItems.begin(); it != self.dequeItems.end(); ++it)
{
ss << CAST(Str&, vm->py_repr(*it));
if (it != self.dequeItems.end() - 1) ss << ", ";
}
vm->_repr_recursion_set.erase(_0);
self.bounded ? ss << "], maxlen=" << self.maxlen << ")" : ss << "])";
return VAR(ss.str());
});
// enables comparison between two deques, == and != are supported
vm->bind(type, "__eq__(self, other) -> bool",
[](VM *vm, ArgsView args)
{
PyDeque &self = _CAST(PyDeque &, args[0]);
PyDeque &other = _CAST(PyDeque &, args[1]);
if (self.dequeItems.size() != other.dequeItems.size()) // trivial case
return VAR(false);
for (int i = 0; i < self.dequeItems.size(); i++)
if (!vm->py_eq(self.dequeItems[i], other.dequeItems[i]))
return VAR(false);
return VAR(true);
});
vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM *vm, PyObject* _0, PyObject* _1)
{
const PyDeque &self = _CAST(PyDeque&, _0);
if(!is_non_tagged_type(_0, PyDeque::_type(vm))) return vm->NotImplemented;
const PyDeque &other = _CAST(PyDeque&, _1);
if (self.dequeItems.size() != other.dequeItems.size()) return vm->False;
for (int i = 0; i < self.dequeItems.size(); i++){
if (vm->py_ne(self.dequeItems[i], other.dequeItems[i])) return vm->False;
}
return vm->True;
});
// clear the deque
vm->bind(type, "clear(self) -> None",
[](VM *vm, ArgsView args)
@ -426,22 +421,6 @@ namespace pkpy
}
}
}
std::string PyDeque::getRepr(VM *vm, PyObject *thisObj)
{
std::stringstream ss;
ss << "deque([";
for (auto it = this->dequeItems.begin(); it != this->dequeItems.end(); ++it)
{
if (*it == thisObj)
ss << "[...]";
else
ss << CAST(Str &, vm->py_repr(*it));
if (it != this->dequeItems.end() - 1)
ss << ", ";
}
this->bounded ? ss << "], maxlen=" << this->maxlen << ")" : ss << "])";
return ss.str();
}
int PyDeque::findIndex(VM *vm, PyObject *obj, int start, int stop)
{
// the following code is special purpose normalization for this method, taken from CPython: _collectionsmodule.c file

View File

@ -659,17 +659,16 @@ void init_builtins(VM* _vm) {
});
_vm->bind__repr__(VM::tp_list, [](VM* vm, PyObject* _0){
if(vm->_repr_recursion_set.count(_0)) return VAR("[...]");
List& iterable = _CAST(List&, _0);
SStream ss;
ss << '[';
vm->_repr_recursion_set.insert(_0);
for(int i=0; i<iterable.size(); i++){
if(iterable[i] == _0){
ss << "[...]";
}else{
ss << CAST(Str&, vm->py_repr(iterable[i]));
}
ss << CAST(Str&, vm->py_repr(iterable[i]));
if(i != iterable.size()-1) ss << ", ";
}
vm->_repr_recursion_set.erase(_0);
ss << ']';
return VAR(ss.str());
});
@ -1080,16 +1079,19 @@ void init_builtins(VM* _vm) {
});
_vm->bind__repr__(VM::tp_mappingproxy, [](VM* vm, PyObject* _0) {
if(vm->_repr_recursion_set.count(_0)) return VAR("{...}");
MappingProxy& self = _CAST(MappingProxy&, _0);
SStream ss;
ss << "mappingproxy({";
bool first = true;
vm->_repr_recursion_set.insert(_0);
for(auto& item : self.attr().items()){
if(!first) ss << ", ";
first = false;
ss << item.first.escape() << ": ";
ss << CAST(Str, vm->py_repr(item.second));
}
vm->_repr_recursion_set.erase(_0);
ss << "})";
return VAR(ss.str());
});
@ -1227,20 +1229,18 @@ void init_builtins(VM* _vm) {
});
_vm->bind__repr__(VM::tp_dict, [](VM* vm, PyObject* _0) {
if(vm->_repr_recursion_set.count(_0)) return VAR("{...}");
Dict& self = _CAST(Dict&, _0);
SStream ss;
ss << "{";
bool first = true;
vm->_repr_recursion_set.insert(_0);
self.apply([&](PyObject* k, PyObject* v){
if(!first) ss << ", ";
first = false;
ss << CAST(Str&, vm->py_repr(k)) << ": ";
if(v == _0){
ss << "{...}";
}else{
ss << CAST(Str&, vm->py_repr(v));
}
ss << CAST(Str&, vm->py_repr(k)) << ": " << CAST(Str&, vm->py_repr(v));
});
vm->_repr_recursion_set.erase(_0);
ss << "}";
return VAR(ss.str());
});

View File

@ -97,7 +97,7 @@ assert b[
0] == 1
a = []
a.append(1)
a.append(a)
a.append(0)
a.append([1, 2, a])
assert repr(a) == '[1, [...]]'
assert repr(a) == "[0, [1, 2, [...]]]"