blueloveTH 3 years ago
parent
commit
8c0e7aad45
4 changed files with 86 additions and 86 deletions
  1. 1 1
      src/common.h
  2. 32 32
      src/compiler.h
  3. 15 15
      src/pocketpy.h
  4. 38 38
      src/vm.h

+ 1 - 1
src/common.h

@@ -42,4 +42,4 @@ typedef double f64;
 #define DUMMY_VAL (i64)0
 
 #define CPP_LAMBDA(x) ([](VM* vm, const pkpy::Args& args) { return x; })
-#define CPP_NOT_IMPLEMENTED() ([](VM* vm, const pkpy::Args& args) { vm->notImplementedError(); return vm->None; })
+#define CPP_NOT_IMPLEMENTED() ([](VM* vm, const pkpy::Args& args) { vm->NotImplementedError(); return vm->None; })

+ 32 - 32
src/compiler.h

@@ -115,10 +115,10 @@ private:
                 if(quote3 && parser->src->mode == SINGLE_MODE){
                     throw NeedMoreLines(false);
                 }
-                syntaxError("EOL while scanning string literal");
+                SyntaxError("EOL while scanning string literal");
             }
             if (c == '\n'){
-                if(!quote3) syntaxError("EOL while scanning string literal");
+                if(!quote3) SyntaxError("EOL while scanning string literal");
                 else{
                     buff.push_back(c);
                     continue;
@@ -132,7 +132,7 @@ private:
                     case 'n':  buff.push_back('\n'); break;
                     case 'r':  buff.push_back('\r'); break;
                     case 't':  buff.push_back('\t'); break;
-                    default: syntaxError("invalid escape character");
+                    default: SyntaxError("invalid escape character");
                 }
             } else {
                 buff.push_back(c);
@@ -167,7 +167,7 @@ private:
                 size_t size;
                 if (m[1].matched) base = 16;
                 if (m[2].matched) {
-                    if(base == 16) syntaxError("hex literal should not contain a dot");
+                    if(base == 16) SyntaxError("hex literal should not contain a dot");
                     parser->set_next_token(TK("@num"), vm->PyFloat(std::stod(m[0], &size)));
                 } else {
                     parser->set_next_token(TK("@num"), vm->PyInt(std::stoll(m[0], &size, base)));
@@ -175,7 +175,7 @@ private:
                 if (size != m.length()) UNREACHABLE();
             }
         }catch(std::exception& _){
-            syntaxError("invalid number literal");
+            SyntaxError("invalid number literal");
         } 
     }
 
@@ -217,7 +217,7 @@ private:
                         if(parser->matchchar('.')) {
                             parser->set_next_token(TK("..."));
                         } else {
-                            syntaxError("invalid token '..'");
+                            SyntaxError("invalid token '..'");
                         }
                     } else {
                         parser->set_next_token(TK("."));
@@ -246,7 +246,7 @@ private:
                 }
                 case '!':
                     if(parser->matchchar('=')) parser->set_next_token(TK("!="));
-                    else syntaxError("expected '=' after '!'");
+                    else SyntaxError("expected '=' after '!'");
                     break;
                 case '*':
                     if (parser->matchchar('*')) {
@@ -266,7 +266,7 @@ private:
                 case ' ': case '\t': parser->eat_spaces(); break;
                 case '\n': {
                     parser->set_next_token(TK("@eol"));
-                    if(!parser->eat_indentation()) indentationError("unindent does not match any outer indentation level");
+                    if(!parser->eat_indentation()) IndentationError("unindent does not match any outer indentation level");
                     return;
                 }
                 default: {
@@ -286,10 +286,10 @@ private:
                     switch (parser->eat_name())
                     {
                         case 0: break;
-                        case 1: syntaxError("invalid char: " + std::string(1, c));
-                        case 2: syntaxError("invalid utf8 sequence: " + std::string(1, c));
-                        case 3: syntaxError("@id contains invalid char"); break;
-                        case 4: syntaxError("invalid JSON token"); break;
+                        case 1: SyntaxError("invalid char: " + std::string(1, c));
+                        case 2: SyntaxError("invalid utf8 sequence: " + std::string(1, c));
+                        case 3: SyntaxError("@id contains invalid char"); break;
+                        case 4: SyntaxError("invalid JSON token"); break;
                         default: UNREACHABLE();
                     }
                     return;
@@ -321,7 +321,7 @@ private:
         if (!match(expected)){
             _StrStream ss;
             ss << "expected '" << TK_STR(expected) << "', but got '" << TK_STR(peek()) << "'";
-            syntaxError(ss.str());
+            SyntaxError(ss.str());
         }
     }
 
@@ -345,7 +345,7 @@ private:
     }
 
     void consume_end_stmt() {
-        if (!match_end_stmt()) syntaxError("expected statement end");
+        if (!match_end_stmt()) SyntaxError("expected statement end");
     }
 
     void exprLiteral() {
@@ -493,7 +493,7 @@ private:
         switch (op) {
             case TK("-"):     emit(OP_UNARY_NEGATIVE); break;
             case TK("not"):   emit(OP_UNARY_NOT);      break;
-            case TK("*"):     syntaxError("cannot use '*' as unary operator"); break;
+            case TK("*"):     SyntaxError("cannot use '*' as unary operator"); break;
             default: UNREACHABLE();
         }
     }
