blueloveTH 1 year ago
parent
commit
50ec46fe83

+ 30 - 12
include/pocketpy/pocketpy.h

@@ -281,7 +281,7 @@ int py_import(const char* path) PY_RAISE;
 
 /************* Errors *************/
 /// Raise an exception by name and message. Always returns false.
-bool py_exception(const char* name, const char* fmt, ...) PY_RAISE;
+bool py_exception(py_Type type, const char* fmt, ...) PY_RAISE;
 /// Raise an expection object. Always returns false.
 bool py_raise(py_Ref) PY_RAISE;
 /// Print the current exception.
@@ -290,22 +290,24 @@ void py_printexc();
 char* py_formatexc();
 /// Check if an exception is raised.
 bool py_checkexc();
+/// Check if the exception is an instance of the given type.
+bool py_matchexc(py_Type type);
 /// Clear the current exception.
 void py_clearexc(py_StackRef p0);
 
-#define IOError(...) py_exception("IOError", __VA_ARGS__)
-#define OSError(...) py_exception("OSError", __VA_ARGS__)
-#define NameError(n) py_exception("NameError", "name '%n' is not defined", (n))
-#define TypeError(...) py_exception("TypeError", __VA_ARGS__)
-#define RuntimeError(...) py_exception("RuntimeError", __VA_ARGS__)
-#define ValueError(...) py_exception("ValueError", __VA_ARGS__)
-#define IndexError(...) py_exception("IndexError", __VA_ARGS__)
-#define ImportError(...) py_exception("ImportError", __VA_ARGS__)
-#define NotImplementedError() py_exception("NotImplementedError", "")
+#define IOError(...) py_exception(tp_IOError, __VA_ARGS__)
+#define OSError(...) py_exception(tp_OSError, __VA_ARGS__)
+#define NameError(n) py_exception(tp_NameError, "name '%n' is not defined", (n))
+#define TypeError(...) py_exception(tp_TypeError, __VA_ARGS__)
+#define RuntimeError(...) py_exception(tp_RuntimeError, __VA_ARGS__)
+#define ValueError(...) py_exception(tp_ValueError, __VA_ARGS__)
+#define IndexError(...) py_exception(tp_IndexError, __VA_ARGS__)
+#define ImportError(...) py_exception(tp_ImportError, __VA_ARGS__)
+#define NotImplementedError() py_exception(tp_NotImplementedError, "")
 #define AttributeError(self, n)                                                                    \
-    py_exception("AttributeError", "'%t' object has no attribute '%n'", (self)->type, (n))
+    py_exception(tp_AttributeError, "'%t' object has no attribute '%n'", (self)->type, (n))
 #define UnboundLocalError(n)                                                                       \
-    py_exception("UnboundLocalError", "local variable '%n' referenced before assignment", (n))
+    py_exception(tp_UnboundLocalError, "local variable '%n' referenced before assignment", (n))
 
 bool StopIteration();
 bool KeyError(py_Ref key) PY_RAISE;
@@ -429,6 +431,22 @@ enum py_PredefinedTypes {
     tp_ellipsis,
     tp_SyntaxError,
     tp_StopIteration,
+    /* builtin exceptions */
+    tp_StackOverflowError,
+    tp_IOError,
+    tp_OSError,
+    tp_NotImplementedError,
+    tp_TypeError,
+    tp_IndexError,
+    tp_ValueError,
+    tp_RuntimeError,
+    tp_ZeroDivisionError,
+    tp_NameError,
+    tp_UnboundLocalError,
+    tp_AttributeError,
+    tp_ImportError,
+    tp_AssertionError,
+    tp_KeyError,
 };
 
 #ifdef __cplusplus

+ 3 - 3
src/interpreter/ceval.c

@@ -909,9 +909,9 @@ FrameResult VM__run_top_frame(VM* self) {
                 if(byte.arg) {
                     if(!py_str(TOP())) goto __ERROR;
                     POP();
-                    py_exception("AssertionError", "%s", py_tostr(py_retval()));
+                    py_exception(tp_AssertionError, "%s", py_tostr(py_retval()));
                 } else {
-                    py_exception("AssertionError", "");
+                    py_exception(tp_AssertionError, "");
                 }
                 goto __ERROR;
             }
@@ -1010,7 +1010,7 @@ bool pk_stack_binaryop(VM* self, py_Name op, py_Name rop) {
         py_newbool(py_retval(), res);
         return true;
     }
