MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add "throw"

+149 -9
+5 -7
meson.build
··· 20 20 libsodium_dep = dependency('libsodium', required: true) 21 21 22 22 # subprojects 23 - uuidv7_proj = subproject('uuidv7') 24 - mongoose_proj = subproject('mongoose') 25 - argtable3_proj = subproject('argtable3') 26 - 27 - uuidv7_dep = uuidv7_proj.get_variable('uuidv7_dep') 28 - mongoose_dep = mongoose_proj.get_variable('mongoose_dep') 29 - argtable3_dep = argtable3_proj.get_variable('argtable3_dep') 23 + curl_dep = subproject('curl').get_variable('curl_dep') 24 + uuidv7_dep = subproject('uuidv7').get_variable('uuidv7_dep') 25 + mongoose_dep = subproject('mongoose').get_variable('mongoose_dep') 26 + argtable3_dep = subproject('argtable3').get_variable('argtable3_dep') 30 27 31 28 git = find_program('git', required: false) 32 29 if git.found() ··· 61 58 sources, 62 59 include_directories: [include, build_include], 63 60 dependencies: [ 61 + curl_dep, 64 62 uuidv7_dep, 65 63 mongoose_dep, 66 64 argtable3_dep,
+117 -2
src/ant.c
··· 21 21 int capacity; 22 22 } this_stack_t; 23 23 24 + typedef struct call_frame { 25 + const char *filename; 26 + const char *function_name; 27 + int line; 28 + int col; 29 + } call_frame_t; 30 + 31 + typedef struct { 32 + call_frame_t *frames; 33 + int depth; 34 + int capacity; 35 + } call_stack_t; 36 + 24 37 static this_stack_t global_this_stack = {NULL, 0, 0}; 38 + static call_stack_t global_call_stack = {NULL, 0, 0}; 25 39 26 40 struct js { 27 41 jsoff_t css; // max observed C stack size ··· 37 51 #define F_CALL 4U // we are inside a function call 38 52 #define F_BREAK 8U // exit the loop 39 53 #define F_RETURN 16U // return has been executed 54 + #define F_THROW 32U // throw has been executed 40 55 jsoff_t clen; // code snippet length 41 56 jsoff_t pos; // current parsing position 42 57 jsoff_t toff; // offset of the last parsed token ··· 355 370 return mkval(T_ERR, 0); 356 371 } 357 372 373 + static jsval_t js_throw(struct js *js, jsval_t value) { 374 + int line = 0, col = 0; 375 + get_line_col(js->code, js->toff > 0 ? js->toff : js->pos, &line, &col); 376 + 377 + size_t n = 0; 378 + if (vtype(value) == T_STR) { 379 + jsoff_t slen, off = vstr(js, value, &slen); 380 + n = (size_t) snprintf(js->errmsg, sizeof(js->errmsg), "Uncaught: %.*s\n", (int)slen, (char *)&js->mem[off]); 381 + } else { 382 + const char *str = js_str(js, value); 383 + n = (size_t) snprintf(js->errmsg, sizeof(js->errmsg), "Uncaught: %s\n", str); 384 + } 385 + 386 + size_t remaining = sizeof(js->errmsg) - n; 387 + if (remaining > 20) { 388 + if (js->filename) { 389 + n += (size_t) snprintf(js->errmsg + n, remaining, " at %s:%d:%d\n", js->filename, line, col); 390 + } else { 391 + n += (size_t) snprintf(js->errmsg + n, remaining, " at <eval>:%d:%d\n", line, col); 392 + } 393 + } 394 + 395 + remaining = sizeof(js->errmsg) - n; 396 + for (int i = global_call_stack.depth - 1; i >= 0 && remaining > 20; i--) { 397 + call_frame_t *frame = &global_call_stack.frames[i]; 398 + const char *fname = frame->function_name ? frame->function_name : "<anonymous>"; 399 + const char *file = frame->filename ? frame->filename : "<eval>"; 400 + 401 + size_t added = (size_t) snprintf(js->errmsg + n, remaining, " at %s (%s:%d:%d)\n", fname, file, frame->line, frame->col); 402 + n += added; 403 + remaining = sizeof(js->errmsg) - n; 404 + } 405 + 406 + js->errmsg[sizeof(js->errmsg) - 1] = '\0'; 407 + js->flags |= F_THROW; 408 + js->pos = js->clen; 409 + js->tok = TOK_EOF; 410 + js->consumed = 0; 411 + return mkval(T_ERR, 0); 412 + } 413 + 358 414 static size_t tostr(struct js *js, jsval_t value, char *buf, size_t len) { 359 415 switch (vtype(value)) { 360 416 case T_UNDEF: return cpy(buf, len, "undefined", 9); ··· 750 806 return js_mkundef(); 751 807 } 752 808 809 + static inline bool push_call_frame(const char *filename, const char *function_name, int line, int col) { 810 + if (global_call_stack.depth >= global_call_stack.capacity) { 811 + int new_capacity = global_call_stack.capacity == 0 ? 32 : global_call_stack.capacity * 2; 812 + call_frame_t *new_stack = (call_frame_t *) realloc(global_call_stack.frames, new_capacity * sizeof(call_frame_t)); 813 + if (!new_stack) return false; 814 + global_call_stack.frames = new_stack; 815 + global_call_stack.capacity = new_capacity; 816 + } 817 + 818 + global_call_stack.frames[global_call_stack.depth].filename = filename; 819 + global_call_stack.frames[global_call_stack.depth].function_name = function_name; 820 + global_call_stack.frames[global_call_stack.depth].line = line; 821 + global_call_stack.frames[global_call_stack.depth].col = col; 822 + global_call_stack.depth++; 823 + 824 + return true; 825 + } 826 + 827 + static inline void pop_call_frame() { 828 + if (global_call_stack.depth > 0) { 829 + global_call_stack.depth--; 830 + } 831 + } 832 + 753 833 static jsval_t js_block(struct js *js, bool create_scope) { 754 834 jsval_t res = js_mkundef(); 755 835 if (create_scope) mkscope(js); ··· 762 842 res = js_mkerr(js, "; expected"); 763 843 break; 764 844 } 765 - if (js->flags & F_RETURN) break; 845 + if (js->flags & (F_RETURN | F_THROW)) break; 766 846 } 767 847 if (create_scope) delscope(js); 768 848 return res; ··· 1308 1388 if (fnlen == 16 && memcmp(code_str, "__builtin_Object", 16) == 0) { 1309 1389 res = call_c(js, builtin_Object); 1310 1390 } else { 1391 + int call_line = 0, call_col = 0; 1392 + get_line_col(code, pos, &call_line, &call_col); 1393 + 1394 + const char *func_name = NULL; 1395 + jsoff_t name_off = lkp(js, func_obj, "name", 4); 1396 + if (name_off != 0) { 1397 + jsval_t name_val = resolveprop(js, mkval(T_PROP, name_off)); 1398 + if (vtype(name_val) == T_STR) { 1399 + jsoff_t name_len, name_offset = vstr(js, name_val, &name_len); 1400 + func_name = (const char *)&js->mem[name_offset]; 1401 + } 1402 + } 1403 + 1404 + push_call_frame(js->filename, func_name ? func_name : "<anonymous>", call_line, call_col); 1405 + 1406 + jsval_t saved_func = js->current_func; 1407 + js->current_func = func; 1311 1408 js->nogc = (jsoff_t) (fnoff - sizeof(jsoff_t)); 1312 1409 res = call_js(js, code_str, fnlen, closure_scope); 1410 + js->current_func = saved_func; 1411 + 1412 + pop_call_frame(); 1313 1413 if (is_async && !is_err(res)) { 1314 1414 jsval_t promise_args[] = { res }; 1315 1415 res = builtin_Promise_resolve(js, promise_args, 1); ··· 3325 3425 case TOK_CASE: case TOK_CATCH: 3326 3426 case TOK_DEFAULT: case TOK_FINALLY: 3327 3427 case TOK_SWITCH: 3328 - case TOK_THROW: case TOK_TRY: 3428 + case TOK_TRY: 3329 3429 case TOK_WITH: case TOK_YIELD: 3330 3430 res = js_mkerr(js, "'%.*s' not implemented", (int) js->tlen, js->code + js->toff); 3331 3431 break; 3432 + case TOK_THROW: { 3433 + js->consumed = 1; 3434 + jsval_t throw_val = js_expr(js); 3435 + if (js->flags & F_NOEXEC) { 3436 + res = js_mkundef(); 3437 + } else { 3438 + throw_val = resolveprop(js, throw_val); 3439 + if (is_err(throw_val)) { 3440 + res = throw_val; 3441 + } else { 3442 + res = js_throw(js, throw_val); 3443 + } 3444 + } 3445 + break; 3446 + } 3332 3447 case TOK_VAR: 3333 3448 if (!js->var_warning_shown) { 3334 3449 fprintf(stderr, "Warning: 'var' is deprecated, use 'let' or 'const' instead\n");
+21
tests/test_throw_stack.cjs
··· 1 + // Test throw statement with stack traces 2 + Ant.println('=== Throw with Stack Trace Test ==='); 3 + 4 + function level3() { 5 + Ant.println('In level3'); 6 + throw "error from level3"; 7 + } 8 + 9 + function level2() { 10 + Ant.println('In level2'); 11 + level3(); 12 + } 13 + 14 + function level1() { 15 + Ant.println('In level1'); 16 + level2(); 17 + } 18 + 19 + Ant.println('Starting test...'); 20 + level1(); 21 + Ant.println('This should not print');
+6
tests/throw.cjs
··· 1 + function meow() { 2 + throw 'meow'; 3 + } 4 + 5 + meow(); 6 + Ant.println('This should not print');