@@ -598,7 +598,7 @@ __LISTCOMP:
                 EXPR();
                 KWARGC++;
             } else{
-                if(KWARGC > 0) syntaxError("positional argument follows keyword argument");
+                if(KWARGC > 0) SyntaxError("positional argument follows keyword argument");
                 EXPR();
                 ARGC++;
             }
@@ -683,7 +683,7 @@ __LISTCOMP:
         if(action == nullptr) action = &Compiler::compile_stmt;
         consume(TK(":"));
         if(!match_newlines(mode()==SINGLE_MODE)){
-            syntaxError("expected a new line after ':'");
+            SyntaxError("expected a new line after ':'");
         }
         consume(TK("@indent"));
         while (peek() != TK("@dedent")) {
@@ -740,7 +740,7 @@ __LISTCOMP:
     void parse_expression(Precedence precedence) {
         lex_token();
         GrammarFn prefix = rules[parser->prev.type].prefix;
-        if (prefix == nullptr) syntaxError(_Str("expected an expression, but got ") + TK_STR(parser->prev.type));
+        if (prefix == nullptr) SyntaxError(_Str("expected an expression, but got ") + TK_STR(parser->prev.type));
         (this->*prefix)();
         while (rules[peek()].precedence >= precedence) {
             lex_token();
@@ -830,16 +830,16 @@ __LISTCOMP:
 
     void compile_stmt() {
         if (match(TK("break"))) {
-            if (!co()->_is_curr_block_loop()) syntaxError("'break' outside loop");
+            if (!co()->_is_curr_block_loop()) SyntaxError("'break' outside loop");
             consume_end_stmt();
             emit(OP_LOOP_BREAK);
         } else if (match(TK("continue"))) {
-            if (!co()->_is_curr_block_loop()) syntaxError("'continue' not properly in loop");
+            if (!co()->_is_curr_block_loop()) SyntaxError("'continue' not properly in loop");
             consume_end_stmt();
             emit(OP_LOOP_CONTINUE);
         } else if (match(TK("return"))) {
             if (codes.size() == 1)
-                syntaxError("'return' outside function");
+                SyntaxError("'return' outside function");
             if(match_end_stmt()){
                 emit(OP_LOAD_NONE);
             }else{
@@ -875,14 +875,14 @@ __LISTCOMP:
             emit(OP_LOAD_NAME_REF, index);
             emit(OP_WITH_EXIT);
         } else if(match(TK("label"))){
-            if(mode() != EXEC_MODE) syntaxError("'label' is only available in EXEC_MODE");
+            if(mode() != EXEC_MODE) SyntaxError("'label' is only available in EXEC_MODE");
             consume(TK(".")); consume(TK("@id"));
             _Str label = parser->prev.str();
             bool ok = co()->add_label(label);
-            if(!ok) syntaxError("label '" + label + "' already exists");
+            if(!ok) SyntaxError("label '" + label + "' already exists");
             consume_end_stmt();
         } else if(match(TK("goto"))){ // https://entrian.com/goto/
-            if(mode() != EXEC_MODE) syntaxError("'goto' is only available in EXEC_MODE");
+            if(mode() != EXEC_MODE) SyntaxError("'goto' is only available in EXEC_MODE");
             consume(TK(".")); consume(TK("@id"));
             emit(OP_GOTO, co()->add_name(parser->prev.str(), NAME_SPECIAL));
             consume_end_stmt();
@@ -940,11 +940,11 @@ __LISTCOMP:
     void _compile_f_args(_Func func, bool enable_type_hints){
         int state = 0;      // 0 for args, 1 for *args, 2 for k=v, 3 for **kwargs
         do {
-            if(state == 3) syntaxError("**kwargs should be the last argument");
+            if(state == 3) SyntaxError("**kwargs should be the last argument");
             match_newlines();
             if(match(TK("*"))){
                 if(state < 1) state = 1;
-                else syntaxError("*args should be placed before **kwargs");
+                else SyntaxError("*args should be placed before **kwargs");
             }
             else if(match(TK("**"))){
                 state = 3;
@@ -952,7 +952,7 @@ __LISTCOMP:
 
             consume(TK("@id"));
             const _Str& name = parser->prev.str();
-            if(func->hasName(name)) syntaxError("duplicate argument name");
+            if(func->hasName(name)) SyntaxError("duplicate argument name");
 
             // eat type hints
             if(enable_type_hints && match(TK(":"))) consume(TK("@id"));
@@ -967,12 +967,12 @@ __LISTCOMP:
                     consume(TK("="));
                     PyVarOrNull value = read_literal();
                     if(value == nullptr){
-                        syntaxError(_Str("expect a literal, not ") + TK_STR(parser->curr.type));
+                        SyntaxError(_Str("expect a literal, not ") + TK_STR(parser->curr.type));
                     }
                     func->kwArgs[name] = value;
                     func->kwArgsOrder.push_back(name);
                 } break;
-                case 3: syntaxError("**kwargs is not supported yet"); break;
+                case 3: SyntaxError("**kwargs is not supported yet"); break;
             }
         } while (match(TK(",")));
     }
@@ -1032,8 +1032,8 @@ __LISTCOMP:
         e.st_push(parser->src->snapshot(lineno, cursor));
         throw e;
     }
-    void syntaxError(_Str msg){ throw_err("SyntaxError", msg); }
-    void indentationError(_Str msg){ throw_err("IndentationError", msg); }
+    void SyntaxError(_Str msg){ throw_err("SyntaxError", msg); }
+    void IndentationError(_Str msg){ throw_err("IndentationError", msg); }
 
 public:
     _Code compile(){
@@ -1057,7 +1057,7 @@ public:
             if(value != nullptr) emit(OP_LOAD_CONST, code->add_const(value));
             else if(match(TK("{"))) exprMap();
             else if(match(TK("["))) exprList();
-            else syntaxError("expect a JSON object or array");
+            else SyntaxError("expect a JSON object or array");
             consume(TK("@eof"));
             return code;    // no need to optimize for JSON decoding
         }

+ 15 - 15
src/pocketpy.h

@@ -29,7 +29,7 @@ _Code VM::compile(_Str source, _Str filename, CompileMode mode) {
         bool _1 = args[1]->is_type(vm->_tp_int) || args[1]->is_type(vm->_tp_float);                     \
         if(!_0 || !_1){                                                                                 \
             if constexpr(is_eq) return vm->PyBool(args[0].get() op args[1].get());                      \
-            vm->typeError("unsupported operand type(s) for " #op );                                     \
+            vm->TypeError("unsupported operand type(s) for " #op );                                     \
         }                                                                                               \
         return vm->PyBool(vm->num_to_float(args[0]) op vm->num_to_float(args[1]));                      \
     });
@@ -57,7 +57,7 @@ void init_builtins(VM* _vm) {
 
     _vm->bind_builtin_func<0>("super", [](VM* vm, const pkpy::Args& args) {
         auto it = vm->top_frame()->f_locals().find(m_self);
-        if(it == vm->top_frame()->f_locals().end()) vm->typeError("super() can only be called in a class method");
+        if(it == vm->top_frame()->f_locals().end()) vm->TypeError("super() can only be called in a class method");
         return vm->new_object(vm->_tp_super, it->second);
     });
 
@@ -75,7 +75,7 @@ void init_builtins(VM* _vm) {
     _vm->bind_builtin_func<-1>("exit", [](VM* vm, const pkpy::Args& args) {
         if(args.size() == 0) std::exit(0);
         else if(args.size() == 1) std::exit((int)vm->PyInt_AS_C(args[0]));
-        else vm->typeError("exit() takes at most 1 argument");
+        else vm->TypeError("exit() takes at most 1 argument");
         return vm->None;
     });
 
@@ -85,13 +85,13 @@ void init_builtins(VM* _vm) {
 
     _vm->bind_builtin_func<1>("chr", [](VM* vm, const pkpy::Args& args) {
         i64 i = vm->PyInt_AS_C(args[0]);
-        if (i < 0 || i > 128) vm->valueError("chr() arg not in range(128)");
+        if (i < 0 || i > 128) vm->ValueError("chr() arg not in range(128)");
         return vm->PyStr(std::string(1, (char)i));
     });
 
     _vm->bind_builtin_func<1>("ord", [](VM* vm, const pkpy::Args& args) {
         _Str s = vm->PyStr_AS_C(args[0]);
-        if (s.size() != 1) vm->typeError("ord() expected an ASCII character");
+        if (s.size() != 1) vm->TypeError("ord() expected an ASCII character");
         return vm->PyInt((i64)(s.c_str()[0]));
     });
 
@@ -150,7 +150,7 @@ void init_builtins(VM* _vm) {
             case 1: r.stop = vm->PyInt_AS_C(args[0]); break;
             case 2: r.start = vm->PyInt_AS_C(args[0]); r.stop = vm->PyInt_AS_C(args[1]); break;
             case 3: r.start = vm->PyInt_AS_C(args[0]); r.stop = vm->PyInt_AS_C(args[1]); r.step = vm->PyInt_AS_C(args[2]); break;
-            default: vm->typeError("expected 1-3 arguments, but got " + std::to_string(args.size()));
+            default: vm->TypeError("expected 1-3 arguments, but got " + std::to_string(args.size()));
         }
         return vm->PyRange(r);
     });
@@ -164,7 +164,7 @@ void init_builtins(VM* _vm) {
 
     _vm->_bind_methods<1>({"int", "float"}, "__truediv__", [](VM* vm, const pkpy::Args& args) {
         f64 rhs = vm->num_to_float(args[1]);
-        if (rhs == 0) vm->zeroDivisionError();
+        if (rhs == 0) vm->ZeroDivisionError();
         return vm->PyFloat(vm->num_to_float(args[0]) / rhs);
     });
 
@@ -189,22 +189,22 @@ void init_builtins(VM* _vm) {
                 if(parsed != s.size()) throw std::invalid_argument("");
                 return vm->PyInt(val);
             }catch(std::invalid_argument&){
-                vm->valueError("invalid literal for int(): '" + s + "'");
+                vm->ValueError("invalid literal for int(): '" + s + "'");
             }
         }
-        vm->typeError("int() argument must be a int, float, bool or str");
+        vm->TypeError("int() argument must be a int, float, bool or str");
         return vm->None;
     });
 
     _vm->bind_method<1>("int", "__floordiv__", [](VM* vm, const pkpy::Args& args) {
         i64 rhs = vm->PyInt_AS_C(args[1]);
-        if(rhs == 0) vm->zeroDivisionError();
+        if(rhs == 0) vm->ZeroDivisionError();
         return vm->PyInt(vm->PyInt_AS_C(args[0]) / rhs);
     });
 
     _vm->bind_method<1>("int", "__mod__", [](VM* vm, const pkpy::Args& args) {
         i64 rhs = vm->PyInt_AS_C(args[1]);
-        if(rhs == 0) vm->zeroDivisionError();
+        if(rhs == 0) vm->ZeroDivisionError();
         return vm->PyInt(vm->PyInt_AS_C(args[0]) % rhs);
     });
 
@@ -242,10 +242,10 @@ void init_builtins(VM* _vm) {
                 f64 val = std::stod(s);
                 return vm->PyFloat(val);
             }catch(std::invalid_argument&){
-                vm->valueError("invalid literal for float(): '" + s + "'");
+                vm->ValueError("invalid literal for float(): '" + s + "'");
             }
         }
-        vm->typeError("float() argument must be a int, float, bool or str");
+        vm->TypeError("float() argument must be a int, float, bool or str");
         return vm->None;
     });
 
@@ -261,7 +261,7 @@ void init_builtins(VM* _vm) {
 
     _vm->bind_method<0>("float", "__json__", [](VM* vm, const pkpy::Args& args) {
         f64 val = vm->PyFloat_AS_C(args[0]);
-        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'");
         return vm->PyStr(std::to_string(val));
     });
 
@@ -373,7 +373,7 @@ void init_builtins(VM* _vm) {
         }else if(args[1]->is_type(vm->_tp_tuple)){
             _list = &vm->PyTuple_AS_C(args[1]);
         }else{
-            vm->typeError("can only join a list or tuple");
+            vm->TypeError("can only join a list or tuple");
         }
         _StrStream ss;
         for(int i = 0; i < _list->size(); i++){

+ 38 - 38
src/vm.h

@@ -23,7 +23,7 @@
 class VM {
     std::vector<PyVar> _small_integers;             // [-5, 256]
     std::stack< std::unique_ptr<Frame> > callstack;
-    PyVar __py2py_call_signal;
+    PyVar _py_op_call;
     
     PyVar run_frame(Frame* frame){
         while(frame->has_next_bytecode()){
@@ -232,7 +232,7 @@ class VM {
                     pkpy::Args args = frame->pop_n_values_reversed(this, ARGC);
                     PyVar callable = frame->pop_value(this);
                     PyVar ret = call(callable, std::move(args), kwargs, true);
-                    if(ret == __py2py_call_signal) return ret;
+                    if(ret == _py_op_call) return ret;
                     frame->push(std::move(ret));
                 } break;
             case OP_JUMP_ABSOLUTE: frame->jump_abs(byte.arg); break;
@@ -254,7 +254,7 @@ class VM {
                         PyIter_AS_C(tmp)->var = var;
                         frame->push(std::move(tmp));
                     }else{
-                        typeError("'" + OBJ_TP_NAME(obj) + "' object is not iterable");
+                        TypeError("'" + OBJ_TP_NAME(obj) + "' object is not iterable");
                     }
                 } break;
             case OP_FOR_ITER:
@@ -407,7 +407,7 @@ public:
             if(val != nullptr) return call(*val, std::move(args));
             cls = cls->attribs[__base__].get();
         }
-        attributeError(args[0], name);
+        AttributeError(args[0], name);
         return nullptr;
     }
 
@@ -454,7 +454,7 @@ public:
         
         if((*callable)->is_type(_tp_native_function)){
             const auto& f = OBJ_GET(_CppFunc, *callable);
-            if(kwargs.size() != 0) typeError("_native_function does not accept keyword arguments");
+            if(kwargs.size() != 0) TypeError("native_function does not accept keyword arguments");
             return f(this, args);
         } else if((*callable)->is_type(_tp_function)){
             const _Func& fn = PyFunction_AS_C((*callable));
@@ -467,7 +467,7 @@ public:
                     locals.emplace(name, args[i++]);
                     continue;
                 }
-                typeError("missing positional argument '" + name + "'");
+                TypeError("missing positional argument '" + name + "'");
             }
 
             locals.insert(fn->kwArgs.begin(), fn->kwArgs.end());
@@ -487,19 +487,19 @@ public:
                         break;
                     }
                 }