-    return py_exception("TypeError", "unsupported operand type(s) for '%n'", op);
+    return TypeError("unsupported operand type(s) for '%n'", op);
 }
 
 bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) {

+ 29 - 31
src/interpreter/vm.c

@@ -129,10 +129,36 @@ void VM__ctor(VM* self) {
 
     validate(tp_SyntaxError, pk_newtype("SyntaxError", tp_Exception, NULL, NULL, false, true));
     validate(tp_StopIteration, pk_newtype("StopIteration", tp_Exception, NULL, NULL, false, true));
-#undef validate
 
     self->builtins = pk_builtins__register();
 
+    // inject some builtin expections
+#define INJECT_BUILTIN_EXC(name)                                                                   \
+    do {                                                                                           \
+        py_Type type = pk_newtype(#name, tp_Exception, &self->builtins, NULL, false, true);         \
+        py_setdict(&self->builtins, py_name(#name), py_tpobject(type));                             \
+        validate(tp_##name, type);                                                                 \
+    } while(0)
+
+    INJECT_BUILTIN_EXC(StackOverflowError);
+    INJECT_BUILTIN_EXC(IOError);
+    INJECT_BUILTIN_EXC(OSError);
+    INJECT_BUILTIN_EXC(NotImplementedError);
+    INJECT_BUILTIN_EXC(TypeError);
+    INJECT_BUILTIN_EXC(IndexError);
+    INJECT_BUILTIN_EXC(ValueError);
+    INJECT_BUILTIN_EXC(RuntimeError);
+    INJECT_BUILTIN_EXC(ZeroDivisionError);
+    INJECT_BUILTIN_EXC(NameError);
+    INJECT_BUILTIN_EXC(UnboundLocalError);
+    INJECT_BUILTIN_EXC(AttributeError);
+    INJECT_BUILTIN_EXC(ImportError);
+    INJECT_BUILTIN_EXC(AssertionError);
+    INJECT_BUILTIN_EXC(KeyError);
+
+#undef INJECT_BUILTIN_EXC
+#undef validate
+
     /* Setup Public Builtin Types */
     py_Type public_types[] = {tp_object,        tp_type,         tp_int,           tp_float,
                               tp_bool,          tp_str,          tp_list,          tp_tuple,
@@ -146,35 +172,7 @@ void VM__ctor(VM* self) {
         py_setdict(&self->builtins, ti->name, py_tpobject(t));
     }
 
-    // inject some builtin expections
-    const char** builtin_exceptions = (const char*[]){
-        "StackOverflowError",
-        "IOError",
-        "OSError",
-        "NotImplementedError",
-        "TypeError",
-        "IndexError",
-        "ValueError",
-        "RuntimeError",
-        "ZeroDivisionError",
-        "NameError",
-        "UnboundLocalError",
-        "AttributeError",
-        "ImportError",
-        "AssertionError",
-        "KeyError",
-        NULL,  // sentinel
-    };
-    const char** it = builtin_exceptions;
-    while(*it) {
-        py_Type type = pk_newtype(*it, tp_Exception, &self->builtins, NULL, false, true);
-        py_setdict(&self->builtins, py_name(*it), py_tpobject(type));
-        it++;
-    }
-
-    py_TValue tmp;
-    py_newnotimplemented(&tmp);
-    py_setdict(&self->builtins, py_name("NotImplemented"), &tmp);
+    py_newnotimplemented(py_emplacedict(&self->builtins, py_name("NotImplemented")));
 
     // add modules
     pk__add_module_pkpy();
@@ -387,7 +385,7 @@ FrameResult VM__vectorcall(VM* self, uint16_t argc, uint16_t kwargc, bool opcall
         /*****************_py_call*****************/
         // check stack overflow
         if(self->stack.sp > self->stack.end) {
-            py_exception("StackOverflowError", "");
+            py_exception(tp_StackOverflowError, "");
             return RES_ERROR;
         }
 

+ 1 - 1
src/public/internal.c

@@ -83,7 +83,7 @@ bool py_exec(const char* source, const char* filename, enum py_CompileMode mode,
     SourceData_ src = SourceData__rcnew(source, filename, mode, false);
     Error* err = pk_compile(src, &co);
     if(err) {
-        py_exception("SyntaxError", err->msg);
+        py_exception(tp_SyntaxError, err->msg);
         py_BaseException__stpush(&vm->curr_exception, src, err->lineno, NULL);
 
         PK_DECREF(src);

+ 22 - 1
src/public/modules.c

@@ -218,7 +218,7 @@ static bool builtins__next(int argc, py_Ref argv) {
     int res = py_next(argv);
     if(res == -1) return false;
     if(res) return true;
-    return py_exception("StopIteration", "");
+    return py_exception(tp_StopIteration, "");
 }
 
 static bool builtins__sorted(int argc, py_Ref argv) {
@@ -355,6 +355,25 @@ static bool builtins__issubclass(int argc, py_Ref argv) {
     return true;
 }
 
+static bool builtins__getattr(int argc, py_Ref argv) {
+    PY_CHECK_ARG_TYPE(1, tp_str);
+    py_Name name = py_namev(py_tosv(py_arg(1)));
+    if(argc == 2) {
+        return py_getattr(py_arg(0), name);
+    } else if(argc == 3) {
+        py_StackRef p0 = py_peek(0);
+        bool ok = py_getattr(py_arg(0), name);
+        if(!ok && py_matchexc(tp_AttributeError)) {
+            py_clearexc(p0);
+            return py_arg(2);  // default value
+        }
+        return ok;
+    } else {
+        return TypeError("getattr() expected 2 or 3 arguments");
+    }
+    return true;
+}
+
 py_TValue pk_builtins__register() {
     py_Ref builtins = py_newmodule("builtins");
     py_bindfunc(builtins, "repr", builtins__repr);
@@ -377,6 +396,8 @@ py_TValue pk_builtins__register() {
     py_bindfunc(builtins, "isinstance", builtins__isinstance);
     py_bindfunc(builtins, "issubclass", builtins__issubclass);
 
+    py_bindfunc(builtins, "getattr", builtins__getattr);
+
     // None __repr__
     py_bindmagic(tp_NoneType, __repr__, NoneType__repr__);
     return *builtins;

+ 13 - 10
src/public/py_exception.c

@@ -115,6 +115,12 @@ bool py_checkexc() {
     return !py_isnil(&vm->curr_exception);
 }
 
+bool py_matchexc(py_Type type) {
+    VM* vm = pk_current_vm;
+    if(py_isnil(&vm->curr_exception)) return false;
+    return py_issubclass(vm->curr_exception.type, type);
+}
+
 void py_clearexc(py_StackRef p0) {
     VM* vm = pk_current_vm;
     vm->last_retval = *py_NIL;
@@ -145,10 +151,10 @@ char* py_formatexc() {
     for(int i = ud->stacktrace.count - 1; i >= 0; i--) {
         BaseExceptionFrame* frame = c11__at(BaseExceptionFrame, &ud->stacktrace, i);
         SourceData__snapshot(frame->src,
-                                &ss,
-                                frame->lineno,
-                                NULL,
-                                frame->name ? frame->name->data : NULL);
+                             &ss,
+                             frame->lineno,
+                             NULL,
+                             frame->name ? frame->name->data : NULL);
         c11_sbuf__write_char(&ss, '\n');
     }
 
@@ -169,7 +175,7 @@ char* py_formatexc() {
     return dup;
 }
 
-bool py_exception(const char* name, const char* fmt, ...) {
+bool py_exception(py_Type type, const char* fmt, ...) {
     c11_sbuf buf;
     c11_sbuf__ctor(&buf);
     va_list args;
@@ -180,9 +186,7 @@ bool py_exception(const char* name, const char* fmt, ...) {
     py_Ref message = py_pushtmp();
     c11_sbuf__py_submit(&buf, message);
 
-    py_Ref exc_type = py_getdict(&pk_current_vm->builtins, py_name(name));
-    if(exc_type == NULL) c11__abort("py_exception(): '%s' not found", name);
-    bool ok = py_call(exc_type, 1, message);
+    bool ok = py_tpcall(type, 1, message);
     if(!ok) c11__abort("py_exception(): failed to create exception object");
     py_pop();
 
@@ -197,8 +201,7 @@ bool py_raise(py_Ref exc) {
 }
 
 bool KeyError(py_Ref key) {
-    py_Ref cls = py_getdict(&pk_current_vm->builtins, py_name("KeyError"));
-    bool ok = py_call(cls, 1, key);
+    bool ok = py_tpcall(tp_KeyError, 1, key);
     if(!ok) return false;
     return py_raise(py_retval());
 }

+ 0 - 0
tests/46_star.py → tests/44_star.py


+ 0 - 0
tests/47_reflection.py → tests/50_reflection.py


+ 0 - 0
tests/44_eval.py → tests/51_eval.py


+ 0 - 0
tests/45_yield.py → tests/52_yield.py