more move

This commit is contained in:
blueloveTH 2024-06-16 19:56:33 +08:00
parent d21a9cffab
commit 175c571fbb
18 changed files with 154 additions and 160 deletions

View File

@ -21,9 +21,8 @@ constexpr inline bool is_floating_point_v = std::is_same_v<T, float> || std::is_
template <typename T> template <typename T>
constexpr inline bool is_sso_v = is_integral_v<T> || is_floating_point_v<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> template <typename T>
using obj_get_t = std::conditional_t<is_sso_v<T>, T, T&>; using obj_get_t = T&;
template <typename T> template <typename T>
constexpr inline bool is_trivially_relocatable_v = constexpr inline bool is_trivially_relocatable_v =

View File

@ -69,7 +69,6 @@ struct CodeEmitContext{
int curr_iblock = 0; int curr_iblock = 0;
bool is_compiling_class = false; 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; small_map<std::string_view, int> _co_consts_string_dedup_map;
int get_loop() const noexcept; int get_loop() const noexcept;

View File

@ -175,14 +175,14 @@ public:
vector<ArgsView> s_view; vector<ArgsView> s_view;
} __c; } __c;
PyVar StopIteration; // a special Exception class PyObject* StopIteration; // a special Exception class
PyObject* builtins; PyObject* builtins;
PyObject* _main; PyObject* _main;
// typeid -> Type // typeid -> Type
small_map<std::type_index, Type> _cxx_typeid_map; small_map<std::type_index, Type> _cxx_typeid_map;
// this is for repr() recursion detection (no need to mark) // this is for repr() recursion detection (no need to mark)
vector<PyVar> _repr_recursion_set; vector<PyObject*> _repr_recursion_set;
ImportContext __import_context; ImportContext __import_context;
PyObject* __last_exception; PyObject* __last_exception;
@ -550,10 +550,18 @@ PyVar py_var(VM* vm, __T&& value) {
return value ? vm->True : vm->False; return value ? vm->True : vm->False;
} else if constexpr(is_integral_v<T>) { } else if constexpr(is_integral_v<T>) {
// int // 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>) { } else if constexpr(is_floating_point_v<T>) {
// float // 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>) { } else if constexpr(std::is_pointer_v<T>) {
return from_void_p(vm, (void*)value); return from_void_p(vm, (void*)value);
} else { } else {
@ -592,23 +600,22 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
static_assert(!std::is_reference_v<__T>); static_assert(!std::is_reference_v<__T>);
// bool // bool
if constexpr(with_check) { if constexpr(with_check) {
if(obj == vm->True) return true; if(obj.type != tp_bool){
if(obj == vm->False) return false; vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape());
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>) { } else if constexpr(is_integral_v<T>) {
static_assert(!std::is_reference_v<__T>); static_assert(!std::is_reference_v<__T>);
// int // int
if constexpr(with_check) { if constexpr(with_check) {
if(is_int(obj)) return (T)obj.as<i64>(); if(!is_int(obj)) vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape());
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>) { } else if constexpr(is_floating_point_v<T>) {
static_assert(!std::is_reference_v<__T>); static_assert(!std::is_reference_v<__T>);
if(is_float(obj)) return (T)obj.as<f64>(); if(is_float(obj)) return (T)obj._f64;
if(is_int(obj)) return (T)obj.as<i64>(); if(is_int(obj)) return (T)obj._i64;
vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape()); vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape());
return 0.0f; return 0.0f;
} else if constexpr(std::is_enum_v<T>) { } else if constexpr(std::is_enum_v<T>) {

View File

@ -207,9 +207,9 @@ static_assert(is_pod_v<Vec3>);
static_assert(is_pod_v<Vec4>); static_assert(is_pod_v<Vec4>);
static_assert(is_pod_v<Mat3x3>); static_assert(is_pod_v<Mat3x3>);
template <> // template <>
constexpr inline bool is_sso_v<Vec2> = true; // constexpr inline bool is_sso_v<Vec2> = true;
template <> // template <>
constexpr inline bool is_sso_v<Vec3> = true; // constexpr inline bool is_sso_v<Vec3> = true;
} // namespace pkpy } // namespace pkpy

View File

@ -19,8 +19,7 @@ typedef struct PyObject PyObject;
typedef struct PyVar{ typedef struct PyVar{
pkpy_Type type; pkpy_Type type;
bool is_ptr; bool is_ptr;
uint8_t flags; int extra;
int flags_ex;
union { union {
int64_t _i64; int64_t _i64;
double _f64; double _f64;
@ -31,33 +30,17 @@ typedef struct PyVar{
}; };
} 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"); 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_object, tp_type;
extern const pkpy_Type tp_int, tp_float, tp_bool, tp_str; extern const pkpy_Type tp_int, tp_float, tp_bool, tp_str;
extern const pkpy_Type tp_list, tp_tuple; 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_staticmethod, tp_classmethod;
extern const pkpy_Type tp_none_type, tp_not_implemented_type; extern const pkpy_Type tp_none_type, tp_not_implemented_type;
extern const pkpy_Type tp_ellipsis; 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; PK_INLINE bool PyVar__is_null(const PyVar* self) { return self->type == 0; }
extern const PyVar pkpy_NotImplemented, pkpy_Ellipsis; PK_INLINE int64_t PyVar__hash(const PyVar* self) { return self->extra + self->_i64; }
extern const PyVar pkpy_NULL;
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 #ifdef __cplusplus
} }
#endif #endif
/*
SSO types:
1. int64_t
2. double
3. bool (dummy)
4. tuple (extra + void*)
5. string (extra + void* or buf)
*/

View File

@ -26,7 +26,7 @@ struct PyVar final: ::PyVar {
// implict conversion // implict conversion
PyVar(PyObject* existing){ PyVar(PyObject* existing){
PyVar__ctor2(this, (::PyObject*)existing); PyVar__ctor3(this, (::PyObject*)existing);
} }
/* We must initialize all members to allow == operator to work correctly */ /* 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); PyVar__ctor(this, type, (::PyObject*)p);
} }
// SSO initialized (is_sso = true) PyVar(Type type, i64 value){
template <typename T>
PyVar(Type type, T value){
static_assert(sizeof(T) <= 12, "SSO size exceeded");
this->type = type; this->type = type;
this->is_ptr = false; this->is_ptr = false;
this->flags = 0; this->_i64 = value;
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);
}
} }
explicit operator bool () const { return (bool)type; } explicit operator bool () const { return (bool)type; }
@ -68,10 +52,12 @@ struct PyVar final: ::PyVar {
memset(this, 0, sizeof(PyVar)); memset(this, 0, sizeof(PyVar));
} }
bool operator== (const PyVar& other) const { return PyVar__equal(this, &other); } bool operator==(PyObject* other){
bool operator!= (const PyVar& other) const { return !PyVar__equal(this, &other); } return is_ptr && (PyObject*)_obj == 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;
}
PyObject* get() const { PyObject* get() const {
assert(is_ptr); assert(is_ptr);
@ -88,11 +74,6 @@ struct PyVar final: ::PyVar {
template <typename T> template <typename T>
obj_get_t<T> obj_get(); 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 // implicit convert from ::PyVar
PyVar(const ::PyVar& var) { PyVar(const ::PyVar& var) {
memcpy(this, &var, sizeof(var)); memcpy(this, &var, sizeof(var));

View File

@ -116,14 +116,11 @@ T to_void_p(VM*, PyVar);
PyVar from_void_p(VM*, void*); PyVar from_void_p(VM*, void*);
template <typename T> template <typename T>
obj_get_t<T> PyVar::obj_get() { T& PyVar::obj_get() {
if constexpr(is_sso_v<T>) { static_assert(!is_sso_v<T>, "unsupported");
return as<T>(); assert(is_ptr);
} else { void* v = PyObject__value_ptr(_obj);
assert(is_ptr); return *reinterpret_cast<T*>(v);
void* v = PyObject__value_ptr(_obj);
return *reinterpret_cast<T*>(v);
}
} }
#define PK_OBJ_GET(T, obj) ((obj).obj_get<T>()) #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 #define PY_NULL nullptr
extern PyVar PY_OP_CALL;
extern PyVar PY_OP_YIELD;
} // namespace pkpy } // namespace pkpy

View File

@ -12,9 +12,10 @@ struct NameDict;
struct PyObject final: ::PyObject { struct PyObject final: ::PyObject {
bool is_attr_valid() const noexcept { return _attr != nullptr; } 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{ NameDict& attr() const{
assert(is_attr_valid());
return *(NameDict*)_attr; return *(NameDict*)_attr;
} }

View File

@ -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){ 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){ void pkpy_SStream__write_double(pkpy_SStream* self, double val, int precision){

View File

@ -137,16 +137,9 @@ int CodeEmitContext::add_const_string(std::string_view key) noexcept{
int CodeEmitContext::add_const(PyVar v) noexcept{ int CodeEmitContext::add_const(PyVar v) noexcept{
assert(!is_type(v, VM::tp_str)); assert(!is_type(v, VM::tp_str));
// non-string deduplication co->consts.push_back(v);
int* val = _co_consts_nonstring_dedup_map.try_get(v); int index = co->consts.size() - 1;
if(val) { return index;
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{ int CodeEmitContext::add_func_decl(FuncDecl_ decl) noexcept{

View File

@ -1,18 +1,19 @@
#include "pocketpy/interpreter/ceval.hpp" #include "pocketpy/interpreter/ceval.hpp"
#include "pocketpy/objects/base.h"
namespace pkpy { namespace pkpy {
#define PREDICT_INT_OP(op) \ #define PREDICT_INT_OP(op) \
if(is_int(_0) && is_int(_1)) { \ if(is_int(_0) && is_int(_1)) { \
TOP() = VAR(_0.as<i64>() op _1.as<i64>()); \ TOP() = VAR(_0._i64 op _1._i64); \
DISPATCH() \ DISPATCH() \
} }
#define PREDICT_INT_DIV_OP(op) \ #define PREDICT_INT_DIV_OP(op) \
if(is_int(_0) && is_int(_1)) { \ if(is_int(_0) && is_int(_1)) { \
i64 divisor = _1.as<i64>(); \ i64 divisor = _1._i64; \
if(divisor == 0) ZeroDivisionError(); \ if(divisor == 0) ZeroDivisionError(); \
TOP() = VAR(_0.as<i64>() op divisor); \ TOP() = VAR(_0._i64 op divisor); \
DISPATCH() \ DISPATCH() \
} }
@ -24,7 +25,7 @@ namespace pkpy {
} else { \ } else { \
PyVar self; \ PyVar self; \
PyVar _2 = get_unbound_method(_0, func, &self, false); \ PyVar _2 = get_unbound_method(_0, func, &self, false); \
if(_2 != nullptr) \ if(_2) \
ret = call_method(self, _2, _1); \ ret = call_method(self, _2, _1); \
else \ else \
ret = NotImplemented; \ ret = NotImplemented; \
@ -32,7 +33,7 @@ namespace pkpy {
if(is_not_implemented(ret)) { \ if(is_not_implemented(ret)) { \
PyVar self; \ PyVar self; \
PyVar _2 = get_unbound_method(_1, rfunc, &self, false); \ PyVar _2 = get_unbound_method(_1, rfunc, &self, false); \
if(_2 != nullptr) \ if(_2) \
ret = call_method(self, _2, _0); \ ret = call_method(self, _2, _0); \
else \ else \
BinaryOptError(op, _0, _1); \ BinaryOptError(op, _0, _1); \
@ -65,22 +66,26 @@ void VM::__op_unpack_sequence(uint16_t arg) {
bool VM::py_lt(PyVar _0, PyVar _1) { bool VM::py_lt(PyVar _0, PyVar _1) {
BINARY_F_COMPARE(__lt__, "<", __gt__); BINARY_F_COMPARE(__lt__, "<", __gt__);
return ret == True; assert(ret.type == tp_bool);
return ret._bool;
} }
bool VM::py_le(PyVar _0, PyVar _1) { bool VM::py_le(PyVar _0, PyVar _1) {
BINARY_F_COMPARE(__le__, "<=", __ge__); BINARY_F_COMPARE(__le__, "<=", __ge__);
return ret == True; assert(ret.type == tp_bool);
return ret._bool;
} }
bool VM::py_gt(PyVar _0, PyVar _1) { bool VM::py_gt(PyVar _0, PyVar _1) {
BINARY_F_COMPARE(__gt__, ">", __lt__); BINARY_F_COMPARE(__gt__, ">", __lt__);
return ret == True; assert(ret.type == tp_bool);
return ret._bool;
} }
bool VM::py_ge(PyVar _0, PyVar _1) { bool VM::py_ge(PyVar _0, PyVar _1) {
BINARY_F_COMPARE(__ge__, ">=", __le__); BINARY_F_COMPARE(__ge__, ">=", __le__);
return ret == True; assert(ret.type == tp_bool);
return ret._bool;
} }
#undef BINARY_F_COMPARE #undef BINARY_F_COMPARE
@ -167,7 +172,7 @@ PyVar VM::__run_top_frame() {
} }
DISPATCH() DISPATCH()
case OP_PRINT_EXPR: case OP_PRINT_EXPR:
if(TOP() != None) stdout_write(py_repr(TOP()) + "\n"); if(!is_none(TOP())) stdout_write(py_repr(TOP()) + "\n");
POP(); POP();
DISPATCH() DISPATCH()
/*****************************************/ /*****************************************/
@ -717,13 +722,13 @@ PyVar VM::__run_top_frame() {
case OP_IS_OP: { case OP_IS_OP: {
PyVar _1 = POPX(); // rhs PyVar _1 = POPX(); // rhs
PyVar _0 = TOP(); // lhs PyVar _0 = TOP(); // lhs
TOP() = _0 == _1 ? True : False; TOP() = PyVar__IS_OP(&_0, &_1) ? True : False;
} }
DISPATCH() DISPATCH()
case OP_IS_NOT_OP: { case OP_IS_NOT_OP: {
PyVar _1 = POPX(); // rhs PyVar _1 = POPX(); // rhs
PyVar _0 = TOP(); // lhs PyVar _0 = TOP(); // lhs
TOP() = _0 != _1 ? True : False; TOP() = PyVar__IS_OP(&_0, &_1) ? False : True;
} }
DISPATCH() DISPATCH()
case OP_CONTAINS_OP: { case OP_CONTAINS_OP: {
@ -801,7 +806,7 @@ PyVar VM::__run_top_frame() {
PyVar _0 = vectorcall(byte.arg & 0xFF, // ARGC PyVar _0 = vectorcall(byte.arg & 0xFF, // ARGC
(byte.arg >> 8) & 0xFF, // KWARGC (byte.arg >> 8) & 0xFF, // KWARGC
true); true);
if(_0 == PY_OP_CALL) { if(_0.type == tp_op_call) {
frame = &callstack.top(); frame = &callstack.top();
goto __NEXT_FRAME; goto __NEXT_FRAME;
} }
@ -835,7 +840,7 @@ PyVar VM::__run_top_frame() {
0, // KWARGC 0, // KWARGC
true); true);
} }
if(_0 == PY_OP_CALL) { if(_0.type == tp_op_call) {
frame = &callstack.top(); frame = &callstack.top();
goto __NEXT_FRAME; goto __NEXT_FRAME;
} }
@ -854,7 +859,7 @@ PyVar VM::__run_top_frame() {
} }
} }
DISPATCH() DISPATCH()
case OP_YIELD_VALUE: return PY_OP_YIELD; case OP_YIELD_VALUE: return pkpy_OP_YIELD;
/*****************************************/ /*****************************************/
case OP_LIST_APPEND: { case OP_LIST_APPEND: {
PyVar _0 = POPX(); PyVar _0 = POPX();
@ -926,7 +931,7 @@ PyVar VM::__run_top_frame() {
DISPATCH_JUMP_ABSOLUTE(target) DISPATCH_JUMP_ABSOLUTE(target)
} else { } else {
PUSH(_0); PUSH(_0);
return PY_OP_YIELD; return pkpy_OP_YIELD;
} }
} }
case OP_FOR_ITER_UNPACK: { case OP_FOR_ITER_UNPACK: {

View File

@ -1,4 +1,5 @@
#include "pocketpy/interpreter/iter.hpp" #include "pocketpy/interpreter/iter.hpp"
#include "pocketpy/objects/base.h"
namespace pkpy { namespace pkpy {
@ -76,7 +77,7 @@ PyVar Generator::next(VM* vm) {
throw; throw;
} }
if(ret == PY_OP_YIELD) { if(ret->type == tp_op_yield) {
// backup the context // backup the context
lf = vm->callstack.popx(); lf = vm->callstack.popx();
ret = vm->s_data.popx(); ret = vm->s_data.popx();

View File

@ -60,7 +60,7 @@ struct JsonSerializer {
if(std::isinf(val) || std::isnan(val)) vm->ValueError("cannot jsonify 'nan' or 'inf'"); if(std::isinf(val) || std::isnan(val)) vm->ValueError("cannot jsonify 'nan' or 'inf'");
ss << val; ss << val;
} else if(obj_t == vm->tp_bool) { } 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) { } else if(obj_t == vm->tp_str) {
ss << _CAST(Str&, obj).escape('"'); ss << _CAST(Str&, obj).escape('"');
} else if(obj_t == vm->tp_list) { } 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) { 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); const PyTypeInfo* ti = _tp_info(lhs);
PyVar res; PyVar res;
if(ti->m__eq__) { if(ti->m__eq__) {
res = ti->m__eq__(this, lhs, rhs); 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); 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); ti = _tp_info(rhs);
if(ti->m__eq__) { if(ti->m__eq__) {
res = ti->m__eq__(this, rhs, lhs); 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); 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; return false;
} }
@ -538,7 +538,8 @@ i64 VM::py_hash(PyVar obj) {
has_custom_eq = true; has_custom_eq = true;
else { else {
f = get_unbound_method(obj, __eq__, &self, false); 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) { if(has_custom_eq) {
TypeError(_S("unhashable type: ", ti->name.escape())); 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_not_implemented_type, new_type_object(nullptr, "NotImplementedType", tp_object, false));
validate(tp_ellipsis, new_type_object(nullptr, "ellipsis", 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 // SyntaxError and IndentationError must be created here
PyObject* SyntaxError = new_type_object(nullptr, "SyntaxError", tp_exception, true); PyObject* SyntaxError = new_type_object(nullptr, "SyntaxError", tp_exception, true);
PyObject* IndentationError = new_type_object(nullptr, "IndentationError", SyntaxError->as<Type>(), 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 // simple or normal
callstack.emplace(p0, co, fn._module, callable.get(), args.begin()); 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(); return __run_top_frame();
/*****************_py_call*****************/ /*****************_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 new_f = *find_name_in_mro(PK_OBJ_GET(Type, callable), __new__);
PyVar obj; PyVar obj;
assert(new_f != nullptr && p0[1] == PY_NULL); 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__ // fast path for object.__new__
obj = vm->new_object<DummyInstance>(PK_OBJ_GET(Type, callable)); obj = vm->new_object<DummyInstance>(PK_OBJ_GET(Type, callable));
} else { } else {
@ -1326,7 +1330,7 @@ void VM::setattr(PyVar obj, StrName name, PyVar value) {
// handle descriptor // handle descriptor
if(is_type(*cls_var, tp_property)) { if(is_type(*cls_var, tp_property)) {
const Property& prop = _CAST(Property&, *cls_var); const Property& prop = _CAST(Property&, *cls_var);
if(prop.setter != vm->None) { if(!is_none(prop.setter)) {
call(prop.setter, obj, value); call(prop.setter, obj, value);
} else { } else {
TypeError(_S("readonly attribute: ", name.escape())); TypeError(_S("readonly attribute: ", name.escape()));

View File

@ -113,8 +113,8 @@ struct Array2d {
const Tuple& xy = CAST(Tuple&, _1); const Tuple& xy = CAST(Tuple&, _1);
if(is_int(xy[0]) && is_int(xy[1])) { if(is_int(xy[0]) && is_int(xy[1])) {
i64 col = xy[0].as<i64>(); i64 col = xy[0]._i64;
i64 row = xy[1].as<i64>(); i64 row = xy[1]._i64;
self.check_valid(vm, col, row); self.check_valid(vm, col, row);
return self._get(col, row); return self._get(col, row);
} }
@ -138,8 +138,8 @@ struct Array2d {
Array2d& self = PK_OBJ_GET(Array2d, _0); Array2d& self = PK_OBJ_GET(Array2d, _0);
const Tuple& xy = CAST(Tuple&, _1); const Tuple& xy = CAST(Tuple&, _1);
if(is_int(xy[0]) && is_int(xy[1])) { if(is_int(xy[0]) && is_int(xy[1])) {
i64 col = xy[0].as<i64>(); i64 col = xy[0]._i64;
i64 row = xy[1].as<i64>(); i64 row = xy[1]._i64;
self.check_valid(vm, col, row); self.check_valid(vm, col, row);
self._set(col, row, _2); self._set(col, row, _2);
return; return;

View File

@ -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_staticmethod = 22, tp_classmethod = 23;
const pkpy_Type tp_none_type = 24, tp_not_implemented_type = 25; const pkpy_Type tp_none_type = 24, tp_not_implemented_type = 25;
const pkpy_Type tp_ellipsis = 26; 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}; PyVar pkpy_True = {.type=tp_bool, .is_ptr=false, ._bool=true};
const PyVar pkpy_False = {.type=tp_bool, .is_ptr=false, .flags=0, .flags_ex=0, ._bool=false}; PyVar pkpy_False = {.type=tp_bool, .is_ptr=false, ._bool=false};
const PyVar pkpy_None = {.type=tp_none_type, .is_ptr=false, .flags=0, .flags_ex=0, ._i64=0}; PyVar pkpy_None = {.type=tp_none_type, .is_ptr=false};
const PyVar pkpy_NotImplemented = {.type=tp_not_implemented_type, .is_ptr=false, .flags=0, .flags_ex=0, ._i64=0}; PyVar pkpy_NotImplemented = {.type=tp_not_implemented_type, .is_ptr=false};
const PyVar pkpy_Ellipsis = {.type=tp_ellipsis, .is_ptr=false, .flags=0, .flags_ex=0, ._i64=0}; PyVar pkpy_Ellipsis = {.type=tp_ellipsis, .is_ptr=false};
const PyVar pkpy_NULL = {.type=0, .is_ptr=false, .flags=0, .flags_ex=0, ._i64=0}; 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};

View File

@ -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

View File

@ -1,10 +1,8 @@
#include "pocketpy/objects/object.h" #include "pocketpy/objects/object.h"
void PyVar__ctor2(PyVar* self, PyObject* existing){ void PyVar__ctor3(PyVar* self, PyObject* existing){
assert(existing); assert(existing);
self->type = existing->type; self->type = existing->type;
self->is_ptr = true; self->is_ptr = true;
self->flags = 0;
self->flags_ex = 0;
self->_obj = existing; self->_obj = existing;
} }

View File

@ -11,6 +11,7 @@
#include "pocketpy/modules/linalg.hpp" #include "pocketpy/modules/linalg.hpp"
#include "pocketpy/modules/random.hpp" #include "pocketpy/modules/random.hpp"
#include "pocketpy/modules/modules.hpp" #include "pocketpy/modules/modules.hpp"
#include "pocketpy/objects/base.h"
#include <iostream> #include <iostream>
#include <algorithm> #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>); static_assert(std::is_same_v<T, List> || std::is_same_v<T, Tuple>);
const T& self = _CAST(T&, _0); const T& self = _CAST(T&, _0);
if(is_int(_1)) { if(is_int(_1)) {
i64 index = _1.as<i64>(); i64 index = _1._i64;
index = vm->normalized_index(index, self.size()); index = vm->normalized_index(index, self.size());
return self[index]; return self[index];
} }
@ -374,7 +375,7 @@ void __init_builtins(VM* _vm) {
}); });
_vm->bind__eq__(VM::tp_object, [](VM* vm, PyVar _0, PyVar _1) { _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) { _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])) { switch(vm->_tp(args[1])) {
case VM::tp_float: return VAR((i64)_CAST(f64, args[1])); case VM::tp_float: return VAR((i64)_CAST(f64, args[1]));
case VM::tp_int: return 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; case VM::tp_str: break;
default: vm->TypeError("invalid arguments for int()"); default: vm->TypeError("invalid arguments for int()");
} }
@ -542,7 +543,7 @@ void __init_builtins(VM* _vm) {
switch(vm->_tp(args[1])) { switch(vm->_tp(args[1])) {
case VM::tp_int: return VAR((f64)CAST(i64, args[1])); case VM::tp_int: return VAR((f64)CAST(i64, args[1]));
case VM::tp_float: return 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; case VM::tp_str: break;
default: vm->TypeError("invalid arguments for float()"); 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 { _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); List& iterable = _CAST(List&, _0);
SStream ss; SStream ss;
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++) { for(int i = 0; i < iterable.size(); i++) {
ss << vm->py_repr(iterable[i]); ss << vm->py_repr(iterable[i]);
if(i != iterable.size() - 1) ss << ", "; if(i != iterable.size() - 1) ss << ", ";
@ -1150,7 +1151,7 @@ void __init_builtins(VM* _vm) {
return VAR(_CAST(bool, _0) != CAST(bool, _1)); return VAR(_CAST(bool, _0) != CAST(bool, _1));
}); });
_vm->bind__eq__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _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)); if(is_int(_1)) return VAR(_CAST(bool, _0) == (bool)CAST(i64, _1));
return vm->NotImplemented; return vm->NotImplemented;
}); });
@ -1316,12 +1317,12 @@ void __init_builtins(VM* _vm) {
}); });
_vm->bind__repr__(VM::tp_mappingproxy, [](VM* vm, PyVar _0) -> Str { _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); MappingProxy& self = _CAST(MappingProxy&, _0);
SStream ss; SStream ss;
ss << "mappingproxy({"; ss << "mappingproxy({";
bool first = true; 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()) { for(auto [k, v]: self.attr().items()) {
if(!first) ss << ", "; if(!first) ss << ", ";
first = false; first = false;
@ -1472,12 +1473,12 @@ void __init_builtins(VM* _vm) {
}); });
_vm->bind__repr__(VM::tp_dict, [](VM* vm, PyVar _0) -> Str { _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); Dict& self = _CAST(Dict&, _0);
SStream ss; SStream ss;
ss << "{"; ss << "{";
bool first = true; bool first = true;
vm->_repr_recursion_set.push_back(_0); vm->_repr_recursion_set.push_back(_0.get());
self.apply([&](PyVar k, PyVar v) { self.apply([&](PyVar k, PyVar v) {
if(!first) ss << ", "; if(!first) ss << ", ";
first = false; 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) { _vm->bind(_vm->_t(VM::tp_exception), "__init__(self, msg=...)", [](VM* vm, ArgsView args) {
Exception& self = _CAST(Exception&, args[0]); Exception& self = _CAST(Exception&, args[0]);
if(args[1] == vm->Ellipsis) { if(args[1].type == tp_ellipsis) {
self.msg = ""; self.msg = "";
} else { } else {
self.msg = CAST(Str, args[1]); 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; if(!is_type(rhs, vm->tp_bound_method)) return vm->NotImplemented;
const BoundMethod& _0 = PK_OBJ_GET(BoundMethod, lhs); const BoundMethod& _0 = PK_OBJ_GET(BoundMethod, lhs);
const BoundMethod& _1 = PK_OBJ_GET(BoundMethod, rhs); 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) { bind_property(_t(tp_slice), "start", [](VM* vm, ArgsView args) {