PyException.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. #include "pocketpy/objects/error.h"
  2. #include "pocketpy/pocketpy.h"
  3. #include "pocketpy/common/utils.h"
  4. #include "pocketpy/interpreter/vm.h"
  5. #include "pocketpy/common/sstream.h"
  6. #include "pocketpy/objects/exception.h"
  7. #include "pocketpy/interpreter/bindings.h"
  8. void py_BaseException__stpush(py_Frame* frame,
  9. py_Ref self,
  10. SourceData_ src,
  11. int lineno,
  12. const char* func_name) {
  13. BaseException* ud = py_touserdata(self);
  14. int max_frame_dumps = py_debugger_status() == 1 ? 31 : 7;
  15. if(ud->stacktrace.length >= max_frame_dumps) return;
  16. BaseExceptionFrame* frame_dump = c11_vector__emplace(&ud->stacktrace);
  17. // `locals` and `globals` are only filled in when the debugger is attached, but the GC
  18. // walks them unconditionally; nil them out before anything below can allocate
  19. py_newnil(&frame_dump->locals);
  20. py_newnil(&frame_dump->globals);
  21. PK_INCREF(src);
  22. frame_dump->src = src;
  23. frame_dump->lineno = lineno;
  24. frame_dump->name = func_name ? c11_string__new(func_name) : NULL;
  25. if(py_debugger_status() == 1) {
  26. if(frame != NULL) {
  27. py_Frame_newlocals(frame, &frame_dump->locals);
  28. py_Frame_newglobals(frame, &frame_dump->globals);
  29. } else {
  30. py_newdict(&frame_dump->locals);
  31. py_newdict(&frame_dump->globals);
  32. }
  33. }
  34. }
  35. static void BaseException__dtor(void* ud) {
  36. BaseException* self = (BaseException*)ud;
  37. c11__foreach(BaseExceptionFrame, &self->stacktrace, it) {
  38. PK_DECREF(it->src);
  39. if(it->name) c11_string__delete(it->name);
  40. }
  41. c11_vector__dtor(&self->stacktrace);
  42. }
  43. static bool _py_BaseException__new__(int argc, py_Ref argv) {
  44. py_Type cls = py_totype(argv);
  45. BaseException* ud = py_newobject(py_retval(), cls, 0, sizeof(BaseException));
  46. py_newnil(&ud->args);
  47. py_newnil(&ud->inner_exc);
  48. c11_vector__ctor(&ud->stacktrace, sizeof(BaseExceptionFrame));
  49. return true;
  50. }
  51. static bool _py_BaseException__init__(int argc, py_Ref argv) {
  52. BaseException* ud = py_touserdata(argv);
  53. py_newnone(py_retval());
  54. if(argc == 1 + 0) return true;
  55. if(argc == 1 + 1) {
  56. py_assign(&ud->args, &argv[1]);
  57. return true;
  58. }
  59. return TypeError("__init__() takes at most 1 arguments but %d were given", argc - 1);
  60. }
  61. static bool _py_BaseException__repr__(int argc, py_Ref argv) {
  62. PY_CHECK_ARGC(1);
  63. BaseException* ud = py_touserdata(argv);
  64. c11_sbuf ss;
  65. c11_sbuf__ctor(&ss);
  66. pk_sprintf(&ss, "%t(", argv->type);
  67. py_Ref args = &ud->args;
  68. if(!py_isnil(args)) {
  69. if(!py_repr(args)) return false;
  70. c11_sbuf__write_sv(&ss, py_tosv(py_retval()));
  71. }
  72. c11_sbuf__write_char(&ss, ')');
  73. c11_sbuf__py_submit(&ss, py_retval());
  74. return true;
  75. }
  76. static bool _py_BaseException__str__(int argc, py_Ref argv) {
  77. PY_CHECK_ARGC(1);
  78. BaseException* ud = py_touserdata(argv);
  79. c11_sbuf ss;
  80. c11_sbuf__ctor(&ss);
  81. py_Ref args = &ud->args;
  82. if(!py_isnil(args)) {
  83. if(argv->type == tp_KeyError) {
  84. if(!py_repr(args)) return false;
  85. } else {
  86. if(!py_str(args)) return false;
  87. }
  88. c11_sbuf__write_sv(&ss, py_tosv(py_retval()));
  89. }
  90. c11_sbuf__py_submit(&ss, py_retval());
  91. return true;
  92. }
  93. static bool BaseException_args(int argc, py_Ref argv) {
  94. BaseException* ud = py_touserdata(argv);
  95. PY_CHECK_ARGC(1);
  96. py_Ref args = &ud->args;
  97. if(!py_isnil(args)) {
  98. py_Ref p = py_newtuple(py_retval(), 1);
  99. p[0] = *args;
  100. } else {
  101. py_newtuple(py_retval(), 0);
  102. }
  103. return true;
  104. }
  105. static bool StopIteration_value(int argc, py_Ref argv) {
  106. BaseException* ud = py_touserdata(argv);
  107. PY_CHECK_ARGC(1);
  108. py_Ref args = &ud->args;
  109. if(py_isnil(args)) {
  110. py_newnone(py_retval());
  111. } else {
  112. py_assign(py_retval(), args);
  113. }
  114. return true;
  115. }
  116. py_Type pk_BaseException__register() {
  117. py_Type type = pk_newtype("BaseException", tp_object, NULL, BaseException__dtor, false, false);
  118. py_bindmagic(type, __new__, _py_BaseException__new__);
  119. py_bindmagic(type, __init__, _py_BaseException__init__);
  120. py_bindmagic(type, __repr__, _py_BaseException__repr__);
  121. py_bindmagic(type, __str__, _py_BaseException__str__);
  122. py_bindproperty(type, "args", BaseException_args, NULL);
  123. return type;
  124. }
  125. py_Type pk_Exception__register() {
  126. py_Type type = pk_newtype("Exception", tp_BaseException, NULL, NULL, false, false);
  127. return type;
  128. }
  129. py_Type pk_StopIteration__register() {
  130. py_Type type = pk_newtype("StopIteration", tp_Exception, NULL, NULL, false, false);
  131. py_bindproperty(type, "value", StopIteration_value, NULL);
  132. return type;
  133. }
  134. static void c11_sbuf__write_exc(c11_sbuf* self, py_Ref exc) {
  135. c11_sbuf__write_cstr(self, "Traceback (most recent call last):\n");
  136. BaseException* ud = py_touserdata(exc);
  137. for(int i = ud->stacktrace.length - 1; i >= 0; i--) {
  138. BaseExceptionFrame* frame = c11__at(BaseExceptionFrame, &ud->stacktrace, i);
  139. SourceData__snapshot(frame->src,
  140. self,
  141. frame->lineno,
  142. NULL,
  143. frame->name ? frame->name->data : NULL);
  144. c11_sbuf__write_char(self, '\n');
  145. }
  146. const char* name = py_tpname(exc->type);
  147. char* message = safe_stringify_exception(exc);
  148. c11_sbuf__write_cstr(self, name);
  149. c11_sbuf__write_cstr(self, ": ");
  150. c11_sbuf__write_cstr(self, message);
  151. PK_FREE(message);
  152. }
  153. char* safe_stringify_exception(py_Ref exc) {
  154. VM* vm = pk_current_vm;
  155. const char* message = "<exception str() failed>";
  156. py_Ref tmp = py_pushtmp();
  157. py_Ref old_unhandled_exc = py_pushtmp();
  158. *tmp = *exc;
  159. *old_unhandled_exc = vm->unhandled_exc;
  160. py_newnil(&vm->unhandled_exc);
  161. py_StackRef p0 = py_peek(0);
  162. bool ok = py_str(tmp);
  163. if(ok) {
  164. if(py_isstr(py_retval())) message = py_tostr(py_retval());
  165. } else {
  166. py_clearexc(p0);
  167. }
  168. vm->unhandled_exc = *old_unhandled_exc;
  169. py_shrink(2);
  170. return c11_strdup(message);
  171. }
  172. //////////////////////////////////////////////////
  173. bool py_checkexc() {
  174. VM* vm = pk_current_vm;
  175. return !py_isnil(&vm->unhandled_exc);
  176. }
  177. bool py_matchexc(py_Type type) {
  178. VM* vm = pk_current_vm;
  179. if(py_isnil(&vm->unhandled_exc)) return false;
  180. bool ok = py_issubclass(vm->unhandled_exc.type, type);
  181. if(ok) vm->last_retval = vm->unhandled_exc;
  182. return ok;
  183. }
  184. void py_clearexc(py_StackRef p0) {
  185. VM* vm = pk_current_vm;
  186. py_newnil(&vm->unhandled_exc);
  187. if(p0) {
  188. c11__rtassert(p0 >= vm->stack.begin && p0 <= vm->stack.sp);
  189. vm->stack.sp = p0;
  190. }
  191. }
  192. void py_printexc() {
  193. char* msg = py_formatexc();
  194. if(!msg) return;
  195. pk_current_vm->callbacks.print(msg);
  196. pk_current_vm->callbacks.print("\n");
  197. PK_FREE(msg);
  198. }
  199. char* py_formatexc() {
  200. VM* vm = pk_current_vm;
  201. if(py_isnil(&vm->unhandled_exc)) return NULL;
  202. char* res = formatexc_internal(&vm->unhandled_exc);
  203. if(py_debugger_status() == 1) py_debugger_exceptionbreakpoint(&vm->unhandled_exc);
  204. return res;
  205. }
  206. char* formatexc_internal(py_Ref exc) {
  207. c11__rtassert(exc != NULL);
  208. c11__rtassert(py_issubclass(exc->type, tp_BaseException));
  209. c11_sbuf ss;
  210. c11_sbuf__ctor(&ss);
  211. BaseException* ud = py_touserdata(exc);
  212. py_Ref inner = &ud->inner_exc;
  213. if(py_isnil(inner)) {
  214. c11_sbuf__write_exc(&ss, exc);
  215. } else {
  216. c11_sbuf__write_exc(&ss, inner);
  217. c11_sbuf__write_cstr(
  218. &ss,
  219. "\n\nDuring handling of the above exception, another exception occurred:\n\n");
  220. c11_sbuf__write_exc(&ss, exc);
  221. }
  222. c11_string* res = c11_sbuf__submit(&ss);
  223. char* dup = PK_MALLOC(res->size + 1);
  224. memcpy(dup, res->data, res->size);
  225. dup[res->size] = '\0';
  226. c11_string__delete(res);
  227. return dup;
  228. }
  229. bool py_exception(py_Type type, const char* fmt, ...) {
  230. #ifndef NDEBUG
  231. if(py_checkexc()) {
  232. const char* name = py_tpname(pk_current_vm->unhandled_exc.type);
  233. c11__abort("py_exception(): `%s` was already set!", name);
  234. }
  235. #endif
  236. c11_sbuf buf;
  237. c11_sbuf__ctor(&buf);
  238. va_list args;
  239. va_start(args, fmt);
  240. pk_vsprintf(&buf, fmt, args);
  241. va_end(args);
  242. py_Ref message = py_pushtmp();
  243. c11_sbuf__py_submit(&buf, message);
  244. bool ok = py_tpcall(type, 1, message);
  245. if(!ok) return false;
  246. py_pop();
  247. return py_raise(py_retval());
  248. }
  249. bool py_raise(py_Ref exc) {
  250. assert(py_isinstance(exc, tp_BaseException));
  251. VM* vm = pk_current_vm;
  252. if(vm->top_frame) {
  253. FrameExcInfo* info = Frame__top_exc_info(vm->top_frame);
  254. if(info && !py_isnil(&info->exc)) {
  255. BaseException* ud = py_touserdata(exc);
  256. ud->inner_exc = info->exc;
  257. }
  258. }
  259. assert(py_isnil(&vm->unhandled_exc));
  260. vm->unhandled_exc = *exc;
  261. return false;
  262. }
  263. bool KeyError(py_Ref key) {
  264. bool ok = py_tpcall(tp_KeyError, 1, key);
  265. if(!ok) return false;
  266. return py_raise(py_retval());
  267. }
  268. bool StopIteration() {
  269. bool ok = py_tpcall(tp_StopIteration, 0, NULL);
  270. if(!ok) return false;
  271. return py_raise(py_retval());
  272. }
  273. bool pk__raise_stopiteration() {
  274. if(py_isnil(py_retval())) return StopIteration();
  275. // carry the value, e.g. `StopIteration(<generator return value>)`
  276. if(!py_tpcall(tp_StopIteration, 1, py_retval())) return false;
  277. return py_raise(py_retval());
  278. }