py_exception.c 7.5 KB

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