-                if(i < args.size()) typeError("too many arguments");
+                if(i < args.size()) TypeError("too many arguments");
             }
             
             for(int i=0; i<kwargs.size(); i+=2){
                 const _Str& key = PyStr_AS_C(kwargs[i]);
                 if(!fn->kwArgs.contains(key)){
-                    typeError(key.escape(true) + " is an invalid keyword argument for " + fn->name + "()");
+                    TypeError(key.escape(true) + " is an invalid keyword argument for " + fn->name + "()");
                 }
                 const PyVar& val = kwargs[i+1];
                 if(!positional_overrided_keys.empty()){
                     auto it = std::find(positional_overrided_keys.begin(), positional_overrided_keys.end(), key);
                     if(it != positional_overrided_keys.end()){
-                        typeError("multiple values for argument '" + key + "'");
+                        TypeError("multiple values for argument '" + key + "'");
                     }
                 }
                 locals[key] = val;
@@ -509,11 +509,11 @@ public:
             PyVar _module = it_m != nullptr ? *it_m : top_frame()->_module;
             if(opCall){
                 __new_frame(fn->code, _module, _locals);
-                return __py2py_call_signal;
+                return _py_op_call;
             }
             return _exec(fn->code, _module, _locals);
         }
-        typeError("'" + OBJ_TP_NAME(*callable) + "' object is not callable");
+        TypeError("'" + OBJ_TP_NAME(*callable) + "' object is not callable");
         return None;
     }
 
