py_exception.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. #include "pocketpy/objects/codeobject.h"
  2. #include "pocketpy/objects/error.h"
  3. #include "pocketpy/pocketpy.h"
  4. #include "pocketpy/common/utils.h"
  5. #include "pocketpy/objects/object.h"
  6. #include "pocketpy/interpreter/vm.h"
  7. #include "pocketpy/common/sstream.h"
  8. typedef struct BaseExceptionFrame {
  9. SourceData_ src;
  10. int lineno;
  11. c11_string* name;
  12. } BaseExceptionFrame;
  13. typedef struct BaseException {
  14. c11_vector /*T=BaseExceptionFrame*/ stacktrace;
  15. } BaseException;
  16. void py_BaseException__stpush(py_Ref self, SourceData_ src, int lineno, const char* func_name) {
  17. BaseException* ud = py_touserdata(self);
  18. if(ud->stacktrace.length >= 7) return;
  19. BaseExceptionFrame* frame = c11_vector__emplace(&ud->stacktrace);
  20. PK_INCREF(src);
  21. frame->src = src;
  22. frame->lineno = lineno;
  23. frame->name = func_name ? c11_string__new(func_name) : NULL;
  24. }
  25. static void BaseException__dtor(void* ud) {
  26. BaseException* self = (BaseException*)ud;
  27. c11__foreach(BaseExceptionFrame, &self->stacktrace, it) {
  28. PK_DECREF(it->src);
  29. if(it->name) c11_string__delete(it->name);
  30. }
  31. c11_vector__dtor(&self->stacktrace);
  32. }
  33. static bool _py_BaseException__new__(int argc, py_Ref argv) {
  34. py_Type cls = py_totype(argv);
  35. BaseException* ud = py_newobject(py_retval(), cls, 2, sizeof(BaseException));
  36. c11_vector__ctor(&ud->stacktrace, sizeof(BaseExceptionFrame));
  37. return true;
  38. }
  39. static bool _py_BaseException__init__(int argc, py_Ref argv) {
  40. py_newnone(py_retval());
  41. if(argc == 1 + 0) return true;
  42. if(argc == 1 + 1) {
  43. py_setslot(py_arg(0), 0, py_arg(1));
  44. return true;
  45. }
  46. return TypeError("__init__() takes at most 1 arguments but %d were given", argc - 1);
  47. }
  48. static bool _py_BaseException__repr__(int argc, py_Ref argv) {
  49. c11_sbuf ss;
  50. c11_sbuf__ctor(&ss);
  51. pk_sprintf(&ss, "%t(", argv->type);
  52. py_Ref arg = py_getslot(argv, 0);
  53. if(!py_isnil(arg)) {
  54. if(!py_repr(arg)) return false;
  55. c11_sbuf__write_sv(&ss, py_tosv(py_retval()));
  56. }
  57. c11_sbuf__write_char(&ss, ')');
  58. c11_sbuf__py_submit(&ss, py_retval());
  59. return true;
  60. }
  61. static bool _py_BaseException__str__(int argc, py_Ref argv) {
  62. c11_sbuf ss;
  63. c11_sbuf__ctor(&ss);
  64. py_Ref arg = py_getslot(argv, 0);
  65. if(!py_isnil(arg)) {
  66. if(argv->type == tp_KeyError) {
  67. if(!py_repr(arg)) return false;
  68. } else {
  69. if(!py_str(arg)) return false;
  70. }
  71. c11_sbuf__write_sv(&ss, py_tosv(py_retval()));
  72. }
  73. c11_sbuf__py_submit(&ss, py_retval());
  74. return true;
  75. }
  76. static bool BaseException_args(int argc, py_Ref argv) {
  77. PY_CHECK_ARGC(1);
  78. py_Ref arg = py_getslot(argv, 0);
  79. if(!py_isnil(arg)) {
  80. py_Ref p = py_newtuple(py_retval(), 1);
  81. p[0] = *arg;
  82. } else {
  83. py_newtuple(py_retval(), 0);
  84. }
  85. return true;
  86. }
  87. static bool StopIteration_value(int argc, py_Ref argv) {
  88. PY_CHECK_ARGC(1);
  89. py_Ref arg = py_getslot(argv, 0);
  90. if(py_isnil(arg)) {
  91. py_newnone(py_retval());
  92. } else {
  93. py_assign(py_retval(), arg);
  94. }
  95. return true;
  96. }
  97. py_Type pk_BaseException__register() {
  98. py_Type type = pk_newtype("BaseException", tp_object, NULL, BaseException__dtor, false, false);
  99. py_bindmagic(type, __new__, _py_BaseException__new__);
  100. py_bindmagic(type, __init__, _py_BaseException__init__);
  101. py_bindmagic(type, __repr__, _py_BaseException__repr__);
  102. py_bindmagic(type, __str__, _py_BaseException__str__);
  103. py_bindproperty(type, "args", BaseException_args, NULL);
  104. return type;
  105. }
  106. py_Type pk_Exception__register() {
  107. py_Type type = pk_newtype("Exception", tp_BaseException, NULL, NULL, false, false);
  108. return type;
  109. }
  110. py_Type pk_StopIteration__register() {
  111. py_Type type = pk_newtype("StopIteration", tp_Exception, NULL, NULL, false, false);
  112. py_bindproperty(type, "value", StopIteration_value, NULL);
  113. return type;
  114. }
  115. //////////////////////////////////////////////////
  116. bool py_checkexc(bool ignore_handled) {
  117. VM* vm = pk_current_vm;
  118. if(ignore_handled && vm->is_curr_exc_handled) return false;
  119. return !py_isnil(&vm->curr_exception);
  120. }
  121. bool py_matchexc(py_Type type) {
  122. VM* vm = pk_current_vm;
  123. if(vm->is_curr_exc_handled) return false;
  124. if(py_isnil(&vm->curr_exception)) return false;
  125. bool ok = py_issubclass(vm->curr_exception.type, type);
  126. if(ok) {
  127. // if match, then the exception is handled
  128. vm->is_curr_exc_handled = true;
  129. vm->last_retval = vm->curr_exception;
  130. }
  131. return ok;
  132. }
  133. void py_clearexc(py_StackRef p0) {
  134. VM* vm = pk_current_vm;
  135. vm->curr_exception = *py_NIL();
  136. vm->is_curr_exc_handled = false;
  137. /* Don't clear this, because StopIteration() may corrupt the class definition */
  138. // vm->curr_class = NULL;
  139. vm->curr_decl_based_function = NULL;
  140. if(p0) vm->stack.sp = p0;
  141. }
  142. void py_printexc() {
  143. char* msg = py_formatexc();
  144. if(!msg) return;
  145. pk_current_vm->callbacks.print(msg);
  146. pk_current_vm->callbacks.print("\n");
  147. PK_FREE(msg);
  148. }
  149. static void c11_sbuf__write_exc(c11_sbuf* self, py_Ref exc) {
  150. if(true) { c11_sbuf__write_cstr(self, "Traceback (most recent call last):\n"); }
  151. BaseException* ud = py_touserdata(exc);
  152. for(int i = ud->stacktrace.length - 1; i >= 0; i--) {
  153. BaseExceptionFrame* frame = c11__at(BaseExceptionFrame, &ud->stacktrace, i);
  154. SourceData__snapshot(frame->src,
  155. self,
  156. frame->lineno,
  157. NULL,
  158. frame->name ? frame->name->data : NULL);
  159. c11_sbuf__write_char(self, '\n');
  160. }
  161. const char* name = py_tpname(exc->type);
  162. const char* message;
  163. bool ok = py_str(exc);
  164. if(!ok || !py_isstr(py_retval())) {
  165. message = "<exception str() failed>";
  166. } else {
  167. message = py_tostr(py_retval());
  168. }
  169. c11_sbuf__write_cstr(self, name);
  170. c11_sbuf__write_cstr(self, ": ");
  171. c11_sbuf__write_cstr(self, message);
  172. }
  173. char* py_formatexc() {
  174. VM* vm = pk_current_vm;
  175. if(py_isnil(&vm->curr_exception)) return NULL;
  176. // when you call `py_formatexc()`, you are handling the exception
  177. vm->is_curr_exc_handled = true;
  178. c11_sbuf ss;
  179. c11_sbuf__ctor(&ss);
  180. py_Ref inner = py_getslot(&vm->curr_exception, 1);
  181. if(py_isnil(inner)) {
  182. c11_sbuf__write_exc(&ss, &vm->curr_exception);
  183. } else {
  184. c11_sbuf__write_exc(&ss, inner);
  185. c11_sbuf__write_cstr(
  186. &ss,
  187. "\n\nDuring handling of the above exception, another exception occurred:\n\n");
  188. c11_sbuf__write_exc(&ss, &vm->curr_exception);
  189. }
  190. c11_string* res = c11_sbuf__submit(&ss);
  191. char* dup = PK_MALLOC(res->size + 1);
  192. memcpy(dup, res->data, res->size);
  193. dup[res->size] = '\0';
  194. c11_string__delete(res);
  195. return dup;
  196. }
  197. bool py_exception(py_Type type, const char* fmt, ...) {
  198. c11_sbuf buf;
  199. c11_sbuf__ctor(&buf);
  200. va_list args;
  201. va_start(args, fmt);
  202. pk_vsprintf(&buf, fmt, args);
  203. va_end(args);
  204. py_Ref message = py_pushtmp();
  205. c11_sbuf__py_submit(&buf, message);
  206. bool ok = py_tpcall(type, 1, message);
  207. if(!ok) return false;
  208. py_pop();
  209. return py_raise(py_retval());
  210. }
  211. bool py_raise(py_Ref exc) {
  212. assert(py_isinstance(exc, tp_BaseException));
  213. VM* vm = pk_current_vm;
  214. if(!py_isnil(&vm->curr_exception)) {
  215. // inner exception
  216. py_setslot(exc, 1, &vm->curr_exception);
  217. }
  218. vm->curr_exception = *exc;
  219. vm->is_curr_exc_handled = false;
  220. if(vm->trace_info.func && !py_istype(exc, tp_StopIteration)) {
  221. py_Frame* frame = vm->top_frame;
  222. vm->trace_info.func(frame, TRACE_EVENT_EXCEPTION);
  223. }
  224. return false;
  225. }
  226. bool KeyError(py_Ref key) {
  227. bool ok = py_tpcall(tp_KeyError, 1, key);
  228. if(!ok) return false;
  229. return py_raise(py_retval());
  230. }