diff --git a/build_g.sh b/build_g.sh index 72f29054..9909b282 100644 --- a/build_g.sh +++ b/build_g.sh @@ -5,8 +5,12 @@ python prebuild.py SRC=$(find src/ -name "*.c") FLAGS="-std=c11 -lm -Iinclude -O0 -Wfatal-errors -g -DDEBUG -DPK_ENABLE_OS=1" + SANITIZE_FLAGS="-fsanitize=address,leak,undefined" -# SANITIZE_FLAGS="" + +if [ "$(uname)" == "Darwin" ]; then + SANITIZE_FLAGS="-fsanitize=address,undefined" +fi echo "Compiling C files..." clang $FLAGS $SANITIZE_FLAGS $SRC src2/main.c -o main diff --git a/include/pocketpy/common/strname.h b/include/pocketpy/common/strname.h index 28503789..08f43fc6 100644 --- a/include/pocketpy/common/strname.h +++ b/include/pocketpy/common/strname.h @@ -10,8 +10,6 @@ extern "C" { typedef uint16_t StrName; -#define py_name(name) pk_StrName__map(name) - uint16_t pk_StrName__map(const char*); uint16_t pk_StrName__map2(c11_string); const char* pk_StrName__rmap(uint16_t index); diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 12c2bacb..52d94a24 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -8,61 +8,54 @@ extern "C" { #endif -typedef struct pk_TypeInfo{ +typedef struct pk_TypeInfo { py_Name name; py_Type base; - py_TValue self; // the type object itself - py_TValue module; // the module where the type is defined + py_TValue self; + py_TValue module; // the module where the type is defined bool subclass_enabled; void (*dtor)(void*); void (*gc_mark)(void*); - c11_vector/*T=StrName*/ annotated_fields; + c11_vector /*T=StrName*/ annotated_fields; - py_CFunction on_end_subclass; // backdoor for enum module + py_CFunction on_end_subclass; // backdoor for enum module - /* Magic Caches */ + /* Magic Slots */ py_TValue magic[64]; - // // unary operators - // py_CFunction m__repr__, m__str__, m__hash__, m__len__; - // py_CFunction m__iter__, m__next__, m__neg__, m__invert__; - // // binary operators - // py_CFunction m__eq__, m__lt__, m__le__, m__gt__, m__ge__, m__contains__; - // py_CFunction m__add__, m__sub__, m__mul__, m__truediv__, m__floordiv__; - // py_CFunction m__mod__, m__pow__, m__matmul__; - // py_CFunction m__lshift__, m__rshift__, m__and__, m__xor__, m__or__; - // // indexer - // py_CFunction m__getitem__, m__setitem__, m__delitem__; - // // attribute access (internal use only) - // py_CFunction m__getattr__, m__setattr__, m__delattr__; } pk_TypeInfo; -void pk_TypeInfo__ctor(pk_TypeInfo* self, py_Name name, py_Type base, PyObject* obj, const py_TValue* module, bool subclass_enabled); +void pk_TypeInfo__ctor(pk_TypeInfo* self, + py_Name name, + py_Type index, + py_Type base, + const py_TValue* module, + bool subclass_enabled); void pk_TypeInfo__dtor(pk_TypeInfo* self); typedef struct pk_VM { Frame* top_frame; - - pk_NameDict modules; - c11_vector/*T=pk_TypeInfo*/ types; - py_TValue StopIteration; // a special Exception class - py_TValue builtins; // builtins module - py_TValue main; // __main__ module + pk_NameDict modules; + c11_vector /*T=pk_TypeInfo*/ types; + + py_TValue StopIteration; // a special Exception class + py_TValue builtins; // builtins module + py_TValue main; // __main__ module void (*_ceval_on_step)(Frame*, Bytecode); unsigned char* (*_import_file)(const char*); void (*_stdout)(const char*, ...); void (*_stderr)(const char*, ...); - + // singleton objects py_TValue True, False, None, NotImplemented, Ellipsis; py_Error* last_error; py_TValue last_retval; - py_TValue reg[8]; // users' registers + py_TValue reg[8]; // users' registers py_TValue __curr_class; py_TValue __cached_object_new; @@ -70,7 +63,7 @@ typedef struct pk_VM { py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES]; pk_ManagedHeap heap; - ValueStack stack; // put `stack` at the end for better cache locality + ValueStack stack; // put `stack` at the end for better cache locality } pk_VM; void pk_VM__ctor(pk_VM* self); @@ -81,7 +74,7 @@ void pk_VM__pop_frame(pk_VM* self); void pk_VM__init_builtins(pk_VM* self); -typedef enum pk_FrameResult{ +typedef enum pk_FrameResult { RES_RETURN, RES_CALL, RES_YIELD, @@ -90,7 +83,11 @@ typedef enum pk_FrameResult{ pk_FrameResult pk_VM__run_top_frame(pk_VM* self); -py_Type pk_VM__new_type(pk_VM* self, const char* name, py_Type base, const py_TValue* module, bool subclass_enabled); +py_Type pk_VM__new_type(pk_VM* self, + const char* name, + py_Type base, + const py_TValue* module, + bool subclass_enabled); // type registration py_Type pk_list__register(); diff --git a/include/pocketpy/objects/base.h b/include/pocketpy/objects/base.h index 8d2811f4..274abcae 100644 --- a/include/pocketpy/objects/base.h +++ b/include/pocketpy/objects/base.h @@ -24,9 +24,9 @@ typedef struct py_TValue { union { int64_t _i64; double _f64; - PyObject* _obj; - void* _ptr; + bool _bool; py_CFunction _cfunc; + PyObject* _obj; // Vec2 }; } py_TValue; @@ -46,20 +46,10 @@ const static py_Type tp_dict = {19}, tp_property = {20}, tp_star_wrapper = {21}; const static py_Type tp_staticmethod = {22}, tp_classmethod = {23}; const static py_Type tp_none_type = {24}, tp_not_implemented_type = {25}; const static py_Type tp_ellipsis = {26}; -const static py_Type tp_op_call = {27}, tp_op_yield = {28}; -const static py_Type tp_syntax_error = {29}, tp_stop_iteration = {30}; +const static py_Type tp_syntax_error = {27}, tp_stop_iteration = {28}; -extern py_TValue PY_NULL, PY_OP_CALL, PY_OP_YIELD; +extern py_TValue PY_NULL; #ifdef __cplusplus } #endif - -/* -SSO types: -1. int64_t -2. double -3. bool (dummy) -4. tuple (extra + void*) -5. string (extra + void* or buf) -*/ \ No newline at end of file diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 2d273e46..9156a557 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -36,7 +36,7 @@ void py_finalize(); /// Run a simple source string. Do not change the stack. bool py_exec(const char*); /// Eval a simple expression. -/// The result will be set to `vm->last_retval`. +/// The result will be set to `py_retval()`. bool py_eval(const char*); /************* Values Creation *************/ @@ -45,10 +45,11 @@ void py_newfloat(py_Ref, double); void py_newbool(py_Ref, bool); void py_newstr(py_Ref, const char*); void py_newstrn(py_Ref, const char*, int); -void py_newStr_(py_Ref, py_Str); // void py_newfstr(py_Ref, const char*, ...); void py_newbytes(py_Ref, const unsigned char*, int); void py_newnone(py_Ref); +void py_newnotimplemented(py_Ref out); +void py_newellipsis(py_Ref out); void py_newnull(py_Ref); /// Create a tuple with n UNINITIALIZED elements. @@ -60,6 +61,10 @@ void py_newlist(py_Ref); /// You should initialize all elements before using it. void py_newlistn(py_Ref, int n); +py_Name py_name(const char*); +const char* py_name2str(py_Name); +bool py_ismagicname(py_Name); + // opaque types void py_newdict(py_Ref); void py_newset(py_Ref); @@ -76,8 +81,6 @@ void py_newfunction2(py_Ref out, // old style argc-based function void py_newnativefunc(py_Ref out, py_CFunction); -void py_newnotimplemented(py_Ref out); - /// Create a new object. /// @param out output reference. /// @param type type of the object. @@ -89,6 +92,7 @@ int64_t py_toint(const py_Ref); double py_tofloat(const py_Ref); bool py_castfloat(const py_Ref, double* out); bool py_tobool(const py_Ref); +py_Type py_totype(const py_Ref); const char* py_tostr(const py_Ref); const char* py_tostrn(const py_Ref, int* size); @@ -104,8 +108,10 @@ bool py_isinstance(const py_Ref obj, py_Type type); bool py_issubclass(py_Type derived, py_Type base); /************* References *************/ +#define py_offset(p, i) (py_Ref)((char*)p + ((i) << 4)) + #define TypeError(x) false -#define py_arg(i) (py_Ref)((char*)argv + ((i) << 4)) +#define py_arg(i) py_offset(argv, i) #define py_checkargc(n) \ if(argc != n) return TypeError() @@ -164,7 +170,7 @@ bool py_delitem(py_Ref self, const py_Ref key); /// Perform a binary operation on the stack. /// It assumes `lhs` and `rhs` are already pushed to the stack. -/// The result will be set to `vm->last_retval`. +/// The result will be set to `py_retval()`. bool py_binaryop(const py_Ref lhs, const py_Ref rhs, py_Name op, py_Name rop); #define py_binaryadd(lhs, rhs) py_binaryop(lhs, rhs, __add__, __radd__) @@ -237,21 +243,21 @@ bool py_isidentical(const py_Ref, const py_Ref); /// A stack operation that calls a function. /// It assumes `argc + kwargc` arguments are already pushed to the stack. -/// The result will be set to `vm->last_retval`. +/// The result will be set to `py_retval()`. /// The stack size will be reduced by `argc + kwargc`. bool pk_vectorcall(int argc, int kwargc, bool op_call); /// Call a function. /// It prepares the stack and then performs a `vectorcall(argc, 0, false)`. -/// The result will be set to `vm->last_retval`. +/// The result will be set to `py_retval()`. /// The stack remains unchanged after the operation. bool py_call(py_Ref f, int argc, py_Ref argv); /// Call a non-magic method. /// It prepares the stack and then performs a `vectorcall(argc+1, 0, false)`. -/// The result will be set to `vm->last_retval`. +/// The result will be set to `py_retval()`. /// The stack remains unchanged after the operation. bool py_callmethod(py_Ref self, py_Name, int argc, py_Ref argv); /// Call a magic method. -/// The result will be set to `vm->last_retval`. +/// The result will be set to `py_retval()`. /// The stack remains unchanged after the operation. bool py_callmagic(py_Name name, int argc, py_Ref argv); @@ -259,7 +265,7 @@ bool py_callmagic(py_Name name, int argc, py_Ref argv); #define py_str(self) py_callmagic(__str__, 1, self) /// The return value of the most recent vectorcall. -py_Ref py_lastretval(); +py_Ref py_retval(); #define py_isnull(self) ((self)->type == 0) diff --git a/src/common/strname.c b/src/common/strname.c index 9f695a31..041e5656 100644 --- a/src/common/strname.c +++ b/src/common/strname.c @@ -2,6 +2,7 @@ #include "pocketpy/common/smallmap.h" #include "pocketpy/common/utils.h" #include "pocketpy/common/vector.h" +#include "pocketpy/pocketpy.h" #include @@ -80,6 +81,18 @@ c11_string pk_StrName__rmap2(uint16_t index) { return (c11_string){p, strlen(p)}; } +py_Name py_name(const char* name) { + return pk_StrName__map(name); +} + +const char* py_name2str(py_Name name) { + return pk_StrName__rmap(name); +} + +bool py_ismagicname(py_Name name){ + return name <= __missing__; +} + /////////////////////////////////// #define MAGIC_METHOD(x) uint16_t x; #include "pocketpy/xmacros/magics.h" diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index a138ddb9..e35309b3 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -13,6 +13,9 @@ int NameError(py_Name name) { return -1; } static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop); +// private +void py_newStr_(py_Ref, py_Str); + #define DISPATCH() \ do { \ frame->ip++; \ diff --git a/src/interpreter/py_number.c b/src/interpreter/py_number.c index 8b06643d..6e097b1a 100644 --- a/src/interpreter/py_number.c +++ b/src/interpreter/py_number.c @@ -45,13 +45,13 @@ if(py_isint(&argv[1])) { \ int64_t lhs = py_toint(&argv[0]); \ int64_t rhs = py_toint(&argv[1]); \ - rint(py_lastretval(), lhs op rhs); \ + rint(py_retval(), lhs op rhs); \ } else if(py_isfloat(&argv[1])) { \ int64_t lhs = py_toint(&argv[0]); \ double rhs = py_tofloat(&argv[1]); \ - rfloat(py_lastretval(), lhs op rhs); \ + rfloat(py_retval(), lhs op rhs); \ } else { \ - py_newnotimplemented(py_lastretval()); \ + py_newnotimplemented(py_retval()); \ } \ return true; \ } \ @@ -60,9 +60,9 @@ double lhs = py_tofloat(&argv[0]); \ double rhs; \ if(py_castfloat(&argv[1], &rhs)) { \ - rfloat(py_lastretval(), lhs op rhs); \ + rfloat(py_retval(), lhs op rhs); \ } else { \ - py_newnotimplemented(py_lastretval()); \ + py_newnotimplemented(py_retval()); \ } \ return true; \ } @@ -83,14 +83,14 @@ DEF_NUM_BINARY_OP(__ge__, >=, py_newbool, py_newbool) static bool _py_int__neg__(int argc, py_Ref argv) { py_checkargc(1); int64_t val = py_toint(&argv[0]); - py_newint(py_lastretval(), -val); + py_newint(py_retval(), -val); return true; } static bool _py_float__neg__(int argc, py_Ref argv) { py_checkargc(1); double val = py_tofloat(&argv[0]); - py_newfloat(py_lastretval(), -val); + py_newfloat(py_retval(), -val); return true; } @@ -99,9 +99,9 @@ static bool _py_int__truediv__(int argc, py_Ref argv) { int64_t lhs = py_toint(&argv[0]); double rhs; if(py_castfloat(&argv[1], &rhs)) { - py_newfloat(py_lastretval(), lhs / rhs); + py_newfloat(py_retval(), lhs / rhs); } else { - py_newnotimplemented(py_lastretval()); + py_newnotimplemented(py_retval()); } return true; } @@ -111,9 +111,9 @@ static bool _py_float__truediv__(int argc, py_Ref argv) { double lhs = py_tofloat(&argv[0]); double rhs; if(py_castfloat(&argv[1], &rhs)) { - py_newfloat(py_lastretval(), lhs / rhs); + py_newfloat(py_retval(), lhs / rhs); } else { - py_newnotimplemented(py_lastretval()); + py_newnotimplemented(py_retval()); } return true; } @@ -129,7 +129,7 @@ static bool _py_number__pow__(int argc, py_Ref argv) { if(lhs == 0) { return ZeroDivisionError("0.0 cannot be raised to a negative power"); } else { - py_newfloat(py_lastretval(), pow(lhs, rhs)); + py_newfloat(py_retval(), pow(lhs, rhs)); } } else { int64_t ret = 1; @@ -138,15 +138,15 @@ static bool _py_number__pow__(int argc, py_Ref argv) { lhs *= lhs; rhs >>= 1; } - py_newint(py_lastretval(), ret); + py_newint(py_retval(), ret); } } else { double lhs, rhs; py_castfloat(&argv[0], &lhs); if(py_castfloat(&argv[1], &rhs)) { - py_newfloat(py_lastretval(), pow(lhs, rhs)); + py_newfloat(py_retval(), pow(lhs, rhs)); } else { - py_newnotimplemented(py_lastretval()); + py_newnotimplemented(py_retval()); } } return true; @@ -158,9 +158,9 @@ static bool _py_int__floordiv__(int argc, py_Ref argv) { if(py_isint(&argv[1])) { int64_t rhs = py_toint(&argv[1]); if(rhs == 0) return -1; - py_newint(py_lastretval(), lhs / rhs); + py_newint(py_retval(), lhs / rhs); } else { - py_newnotimplemented(py_lastretval()); + py_newnotimplemented(py_retval()); } return true; } @@ -171,9 +171,9 @@ static bool _py_int__mod__(int argc, py_Ref argv) { if(py_isint(&argv[1])) { int64_t rhs = py_toint(&argv[1]); if(rhs == 0) return ZeroDivisionError("integer division or modulo by zero"); - py_newint(py_lastretval(), lhs % rhs); + py_newint(py_retval(), lhs % rhs); } else { - py_newnotimplemented(py_lastretval()); + py_newnotimplemented(py_retval()); } return true; } @@ -181,7 +181,7 @@ static bool _py_int__mod__(int argc, py_Ref argv) { static bool _py_int__invert__(int argc, py_Ref argv) { py_checkargc(1); int64_t val = py_toint(&argv[0]); - py_newint(py_lastretval(), ~val); + py_newint(py_retval(), ~val); return true; } @@ -194,7 +194,7 @@ static bool _py_int__bit_length(int argc, py_Ref argv) { x >>= 1; bits++; } - py_newint(py_lastretval(), bits); + py_newint(py_retval(), bits); return true; } @@ -204,9 +204,9 @@ static bool _py_int__bit_length(int argc, py_Ref argv) { int64_t lhs = py_toint(&argv[0]); \ if(py_isint(&argv[1])) { \ int64_t rhs = py_toint(&argv[1]); \ - py_newint(py_lastretval(), lhs op rhs); \ + py_newint(py_retval(), lhs op rhs); \ } else { \ - py_newnotimplemented(py_lastretval()); \ + py_newnotimplemented(py_retval()); \ } \ return true; \ } diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 6e106499..8222bb78 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -1,8 +1,11 @@ #include "pocketpy/interpreter/vm.h" #include "pocketpy/common/memorypool.h" #include "pocketpy/common/sstream.h" +#include "pocketpy/objects/base.h" #include "pocketpy/pocketpy.h" +#include + static unsigned char* pk_default_import_file(const char* path) { return NULL; } static void pk_default_stdout(const char* fmt, ...) { @@ -23,8 +26,8 @@ static void pk_default_stderr(const char* fmt, ...) { void pk_TypeInfo__ctor(pk_TypeInfo* self, py_Name name, + py_Type index, py_Type base, - PyObject* obj, const py_TValue* module, bool subclass_enabled) { memset(self, 0, sizeof(pk_TypeInfo)); @@ -32,7 +35,11 @@ void pk_TypeInfo__ctor(pk_TypeInfo* self, self->name = name; self->base = base; - self->self = PyVar__fromobj(obj); + // create type object with __dict__ + pk_ManagedHeap* heap = &pk_current_vm->heap; + PyObject* typeobj = pk_ManagedHeap__new(heap, tp_type, -1, sizeof(py_Type)); + self->self = PyVar__fromobj(typeobj); + self->module = module ? *module : PY_NULL; self->subclass_enabled = subclass_enabled; @@ -66,37 +73,9 @@ void pk_VM__ctor(pk_VM* self) { pk_ManagedHeap__ctor(&self->heap, self); ValueStack__ctor(&self->stack); - self->True = (py_TValue){ - .type = tp_bool, - .is_ptr = true, - .extra = 1, - ._obj = pk_ManagedHeap__gcnew(&self->heap, tp_bool, 0, 0), - }; - self->False = (py_TValue){ - .type = tp_bool, - .is_ptr = true, - .extra = 0, - ._obj = pk_ManagedHeap__gcnew(&self->heap, tp_bool, 0, 0), - }; - self->None = (py_TValue){ - .type = tp_none_type, - .is_ptr = true, - ._obj = pk_ManagedHeap__gcnew(&self->heap, tp_none_type, 0, 0), - }; - self->NotImplemented = (py_TValue){ - .type = tp_not_implemented_type, - .is_ptr = true, - ._obj = pk_ManagedHeap__gcnew(&self->heap, tp_not_implemented_type, 0, 0), - }; - self->Ellipsis = (py_TValue){ - .type = tp_ellipsis, - .is_ptr = true, - ._obj = pk_ManagedHeap__gcnew(&self->heap, tp_ellipsis, 0, 0), - }; - /* Init Builtin Types */ // 0: unused - pk_TypeInfo__ctor(c11_vector__emplace(&self->types), 0, 0, NULL, NULL, false); + pk_TypeInfo__ctor(c11_vector__emplace(&self->types), 0, 0, 0, NULL, false); #define validate(t, expr) \ if(t != (expr)) abort() @@ -136,14 +115,11 @@ void pk_VM__ctor(pk_VM* self) { pk_VM__new_type(self, "NotImplementedType", tp_object, NULL, false)); validate(tp_ellipsis, pk_VM__new_type(self, "ellipsis", tp_object, NULL, false)); - validate(tp_op_call, pk_VM__new_type(self, "__op_call", tp_object, NULL, false)); - validate(tp_op_yield, pk_VM__new_type(self, "__op_yield", tp_object, NULL, false)); - validate(tp_syntax_error, pk_VM__new_type(self, "SyntaxError", tp_exception, NULL, false)); validate(tp_stop_iteration, pk_VM__new_type(self, "StopIteration", tp_exception, NULL, false)); #undef validate - self->StopIteration = c11__at(pk_TypeInfo, &self->types, tp_stop_iteration)->self; + self->StopIteration = *py_tpobject(tp_stop_iteration); self->builtins = *py_newmodule("builtins", NULL); /* Setup Public Builtin Types */ @@ -167,7 +143,7 @@ void pk_VM__ctor(pk_VM* self) { for(int i = 0; i < PK_ARRAY_COUNT(public_types); i++) { py_Type t = public_types[i]; pk_TypeInfo* ti = c11__at(pk_TypeInfo, &self->types, t); - py_setdict(&self->builtins, ti->name, &ti->self); + py_setdict(&self->builtins, ti->name, py_tpobject(t)); } py_setdict(&self->builtins, py_name("NotImplemented"), &self->NotImplemented); @@ -207,13 +183,10 @@ py_Type pk_VM__new_type(pk_VM* self, py_Type base, const py_TValue* module, bool subclass_enabled) { - py_Type type = self->types.count; + py_Type index = self->types.count; pk_TypeInfo* ti = c11_vector__emplace(&self->types); - PyObject* typeobj = pk_ManagedHeap__gcnew(&self->heap, tp_type, -1, sizeof(py_Type)); - py_Type* value = PyObject__value(typeobj); - *value = type; - pk_TypeInfo__ctor(ti, py_name(name), base, typeobj, module, subclass_enabled); - return type; + pk_TypeInfo__ctor(ti, py_name(name), index, base, module, subclass_enabled); + return index; } /****************************************/ diff --git a/src/objects/base.c b/src/objects/base.c index 9116256d..9531b69c 100644 --- a/src/objects/base.c +++ b/src/objects/base.c @@ -1,6 +1,4 @@ #include "pocketpy/objects/base.h" py_TValue PY_NULL = {.type=0, .is_ptr=false, .extra=0, ._i64=0}; -py_TValue PY_OP_CALL = {.type=27, .is_ptr=false, .extra=0, ._i64=0}; -py_TValue PY_OP_YIELD = {.type=28, .is_ptr=false, .extra=0, ._i64=0}; diff --git a/src/public/cast.c b/src/public/cast.c index c4f9d292..97668e46 100644 --- a/src/public/cast.c +++ b/src/public/cast.c @@ -29,7 +29,13 @@ bool py_castfloat(const py_Ref self, double* out){ bool py_tobool(const py_Ref self){ assert(self->type == tp_bool); - return self->extra; + return self->_bool; +} + +py_Type py_totype(const py_Ref self){ + assert(self->type == tp_type); + py_Type* ud = py_touserdata(self); + return *ud; } const char* py_tostr(const py_Ref self){ diff --git a/src/public/py_ops.c b/src/public/py_ops.c index 326c3b6d..757de0f7 100644 --- a/src/public/py_ops.c +++ b/src/public/py_ops.c @@ -1,9 +1,20 @@ #include "pocketpy/interpreter/vm.h" +#include "pocketpy/objects/base.h" #include "pocketpy/pocketpy.h" bool py_isidentical(const py_Ref lhs, const py_Ref rhs) { - if(lhs->is_ptr && rhs->is_ptr) { return lhs->_obj == rhs->_obj; } - return false; + if(lhs->type != rhs->type) return false; + switch(lhs->type){ + case tp_int: return lhs->_i64 == rhs->_i64; + case tp_float: return lhs->_f64 == rhs->_f64; + case tp_bool: return lhs->_bool == rhs->_bool; + case tp_nativefunc: return lhs->_cfunc == rhs->_cfunc; + case tp_none_type: return true; + case tp_not_implemented_type: return true; + case tp_ellipsis: return true; + // fallback to pointer comparison + default: return lhs->is_ptr && rhs->is_ptr && lhs->_obj == rhs->_obj; + } } int py_bool(const py_Ref val) { return 1; } @@ -26,7 +37,7 @@ bool py_delitem(py_Ref self, const py_Ref key) { return -1; } int py_##name(const py_Ref lhs, const py_Ref rhs) { \ bool ok = py_binaryop(lhs, rhs, op, rop); \ if(!ok) return -1; \ - return py_tobool(py_lastretval()); \ + return py_tobool(py_retval()); \ } COMPARE_OP_IMPL(eq, __eq__, __eq__) diff --git a/src/public/stack_ops.c b/src/public/stack_ops.c index b03d1d33..acbba5a3 100644 --- a/src/public/stack_ops.c +++ b/src/public/stack_ops.c @@ -10,11 +10,20 @@ py_Ref py_reg(int i){ py_Ref py_getdict(const py_Ref self, py_Name name){ assert(self && self->is_ptr); + if(self->type == tp_type && py_ismagicname(name)){ + py_Type* ud = py_touserdata(self); + py_Ref slot = py_tpmagic(*ud, name); + return py_isnull(slot) ? NULL : slot; + } return pk_NameDict__try_get(PyObject__dict(self->_obj), name); } void py_setdict(py_Ref self, py_Name name, const py_Ref val){ assert(self && self->is_ptr); + if(self->type == tp_type && py_ismagicname(name)){ + py_Type* ud = py_touserdata(self); + *py_tpmagic(*ud, name) = *val; + } pk_NameDict__set(PyObject__dict(self->_obj), name, *val); } diff --git a/src/public/values.c b/src/public/values.c index bf6df138..327cc6fc 100644 --- a/src/public/values.c +++ b/src/public/values.c @@ -17,10 +17,29 @@ void py_newfloat(py_Ref out, double val) { } void py_newbool(py_Ref out, bool val) { - pk_VM* vm = pk_current_vm; - *out = val ? vm->True : vm->False; + out->type = tp_bool; + out->is_ptr = false; + out->_bool = val; } +void py_newnone(py_Ref out) { + out->type = tp_none_type; + out->is_ptr = false; +} + +void py_newnotimplemented(py_Ref out) { + out->type = tp_not_implemented_type; + out->is_ptr = false; +} + +void py_newellipsis(py_Ref out) { + out->type = tp_ellipsis; + out->is_ptr = false; +} + + +void py_newnull(py_Ref out) { out->type = 0; } + void py_newstr(py_Ref out, const char* data) { pk_ManagedHeap* heap = &pk_current_vm->heap; PyObject* obj = pk_ManagedHeap__gcnew(heap, tp_str, 0, sizeof(py_Str)); @@ -61,13 +80,6 @@ void py_newbytes(py_Ref out, const unsigned char* data, int size) { out->_obj = obj; } -void py_newnone(py_Ref out) { - pk_VM* vm = pk_current_vm; - *out = vm->None; -} - -void py_newnull(py_Ref out) { out->type = 0; } - void py_newfunction(py_Ref out, py_CFunction f, const char* sig) { py_newfunction2(out, f, sig, BindType_FUNCTION, NULL, NULL); } @@ -101,11 +113,6 @@ void py_bindnativefunc(py_Ref obj, const char *name, py_CFunction f){ py_setdict(obj, py_name(name), &tmp); } -void py_newnotimplemented(py_Ref out) { - pk_VM* vm = pk_current_vm; - *out = vm->NotImplemented; -} - void py_newslice(py_Ref out, const py_Ref start, const py_Ref stop, const py_Ref step) { py_newobject(out, tp_slice, 3, 0); py_setslot(out, 0, start); diff --git a/src/public/vm.c b/src/public/vm.c index 07ce8b8b..62b1e92d 100644 --- a/src/public/vm.c +++ b/src/public/vm.c @@ -50,7 +50,7 @@ bool py_callmethod(py_Ref self, py_Name name, int argc, py_Ref argv) { return -1 bool pk_vectorcall(int argc, int kwargc, bool op_call) { return -1; } -py_Ref py_lastretval() { return &pk_current_vm->last_retval; } +py_Ref py_retval() { return &pk_current_vm->last_retval; } bool py_getunboundmethod(const py_Ref self, py_Name name, @@ -66,7 +66,7 @@ pk_TypeInfo* pk_tpinfo(const py_Ref self) { } py_Ref py_tpfindmagic(py_Type t, py_Name name) { - assert(name < 64); + assert(py_ismagicname(name)); pk_TypeInfo* types = (pk_TypeInfo*)pk_current_vm->types.data; do { py_Ref f = &types[t].magic[name]; @@ -77,7 +77,7 @@ py_Ref py_tpfindmagic(py_Type t, py_Name name) { } py_Ref py_tpmagic(py_Type type, py_Name name) { - assert(name < 64); + assert(py_ismagicname(name)); pk_VM* vm = pk_current_vm; return &c11__at(pk_TypeInfo, &vm->types, type)->magic[name]; } @@ -89,6 +89,7 @@ py_Ref py_tpobject(py_Type type) { bool py_callmagic(py_Name name, int argc, py_Ref argv) { assert(argc >= 1); + assert(py_ismagicname(name)); py_Ref tmp = py_tpfindmagic(argv->type, name); if(!tmp) return TypeError(name); if(tmp->type == tp_nativefunc) { return tmp->_cfunc(argc, argv); } diff --git a/src2/main.c b/src2/main.c index d50f1c47..45676900 100644 --- a/src2/main.c +++ b/src2/main.c @@ -30,7 +30,7 @@ int main(int argc, char** argv) { if(py_eval(source)) { // handle the result - bool _L0 = py_tobool(py_lastretval()); + bool _L0 = py_tobool(py_retval()); printf("%d\n", _L0); } @@ -42,7 +42,7 @@ int main(int argc, char** argv) { bool ok = py_binaryadd(r0, r1); assert(ok); - double res = py_tofloat(py_lastretval()); + double res = py_tofloat(py_retval()); printf("%f\n", res); py_finalize();