@@ -557,7 +557,7 @@ public:
                 if(need_raise){ need_raise = false; _raise(); }
                 ret = run_frame(frame);
 
-                if(ret != __py2py_call_signal){
+                if(ret != _py_op_call){
                     if(frame->id == base_id){      // [ frameBase<- ]
                         callstack.pop();
                         return ret;
@@ -659,7 +659,7 @@ public:
             }
             cls = cls->attribs[__base__].get();
         }
-        if(throw_err) attributeError(obj, name);
+        if(throw_err) AttributeError(obj, name);
         return nullptr;
     }
 
@@ -707,7 +707,7 @@ public:
         }else if(obj->is_type(_tp_float)){
             return PyFloat_AS_C(obj);
         }
-        typeError("expected int or float, got " + OBJ_TP_NAME(obj));
+        TypeError("expected int or float, got " + OBJ_TP_NAME(obj));
         return 0;
     }
 
@@ -717,14 +717,14 @@ public:
         }else if(obj->is_type(_tp_float)){
             return PyFloat(-PyFloat_AS_C(obj));
         }
-        typeError("unsupported operand type(s) for -");
+        TypeError("unsupported operand type(s) for -");
         return nullptr;
     }
 
     int normalized_index(int index, int size){
         if(index < 0) index += size;
         if(index < 0 || index >= size){
-            indexError(std::to_string(index) + " not in [0, " + std::to_string(size) + ")");
+            IndexError(std::to_string(index) + " not in [0, " + std::to_string(size) + ")");
         }
         return index;
     }
