This commit is contained in:
blueloveTH 2024-08-05 14:20:39 +08:00
parent 0c081ba912
commit 50ec46fe83
10 changed files with 98 additions and 58 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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());
}