mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-25 14:00:18 +00:00
...
This commit is contained in:
parent
8c85881d14
commit
ca0aa5e1ab
119
python/_dict.py
119
python/_dict.py
@ -1,119 +0,0 @@
|
|||||||
class dict:
|
|
||||||
def __init__(self, mapping=None):
|
|
||||||
self._capacity = 16
|
|
||||||
self._a = [None] * self._capacity
|
|
||||||
self._len = 0
|
|
||||||
|
|
||||||
if mapping is not None:
|
|
||||||
for k,v in mapping:
|
|
||||||
self[k] = v
|
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return self._len
|
|
||||||
|
|
||||||
def __probe(self, key):
|
|
||||||
i = hash(key) % self._capacity
|
|
||||||
while self._a[i] is not None:
|
|
||||||
if self._a[i][0] == key:
|
|
||||||
return True, i
|
|
||||||
i = (i + 1) % self._capacity
|
|
||||||
return False, i
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
ok, i = self.__probe(key)
|
|
||||||
if not ok:
|
|
||||||
raise KeyError(repr(key))
|
|
||||||
return self._a[i][1]
|
|
||||||
|
|
||||||
def __contains__(self, key):
|
|
||||||
ok, i = self.__probe(key)
|
|
||||||
return ok
|
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
|
||||||
ok, i = self.__probe(key)
|
|
||||||
if ok:
|
|
||||||
self._a[i][1] = value
|
|
||||||
else:
|
|
||||||
self._a[i] = [key, value]
|
|
||||||
self._len += 1
|
|
||||||
if self._len > self._capacity * 0.67:
|
|
||||||
self._capacity *= 2
|
|
||||||
self.__rehash()
|
|
||||||
|
|
||||||
def __delitem__(self, key):
|
|
||||||
ok, i = self.__probe(key)
|
|
||||||
if not ok:
|
|
||||||
raise KeyError(repr(key))
|
|
||||||
self._a[i] = None
|
|
||||||
self._len -= 1
|
|
||||||
|
|
||||||
def __rehash(self):
|
|
||||||
old_a = self._a
|
|
||||||
self._a = [None] * self._capacity
|
|
||||||
self._len = 0
|
|
||||||
for kv in old_a:
|
|
||||||
if kv is not None:
|
|
||||||
self[kv[0]] = kv[1]
|
|
||||||
|
|
||||||
def get(self, key, default=None):
|
|
||||||
ok, i = self.__probe(key)
|
|
||||||
if ok:
|
|
||||||
return self._a[i][1]
|
|
||||||
return default
|
|
||||||
|
|
||||||
def keys(self):
|
|
||||||
for kv in self._a:
|
|
||||||
if kv is not None:
|
|
||||||
yield kv[0]
|
|
||||||
|
|
||||||
def values(self):
|
|
||||||
for kv in self._a:
|
|
||||||
if kv is not None:
|
|
||||||
yield kv[1]
|
|
||||||
|
|
||||||
def items(self):
|
|
||||||
for kv in self._a:
|
|
||||||
if kv is not None:
|
|
||||||
yield kv[0], kv[1]
|
|
||||||
|
|
||||||
def clear(self):
|
|
||||||
self._a = [None] * self._capacity
|
|
||||||
self._len = 0
|
|
||||||
|
|
||||||
def update(self, other):
|
|
||||||
for k, v in other.items():
|
|
||||||
self[k] = v
|
|
||||||
|
|
||||||
def copy(self):
|
|
||||||
d = dict()
|
|
||||||
for kv in self._a:
|
|
||||||
if kv is not None:
|
|
||||||
d[kv[0]] = kv[1]
|
|
||||||
return d
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
a = [repr(k)+': '+repr(v) for k,v in self.items()]
|
|
||||||
return '{'+ ', '.join(a) + '}'
|
|
||||||
|
|
||||||
def __json__(self):
|
|
||||||
a = []
|
|
||||||
for k,v in self.items():
|
|
||||||
if type(k) is not str:
|
|
||||||
raise TypeError('json keys must be strings, got ' + repr(k) )
|
|
||||||
a.append(k.__json__()+': '+v.__json__())
|
|
||||||
return '{'+ ', '.join(a) + '}'
|
|
||||||
|
|
||||||
def __eq__(self, __o: object) -> bool:
|
|
||||||
if type(__o) is not dict:
|
|
||||||
return False
|
|
||||||
if len(self) != len(__o):
|
|
||||||
return False
|
|
||||||
for k in self.keys():
|
|
||||||
if k not in __o:
|
|
||||||
return False
|
|
||||||
if self[k] != __o[k]:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
def __ne__(self, __o: object) -> bool:
|
|
||||||
return not self.__eq__(__o)
|
|
||||||
13
src/ceval.h
13
src/ceval.h
@ -368,6 +368,7 @@ __NEXT_STEP:;
|
|||||||
DISPATCH();
|
DISPATCH();
|
||||||
|
|
||||||
#undef BINARY_OP_SPECIAL
|
#undef BINARY_OP_SPECIAL
|
||||||
|
#undef PREDICT_INT_OP
|
||||||
|
|
||||||
TARGET(IS_OP)
|
TARGET(IS_OP)
|
||||||
_1 = POPX(); // rhs
|
_1 = POPX(); // rhs
|
||||||
@ -398,14 +399,14 @@ __NEXT_STEP:;
|
|||||||
frame->jump_abs(byte.arg);
|
frame->jump_abs(byte.arg);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
TARGET(POP_JUMP_IF_FALSE)
|
TARGET(POP_JUMP_IF_FALSE)
|
||||||
if(!asBool(POPX())) frame->jump_abs(byte.arg);
|
if(!py_bool(POPX())) frame->jump_abs(byte.arg);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
TARGET(JUMP_IF_TRUE_OR_POP)
|
TARGET(JUMP_IF_TRUE_OR_POP)
|
||||||
if(asBool(TOP()) == true) frame->jump_abs(byte.arg);
|
if(py_bool(TOP()) == true) frame->jump_abs(byte.arg);
|
||||||
else POP();
|
else POP();
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
TARGET(JUMP_IF_FALSE_OR_POP)
|
TARGET(JUMP_IF_FALSE_OR_POP)
|
||||||
if(asBool(TOP()) == false) frame->jump_abs(byte.arg);
|
if(py_bool(TOP()) == false) frame->jump_abs(byte.arg);
|
||||||
else POP();
|
else POP();
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
TARGET(LOOP_CONTINUE)
|
TARGET(LOOP_CONTINUE)
|
||||||
@ -461,10 +462,10 @@ __NEXT_STEP:;
|
|||||||
DISPATCH();
|
DISPATCH();
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
TARGET(UNARY_NEGATIVE)
|
TARGET(UNARY_NEGATIVE)
|
||||||
TOP() = num_negated(TOP());
|
TOP() = py_negate(TOP());
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
TARGET(UNARY_NOT)
|
TARGET(UNARY_NOT)
|
||||||
TOP() = VAR(!asBool(TOP()));
|
TOP() = VAR(!py_bool(TOP()));
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
TARGET(GET_ITER)
|
TARGET(GET_ITER)
|
||||||
@ -578,7 +579,7 @@ __NEXT_STEP:;
|
|||||||
_0 = t[0];
|
_0 = t[0];
|
||||||
msg = CAST(Str&, py_str(t[1]));
|
msg = CAST(Str&, py_str(t[1]));
|
||||||
}
|
}
|
||||||
bool ok = asBool(_0);
|
bool ok = py_bool(_0);
|
||||||
POP();
|
POP();
|
||||||
if(!ok) _error("AssertionError", msg);
|
if(!ok) _error("AssertionError", msg);
|
||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
|
|||||||
@ -980,7 +980,7 @@ __SUBSCR_END:
|
|||||||
case TK("-"): {
|
case TK("-"): {
|
||||||
consume(TK("@num"));
|
consume(TK("@num"));
|
||||||
PyObject* val = to_object(prev().value);
|
PyObject* val = to_object(prev().value);
|
||||||
return vm->num_negated(val);
|
return vm->py_negate(val);
|
||||||
}
|
}
|
||||||
case TK("@num"): return to_object(prev().value);
|
case TK("@num"): return to_object(prev().value);
|
||||||
case TK("@str"): return to_object(prev().value);
|
case TK("@str"): return to_object(prev().value);
|
||||||
|
|||||||
28
src/dict.h
28
src/dict.h
@ -70,6 +70,34 @@ struct Dict{
|
|||||||
return _items[i].second;
|
return _items[i].second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool contains(PyObject* key) const{
|
||||||
|
bool ok; int i;
|
||||||
|
_probe(key, ok, i);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase(PyObject* key){
|
||||||
|
bool ok; int i;
|
||||||
|
_probe(key, ok, i);
|
||||||
|
if(!ok) return;
|
||||||
|
_items[i].first = nullptr;
|
||||||
|
_size--;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Item> items() const {
|
||||||
|
std::vector<Item> v;
|
||||||
|
for(uint16_t i=0; i<_capacity; i++){
|
||||||
|
if(_items[i].first == nullptr) continue;
|
||||||
|
v.push_back(_items[i]);
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear(){
|
||||||
|
memset(_items, 0, _capacity * sizeof(Item));
|
||||||
|
_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
~Dict(){ pool128.dealloc(_items); }
|
~Dict(){ pool128.dealloc(_items); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
190
src/pocketpy.h
190
src/pocketpy.h
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "ceval.h"
|
#include "ceval.h"
|
||||||
#include "compiler.h"
|
#include "compiler.h"
|
||||||
|
#include "dict.h"
|
||||||
#include "obj.h"
|
#include "obj.h"
|
||||||
#include "repl.h"
|
#include "repl.h"
|
||||||
#include "iter.h"
|
#include "iter.h"
|
||||||
@ -139,7 +140,7 @@ inline void init_builtins(VM* _vm) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_builtin_func<1>("hash", [](VM* vm, ArgsView args){
|
_vm->bind_builtin_func<1>("hash", [](VM* vm, ArgsView args){
|
||||||
i64 value = vm->hash(args[0]);
|
i64 value = vm->py_hash(args[0]);
|
||||||
if(((value << 2) >> 2) != value) value >>= 2;
|
if(((value << 2) >> 2) != value) value >>= 2;
|
||||||
return VAR(value);
|
return VAR(value);
|
||||||
});
|
});
|
||||||
@ -262,7 +263,7 @@ inline void init_builtins(VM* _vm) {
|
|||||||
_vm->bind__pow__(_vm->tp_int, py_number_pow);
|
_vm->bind__pow__(_vm->tp_int, py_number_pow);
|
||||||
_vm->bind__pow__(_vm->tp_float, py_number_pow);
|
_vm->bind__pow__(_vm->tp_float, py_number_pow);
|
||||||
|
|
||||||
/************ PyInt ************/
|
/************ int ************/
|
||||||
_vm->bind_constructor<2>("int", [](VM* vm, ArgsView args) {
|
_vm->bind_constructor<2>("int", [](VM* vm, ArgsView args) {
|
||||||
if (is_type(args[1], vm->tp_float)) return VAR((i64)CAST(f64, args[1]));
|
if (is_type(args[1], vm->tp_float)) return VAR((i64)CAST(f64, args[1]));
|
||||||
if (is_type(args[1], vm->tp_int)) return args[1];
|
if (is_type(args[1], vm->tp_int)) return args[1];
|
||||||
@ -295,6 +296,8 @@ inline void init_builtins(VM* _vm) {
|
|||||||
_vm->bind__repr__(_vm->tp_int, [](VM* vm, PyObject* obj) { return VAR(std::to_string(_CAST(i64, obj))); });
|
_vm->bind__repr__(_vm->tp_int, [](VM* vm, PyObject* obj) { return VAR(std::to_string(_CAST(i64, obj))); });
|
||||||
_vm->bind__json__(_vm->tp_int, [](VM* vm, PyObject* obj) { return VAR(std::to_string(_CAST(i64, obj))); });
|
_vm->bind__json__(_vm->tp_int, [](VM* vm, PyObject* obj) { return VAR(std::to_string(_CAST(i64, obj))); });
|
||||||
|
|
||||||
|
_vm->bind__neg__(_vm->tp_int, [](VM* vm, PyObject* obj) { return VAR(-_CAST(i64, obj)); });
|
||||||
|
|
||||||
_vm->bind__hash__(_vm->tp_int, [](VM* vm, PyObject* obj) { return _CAST(i64, obj); });
|
_vm->bind__hash__(_vm->tp_int, [](VM* vm, PyObject* obj) { return _CAST(i64, obj); });
|
||||||
|
|
||||||
#define INT_BITWISE_OP(name, op) \
|
#define INT_BITWISE_OP(name, op) \
|
||||||
@ -310,7 +313,7 @@ inline void init_builtins(VM* _vm) {
|
|||||||
|
|
||||||
#undef INT_BITWISE_OP
|
#undef INT_BITWISE_OP
|
||||||
|
|
||||||
/************ PyFloat ************/
|
/************ float ************/
|
||||||
_vm->bind_constructor<2>("float", [](VM* vm, ArgsView args) {
|
_vm->bind_constructor<2>("float", [](VM* vm, ArgsView args) {
|
||||||
if (is_type(args[1], vm->tp_int)) return VAR((f64)CAST(i64, args[1]));
|
if (is_type(args[1], vm->tp_int)) return VAR((f64)CAST(i64, args[1]));
|
||||||
if (is_type(args[1], vm->tp_float)) return args[1];
|
if (is_type(args[1], vm->tp_float)) return args[1];
|
||||||
@ -335,6 +338,8 @@ inline void init_builtins(VM* _vm) {
|
|||||||
return (i64)std::hash<f64>()(val);
|
return (i64)std::hash<f64>()(val);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_vm->bind__neg__(_vm->tp_float, [](VM* vm, PyObject* obj) { return VAR(-_CAST(f64, obj)); });
|
||||||
|
|
||||||
_vm->bind__repr__(_vm->tp_float, [](VM* vm, PyObject* obj) {
|
_vm->bind__repr__(_vm->tp_float, [](VM* vm, PyObject* obj) {
|
||||||
f64 val = _CAST(f64, obj);
|
f64 val = _CAST(f64, obj);
|
||||||
if(std::isinf(val) || std::isnan(val)) return VAR(std::to_string(val));
|
if(std::isinf(val) || std::isnan(val)) return VAR(std::to_string(val));
|
||||||
@ -350,7 +355,7 @@ inline void init_builtins(VM* _vm) {
|
|||||||
return VAR(std::to_string(val));
|
return VAR(std::to_string(val));
|
||||||
});
|
});
|
||||||
|
|
||||||
/************ PyString ************/
|
/************ str ************/
|
||||||
_vm->bind_constructor<2>("str", CPP_LAMBDA(vm->py_str(args[1])));
|
_vm->bind_constructor<2>("str", CPP_LAMBDA(vm->py_str(args[1])));
|
||||||
|
|
||||||
_vm->bind__hash__(_vm->tp_str, [](VM* vm, PyObject* obj) {
|
_vm->bind__hash__(_vm->tp_str, [](VM* vm, PyObject* obj) {
|
||||||
@ -475,9 +480,9 @@ inline void init_builtins(VM* _vm) {
|
|||||||
return VAR(Str(p));
|
return VAR(Str(p));
|
||||||
});
|
});
|
||||||
|
|
||||||
/************ PyList ************/
|
/************ list ************/
|
||||||
_vm->bind_constructor<2>("list", [](VM* vm, ArgsView args) {
|
_vm->bind_constructor<2>("list", [](VM* vm, ArgsView args) {
|
||||||
return vm->asList(args[1]);
|
return vm->py_list(args[1]);
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_method<1>("list", "append", [](VM* vm, ArgsView args) {
|
_vm->bind_method<1>("list", "append", [](VM* vm, ArgsView args) {
|
||||||
@ -563,9 +568,9 @@ inline void init_builtins(VM* _vm) {
|
|||||||
self.erase(i);
|
self.erase(i);
|
||||||
});
|
});
|
||||||
|
|
||||||
/************ PyTuple ************/
|
/************ tuple ************/
|
||||||
_vm->bind_constructor<2>("tuple", [](VM* vm, ArgsView args) {
|
_vm->bind_constructor<2>("tuple", [](VM* vm, ArgsView args) {
|
||||||
List list = CAST(List, vm->asList(args[1]));
|
List list = CAST(List, vm->py_list(args[1]));
|
||||||
return VAR(Tuple(std::move(list)));
|
return VAR(Tuple(std::move(list)));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -573,7 +578,7 @@ inline void init_builtins(VM* _vm) {
|
|||||||
i64 x = 1000003;
|
i64 x = 1000003;
|
||||||
const Tuple& items = CAST(Tuple&, obj);
|
const Tuple& items = CAST(Tuple&, obj);
|
||||||
for (int i=0; i<items.size(); i++) {
|
for (int i=0; i<items.size(); i++) {
|
||||||
i64 y = vm->hash(items[i]);
|
i64 y = vm->py_hash(items[i]);
|
||||||
// recommended by Github Copilot
|
// recommended by Github Copilot
|
||||||
x = x ^ (y + 0x9e3779b9 + (x << 6) + (x >> 2));
|
x = x ^ (y + 0x9e3779b9 + (x << 6) + (x >> 2));
|
||||||
}
|
}
|
||||||
@ -590,7 +595,7 @@ inline void init_builtins(VM* _vm) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/************ bool ************/
|
/************ bool ************/
|
||||||
_vm->bind_constructor<2>("bool", CPP_LAMBDA(VAR(vm->asBool(args[1]))));
|
_vm->bind_constructor<2>("bool", CPP_LAMBDA(VAR(vm->py_bool(args[1]))));
|
||||||
_vm->bind__hash__(_vm->tp_bool, [](VM* vm, PyObject* obj) {
|
_vm->bind__hash__(_vm->tp_bool, [](VM* vm, PyObject* obj) {
|
||||||
return (i64)_CAST(bool, obj);
|
return (i64)_CAST(bool, obj);
|
||||||
});
|
});
|
||||||
@ -758,6 +763,165 @@ inline void init_builtins(VM* _vm) {
|
|||||||
MappingProxy& self = _CAST(MappingProxy&, obj);
|
MappingProxy& self = _CAST(MappingProxy&, obj);
|
||||||
return self.attr().contains(CAST(Str&, key));
|
return self.attr().contains(CAST(Str&, key));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/************ dict ************/
|
||||||
|
_vm->bind_constructor<-1>("dict", [](VM* vm, ArgsView args){
|
||||||
|
return VAR(Dict(vm));
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind_method<-1>("dict", "__init__", [](VM* vm, ArgsView args){
|
||||||
|
if(args.size() == 1+0) return vm->None;
|
||||||
|
if(args.size() == 1+1){
|
||||||
|
auto _lock = vm->heap.gc_scope_lock();
|
||||||
|
Dict& self = _CAST(Dict&, args[0]);
|
||||||
|
List& list = CAST(List&, vm->py_list(args[1]));
|
||||||
|
for(PyObject* item : list){
|
||||||
|
Tuple& t = CAST(Tuple&, item);
|
||||||
|
if(t.size() != 2){
|
||||||
|
vm->ValueError("dict() takes an iterable of tuples (key, value)");
|
||||||
|
return vm->None;
|
||||||
|
}
|
||||||
|
self.set(t[0], t[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vm->TypeError("dict() takes at most 1 argument");
|
||||||
|
return vm->None;
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind__len__(_vm->tp_dict, [](VM* vm, PyObject* obj) {
|
||||||
|
return (i64)_CAST(Dict&, obj).size();
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind__getitem__(_vm->tp_dict, [](VM* vm, PyObject* obj, PyObject* index) {
|
||||||
|
Dict& self = _CAST(Dict&, obj);
|
||||||
|
PyObject* ret = self.try_get(index);
|
||||||
|
if(ret == nullptr) vm->KeyError(index);
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind__setitem__(_vm->tp_dict, [](VM* vm, PyObject* obj, PyObject* key, PyObject* value) {
|
||||||
|
Dict& self = _CAST(Dict&, obj);
|
||||||
|
self.set(key, value);
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind__delitem__(_vm->tp_dict, [](VM* vm, PyObject* obj, PyObject* key) {
|
||||||
|
Dict& self = _CAST(Dict&, obj);
|
||||||
|
if(!self.contains(key)) vm->KeyError(key);
|
||||||
|
self.erase(key);
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind__contains__(_vm->tp_dict, [](VM* vm, PyObject* obj, PyObject* key) {
|
||||||
|
Dict& self = _CAST(Dict&, obj);
|
||||||
|
return self.contains(key);
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind_method<-1>("dict", "get", [](VM* vm, ArgsView args) {
|
||||||
|
Dict& self = _CAST(Dict&, args[0]);
|
||||||
|
if(args.size() == 1+1){
|
||||||
|
PyObject* ret = self.try_get(args[1]);
|
||||||
|
if(ret != nullptr) return ret;
|
||||||
|
return vm->None;
|
||||||
|
}else if(args.size() == 1+2){
|
||||||
|
PyObject* ret = self.try_get(args[1]);
|
||||||
|
if(ret != nullptr) return ret;
|
||||||
|
return args[2];
|
||||||
|
}
|
||||||
|
vm->TypeError("get() takes at most 2 arguments");
|
||||||
|
return vm->None;
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind_method<0>("dict", "keys", [](VM* vm, ArgsView args) {
|
||||||
|
Dict& self = _CAST(Dict&, args[0]);
|
||||||
|
List keys;
|
||||||
|
for(auto& item : self.items()) keys.push_back(item.first);
|
||||||
|
return VAR(std::move(keys));
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind_method<0>("dict", "values", [](VM* vm, ArgsView args) {
|
||||||
|
Dict& self = _CAST(Dict&, args[0]);
|
||||||
|
List values;
|
||||||
|
for(auto& item : self.items()) values.push_back(item.second);
|
||||||
|
return VAR(std::move(values));
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind_method<0>("dict", "items", [](VM* vm, ArgsView args) {
|
||||||
|
Dict& self = _CAST(Dict&, args[0]);
|
||||||
|
List items;
|
||||||
|
for(auto& item : self.items()){
|
||||||
|
PyObject* t = VAR(Tuple({item.first, item.second}));
|
||||||
|
items.push_back(std::move(t));
|
||||||
|
}
|
||||||
|
return VAR(std::move(items));
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind_method<-1>("dict", "update", [](VM* vm, ArgsView args) {
|
||||||
|
Dict& self = _CAST(Dict&, args[0]);
|
||||||
|
Dict& other = CAST(Dict&, args[1]);
|
||||||
|
for(auto& item : other.items()) self.set(item.first, item.second);
|
||||||
|
return vm->None;
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind_method<0>("dict", "copy", [](VM* vm, ArgsView args) {
|
||||||
|
Dict& self = _CAST(Dict&, args[0]);
|
||||||
|
Dict copy(vm);
|
||||||
|
for(auto& item : self.items()) copy.set(item.first, item.second);
|
||||||
|
return VAR(std::move(copy));
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind_method<0>("dict", "clear", [](VM* vm, ArgsView args) {
|
||||||
|
Dict& self = _CAST(Dict&, args[0]);
|
||||||
|
self.clear();
|
||||||
|
return vm->None;
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind__repr__(_vm->tp_dict, [](VM* vm, PyObject* obj) {
|
||||||
|
Dict& self = _CAST(Dict&, obj);
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "{";
|
||||||
|
bool first = true;
|
||||||
|
for(auto& item : self.items()){
|
||||||
|
if(!first) ss << ", ";
|
||||||
|
first = false;
|
||||||
|
Str key = CAST(Str&, vm->py_repr(item.first));
|
||||||
|
Str value = CAST(Str&, vm->py_repr(item.second));
|
||||||
|
ss << key << ": " << value;
|
||||||
|
}
|
||||||
|
ss << "}";
|
||||||
|
return VAR(ss.str());
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind__json__(_vm->tp_dict, [](VM* vm, PyObject* obj) {
|
||||||
|
Dict& self = _CAST(Dict&, obj);
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "{";
|
||||||
|
bool first = true;
|
||||||
|
for(auto& item : self.items()){
|
||||||
|
if(!first) ss << ", ";
|
||||||
|
first = false;
|
||||||
|
Str key = CAST(Str&, item.first);
|
||||||
|
Str value = CAST(Str&, vm->py_json(item.second));
|
||||||
|
ss << key << ": " << value;
|
||||||
|
}
|
||||||
|
ss << "}";
|
||||||
|
return VAR(ss.str());
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind__eq__(_vm->tp_dict, [](VM* vm, PyObject* a, PyObject* b) {
|
||||||
|
Dict& self = _CAST(Dict&, a);
|
||||||
|
if(!is_non_tagged_type(b, vm->tp_dict)) return false;
|
||||||
|
Dict& other = _CAST(Dict&, b);
|
||||||
|
if(self.size() != other.size()) return false;
|
||||||
|
for(auto& item : self.items()){
|
||||||
|
PyObject* value = other.try_get(item.first);
|
||||||
|
if(value == nullptr) return false;
|
||||||
|
if(!vm->py_equals(item.second, value)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
_vm->bind__ne__(_vm->tp_dict, [](VM* vm, PyObject* a, PyObject* b) {
|
||||||
|
return !vm->py_equals(a, b);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -819,9 +983,7 @@ inline void add_module_json(VM* vm){
|
|||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func<1>(mod, "dumps", [](VM* vm, ArgsView args) {
|
vm->bind_func<1>(mod, "dumps", [](VM* vm, ArgsView args) {
|
||||||
const PyTypeInfo* ti = vm->_inst_type_info(args[0]);
|
return vm->py_json(args[0]);
|
||||||
if(ti->m__json__) return ti->m__json__(vm, args[0]);
|
|
||||||
return vm->call_method(args[0], __json__);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1049,8 +1211,6 @@ inline void VM::post_init(){
|
|||||||
|
|
||||||
CodeObject_ code = compile(kPythonLibs["builtins"], "<builtins>", EXEC_MODE);
|
CodeObject_ code = compile(kPythonLibs["builtins"], "<builtins>", EXEC_MODE);
|
||||||
this->_exec(code, this->builtins);
|
this->_exec(code, this->builtins);
|
||||||
code = compile(kPythonLibs["_dict"], "<dict>", EXEC_MODE);
|
|
||||||
this->_exec(code, this->builtins);
|
|
||||||
code = compile(kPythonLibs["_set"], "<set>", EXEC_MODE);
|
code = compile(kPythonLibs["_set"], "<set>", EXEC_MODE);
|
||||||
this->_exec(code, this->builtins);
|
this->_exec(code, this->builtins);
|
||||||
|
|
||||||
|
|||||||
61
src/vm.h
61
src/vm.h
@ -9,7 +9,7 @@
|
|||||||
#include "obj.h"
|
#include "obj.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
#include "tuplelist.h"
|
#include "tuplelist.h"
|
||||||
// #include "dict.h"
|
#include "dict.h"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
|
|
||||||
@ -147,6 +147,7 @@ public:
|
|||||||
Type tp_function, tp_native_func, tp_iterator, tp_bound_method;
|
Type tp_function, tp_native_func, tp_iterator, tp_bound_method;
|
||||||
Type tp_slice, tp_range, tp_module;
|
Type tp_slice, tp_range, tp_module;
|
||||||
Type tp_super, tp_exception, tp_bytes, tp_mappingproxy;
|
Type tp_super, tp_exception, tp_bytes, tp_mappingproxy;
|
||||||
|
Type tp_dict;
|
||||||
|
|
||||||
const bool enable_os;
|
const bool enable_os;
|
||||||
|
|
||||||
@ -181,6 +182,12 @@ public:
|
|||||||
return call_method(obj, __repr__);
|
return call_method(obj, __repr__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject* py_json(PyObject* obj){
|
||||||
|
const PyTypeInfo* ti = _inst_type_info(obj);
|
||||||
|
if(ti->m__json__) return ti->m__json__(this, obj);
|
||||||
|
return call_method(obj, __json__);
|
||||||
|
}
|
||||||
|
|
||||||
PyObject* py_iter(PyObject* obj){
|
PyObject* py_iter(PyObject* obj){
|
||||||
if(is_type(obj, tp_iterator)) return obj;
|
if(is_type(obj, tp_iterator)) return obj;
|
||||||
const PyTypeInfo* ti = _inst_type_info(obj);
|
const PyTypeInfo* ti = _inst_type_info(obj);
|
||||||
@ -521,7 +528,7 @@ public:
|
|||||||
void IndexError(const Str& msg){ _error("IndexError", msg); }
|
void IndexError(const Str& msg){ _error("IndexError", msg); }
|
||||||
void ValueError(const Str& msg){ _error("ValueError", msg); }
|
void ValueError(const Str& msg){ _error("ValueError", msg); }
|
||||||
void NameError(StrName name){ _error("NameError", fmt("name ", name.escape() + " is not defined")); }
|
void NameError(StrName name){ _error("NameError", fmt("name ", name.escape() + " is not defined")); }
|
||||||
void KeyError(const Str& msg){ _error("KeyError", msg); }
|
void KeyError(PyObject* obj){ _error("KeyError", OBJ_GET(Str, py_repr(obj))); }
|
||||||
|
|
||||||
void AttributeError(PyObject* obj, StrName name){
|
void AttributeError(PyObject* obj, StrName name){
|
||||||
// OBJ_NAME calls getattr, which may lead to a infinite recursion
|
// OBJ_NAME calls getattr, which may lead to a infinite recursion
|
||||||
@ -567,15 +574,16 @@ public:
|
|||||||
_modules.clear();
|
_modules.clear();
|
||||||
_lazy_modules.clear();
|
_lazy_modules.clear();
|
||||||
}
|
}
|
||||||
|
#if DEBUG_CEVAL_STEP
|
||||||
void _log_s_data(const char* title = nullptr);
|
void _log_s_data(const char* title = nullptr);
|
||||||
|
#endif
|
||||||
PyObject* vectorcall(int ARGC, int KWARGC=0, bool op_call=false);
|
PyObject* vectorcall(int ARGC, int KWARGC=0, bool op_call=false);
|
||||||
CodeObject_ compile(Str source, Str filename, CompileMode mode, bool unknown_global_scope=false);
|
CodeObject_ compile(Str source, Str filename, CompileMode mode, bool unknown_global_scope=false);
|
||||||
PyObject* num_negated(PyObject* obj);
|
PyObject* py_negate(PyObject* obj);
|
||||||
f64 num_to_float(PyObject* obj);
|
f64 num_to_float(PyObject* obj);
|
||||||
bool asBool(PyObject* obj);
|
bool py_bool(PyObject* obj);
|
||||||
i64 hash(PyObject* obj);
|
i64 py_hash(PyObject* obj);
|
||||||
PyObject* asList(PyObject*);
|
PyObject* py_list(PyObject*);
|
||||||
PyObject* new_module(StrName name);
|
PyObject* new_module(StrName name);
|
||||||
Str disassemble(CodeObject_ co);
|
Str disassemble(CodeObject_ co);
|
||||||
void init_builtin_types();
|
void init_builtin_types();
|
||||||
@ -622,6 +630,7 @@ DEF_NATIVE_2(Slice, tp_slice)
|
|||||||
DEF_NATIVE_2(Exception, tp_exception)
|
DEF_NATIVE_2(Exception, tp_exception)
|
||||||
DEF_NATIVE_2(Bytes, tp_bytes)
|
DEF_NATIVE_2(Bytes, tp_bytes)
|
||||||
DEF_NATIVE_2(MappingProxy, tp_mappingproxy)
|
DEF_NATIVE_2(MappingProxy, tp_mappingproxy)
|
||||||
|
DEF_NATIVE_2(Dict, tp_dict)
|
||||||
|
|
||||||
#define PY_CAST_INT(T) \
|
#define PY_CAST_INT(T) \
|
||||||
template<> inline T py_cast<T>(VM* vm, PyObject* obj){ \
|
template<> inline T py_cast<T>(VM* vm, PyObject* obj){ \
|
||||||
@ -733,14 +742,10 @@ inline PyObject* py_var(VM* vm, PyObject* val){
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyObject* VM::num_negated(PyObject* obj){
|
inline PyObject* VM::py_negate(PyObject* obj){
|
||||||
if (is_int(obj)){
|
const PyTypeInfo* ti = _inst_type_info(obj);
|
||||||
return VAR(-CAST(i64, obj));
|
if(ti->m__neg__) return ti->m__neg__(this, obj);
|
||||||
}else if(is_float(obj)){
|
return call_method(obj, __neg__);
|
||||||
return VAR(-CAST(f64, obj));
|
|
||||||
}
|
|
||||||
TypeError("expected 'int' or 'float', got " + OBJ_NAME(_t(obj)).escape());
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline f64 VM::num_to_float(PyObject* obj){
|
inline f64 VM::num_to_float(PyObject* obj){
|
||||||
@ -753,7 +758,7 @@ inline f64 VM::num_to_float(PyObject* obj){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool VM::asBool(PyObject* obj){
|
inline bool VM::py_bool(PyObject* obj){
|
||||||
if(is_non_tagged_type(obj, tp_bool)) return obj == True;
|
if(is_non_tagged_type(obj, tp_bool)) return obj == True;
|
||||||
if(obj == None) return false;
|
if(obj == None) return false;
|
||||||
if(is_int(obj)) return _CAST(i64, obj) != 0;
|
if(is_int(obj)) return _CAST(i64, obj) != 0;
|
||||||
@ -767,7 +772,7 @@ inline bool VM::asBool(PyObject* obj){
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyObject* VM::asList(PyObject* it){
|
inline PyObject* VM::py_list(PyObject* it){
|
||||||
auto _lock = heap.gc_scope_lock();
|
auto _lock = heap.gc_scope_lock();
|
||||||
it = py_iter(it);
|
it = py_iter(it);
|
||||||
List list;
|
List list;
|
||||||
@ -821,7 +826,7 @@ inline void VM::parse_int_slice(const Slice& s, int length, int& start, int& sto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline i64 VM::hash(PyObject* obj){
|
inline i64 VM::py_hash(PyObject* obj){
|
||||||
const PyTypeInfo* ti = _inst_type_info(obj);
|
const PyTypeInfo* ti = _inst_type_info(obj);
|
||||||
if(ti->m__hash__) return ti->m__hash__(this, obj);
|
if(ti->m__hash__) return ti->m__hash__(this, obj);
|
||||||
PyObject* ret = call_method(obj, __hash__);
|
PyObject* ret = call_method(obj, __hash__);
|
||||||
@ -974,6 +979,7 @@ inline Str VM::disassemble(CodeObject_ co){
|
|||||||
return Str(ss.str());
|
return Str(ss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG_CEVAL_STEP
|
||||||
inline void VM::_log_s_data(const char* title) {
|
inline void VM::_log_s_data(const char* title) {
|
||||||
if(_main == nullptr) return;
|
if(_main == nullptr) return;
|
||||||
if(callstack.empty()) return;
|
if(callstack.empty()) return;
|
||||||
@ -1023,6 +1029,7 @@ inline void VM::_log_s_data(const char* title) {
|
|||||||
Bytecode byte = frame->co->codes[frame->_ip];
|
Bytecode byte = frame->co->codes[frame->_ip];
|
||||||
std::cout << output << " " << OP_NAMES[byte.op] << " " << _opcode_argstr(nullptr, byte, frame->co) << std::endl;
|
std::cout << output << " " << OP_NAMES[byte.op] << " " << _opcode_argstr(nullptr, byte, frame->co) << std::endl;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
inline void VM::init_builtin_types(){
|
inline void VM::init_builtin_types(){
|
||||||
_all_types.push_back({heap._new<Type>(Type(1), Type(0)), -1, "object", true});
|
_all_types.push_back({heap._new<Type>(Type(1), Type(0)), -1, "object", true});
|
||||||
@ -1048,6 +1055,7 @@ inline void VM::init_builtin_types(){
|
|||||||
tp_exception = _new_type_object("Exception");
|
tp_exception = _new_type_object("Exception");
|
||||||
tp_bytes = _new_type_object("bytes");
|
tp_bytes = _new_type_object("bytes");
|
||||||
tp_mappingproxy = _new_type_object("mappingproxy");
|
tp_mappingproxy = _new_type_object("mappingproxy");
|
||||||
|
tp_dict = _new_type_object("dict");
|
||||||
|
|
||||||
this->None = heap._new<Dummy>(_new_type_object("NoneType"), {});
|
this->None = heap._new<Dummy>(_new_type_object("NoneType"), {});
|
||||||
this->Ellipsis = heap._new<Dummy>(_new_type_object("ellipsis"), {});
|
this->Ellipsis = heap._new<Dummy>(_new_type_object("ellipsis"), {});
|
||||||
@ -1068,6 +1076,7 @@ inline void VM::init_builtin_types(){
|
|||||||
builtins->attr().set("tuple", _t(tp_tuple));
|
builtins->attr().set("tuple", _t(tp_tuple));
|
||||||
builtins->attr().set("range", _t(tp_range));
|
builtins->attr().set("range", _t(tp_range));
|
||||||
builtins->attr().set("bytes", _t(tp_bytes));
|
builtins->attr().set("bytes", _t(tp_bytes));
|
||||||
|
builtins->attr().set("dict", _t(tp_dict));
|
||||||
builtins->attr().set("StopIteration", StopIteration);
|
builtins->attr().set("StopIteration", StopIteration);
|
||||||
builtins->attr().set("slice", _t(tp_slice));
|
builtins->attr().set("slice", _t(tp_slice));
|
||||||
|
|
||||||
@ -1444,13 +1453,13 @@ inline void VM::bind__len__(Type type, i64 (*f)(VM*, PyObject*)){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// inline void Dict::_probe(PyObject *key, bool &ok, int &i) const{
|
inline void Dict::_probe(PyObject *key, bool &ok, int &i) const{
|
||||||
// ok = false;
|
ok = false;
|
||||||
// i = vm->hash(key) & _mask;
|
i = vm->py_hash(key) & _mask;
|
||||||
// while(_items[i].first != nullptr) {
|
while(_items[i].first != nullptr) {
|
||||||
// if(vm->py_equals(_items[i].first, key)) { ok = true; break; }
|
if(vm->py_equals(_items[i].first, key)) { ok = true; break; }
|
||||||
// i = (i + 1) & _mask;
|
i = (i + 1) & _mask;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
} // namespace pkpy
|
} // namespace pkpy
|
||||||
Loading…
x
Reference in New Issue
Block a user