@@ -807,7 +807,7 @@ public:
 
     inline const BaseRef* PyRef_AS_C(const PyVar& obj)
     {
-        if(!obj->is_type(_tp_ref)) typeError("expected an l-value");
+        if(!obj->is_type(_tp_ref)) TypeError("expected an l-value");
         return (const BaseRef*)(obj->value());
     }
 
@@ -851,8 +851,8 @@ public:
         _tp_ref = new_type_object("_ref");
         
         _tp_function = new_type_object("function");
-        _tp_native_function = new_type_object("_native_function");
-        _tp_native_iterator = new_type_object("_native_iterator");
+        _tp_native_function = new_type_object("native_function");
+        _tp_native_iterator = new_type_object("native_iterator");
         _tp_bound_method = new_type_object("bound_method");
         _tp_super = new_type_object("super");
         _tp_exception = new_type_object("Exception");
@@ -863,7 +863,7 @@ public:
         this->False = new_object(_tp_bool, false);
         this->builtins = new_module("builtins");
         this->_main = new_module("__main__");
-        this->__py2py_call_signal = new_object(new_type_object("_signal"), DUMMY_VAL);
+        this->_py_op_call = new_object(new_type_object("_internal"), DUMMY_VAL);
 
         setattr(_tp_type, __base__, _tp_object);
         _tp_type->type = _tp_type;
