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* _last_exception; // last exception
PyObject* _curr_class; // current class being defined 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 // cached code objects for FSTRING_EVAL
std::map<std::string_view, CodeObject_> _cached_codes; 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 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 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 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 // Special methods
static void _register(VM *vm, PyObject *mod, PyObject *type); // register the type 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 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) // 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 // if the index is out of range, IndexError will be thrown --> required for [] operator
vm->bind(type, "__getitem__(self, index) -> PyObject", vm->bind__getitem__(PK_OBJ_GET(Type, type), [](VM *vm, PyObject* _0, PyObject* _1)
[](VM *vm, ArgsView args)
{ {
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque &, _0);
int index = CAST(int, args[1]); int index = CAST(int, _1);
index = vm->normalized_index(index, self.dequeItems.size()); // error is handled by the vm->normalized_index index = vm->normalized_index(index, self.dequeItems.size()); // error is handled by the vm->normalized_index
return self.dequeItems.at(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) // 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 // if the index is out of range, IndexError will be thrown --> required for [] operator
vm->bind(type, "__setitem__(self, index, newValue) -> None", vm->bind__setitem__(PK_OBJ_GET(Type, type), [](VM *vm, PyObject* _0, PyObject* _1, PyObject* _2)
[](VM *vm, ArgsView args)
{ {
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque&, _0);
int index = CAST(int, args[1]); int index = CAST(int, _1);
PyObject *newValue = args[2];
index = vm->normalized_index(index, self.dequeItems.size()); // error is handled by the vm->normalized_index index = vm->normalized_index(index, self.dequeItems.size()); // error is handled by the vm->normalized_index
self.dequeItems.at(index) = newValue; self.dequeItems.at(index) = _2;
return vm->None;
}); });
// erases the item at the given index, if index is negative, it will be treated as index + len(deque) // 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 // if the index is out of range, IndexError will be thrown --> required for [] operator
vm->bind(type, "__delitem__(self, index) -> None", vm->bind__delitem__(PK_OBJ_GET(Type, type), [](VM *vm, PyObject* _0, PyObject* _1)
[](VM *vm, ArgsView args)
{ {
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque&, _0);
int index = CAST(int, args[1]); int index = CAST(int, _1);
index = vm->normalized_index(index, self.dequeItems.size()); // error is handled by the vm->normalized_index index = vm->normalized_index(index, self.dequeItems.size()); // error is handled by the vm->normalized_index
self.dequeItems.erase(self.dequeItems.begin() + index); self.dequeItems.erase(self.dequeItems.begin() + index);
return vm->None;
}); });
// returns the length of the deque
vm->bind(type, "__len__(self) -> int", vm->bind__len__(PK_OBJ_GET(Type, type), [](VM *vm, PyObject* _0)
[](VM *vm, ArgsView args)
{ {
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque&, _0);
return VAR(self.dequeItems.size()); return (i64)self.dequeItems.size();
}); });
// returns an iterator for the deque
vm->bind(type, "__iter__(self) -> deque_iterator", vm->bind__iter__(PK_OBJ_GET(Type, type), [](VM *vm, PyObject* _0)
[](VM *vm, ArgsView args)
{ {
PyDeque &self = _CAST(PyDeque &, args[0]); PyDeque &self = _CAST(PyDeque &, _0);
return vm->heap.gcnew<PyDequeIter>( return vm->heap.gcnew<PyDequeIter>(
PyDequeIter::_type(vm), args[0], PyDequeIter::_type(vm), _0,
self.dequeItems.begin(), self.dequeItems.end()); self.dequeItems.begin(), self.dequeItems.end());
}); });
// returns a string representation of the deque
vm->bind(type, "__repr__(self) -> str", vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM *vm, PyObject* _0)
[](VM *vm, ArgsView args)
{ {
PyDeque &self = _CAST(PyDeque &, args[0]); if(vm->_repr_recursion_set.count(_0)) return VAR("[...]");
return VAR(self.getRepr(vm, args[0])); const PyDeque &self = _CAST(PyDeque&, _0);
}); SStream ss;
// returns a string representation of the deque ss << "deque([";
vm->bind(type, "__str__(self) -> str", vm->_repr_recursion_set.insert(_0);
[](VM *vm, ArgsView args) for (auto it = self.dequeItems.begin(); it != self.dequeItems.end(); ++it)
{ {
PyDeque &self = _CAST(PyDeque &, args[0]); ss << CAST(Str&, vm->py_repr(*it));
return VAR(self.getRepr(vm, args[0])); 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 // enables comparison between two deques, == and != are supported
vm->bind(type, "__eq__(self, other) -> bool", vm->bind__eq__(PK_OBJ_GET(Type, type), [](VM *vm, PyObject* _0, PyObject* _1)
[](VM *vm, ArgsView args)
{ {
PyDeque &self = _CAST(PyDeque &, args[0]); const PyDeque &self = _CAST(PyDeque&, _0);
PyDeque &other = _CAST(PyDeque &, args[1]); if(!is_non_tagged_type(_0, PyDeque::_type(vm))) return vm->NotImplemented;
if (self.dequeItems.size() != other.dequeItems.size()) // trivial case const PyDeque &other = _CAST(PyDeque&, _1);
return VAR(false); if (self.dequeItems.size() != other.dequeItems.size()) return vm->False;
for (int i = 0; i < self.dequeItems.size(); i++) for (int i = 0; i < self.dequeItems.size(); i++){
if (!vm->py_eq(self.dequeItems[i], other.dequeItems[i])) if (vm->py_ne(self.dequeItems[i], other.dequeItems[i])) return vm->False;
return VAR(false); }
return VAR(true); return vm->True;
}); });
// clear the deque // clear the deque
vm->bind(type, "clear(self) -> None", vm->bind(type, "clear(self) -> None",
[](VM *vm, ArgsView args) [](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) 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 // 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){ _vm->bind__repr__(VM::tp_list, [](VM* vm, PyObject* _0){
if(vm->_repr_recursion_set.count(_0)) return VAR("[...]");
List& iterable = _CAST(List&, _0); List& iterable = _CAST(List&, _0);
SStream ss; SStream ss;
ss << '['; ss << '[';
vm->_repr_recursion_set.insert(_0);
for(int i=0; i<iterable.size(); i++){ 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 << ", "; if(i != iterable.size()-1) ss << ", ";
} }
vm->_repr_recursion_set.erase(_0);
ss << ']'; ss << ']';
return VAR(ss.str()); return VAR(ss.str());
}); });
@ -1080,16 +1079,19 @@ void init_builtins(VM* _vm) {
}); });
_vm->bind__repr__(VM::tp_mappingproxy, [](VM* vm, PyObject* _0) { _vm->bind__repr__(VM::tp_mappingproxy, [](VM* vm, PyObject* _0) {
if(vm->_repr_recursion_set.count(_0)) return VAR("{...}");
MappingProxy& self = _CAST(MappingProxy&, _0); MappingProxy& self = _CAST(MappingProxy&, _0);
SStream ss; SStream ss;
ss << "mappingproxy({"; ss << "mappingproxy({";
bool first = true; bool first = true;
vm->_repr_recursion_set.insert(_0);
for(auto& item : self.attr().items()){ for(auto& item : self.attr().items()){
if(!first) ss << ", "; if(!first) ss << ", ";
first = false; first = false;
ss << item.first.escape() << ": "; ss << item.first.escape() << ": ";
ss << CAST(Str, vm->py_repr(item.second)); ss << CAST(Str, vm->py_repr(item.second));
} }
vm->_repr_recursion_set.erase(_0);
ss << "})"; ss << "})";
return VAR(ss.str()); return VAR(ss.str());
}); });
@ -1227,20 +1229,18 @@ void init_builtins(VM* _vm) {
}); });
_vm->bind__repr__(VM::tp_dict, [](VM* vm, PyObject* _0) { _vm->bind__repr__(VM::tp_dict, [](VM* vm, PyObject* _0) {
if(vm->_repr_recursion_set.count(_0)) return VAR("{...}");
Dict& self = _CAST(Dict&, _0); Dict& self = _CAST(Dict&, _0);
SStream ss; SStream ss;
ss << "{"; ss << "{";
bool first = true; bool first = true;
vm->_repr_recursion_set.insert(_0);
self.apply([&](PyObject* k, PyObject* v){ self.apply([&](PyObject* k, PyObject* v){
if(!first) ss << ", "; if(!first) ss << ", ";
first = false; first = false;
ss << CAST(Str&, vm->py_repr(k)) << ": "; ss << CAST(Str&, vm->py_repr(k)) << ": " << CAST(Str&, vm->py_repr(v));
if(v == _0){
ss << "{...}";
}else{
ss << CAST(Str&, vm->py_repr(v));
}
}); });
vm->_repr_recursion_set.erase(_0);
ss << "}"; ss << "}";
return VAR(ss.str()); return VAR(ss.str());
}); });

View File

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