mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-21 12:00:18 +00:00
more move
This commit is contained in:
parent
d21a9cffab
commit
175c571fbb
@ -21,9 +21,8 @@ constexpr inline bool is_floating_point_v = std::is_same_v<T, float> || std::is_
|
||||
template <typename T>
|
||||
constexpr inline bool is_sso_v = is_integral_v<T> || is_floating_point_v<T>;
|
||||
|
||||
// if is_sso_v<T> is true, return T, else return T&
|
||||
template <typename T>
|
||||
using obj_get_t = std::conditional_t<is_sso_v<T>, T, T&>;
|
||||
using obj_get_t = T&;
|
||||
|
||||
template <typename T>
|
||||
constexpr inline bool is_trivially_relocatable_v =
|
||||
|
@ -69,7 +69,6 @@ struct CodeEmitContext{
|
||||
int curr_iblock = 0;
|
||||
bool is_compiling_class = false;
|
||||
|
||||
small_map<PyVar, int> _co_consts_nonstring_dedup_map;
|
||||
small_map<std::string_view, int> _co_consts_string_dedup_map;
|
||||
|
||||
int get_loop() const noexcept;
|
||||
|
@ -175,14 +175,14 @@ public:
|
||||
vector<ArgsView> s_view;
|
||||
} __c;
|
||||
|
||||
PyVar StopIteration; // a special Exception class
|
||||
PyObject* StopIteration; // a special Exception class
|
||||
PyObject* builtins;
|
||||
PyObject* _main;
|
||||
|
||||
// typeid -> Type
|
||||
small_map<std::type_index, Type> _cxx_typeid_map;
|
||||
// this is for repr() recursion detection (no need to mark)
|
||||
vector<PyVar> _repr_recursion_set;
|
||||
vector<PyObject*> _repr_recursion_set;
|
||||
|
||||
ImportContext __import_context;
|
||||
PyObject* __last_exception;
|
||||
@ -550,10 +550,18 @@ PyVar py_var(VM* vm, __T&& value) {
|
||||
return value ? vm->True : vm->False;
|
||||
} else if constexpr(is_integral_v<T>) {
|
||||
// int
|
||||
return PyVar(VM::tp_int, static_cast<i64>(value));
|
||||
::PyVar retval;
|
||||
retval.type = tp_int;
|
||||
retval.is_ptr = false;
|
||||
retval._i64 = (i64)value;
|
||||
return retval;
|
||||
} else if constexpr(is_floating_point_v<T>) {
|
||||
// float
|
||||
return PyVar(VM::tp_float, static_cast<f64>(value));
|
||||
::PyVar retval;
|
||||
retval.type = tp_float;
|
||||
retval.is_ptr = false;
|
||||
retval._f64 = (f64)value;
|
||||
return retval;
|
||||
} else if constexpr(std::is_pointer_v<T>) {
|
||||
return from_void_p(vm, (void*)value);
|
||||
} else {
|
||||
@ -592,23 +600,22 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
|
||||
static_assert(!std::is_reference_v<__T>);
|
||||
// bool
|
||||
if constexpr(with_check) {
|
||||
if(obj == vm->True) return true;
|
||||
if(obj == vm->False) return false;
|
||||
if(obj.type != tp_bool){
|
||||
vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape());
|
||||
}
|
||||
return obj == vm->True;
|
||||
}
|
||||
return obj._bool;
|
||||
} else if constexpr(is_integral_v<T>) {
|
||||
static_assert(!std::is_reference_v<__T>);
|
||||
// int
|
||||
if constexpr(with_check) {
|
||||
if(is_int(obj)) return (T)obj.as<i64>();
|
||||
vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape());
|
||||
if(!is_int(obj)) vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape());
|
||||
}
|
||||
return (T)obj.as<i64>();
|
||||
return (T)obj._i64;
|
||||
} else if constexpr(is_floating_point_v<T>) {
|
||||
static_assert(!std::is_reference_v<__T>);
|
||||
if(is_float(obj)) return (T)obj.as<f64>();
|
||||
if(is_int(obj)) return (T)obj.as<i64>();
|
||||
if(is_float(obj)) return (T)obj._f64;
|
||||
if(is_int(obj)) return (T)obj._i64;
|
||||
vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape());
|
||||
return 0.0f;
|
||||
} else if constexpr(std::is_enum_v<T>) {
|
||||
|
@ -207,9 +207,9 @@ static_assert(is_pod_v<Vec3>);
|
||||
static_assert(is_pod_v<Vec4>);
|
||||
static_assert(is_pod_v<Mat3x3>);
|
||||
|
||||
template <>
|
||||
constexpr inline bool is_sso_v<Vec2> = true;
|
||||
template <>
|
||||
constexpr inline bool is_sso_v<Vec3> = true;
|
||||
// template <>
|
||||
// constexpr inline bool is_sso_v<Vec2> = true;
|
||||
// template <>
|
||||
// constexpr inline bool is_sso_v<Vec3> = true;
|
||||
|
||||
} // namespace pkpy
|
||||
|
@ -19,8 +19,7 @@ typedef struct PyObject PyObject;
|
||||
typedef struct PyVar{
|
||||
pkpy_Type type;
|
||||
bool is_ptr;
|
||||
uint8_t flags;
|
||||
int flags_ex;
|
||||
int extra;
|
||||
union {
|
||||
int64_t _i64;
|
||||
double _f64;
|
||||
@ -31,33 +30,17 @@ typedef struct PyVar{
|
||||
};
|
||||
} PyVar;
|
||||
|
||||
|
||||
#define PyVar__as(T, self) _Generic((T), \
|
||||
int64_t: self->_i64, \
|
||||
double: self->_f64, \
|
||||
bool: self->_bool, \
|
||||
PyObject*: self->_obj, \
|
||||
void*: self->_ptr, \
|
||||
)
|
||||
|
||||
static_assert(sizeof(PyVar) == 16, "sizeof(PyVar) != 16");
|
||||
|
||||
PK_INLINE bool PyVar__is_null(const PyVar* self) { return self->type == 0; }
|
||||
PK_INLINE int64_t PyVar__hash(const PyVar* self) { return self->flags_ex + self->_i64; }
|
||||
|
||||
PK_INLINE bool PyVar__less(const PyVar* self, const PyVar* other){
|
||||
return memcmp(self, other, sizeof(PyVar)) < 0;
|
||||
}
|
||||
PK_INLINE bool PyVar__equal(const PyVar* self, const PyVar* other){
|
||||
return memcmp(self, other, sizeof(PyVar)) == 0;
|
||||
}
|
||||
|
||||
PK_INLINE void PyVar__ctor(PyVar* self, pkpy_Type type, PyObject* obj){
|
||||
self->type = type;
|
||||
self->is_ptr = true;
|
||||
self->flags = 0;
|
||||
self->flags_ex = 0;
|
||||
self->_obj = obj;
|
||||
}
|
||||
|
||||
void PyVar__ctor2(PyVar* self, PyObject* existing);
|
||||
|
||||
#define pkpy_Var__is_null(self) ((self)->type == 0)
|
||||
#define pkpy_Var__set_null(self) do { (self)->type = 0; } while(0)
|
||||
bool pkpy_Var__eq__(void *vm, PyVar a, PyVar b);
|
||||
int64_t pkpy_Var__hash__(void *vm, PyVar a);
|
||||
|
||||
extern const pkpy_Type tp_object, tp_type;
|
||||
extern const pkpy_Type tp_int, tp_float, tp_bool, tp_str;
|
||||
extern const pkpy_Type tp_list, tp_tuple;
|
||||
@ -68,11 +51,41 @@ extern const pkpy_Type tp_dict, tp_property, tp_star_wrapper;
|
||||
extern const pkpy_Type tp_staticmethod, tp_classmethod;
|
||||
extern const pkpy_Type tp_none_type, tp_not_implemented_type;
|
||||
extern const pkpy_Type tp_ellipsis;
|
||||
extern const pkpy_Type tp_op_call, tp_op_yield;
|
||||
|
||||
extern const PyVar pkpy_True, pkpy_False, pkpy_None;
|
||||
extern const PyVar pkpy_NotImplemented, pkpy_Ellipsis;
|
||||
extern const PyVar pkpy_NULL;
|
||||
PK_INLINE bool PyVar__is_null(const PyVar* self) { return self->type == 0; }
|
||||
PK_INLINE int64_t PyVar__hash(const PyVar* self) { return self->extra + self->_i64; }
|
||||
|
||||
PK_INLINE void PyVar__ctor(PyVar* self, pkpy_Type type, PyObject* obj){
|
||||
self->type = type;
|
||||
self->is_ptr = true;
|
||||
self->_obj = obj;
|
||||
}
|
||||
|
||||
void PyVar__ctor3(PyVar* self, PyObject* existing);
|
||||
|
||||
PK_INLINE bool PyVar__IS_OP(const PyVar* a, const PyVar* b){
|
||||
return a->is_ptr && b->is_ptr && a->_obj == b->_obj;
|
||||
}
|
||||
|
||||
#define pkpy_Var__is_null(self) ((self)->type == 0)
|
||||
#define pkpy_Var__set_null(self) do { (self)->type = 0; } while(0)
|
||||
bool pkpy_Var__eq__(void *vm, PyVar a, PyVar b);
|
||||
int64_t pkpy_Var__hash__(void *vm, PyVar a);
|
||||
|
||||
extern PyVar pkpy_True, pkpy_False, pkpy_None;
|
||||
extern PyVar pkpy_NotImplemented, pkpy_Ellipsis;
|
||||
extern PyVar pkpy_NULL, pkpy_OP_CALL, pkpy_OP_YIELD;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
SSO types:
|
||||
1. int64_t
|
||||
2. double
|
||||
3. bool (dummy)
|
||||
4. tuple (extra + void*)
|
||||
5. string (extra + void* or buf)
|
||||
*/
|
@ -26,7 +26,7 @@ struct PyVar final: ::PyVar {
|
||||
|
||||
// implict conversion
|
||||
PyVar(PyObject* existing){
|
||||
PyVar__ctor2(this, (::PyObject*)existing);
|
||||
PyVar__ctor3(this, (::PyObject*)existing);
|
||||
}
|
||||
|
||||
/* We must initialize all members to allow == operator to work correctly */
|
||||
@ -40,26 +40,10 @@ struct PyVar final: ::PyVar {
|
||||
PyVar__ctor(this, type, (::PyObject*)p);
|
||||
}
|
||||
|
||||
// SSO initialized (is_sso = true)
|
||||
template <typename T>
|
||||
PyVar(Type type, T value){
|
||||
static_assert(sizeof(T) <= 12, "SSO size exceeded");
|
||||
PyVar(Type type, i64 value){
|
||||
this->type = type;
|
||||
this->is_ptr = false;
|
||||
this->flags = 0;
|
||||
this->flags_ex = 0;
|
||||
this->_i64 = 0;
|
||||
as<T>() = value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& as() {
|
||||
static_assert(!std::is_reference_v<T>);
|
||||
if constexpr(sizeof(T) <= 8) {
|
||||
return reinterpret_cast<T&>(_i64);
|
||||
} else {
|
||||
return reinterpret_cast<T&>(flags_ex);
|
||||
}
|
||||
this->_i64 = value;
|
||||
}
|
||||
|
||||
explicit operator bool () const { return (bool)type; }
|
||||
@ -68,10 +52,12 @@ struct PyVar final: ::PyVar {
|
||||
memset(this, 0, sizeof(PyVar));
|
||||
}
|
||||
|
||||
bool operator== (const PyVar& other) const { return PyVar__equal(this, &other); }
|
||||
bool operator!= (const PyVar& other) const { return !PyVar__equal(this, &other); }
|
||||
bool operator== (std::nullptr_t) const { return !(bool)type; }
|
||||
bool operator!= (std::nullptr_t) const { return (bool)type; }
|
||||
bool operator==(PyObject* other){
|
||||
return is_ptr && (PyObject*)_obj == other;
|
||||
}
|
||||
bool operator!=(PyObject* other){
|
||||
return !is_ptr || (PyObject*)_obj != other;
|
||||
}
|
||||
|
||||
PyObject* get() const {
|
||||
assert(is_ptr);
|
||||
@ -88,11 +74,6 @@ struct PyVar final: ::PyVar {
|
||||
template <typename T>
|
||||
obj_get_t<T> obj_get();
|
||||
|
||||
// std::less<> for map-like containers
|
||||
bool operator< (const PyVar& other) const {
|
||||
return PyVar__less(this, &other);
|
||||
}
|
||||
|
||||
// implicit convert from ::PyVar
|
||||
PyVar(const ::PyVar& var) {
|
||||
memcpy(this, &var, sizeof(var));
|
||||
|
@ -116,14 +116,11 @@ T to_void_p(VM*, PyVar);
|
||||
PyVar from_void_p(VM*, void*);
|
||||
|
||||
template <typename T>
|
||||
obj_get_t<T> PyVar::obj_get() {
|
||||
if constexpr(is_sso_v<T>) {
|
||||
return as<T>();
|
||||
} else {
|
||||
T& PyVar::obj_get() {
|
||||
static_assert(!is_sso_v<T>, "unsupported");
|
||||
assert(is_ptr);
|
||||
void* v = PyObject__value_ptr(_obj);
|
||||
return *reinterpret_cast<T*>(v);
|
||||
}
|
||||
}
|
||||
|
||||
#define PK_OBJ_GET(T, obj) ((obj).obj_get<T>())
|
||||
@ -140,7 +137,5 @@ obj_get_t<T> PyVar::obj_get() {
|
||||
|
||||
/*****************************************************************/
|
||||
#define PY_NULL nullptr
|
||||
extern PyVar PY_OP_CALL;
|
||||
extern PyVar PY_OP_YIELD;
|
||||
|
||||
} // namespace pkpy
|
||||
|
@ -12,9 +12,10 @@ struct NameDict;
|
||||
struct PyObject final: ::PyObject {
|
||||
bool is_attr_valid() const noexcept { return _attr != nullptr; }
|
||||
|
||||
void* _value_ptr() noexcept { return (char*)this + 16; }
|
||||
void* _value_ptr() noexcept { return PyObject__value_ptr(this); }
|
||||
|
||||
NameDict& attr() const{
|
||||
assert(is_attr_valid());
|
||||
return *(NameDict*)_attr;
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,7 @@ void pkpy_SStream__write_i64(pkpy_SStream* self, int64_t val) {
|
||||
}
|
||||
|
||||
void pkpy_SStream__write_float(pkpy_SStream* self, float val, int precision){
|
||||
return pkpy_SStream__write_double(self, val, precision);
|
||||
pkpy_SStream__write_double(self, val, precision);
|
||||
}
|
||||
|
||||
void pkpy_SStream__write_double(pkpy_SStream* self, double val, int precision){
|
||||
|
@ -137,16 +137,9 @@ int CodeEmitContext::add_const_string(std::string_view key) noexcept{
|
||||
|
||||
int CodeEmitContext::add_const(PyVar v) noexcept{
|
||||
assert(!is_type(v, VM::tp_str));
|
||||
// non-string deduplication
|
||||
int* val = _co_consts_nonstring_dedup_map.try_get(v);
|
||||
if(val) {
|
||||
return *val;
|
||||
} else {
|
||||
co->consts.push_back(v);
|
||||
int index = co->consts.size() - 1;
|
||||
_co_consts_nonstring_dedup_map.insert(v, index);
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
int CodeEmitContext::add_func_decl(FuncDecl_ decl) noexcept{
|
||||
|
@ -1,18 +1,19 @@
|
||||
#include "pocketpy/interpreter/ceval.hpp"
|
||||
#include "pocketpy/objects/base.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
#define PREDICT_INT_OP(op) \
|
||||
if(is_int(_0) && is_int(_1)) { \
|
||||
TOP() = VAR(_0.as<i64>() op _1.as<i64>()); \
|
||||
TOP() = VAR(_0._i64 op _1._i64); \
|
||||
DISPATCH() \
|
||||
}
|
||||
|
||||
#define PREDICT_INT_DIV_OP(op) \
|
||||
if(is_int(_0) && is_int(_1)) { \
|
||||
i64 divisor = _1.as<i64>(); \
|
||||
i64 divisor = _1._i64; \
|
||||
if(divisor == 0) ZeroDivisionError(); \
|
||||
TOP() = VAR(_0.as<i64>() op divisor); \
|
||||
TOP() = VAR(_0._i64 op divisor); \
|
||||
DISPATCH() \
|
||||
}
|
||||
|
||||
@ -24,7 +25,7 @@ namespace pkpy {
|
||||
} else { \
|
||||
PyVar self; \
|
||||
PyVar _2 = get_unbound_method(_0, func, &self, false); \
|
||||
if(_2 != nullptr) \
|
||||
if(_2) \
|
||||
ret = call_method(self, _2, _1); \
|
||||
else \
|
||||
ret = NotImplemented; \
|
||||
@ -32,7 +33,7 @@ namespace pkpy {
|
||||
if(is_not_implemented(ret)) { \
|
||||
PyVar self; \
|
||||
PyVar _2 = get_unbound_method(_1, rfunc, &self, false); \
|
||||
if(_2 != nullptr) \
|
||||
if(_2) \
|
||||
ret = call_method(self, _2, _0); \
|
||||
else \
|
||||
BinaryOptError(op, _0, _1); \
|
||||
@ -65,22 +66,26 @@ void VM::__op_unpack_sequence(uint16_t arg) {
|
||||
|
||||
bool VM::py_lt(PyVar _0, PyVar _1) {
|
||||
BINARY_F_COMPARE(__lt__, "<", __gt__);
|
||||
return ret == True;
|
||||
assert(ret.type == tp_bool);
|
||||
return ret._bool;
|
||||
}
|
||||
|
||||
bool VM::py_le(PyVar _0, PyVar _1) {
|
||||
BINARY_F_COMPARE(__le__, "<=", __ge__);
|
||||
return ret == True;
|
||||
assert(ret.type == tp_bool);
|
||||
return ret._bool;
|
||||
}
|
||||
|
||||
bool VM::py_gt(PyVar _0, PyVar _1) {
|
||||
BINARY_F_COMPARE(__gt__, ">", __lt__);
|
||||
return ret == True;
|
||||
assert(ret.type == tp_bool);
|
||||
return ret._bool;
|
||||
}
|
||||
|
||||
bool VM::py_ge(PyVar _0, PyVar _1) {
|
||||
BINARY_F_COMPARE(__ge__, ">=", __le__);
|
||||
return ret == True;
|
||||
assert(ret.type == tp_bool);
|
||||
return ret._bool;
|
||||
}
|
||||
|
||||
#undef BINARY_F_COMPARE
|
||||
@ -167,7 +172,7 @@ PyVar VM::__run_top_frame() {
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_PRINT_EXPR:
|
||||
if(TOP() != None) stdout_write(py_repr(TOP()) + "\n");
|
||||
if(!is_none(TOP())) stdout_write(py_repr(TOP()) + "\n");
|
||||
POP();
|
||||
DISPATCH()
|
||||
/*****************************************/
|
||||
@ -717,13 +722,13 @@ PyVar VM::__run_top_frame() {
|
||||
case OP_IS_OP: {
|
||||
PyVar _1 = POPX(); // rhs
|
||||
PyVar _0 = TOP(); // lhs
|
||||
TOP() = _0 == _1 ? True : False;
|
||||
TOP() = PyVar__IS_OP(&_0, &_1) ? True : False;
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_IS_NOT_OP: {
|
||||
PyVar _1 = POPX(); // rhs
|
||||
PyVar _0 = TOP(); // lhs
|
||||
TOP() = _0 != _1 ? True : False;
|
||||
TOP() = PyVar__IS_OP(&_0, &_1) ? False : True;
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_CONTAINS_OP: {
|
||||
@ -801,7 +806,7 @@ PyVar VM::__run_top_frame() {
|
||||
PyVar _0 = vectorcall(byte.arg & 0xFF, // ARGC
|
||||
(byte.arg >> 8) & 0xFF, // KWARGC
|
||||
true);
|
||||
if(_0 == PY_OP_CALL) {
|
||||
if(_0.type == tp_op_call) {
|
||||
frame = &callstack.top();
|
||||
goto __NEXT_FRAME;
|
||||
}
|
||||
@ -835,7 +840,7 @@ PyVar VM::__run_top_frame() {
|
||||
0, // KWARGC
|
||||
true);
|
||||
}
|
||||
if(_0 == PY_OP_CALL) {
|
||||
if(_0.type == tp_op_call) {
|
||||
frame = &callstack.top();
|
||||
goto __NEXT_FRAME;
|
||||
}
|
||||
@ -854,7 +859,7 @@ PyVar VM::__run_top_frame() {
|
||||
}
|
||||
}
|
||||
DISPATCH()
|
||||
case OP_YIELD_VALUE: return PY_OP_YIELD;
|
||||
case OP_YIELD_VALUE: return pkpy_OP_YIELD;
|
||||
/*****************************************/
|
||||
case OP_LIST_APPEND: {
|
||||
PyVar _0 = POPX();
|
||||
@ -926,7 +931,7 @@ PyVar VM::__run_top_frame() {
|
||||
DISPATCH_JUMP_ABSOLUTE(target)
|
||||
} else {
|
||||
PUSH(_0);
|
||||
return PY_OP_YIELD;
|
||||
return pkpy_OP_YIELD;
|
||||
}
|
||||
}
|
||||
case OP_FOR_ITER_UNPACK: {
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "pocketpy/interpreter/iter.hpp"
|
||||
#include "pocketpy/objects/base.h"
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
@ -76,7 +77,7 @@ PyVar Generator::next(VM* vm) {
|
||||
throw;
|
||||
}
|
||||
|
||||
if(ret == PY_OP_YIELD) {
|
||||
if(ret->type == tp_op_yield) {
|
||||
// backup the context
|
||||
lf = vm->callstack.popx();
|
||||
ret = vm->s_data.popx();
|
||||
|
@ -60,7 +60,7 @@ struct JsonSerializer {
|
||||
if(std::isinf(val) || std::isnan(val)) vm->ValueError("cannot jsonify 'nan' or 'inf'");
|
||||
ss << val;
|
||||
} else if(obj_t == vm->tp_bool) {
|
||||
ss << (obj == vm->True ? "true" : "false");
|
||||
ss << (obj._bool ? "true" : "false");
|
||||
} else if(obj_t == vm->tp_str) {
|
||||
ss << _CAST(Str&, obj).escape('"');
|
||||
} else if(obj_t == vm->tp_list) {
|
||||
@ -230,23 +230,23 @@ PyObject* VM::new_type_object(PyObject* mod, StrName name, Type base, bool subcl
|
||||
}
|
||||
|
||||
bool VM::py_eq(PyVar lhs, PyVar rhs) {
|
||||
if(is_int(lhs) && is_int(rhs)) return lhs.as<i64>() == rhs.as<i64>();
|
||||
if(is_int(lhs) && is_int(rhs)) return lhs._i64 == rhs._i64;
|
||||
const PyTypeInfo* ti = _tp_info(lhs);
|
||||
PyVar res;
|
||||
if(ti->m__eq__) {
|
||||
res = ti->m__eq__(this, lhs, rhs);
|
||||
if(!is_not_implemented(res)) return res == vm->True;
|
||||
if(!is_not_implemented(res)) return res._bool;
|
||||
}
|
||||
res = call_method(lhs, __eq__, rhs);
|
||||
if(!is_not_implemented(res)) return res == vm->True;
|
||||
if(!is_not_implemented(res)) return res._bool;
|
||||
|
||||
ti = _tp_info(rhs);
|
||||
if(ti->m__eq__) {
|
||||
res = ti->m__eq__(this, rhs, lhs);
|
||||
if(!is_not_implemented(res)) return res == vm->True;
|
||||
if(!is_not_implemented(res)) return res._bool;
|
||||
}
|
||||
res = call_method(rhs, __eq__, lhs);
|
||||
if(!is_not_implemented(res)) return res == vm->True;
|
||||
if(!is_not_implemented(res)) return res._bool;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -538,7 +538,8 @@ i64 VM::py_hash(PyVar obj) {
|
||||
has_custom_eq = true;
|
||||
else {
|
||||
f = get_unbound_method(obj, __eq__, &self, false);
|
||||
has_custom_eq = f != _t(tp_object)->attr()[__eq__];
|
||||
PyVar base_eq = _t(tp_object)->attr()[__eq__];
|
||||
has_custom_eq = !PyVar__IS_OP(&f, &base_eq);
|
||||
}
|
||||
if(has_custom_eq) {
|
||||
TypeError(_S("unhashable type: ", ti->name.escape()));
|
||||
@ -901,6 +902,9 @@ void VM::__init_builtin_types() {
|
||||
validate(tp_not_implemented_type, new_type_object(nullptr, "NotImplementedType", tp_object, false));
|
||||
validate(tp_ellipsis, new_type_object(nullptr, "ellipsis", tp_object, false));
|
||||
|
||||
validate(::tp_op_call, new_type_object(nullptr, "__op_call", tp_object, false));
|
||||
validate(::tp_op_yield, new_type_object(nullptr, "__op_yield", tp_object, false));
|
||||
|
||||
// SyntaxError and IndentationError must be created here
|
||||
PyObject* SyntaxError = new_type_object(nullptr, "SyntaxError", tp_exception, true);
|
||||
PyObject* IndentationError = new_type_object(nullptr, "IndentationError", SyntaxError->as<Type>(), true);
|
||||
@ -1103,7 +1107,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
|
||||
// simple or normal
|
||||
callstack.emplace(p0, co, fn._module, callable.get(), args.begin());
|
||||
if(op_call) return PY_OP_CALL;
|
||||
if(op_call) return pkpy_OP_CALL;
|
||||
return __run_top_frame();
|
||||
/*****************_py_call*****************/
|
||||
}
|
||||
@ -1137,7 +1141,7 @@ PyVar VM::vectorcall(int ARGC, int KWARGC, bool op_call) {
|
||||
PyVar new_f = *find_name_in_mro(PK_OBJ_GET(Type, callable), __new__);
|
||||
PyVar obj;
|
||||
assert(new_f != nullptr && p0[1] == PY_NULL);
|
||||
if(new_f == __cached_object_new) {
|
||||
if(PyVar__IS_OP(&new_f, &__cached_object_new)) {
|
||||
// fast path for object.__new__
|
||||
obj = vm->new_object<DummyInstance>(PK_OBJ_GET(Type, callable));
|
||||
} else {
|
||||
@ -1326,7 +1330,7 @@ void VM::setattr(PyVar obj, StrName name, PyVar value) {
|
||||
// handle descriptor
|
||||
if(is_type(*cls_var, tp_property)) {
|
||||
const Property& prop = _CAST(Property&, *cls_var);
|
||||
if(prop.setter != vm->None) {
|
||||
if(!is_none(prop.setter)) {
|
||||
call(prop.setter, obj, value);
|
||||
} else {
|
||||
TypeError(_S("readonly attribute: ", name.escape()));
|
||||
|
@ -113,8 +113,8 @@ struct Array2d {
|
||||
const Tuple& xy = CAST(Tuple&, _1);
|
||||
|
||||
if(is_int(xy[0]) && is_int(xy[1])) {
|
||||
i64 col = xy[0].as<i64>();
|
||||
i64 row = xy[1].as<i64>();
|
||||
i64 col = xy[0]._i64;
|
||||
i64 row = xy[1]._i64;
|
||||
self.check_valid(vm, col, row);
|
||||
return self._get(col, row);
|
||||
}
|
||||
@ -138,8 +138,8 @@ struct Array2d {
|
||||
Array2d& self = PK_OBJ_GET(Array2d, _0);
|
||||
const Tuple& xy = CAST(Tuple&, _1);
|
||||
if(is_int(xy[0]) && is_int(xy[1])) {
|
||||
i64 col = xy[0].as<i64>();
|
||||
i64 row = xy[1].as<i64>();
|
||||
i64 col = xy[0]._i64;
|
||||
i64 row = xy[1]._i64;
|
||||
self.check_valid(vm, col, row);
|
||||
self._set(col, row, _2);
|
||||
return;
|
||||
|
@ -11,10 +11,13 @@ const pkpy_Type tp_dict = 19, tp_property = 20, tp_star_wrapper = 21;
|
||||
const pkpy_Type tp_staticmethod = 22, tp_classmethod = 23;
|
||||
const pkpy_Type tp_none_type = 24, tp_not_implemented_type = 25;
|
||||
const pkpy_Type tp_ellipsis = 26;
|
||||
const pkpy_Type tp_op_call = 27, tp_op_yield = 28;
|
||||
|
||||
const PyVar pkpy_True = {.type=tp_bool, .is_ptr=false, .flags=0, .flags_ex=0, ._bool=true};
|
||||
const PyVar pkpy_False = {.type=tp_bool, .is_ptr=false, .flags=0, .flags_ex=0, ._bool=false};
|
||||
const PyVar pkpy_None = {.type=tp_none_type, .is_ptr=false, .flags=0, .flags_ex=0, ._i64=0};
|
||||
const PyVar pkpy_NotImplemented = {.type=tp_not_implemented_type, .is_ptr=false, .flags=0, .flags_ex=0, ._i64=0};
|
||||
const PyVar pkpy_Ellipsis = {.type=tp_ellipsis, .is_ptr=false, .flags=0, .flags_ex=0, ._i64=0};
|
||||
const PyVar pkpy_NULL = {.type=0, .is_ptr=false, .flags=0, .flags_ex=0, ._i64=0};
|
||||
PyVar pkpy_True = {.type=tp_bool, .is_ptr=false, ._bool=true};
|
||||
PyVar pkpy_False = {.type=tp_bool, .is_ptr=false, ._bool=false};
|
||||
PyVar pkpy_None = {.type=tp_none_type, .is_ptr=false};
|
||||
PyVar pkpy_NotImplemented = {.type=tp_not_implemented_type, .is_ptr=false};
|
||||
PyVar pkpy_Ellipsis = {.type=tp_ellipsis, .is_ptr=false};
|
||||
PyVar pkpy_NULL = {.type=0, .is_ptr=false};
|
||||
PyVar pkpy_OP_CALL = {.type=tp_op_call, .is_ptr=false};
|
||||
PyVar pkpy_OP_YIELD = {.type=tp_op_yield, .is_ptr=false};
|
||||
|
@ -1,6 +0,0 @@
|
||||
#include "pocketpy/objects/builtins.hpp"
|
||||
|
||||
namespace pkpy {
|
||||
PyVar PY_OP_CALL(Type(), new PyObject(Type(), true));
|
||||
PyVar PY_OP_YIELD(Type(), new PyObject(Type(), true));
|
||||
} // namespace pkpy
|
@ -1,10 +1,8 @@
|
||||
#include "pocketpy/objects/object.h"
|
||||
|
||||
void PyVar__ctor2(PyVar* self, PyObject* existing){
|
||||
void PyVar__ctor3(PyVar* self, PyObject* existing){
|
||||
assert(existing);
|
||||
self->type = existing->type;
|
||||
self->is_ptr = true;
|
||||
self->flags = 0;
|
||||
self->flags_ex = 0;
|
||||
self->_obj = existing;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "pocketpy/modules/linalg.hpp"
|
||||
#include "pocketpy/modules/random.hpp"
|
||||
#include "pocketpy/modules/modules.hpp"
|
||||
#include "pocketpy/objects/base.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
@ -26,7 +27,7 @@ PyVar PyArrayGetItem(VM* vm, PyVar _0, PyVar _1) {
|
||||
static_assert(std::is_same_v<T, List> || std::is_same_v<T, Tuple>);
|
||||
const T& self = _CAST(T&, _0);
|
||||
if(is_int(_1)) {
|
||||
i64 index = _1.as<i64>();
|
||||
i64 index = _1._i64;
|
||||
index = vm->normalized_index(index, self.size());
|
||||
return self[index];
|
||||
}
|
||||
@ -374,7 +375,7 @@ void __init_builtins(VM* _vm) {
|
||||
});
|
||||
|
||||
_vm->bind__eq__(VM::tp_object, [](VM* vm, PyVar _0, PyVar _1) {
|
||||
return VAR(_0 == _1);
|
||||
return PyVar__IS_OP(&_0, &_1) ? vm->True : vm->False;
|
||||
});
|
||||
|
||||
_vm->__cached_object_new = _vm->bind_func(VM::tp_object, __new__, 1, [](VM* vm, ArgsView args) {
|
||||
@ -461,7 +462,7 @@ void __init_builtins(VM* _vm) {
|
||||
switch(vm->_tp(args[1])) {
|
||||
case VM::tp_float: return VAR((i64)_CAST(f64, args[1]));
|
||||
case VM::tp_int: return args[1];
|
||||
case VM::tp_bool: return VAR(args[1] == vm->True ? 1 : 0);
|
||||
case VM::tp_bool: return VAR(args[1]._bool ? 1 : 0);
|
||||
case VM::tp_str: break;
|
||||
default: vm->TypeError("invalid arguments for int()");
|
||||
}
|
||||
@ -542,7 +543,7 @@ void __init_builtins(VM* _vm) {
|
||||
switch(vm->_tp(args[1])) {
|
||||
case VM::tp_int: return VAR((f64)CAST(i64, args[1]));
|
||||
case VM::tp_float: return args[1];
|
||||
case VM::tp_bool: return VAR(args[1] == vm->True ? 1.0 : 0.0);
|
||||
case VM::tp_bool: return VAR(args[1]._bool ? 1.0 : 0.0);
|
||||
case VM::tp_str: break;
|
||||
default: vm->TypeError("invalid arguments for float()");
|
||||
}
|
||||
@ -847,11 +848,11 @@ void __init_builtins(VM* _vm) {
|
||||
});
|
||||
|
||||
_vm->bind__repr__(VM::tp_list, [](VM* vm, PyVar _0) -> Str {
|
||||
if(vm->_repr_recursion_set.contains(_0)) return "[...]";
|
||||
if(vm->_repr_recursion_set.contains(_0.get())) return "[...]";
|
||||
List& iterable = _CAST(List&, _0);
|
||||
SStream ss;
|
||||
ss << '[';
|
||||
vm->_repr_recursion_set.push_back(_0);
|
||||
vm->_repr_recursion_set.push_back(_0.get());
|
||||
for(int i = 0; i < iterable.size(); i++) {
|
||||
ss << vm->py_repr(iterable[i]);
|
||||
if(i != iterable.size() - 1) ss << ", ";
|
||||
@ -1150,7 +1151,7 @@ void __init_builtins(VM* _vm) {
|
||||
return VAR(_CAST(bool, _0) != CAST(bool, _1));
|
||||
});
|
||||
_vm->bind__eq__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) {
|
||||
if(is_type(_1, vm->tp_bool)) return VAR(_0 == _1);
|
||||
if(is_type(_1, vm->tp_bool)) return VAR(_0._bool == _1._bool);
|
||||
if(is_int(_1)) return VAR(_CAST(bool, _0) == (bool)CAST(i64, _1));
|
||||
return vm->NotImplemented;
|
||||
});
|
||||
@ -1316,12 +1317,12 @@ void __init_builtins(VM* _vm) {
|
||||
});
|
||||
|
||||
_vm->bind__repr__(VM::tp_mappingproxy, [](VM* vm, PyVar _0) -> Str {
|
||||
if(vm->_repr_recursion_set.contains(_0)) return "{...}";
|
||||
if(vm->_repr_recursion_set.contains(_0.get())) return "{...}";
|
||||
MappingProxy& self = _CAST(MappingProxy&, _0);
|
||||
SStream ss;
|
||||
ss << "mappingproxy({";
|
||||
bool first = true;
|
||||
vm->_repr_recursion_set.push_back(_0);
|
||||
vm->_repr_recursion_set.push_back(_0.get());
|
||||
for(auto [k, v]: self.attr().items()) {
|
||||
if(!first) ss << ", ";
|
||||
first = false;
|
||||
@ -1472,12 +1473,12 @@ void __init_builtins(VM* _vm) {
|
||||
});
|
||||
|
||||
_vm->bind__repr__(VM::tp_dict, [](VM* vm, PyVar _0) -> Str {
|
||||
if(vm->_repr_recursion_set.contains(_0)) return "{...}";
|
||||
if(vm->_repr_recursion_set.contains(_0.get())) return "{...}";
|
||||
Dict& self = _CAST(Dict&, _0);
|
||||
SStream ss;
|
||||
ss << "{";
|
||||
bool first = true;
|
||||
vm->_repr_recursion_set.push_back(_0);
|
||||
vm->_repr_recursion_set.push_back(_0.get());
|
||||
self.apply([&](PyVar k, PyVar v) {
|
||||
if(!first) ss << ", ";
|
||||
first = false;
|
||||
@ -1544,7 +1545,7 @@ void __init_builtins(VM* _vm) {
|
||||
|
||||
_vm->bind(_vm->_t(VM::tp_exception), "__init__(self, msg=...)", [](VM* vm, ArgsView args) {
|
||||
Exception& self = _CAST(Exception&, args[0]);
|
||||
if(args[1] == vm->Ellipsis) {
|
||||
if(args[1].type == tp_ellipsis) {
|
||||
self.msg = "";
|
||||
} else {
|
||||
self.msg = CAST(Str, args[1]);
|
||||
@ -1627,7 +1628,7 @@ void VM::__post_init_builtin_types() {
|
||||
if(!is_type(rhs, vm->tp_bound_method)) return vm->NotImplemented;
|
||||
const BoundMethod& _0 = PK_OBJ_GET(BoundMethod, lhs);
|
||||
const BoundMethod& _1 = PK_OBJ_GET(BoundMethod, rhs);
|
||||
return VAR(_0.self == _1.self && _0.func == _1.func);
|
||||
return VAR(PyVar__IS_OP(&_0.self, &_1.self) && PyVar__IS_OP(&_0.func, &_1.func));
|
||||
});
|
||||
|
||||
bind_property(_t(tp_slice), "start", [](VM* vm, ArgsView args) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user