@@ -897,7 +897,7 @@ public:
             }
             return x;
         }
-        typeError("unhashable type: " +  OBJ_TP_NAME(obj));
+        TypeError("unhashable type: " +  OBJ_TP_NAME(obj));
         return 0;
     }
 
@@ -923,19 +923,19 @@ private:
     }
 
 public:
-    void notImplementedError(){ _error("NotImplementedError", ""); }
-    void typeError(const _Str& msg){ _error("TypeError", msg); }
-    void zeroDivisionError(){ _error("ZeroDivisionError", "division by zero"); }
-    void indexError(const _Str& msg){ _error("IndexError", msg); }
-    void valueError(const _Str& msg){ _error("ValueError", msg); }
-    void nameError(const _Str& name){ _error("NameError", "name '" + name + "' is not defined"); }
-
-    void attributeError(PyVar obj, const _Str& name){
+    void NotImplementedError(){ _error("NotImplementedError", ""); }
+    void TypeError(const _Str& msg){ _error("TypeError", msg); }
+    void ZeroDivisionError(){ _error("ZeroDivisionError", "division by zero"); }
+    void IndexError(const _Str& msg){ _error("IndexError", msg); }
+    void ValueError(const _Str& msg){ _error("ValueError", msg); }
+    void NameError(const _Str& name){ _error("NameError", "name '" + name + "' is not defined"); }
+
+    void AttributeError(PyVar obj, const _Str& name){
         _error("AttributeError", "type '" +  OBJ_TP_NAME(obj) + "' has no attribute '" + name + "'");
     }
 
     inline void check_type(const PyVar& obj, const PyVar& type){
-        if(!obj->is_type(type)) typeError("expected '" + OBJ_NAME(type) + "', but got '" + OBJ_TP_NAME(obj) + "'");
+        if(!obj->is_type(type)) TypeError("expected '" + OBJ_NAME(type) + "', but got '" + OBJ_TP_NAME(obj) + "'");
     }
 
     template<typename T>
@@ -971,7 +971,7 @@ PyVar NameRef::get(VM* vm, Frame* frame) const{
     if(val) return *val;
     val = vm->builtins->attribs.try_get(pair->first);
     if(val) return *val;
-    vm->nameError(pair->first);
+    vm->NameError(pair->first);
     return nullptr;
 }
 
@@ -997,7 +997,7 @@ void NameRef::del(VM* vm, Frame* frame) const{
             if(frame->f_locals().contains(pair->first)){
                 frame->f_locals().erase(pair->first);
             }else{
-                vm->nameError(pair->first);
+                vm->NameError(pair->first);
             }
         } break;
         case NAME_GLOBAL:
@@ -1008,7 +1008,7 @@ void NameRef::del(VM* vm, Frame* frame) const{
                 if(frame->f_globals().contains(pair->first)){
                     frame->f_globals().erase(pair->first);
                 }else{
-                    vm->nameError(pair->first);
+                    vm->NameError(pair->first);
                 }
             }
         } break;
