diff --git a/include/pocketpy/bindings.h b/include/pocketpy/bindings.h index 3ac31b04..a760f007 100644 --- a/include/pocketpy/bindings.h +++ b/include/pocketpy/bindings.h @@ -16,7 +16,7 @@ struct NativeProxyFuncC final: NativeProxyFuncCBase { NativeProxyFuncC(_Fp func) : func(func) {} PyObject* operator()(VM* vm, ArgsView args) override { - PK_ASSERT(args.size() == N); + PK_DEBUG_ASSERT(args.size() == N); return call(vm, args, std::make_index_sequence()); } @@ -40,7 +40,7 @@ struct NativeProxyMethodC final: NativeProxyFuncCBase { NativeProxyMethodC(_Fp func) : func(func) {} PyObject* operator()(VM* vm, ArgsView args) override { - PK_ASSERT(args.size() == N+1); + PK_DEBUG_ASSERT(args.size() == N+1); return call(vm, args, std::make_index_sequence()); } diff --git a/include/pocketpy/codeobject.h b/include/pocketpy/codeobject.h index ee278eb7..6136438b 100644 --- a/include/pocketpy/codeobject.h +++ b/include/pocketpy/codeobject.h @@ -136,9 +136,7 @@ struct UserData{ T get() const{ static_assert(std::is_trivially_copyable_v); static_assert(sizeof(T) <= sizeof(data)); -#if PK_DEBUG_EXTRA_CHECK - PK_ASSERT(!empty); -#endif + PK_DEBUG_ASSERT(!empty); return reinterpret_cast(data); } }; diff --git a/include/pocketpy/common.h b/include/pocketpy/common.h index 69622002..7f661317 100644 --- a/include/pocketpy/common.h +++ b/include/pocketpy/common.h @@ -117,6 +117,12 @@ struct Type { #define PK_ASSERT(x) if(!(x)) PK_FATAL_ERROR(); +#if PK_DEBUG_EXTRA_CHECK +#define PK_DEBUG_ASSERT(x) if(!(x)) PK_FATAL_ERROR(); +#else +#define PK_DEBUG_ASSERT(x) +#endif + struct PyObject; #define PK_BITS(p) (reinterpret_cast(p)) #define PK_SMALL_INT(val) (reinterpret_cast(val << 2 | 0b10)) diff --git a/include/pocketpy/frame.h b/include/pocketpy/frame.h index b810b1bf..3bc608ed 100644 --- a/include/pocketpy/frame.h +++ b/include/pocketpy/frame.h @@ -55,12 +55,7 @@ struct ValueStack { bool empty() const { return _sp == _begin; } PyObject** begin() { return _begin; } PyObject** end() { return _sp; } - void reset(PyObject** sp) { -#if PK_DEBUG_EXTRA_CHECK - if(sp < _begin || sp > _begin + MAX_SIZE) PK_FATAL_ERROR(); -#endif - _sp = sp; - } + void reset(PyObject** sp) { _sp = sp; } void clear() { _sp = _begin; } bool is_overflow() const { return _sp >= _max_end; } @@ -101,9 +96,7 @@ struct Frame { int next_bytecode() { _ip = _next_ip++; -#if PK_DEBUG_EXTRA_CHECK - if(_ip >= co->codes.size()) PK_FATAL_ERROR(); -#endif + PK_DEBUG_ASSERT(_ip >= 0 && _ip < co->codes.size()); return _ip; } @@ -152,16 +145,17 @@ struct CallStack{ } void pop(){ -#if PK_DEBUG_EXTRA_CHECK - if(empty()) PK_FATAL_ERROR(); -#endif + PK_DEBUG_ASSERT(!empty()) LinkedFrame* p = _tail; _tail = p->f_back; pool64_dealloc(p); --_size; } - Frame& top() const { return _tail->frame; } + Frame& top() const { + PK_DEBUG_ASSERT(!empty()) + return _tail->frame; + } template void apply(Func&& f){ diff --git a/include/pocketpy/obj.h b/include/pocketpy/obj.h index bf4f7968..57e75f98 100644 --- a/include/pocketpy/obj.h +++ b/include/pocketpy/obj.h @@ -100,8 +100,16 @@ struct PyObject{ NameDict* _attr; bool is_attr_valid() const noexcept { return _attr != nullptr; } - NameDict& attr() { return *_attr; } - PyObject* attr(StrName name) const { return (*_attr)[name]; } + + NameDict& attr() { + PK_DEBUG_ASSERT(is_attr_valid()) + return *_attr; + } + + PyObject* attr(StrName name) const { + PK_DEBUG_ASSERT(is_attr_valid()) + return (*_attr)[name]; + } virtual void _obj_gc_mark() = 0; @@ -132,9 +140,7 @@ inline bool is_float(PyObject* p) noexcept { return !is_tagged(p) && p->type.ind inline bool is_int(PyObject* p) noexcept { return is_small_int(p) || is_heap_int(p); } inline bool is_type(PyObject* obj, Type type) { -#if PK_DEBUG_EXTRA_CHECK - if(obj == nullptr) throw std::runtime_error("is_type() called with nullptr"); -#endif + PK_DEBUG_ASSERT(obj != nullptr) return is_small_int(obj) ? type.index == kTpIntIndex : obj->type == type; } diff --git a/src/expr.cpp b/src/expr.cpp index 7e0781f2..c2d2a6c4 100644 --- a/src/expr.cpp +++ b/src/expr.cpp @@ -397,7 +397,7 @@ namespace pkpy{ int for_codei = ctx->emit_(OP_FOR_ITER, BC_NOARG, BC_KEEPLINE); bool ok = vars->emit_store(ctx); // this error occurs in `vars` instead of this line, but...nevermind - PK_ASSERT(ok); // TODO: raise a SyntaxError instead + if(!ok) throw std::runtime_error("SyntaxError"); ctx->try_merge_for_iter_store(for_codei); if(cond){ cond->emit_(ctx); diff --git a/src/pocketpy.cpp b/src/pocketpy.cpp index 64d66d71..43cb8c17 100644 --- a/src/pocketpy.cpp +++ b/src/pocketpy.cpp @@ -518,7 +518,7 @@ void init_builtins(VM* _vm) { char* p_end; try{ float_out = std::strtod(s.data, &p_end); - PK_ASSERT(p_end == s.end()); + if(p_end != s.end()) throw 1; }catch(...){ vm->ValueError("invalid literal for float(): " + s.escape()); } diff --git a/src/vm.cpp b/src/vm.cpp index b3459dd2..2465dc47 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -953,9 +953,7 @@ PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){ // [type, NULL, args..., kwargs...] PyObject* new_f = find_name_in_mro(PK_OBJ_GET(Type, callable), __new__); PyObject* obj; -#if PK_DEBUG_EXTRA_CHECK - PK_ASSERT(new_f != nullptr && !method_call); -#endif + PK_DEBUG_ASSERT(new_f != nullptr && !method_call); if(new_f == cached_object__new__) { // fast path for object.__new__ obj = vm->heap.gcnew(PK_OBJ_GET(Type, callable)); diff --git a/tests/02_float.py b/tests/02_float.py index 8f079574..4ca8c9b9 100644 --- a/tests/02_float.py +++ b/tests/02_float.py @@ -90,3 +90,8 @@ assert -2e-3j == -0.002j assert 3.4e-3 == 0.0034 assert 3.4e+3 == 3400.0 +try: + float('-x13') + exit(1) +except ValueError: + pass