diff --git a/include/pocketpy/common/utils.h b/include/pocketpy/common/utils.h index 3d25f481..66ae8480 100644 --- a/include/pocketpy/common/utils.h +++ b/include/pocketpy/common/utils.h @@ -15,7 +15,8 @@ extern "C" { #define PK_REGION(name) 1 -#define PK_SLICE_LOOP(i, start, stop, step) for(int i = start; step > 0 ? i < stop : i > stop; i += step) +#define PK_SLICE_LOOP(i, start, stop, step) \ + for(int i = start; step > 0 ? i < stop : i > stop; i += step) // global constants #define PK_HEX_TABLE "0123456789abcdef" @@ -23,17 +24,21 @@ extern "C" { extern const char* kPlatformStrings[]; #ifdef _MSC_VER -#define PK_UNREACHABLE() __assume(0); +#define c11__unreachedable() __assume(0) #else -#define PK_UNREACHABLE() __builtin_unreachable(); +#define c11__unreachedable() __builtin_unreachable() #endif -#define PK_FATAL_ERROR(...) { fprintf(stderr, __VA_ARGS__); abort(); } +#define PK_FATAL_ERROR(...) \ + do { \ + fprintf(stderr, __VA_ARGS__); \ + abort(); \ + } while(0) -#define PK_MIN(a, b) ((a) < (b) ? (a) : (b)) -#define PK_MAX(a, b) ((a) > (b) ? (a) : (b)) +#define c11__min(a, b) ((a) < (b) ? (a) : (b)) +#define c11__max(a, b) ((a) > (b) ? (a) : (b)) -#define PK_ARRAY_COUNT(a) (sizeof(a) / sizeof(a[0])) +#define c11__count_array(a) (sizeof(a) / sizeof(a[0])) // NARGS #define PK_NARGS_SEQ(_1, _2, _3, _4, N, ...) N @@ -47,12 +52,13 @@ typedef struct RefCounted { } RefCounted; #define PK_INCREF(obj) (obj)->rc.count++ -#define PK_DECREF(obj) do { \ - if(--(obj)->rc.count == 0) { \ - (obj)->rc.dtor(obj); \ - free(obj); \ - } \ -} while(0) +#define PK_DECREF(obj) \ + do { \ + if(--(obj)->rc.count == 0) { \ + (obj)->rc.dtor(obj); \ + free(obj); \ + } \ + } while(0) #ifdef __cplusplus } diff --git a/include/pocketpy/common/vector.h b/include/pocketpy/common/vector.h index 3d35e422..398fe7a7 100644 --- a/include/pocketpy/common/vector.h +++ b/include/pocketpy/common/vector.h @@ -87,7 +87,6 @@ c11_array c11_vector__submit(c11_vector* self); } \ } while(0) - // NOTE: here we do an extra NULL check for it to avoid UB #define c11__foreach(T, self, it) \ for(T* it = (self)->data; it && it != (T*)(self)->data + (self)->count; it++) diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 1c36490a..2e3db29d 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -57,7 +57,6 @@ typedef struct pk_VM { py_TValue reg[8]; // users' registers py_TValue __curr_class; - py_TValue __cached_object_new; FuncDecl_ __dynamic_func_decl; py_TValue __vectorcall_buffer[PK_MAX_CO_VARNAMES]; diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 2de828fa..3a5fcc0a 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -115,10 +115,13 @@ bool py_isinstance(const py_Ref obj, py_Type type); bool py_issubclass(py_Type derived, py_Type base); /************* References *************/ +#define PY_CHECK_ARGC(n) \ + if(argc != n) return TypeError("expected %d arguments, got %d", n, argc) + +#define PY_CHECK_ARG_TYPE(i, type) if(!py_checktype(py_arg(i), type)) return false + #define py_offset(p, i) (py_Ref)((char*)p + ((i) << 4)) #define py_arg(i) py_offset(argv, i) -#define py_checkargc(n) \ - if(argc != n) return TypeError("expected %d arguments, got %d", n, argc) py_GlobalRef py_tpmagic(py_Type type, py_Name name); #define py_bindmagic(type, __magic__, f) py_newnativefunc(py_tpmagic((type), __magic__), (f)) @@ -375,3 +378,13 @@ enum py_PredefinedTypes { #ifdef __cplusplus } #endif + + +/* +Some notes: + +## Macros +1. Function macros are partial functions. They can be used as normal expressions. Use the same naming convention as functions. +2. Snippet macros are `do {...} while(0)` blocks. They cannot be used as expressions. Use `UPPER_CASE` naming convention. +3. Constant macros are used for global constants. Use `UPPER_CASE` or k-prefix naming convention. +*/ \ No newline at end of file diff --git a/src/common/str.c b/src/common/str.c index f5932d59..7caf2468 100644 --- a/src/common/str.c +++ b/src/common/str.c @@ -197,14 +197,14 @@ int c11__byte_index_to_unicode(const char* data, int n) { ////////////// int c11_sv__cmp(c11_sv self, c11_sv other) { - int res = strncmp(self.data, other.data, PK_MIN(self.size, other.size)); + int res = strncmp(self.data, other.data, c11__min(self.size, other.size)); if(res != 0) return res; return self.size - other.size; } int c11_sv__cmp2(c11_sv self, const char* other) { int size = strlen(other); - int res = strncmp(self.data, other, PK_MIN(self.size, size)); + int res = strncmp(self.data, other, c11__min(self.size, size)); if(res != 0) return res; return self.size - size; } @@ -241,14 +241,14 @@ int c11__u8_header(unsigned char c, bool suppress) { if((c & 0b11111000) == 0b11110000) return 4; if((c & 0b11111100) == 0b11111000) return 5; if((c & 0b11111110) == 0b11111100) return 6; - if(!suppress) PK_FATAL_ERROR("invalid utf8 char\n") + if(!suppress) PK_FATAL_ERROR("invalid utf8 char\n"); return 0; } IntParsingResult c11__parse_uint(c11_sv text, int64_t* out, int base) { *out = 0; - c11_sv prefix = {.data = text.data, .size = PK_MIN(2, text.size)}; + c11_sv prefix = {.data = text.data, .size = c11__min(2, text.size)}; if(base == -1) { if(c11__sveq(prefix, "0b")) base = 2; diff --git a/src/common/strname.c b/src/common/strname.c index f9d56ba8..0097ab03 100644 --- a/src/common/strname.c +++ b/src/common/strname.c @@ -31,16 +31,14 @@ void py_Name__finalize() { c11_vector__dtor(&_r_interned); } -py_Name py_name(const char* name) { - return py_name2((c11_sv){name, strlen(name)}); -} +py_Name py_name(const char* name) { return py_name2((c11_sv){name, strlen(name)}); } py_Name py_name2(c11_sv name) { // TODO: PK_GLOBAL_SCOPE_LOCK() uint16_t index = c11_smallmap_s2n__get(&_interned, name, 0); if(index != 0) return index; // generate new index - if(_interned.count > 65530) { PK_FATAL_ERROR("py_Name index overflow\n"); } + if(_interned.count > 65530) PK_FATAL_ERROR("py_Name index overflow\n"); // NOTE: we must allocate the string in the heap so iterators are not invalidated char* p = malloc(name.size + 1); memcpy(p, name.data, name.size); @@ -64,8 +62,4 @@ c11_sv py_name2sv(py_Name index) { return (c11_sv){p, strlen(p)}; } - -bool py_ismagicname(py_Name name){ - return name <= __missing__; -} - +bool py_ismagicname(py_Name name) { return name <= __missing__; } diff --git a/src/compiler/compiler.c b/src/compiler/compiler.c index 423bbcc7..0ef8393b 100644 --- a/src/compiler/compiler.c +++ b/src/compiler/compiler.c @@ -129,7 +129,7 @@ bool NameExpr__emit_del(Expr* self_, Ctx* ctx) { break; case NAME_GLOBAL: Ctx__emit_(ctx, OP_DELETE_GLOBAL, self->name, self->line); break; case NAME_GLOBAL_UNKNOWN: Ctx__emit_(ctx, OP_DELETE_NAME, self->name, self->line); break; - default: PK_UNREACHABLE(); + default: c11__unreachedable(); } return true; } @@ -294,7 +294,7 @@ void LiteralExpr__emit_(Expr* self_, Ctx* ctx) { Ctx__emit_(ctx, OP_LOAD_CONST, index, self->line); break; } - default: PK_UNREACHABLE(); + default: c11__unreachedable(); } } @@ -1376,7 +1376,7 @@ static void Ctx__emit_store_name(Ctx* self, NameScope scope, py_Name name, int l case NAME_LOCAL: Ctx__emit_(self, OP_STORE_FAST, Ctx__add_varname(self, name), line); break; case NAME_GLOBAL: Ctx__emit_(self, OP_STORE_GLOBAL, name, line); break; case NAME_GLOBAL_UNKNOWN: Ctx__emit_(self, OP_STORE_NAME, name, line); break; - default: PK_UNREACHABLE(); + default: c11__unreachedable(); } } @@ -1478,6 +1478,7 @@ static NameScope name_scope(Compiler* self) { } #define SyntaxError(...) NULL + static Error* NeedMoreLines() { return NULL; } /* Matchers */ diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 74e8316b..2e879c7d 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -52,7 +52,7 @@ static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop); PUSH(&self->last_retval); \ goto __NEXT_FRAME; \ case RES_ERROR: goto __ERROR; \ - default: PK_UNREACHABLE(); \ + default: c11__unreachedable(); \ } \ } while(0) @@ -671,7 +671,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { *TOP() = self->last_retval; DISPATCH(); } - default: PK_UNREACHABLE(); + default: c11__unreachedable(); } assert(false); // should never reach here diff --git a/src/interpreter/py_number.c b/src/interpreter/py_number.c index dcd625d3..93729f23 100644 --- a/src/interpreter/py_number.c +++ b/src/interpreter/py_number.c @@ -5,7 +5,7 @@ #define DEF_NUM_BINARY_OP(name, op, rint, rfloat) \ static bool _py_int##name(int argc, py_Ref argv) { \ - py_checkargc(2); \ + PY_CHECK_ARGC(2); \ if(py_isint(&argv[1])) { \ int64_t lhs = py_toint(&argv[0]); \ int64_t rhs = py_toint(&argv[1]); \ @@ -20,7 +20,7 @@ return true; \ } \ static bool _py_float##name(int argc, py_Ref argv) { \ - py_checkargc(2); \ + PY_CHECK_ARGC(2); \ double lhs = py_tofloat(&argv[0]); \ double rhs; \ if(py_castfloat(&argv[1], &rhs)) { \ @@ -45,21 +45,21 @@ DEF_NUM_BINARY_OP(__ge__, >=, py_newbool, py_newbool) #undef DEF_NUM_BINARY_OP static bool _py_int__neg__(int argc, py_Ref argv) { - py_checkargc(1); + PY_CHECK_ARGC(1); int64_t val = py_toint(&argv[0]); py_newint(py_retval(), -val); return true; } static bool _py_float__neg__(int argc, py_Ref argv) { - py_checkargc(1); + PY_CHECK_ARGC(1); double val = py_tofloat(&argv[0]); py_newfloat(py_retval(), -val); return true; } static bool _py_int__truediv__(int argc, py_Ref argv) { - py_checkargc(2); + PY_CHECK_ARGC(2); int64_t lhs = py_toint(&argv[0]); double rhs; if(py_castfloat(&argv[1], &rhs)) { @@ -71,7 +71,7 @@ static bool _py_int__truediv__(int argc, py_Ref argv) { } static bool _py_float__truediv__(int argc, py_Ref argv) { - py_checkargc(2); + PY_CHECK_ARGC(2); double lhs = py_tofloat(&argv[0]); double rhs; if(py_castfloat(&argv[1], &rhs)) { @@ -85,7 +85,7 @@ static bool _py_float__truediv__(int argc, py_Ref argv) { #define ZeroDivisionError(msg) false static bool _py_number__pow__(int argc, py_Ref argv) { - py_checkargc(2); + PY_CHECK_ARGC(2); if(py_isint(&argv[0]) && py_isint(&argv[1])) { int64_t lhs = py_toint(&argv[0]); int64_t rhs = py_toint(&argv[1]); @@ -98,11 +98,11 @@ static bool _py_number__pow__(int argc, py_Ref argv) { } else { // rhs >= 0 int64_t ret = 1; - while(true){ + while(true) { if(rhs & 1) ret *= lhs; rhs >>= 1; if(!rhs) break; - lhs *= lhs; // place this here to avoid overflow + lhs *= lhs; // place this here to avoid overflow } py_newint(py_retval(), ret); } @@ -119,7 +119,7 @@ static bool _py_number__pow__(int argc, py_Ref argv) { } static bool _py_int__floordiv__(int argc, py_Ref argv) { - py_checkargc(2); + PY_CHECK_ARGC(2); int64_t lhs = py_toint(&argv[0]); if(py_isint(&argv[1])) { int64_t rhs = py_toint(&argv[1]); @@ -132,7 +132,7 @@ static bool _py_int__floordiv__(int argc, py_Ref argv) { } static bool _py_int__mod__(int argc, py_Ref argv) { - py_checkargc(2); + PY_CHECK_ARGC(2); int64_t lhs = py_toint(&argv[0]); if(py_isint(&argv[1])) { int64_t rhs = py_toint(&argv[1]); @@ -145,14 +145,14 @@ static bool _py_int__mod__(int argc, py_Ref argv) { } static bool _py_int__invert__(int argc, py_Ref argv) { - py_checkargc(1); + PY_CHECK_ARGC(1); int64_t val = py_toint(&argv[0]); py_newint(py_retval(), ~val); return true; } static bool _py_int__bit_length(int argc, py_Ref argv) { - py_checkargc(1); + PY_CHECK_ARGC(1); int64_t x = py_toint(py_arg(0)); if(x < 0) x = -x; int bits = 0; @@ -166,7 +166,7 @@ static bool _py_int__bit_length(int argc, py_Ref argv) { #define DEF_INT_BITWISE_OP(name, op) \ static bool _py_int##name(int argc, py_Ref argv) { \ - py_checkargc(2); \ + PY_CHECK_ARGC(2); \ int64_t lhs = py_toint(&argv[0]); \ if(py_isint(&argv[1])) { \ int64_t rhs = py_toint(&argv[1]); \ @@ -186,7 +186,7 @@ DEF_INT_BITWISE_OP(__rshift__, >>) #undef DEF_INT_BITWISE_OP static bool _py_int__repr__(int argc, py_Ref argv) { - py_checkargc(1); + PY_CHECK_ARGC(1); int64_t val = py_toint(&argv[0]); char buf[32]; int size = snprintf(buf, sizeof(buf), "%lld", (long long)val); @@ -195,7 +195,7 @@ static bool _py_int__repr__(int argc, py_Ref argv) { } static bool _py_float__repr__(int argc, py_Ref argv) { - py_checkargc(1); + PY_CHECK_ARGC(1); double val = py_tofloat(&argv[0]); char buf[32]; int size = snprintf(buf, sizeof(buf), "%f", val); @@ -222,7 +222,7 @@ static py_i64 c11_8bytes__hash(union c11_8bytes u) { } static bool _py_int__hash__(int argc, py_Ref argv) { - py_checkargc(1); + PY_CHECK_ARGC(1); int64_t val = py_toint(&argv[0]); union c11_8bytes u = {._i64 = val}; py_newint(py_retval(), c11_8bytes__hash(u)); @@ -230,7 +230,7 @@ static bool _py_int__hash__(int argc, py_Ref argv) { } static bool _py_float__hash__(int argc, py_Ref argv) { - py_checkargc(1); + PY_CHECK_ARGC(1); double val = py_tofloat(&argv[0]); union c11_8bytes u = {._f64 = val}; py_newint(py_retval(), c11_8bytes__hash(u)); @@ -270,11 +270,12 @@ static bool _py_int__new__(int argc, py_Ref argv) { // 1 or 2 args with str int base = 10; if(argc == 1 + 2) { - if(!py_checktype(py_arg(2), tp_int)) return false; + PY_CHECK_ARG_TYPE(2, tp_int); base = py_toint(py_arg(2)); } - if(!py_checktype(py_arg(1), tp_str)) return false; + PY_CHECK_ARG_TYPE(1, tp_str); + int size; const char* data = py_tostrn(py_arg(1), &size); bool negative = false; @@ -322,20 +323,18 @@ static bool _py_float__new__(int argc, py_Ref argv) { int size; const char* data = py_tostrn(py_arg(1), &size); - if(c11__streq(data, "inf")){ + if(c11__streq(data, "inf")) { py_newfloat(py_retval(), INFINITY); return true; } - if(c11__streq(data, "-inf")){ + if(c11__streq(data, "-inf")) { py_newfloat(py_retval(), -INFINITY); return true; } char* p_end; py_f64 float_out = strtod(data, &p_end); - if(p_end != data + size){ - return ValueError("invalid literal for float(): %q", data); - } + if(p_end != data + size) { return ValueError("invalid literal for float(): %q", data); } py_newfloat(py_retval(), float_out); return true; } diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 324d9712..6232aaf7 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -82,7 +82,6 @@ void pk_VM__ctor(pk_VM* self) { self->has_error = false; self->__curr_class = PY_NIL; - self->__cached_object_new = PY_NIL; self->__dynamic_func_decl = NULL; pk_ManagedHeap__ctor(&self->heap, self); @@ -99,6 +98,7 @@ void pk_VM__ctor(pk_VM* self) { validate(tp_int, pk_VM__new_type(self, "int", tp_object, NULL, false)); validate(tp_float, pk_VM__new_type(self, "float", tp_object, NULL, false)); + pk_number__register(); validate(tp_bool, pk_VM__new_type(self, "bool", tp_object, NULL, false)); validate(tp_str, pk_str__register()); @@ -155,7 +155,7 @@ void pk_VM__ctor(pk_VM* self) { tp_stop_iteration, tp_syntax_error}; - for(int i = 0; i < PK_ARRAY_COUNT(public_types); i++) { + for(int i = 0; i < c11__count_array(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, py_tpobject(t)); @@ -166,7 +166,6 @@ void pk_VM__ctor(pk_VM* self) { py_setdict(&self->builtins, py_name("NotImplemented"), &tmp); /* Do Buildin Bindings*/ - pk_number__register(); // object.__new__ py_bindmagic(tp_object, __new__, _py_object__new__); @@ -286,7 +285,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo return __py_generator( callstack.popx(), ArgsView(__vectorcall_buffer, __vectorcall_buffer + co->nlocals)); - default: PK_UNREACHABLE() + default: c11__unreachedable() }; // simple or normal @@ -373,7 +372,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo } TypeError("'%t' object is not callable", p0->type); - PK_UNREACHABLE(); + c11__unreachedable(); } /****************************************/ diff --git a/src/objects/dict.c b/src/objects/dict.c index 5cac91fb..901b9655 100644 --- a/src/objects/dict.c +++ b/src/objects/dict.c @@ -89,7 +89,7 @@ static int pkpy_Dict__probe0(const pkpy_Dict* self, py_TValue key, int hash) { struct pkpy_DictEntry* entry = &c11__getitem(struct pkpy_DictEntry, &self->_entries, idx); if(pkpy_Var__is_null(&entry->key)) return h; } - PK_UNREACHABLE(); + c11__unreachedable(); } static int pkpy_Dict__probe1(const pkpy_Dict* self, py_TValue key, int hash) { @@ -103,7 +103,7 @@ static int pkpy_Dict__probe1(const pkpy_Dict* self, py_TValue key, int hash) { if(pkpy_Var__is_null(&entry->key)) continue; if(py_eq(&entry->key, &key)) return h; } - PK_UNREACHABLE(); + c11__unreachedable(); } static void pkpy_Dict__extendht(pkpy_Dict* self) { diff --git a/src/public/py_list.c b/src/public/py_list.c index 8f7e9c0b..fab80d4a 100644 --- a/src/public/py_list.c +++ b/src/public/py_list.c @@ -6,13 +6,6 @@ typedef c11_vector List; -py_Type pk_list__register() { - pk_VM* vm = pk_current_vm; - py_Type type = pk_VM__new_type(vm, "list", tp_object, NULL, false); - pk_TypeInfo* ti = c11__at(pk_TypeInfo, &vm->types, type); - ti->dtor = (void (*)(void*))c11_vector__dtor; - return type; -} void py_newlist(py_Ref out) { pk_VM* vm = pk_current_vm; @@ -67,9 +60,19 @@ void py_list__insert(py_Ref self, int i, const py_Ref val) { } //////////////////////////////// -bool _py_list__len__(int argc, py_Ref argv){ - py_checkargc(1); +static bool _py_list__len__(int argc, py_Ref argv){ + PY_CHECK_ARGC(1); py_i64 res = py_list__len(py_arg(0)); py_newint(py_retval(), res); return true; } + +py_Type pk_list__register() { + pk_VM* vm = pk_current_vm; + py_Type type = pk_VM__new_type(vm, "list", tp_object, NULL, false); + pk_TypeInfo* ti = c11__at(pk_TypeInfo, &vm->types, type); + ti->dtor = (void (*)(void*))c11_vector__dtor; + + py_bindmagic(type, __len__, _py_list__len__); + return type; +} \ No newline at end of file diff --git a/src/public/vm.c b/src/public/vm.c index 7e74be5b..430439af 100644 --- a/src/public/vm.c +++ b/src/public/vm.c @@ -177,7 +177,7 @@ static bool PK_DECREF(src); if(res == RES_ERROR) return false; if(res == RES_RETURN) return true; - PK_UNREACHABLE(); + c11__unreachedable(); } bool py_exec(const char* source) { return pk_VM__exec(pk_current_vm, source, "", EXEC_MODE); } @@ -225,7 +225,7 @@ bool py_getunboundmethod(py_Ref self, py_Name name, py_Ref out, py_Ref out_self) *out = *py_getslot(cls_var, 0); *out_self = c11__getitem(pk_TypeInfo, &pk_current_vm->types, type).self; break; - default: PK_UNREACHABLE(); + default: c11__unreachedable(); } return true; } diff --git a/tests/00_tmp.py b/tests/00_tmp.py index 51513292..95f60179 100644 --- a/tests/00_tmp.py +++ b/tests/00_tmp.py @@ -98,3 +98,6 @@ assert (-4)**13 == -67108864 assert ~3 == -4 assert ~-3 == 2 assert ~0 == -1 + +# tmp code +assert [1, 2].__len__() == 2 \ No newline at end of file