@@ -1025,7 +1025,7 @@ void AttrRef::set(VM* vm, Frame* frame, PyVar val) const{
 }
 
 void AttrRef::del(VM* vm, Frame* frame) const{
-    vm->typeError("cannot delete attribute");
+    vm->TypeError("cannot delete attribute");
 }
 
 PyVar IndexRef::get(VM* vm, Frame* frame) const{
@@ -1050,11 +1050,11 @@ PyVar TupleRef::get(VM* vm, Frame* frame) const{
 
 void TupleRef::set(VM* vm, Frame* frame, PyVar val) const{
     if(!val->is_type(vm->_tp_tuple) && !val->is_type(vm->_tp_list)){
-        vm->typeError("only tuple or list can be unpacked");
+        vm->TypeError("only tuple or list can be unpacked");
     }
     const PyVarList& args = OBJ_GET(PyVarList, val);
-    if(args.size() > varRefs.size()) vm->valueError("too many values to unpack");
-    if(args.size() < varRefs.size()) vm->valueError("not enough values to unpack");
+    if(args.size() > varRefs.size()) vm->ValueError("too many values to unpack");
+    if(args.size() < varRefs.size()) vm->ValueError("not enough values to unpack");
     for (int i = 0; i < varRefs.size(); i++) {
         vm->PyRef_AS_C(varRefs[i])->set(vm, frame, args[i]);
     }
@@ -1083,7 +1083,7 @@ PyVar StringIterator::next(){
 PyVar _CppFunc::operator()(VM* vm, const pkpy::Args& args) const{
     int args_size = args.size() - (int)method;  // remove self
     if(argc != -1 && args_size != argc) {
-        vm->typeError("expected " + std::to_string(argc) + " arguments, but got " + std::to_string(args_size));
+        vm->TypeError("expected " + std::to_string(argc) + " arguments, but got " + std::to_string(args_size));
     }
     return f(vm, args);
 }