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.

seperate stack, types, and errors

+641 -557
+4 -27
include/ant.h
··· 4 4 #pragma once 5 5 #define PCRE2_CODE_UNIT_WIDTH 8 6 6 7 + #include "types.h" 8 + #include "common.h" 9 + 7 10 #include <math.h> 8 - #include <common.h> 9 11 #include <stdbool.h> 10 12 #include <stddef.h> 11 13 #include <stdint.h> ··· 25 27 #define JS_INF ((double)INFINITY) 26 28 #define JS_NEG_INF ((double)(-INFINITY)) 27 29 28 - struct js; 29 - 30 - typedef struct js ant_t; 31 - typedef unsigned long long u64; 32 - 33 - typedef int jshdl_t; 34 - typedef uint64_t jsoff_t; 35 - typedef uint64_t jsval_t; 36 - 37 30 #define ANT_LIMIT_SIZE_CACHE 16384 38 31 #define CORO_PER_TICK_LIMIT 10000 39 32 ··· 45 38 JS_ERR, JS_PRIV, JS_PROMISE, JS_OBJ, JS_FUNC, JS_SYMBOL 46 39 }; 47 40 48 - typedef enum { 49 - JS_ERR_TYPE, 50 - JS_ERR_SYNTAX, 51 - JS_ERR_REFERENCE, 52 - JS_ERR_RANGE, 53 - JS_ERR_EVAL, 54 - JS_ERR_URI, 55 - JS_ERR_INTERNAL, 56 - JS_ERR_AGGREGATE, 57 - JS_ERR_GENERIC 58 - } js_err_type_t; 59 - 60 41 #define JS_DESC_W (1 << 0) 61 42 #define JS_DESC_E (1 << 1) 62 43 #define JS_DESC_C (1 << 2) 63 - 64 - #define js_mkerr(js, ...) js_create_error(js, JS_ERR_TYPE, js_mkundef(), __VA_ARGS__) 65 - #define js_mkerr_typed(js, err_type, ...) js_create_error(js, err_type, js_mkundef(), __VA_ARGS__) 66 - #define js_mkerr_props(js, err_type, props, ...) js_create_error(js, err_type, props, __VA_ARGS__) 67 - jsval_t js_create_error(ant_t *js, js_err_type_t err_type, jsval_t props, const char *fmt, ...); 68 44 69 45 ant_t *js_create(void *buf, size_t len); 70 46 ant_t *js_create_dynamic(size_t initial_size, size_t max_size); ··· 154 130 char *js_getstr(ant_t *js, jsval_t val, size_t *len); 155 131 156 132 const char *js_str(ant_t *, jsval_t val); 133 + const char *get_str_prop(struct js *js, jsval_t obj, const char *key, jsoff_t klen, jsoff_t *out_len); 157 134 158 135 typedef struct { 159 136 void *ctx;
+33
include/errors.h
··· 1 + #ifndef ERRORS_H 2 + #define ERRORS_H 3 + 4 + #include "types.h" 5 + #include <stdio.h> 6 + 7 + #define ERR_FMT "\x1b[31m%.*s\x1b[0m: \x1b[1m%.*s\x1b[0m" 8 + #define ERR_NAME_ONLY "\x1b[31m%.*s\x1b[0m" 9 + 10 + typedef enum { 11 + JS_ERR_GENERIC = 0, 12 + JS_ERR_TYPE, 13 + JS_ERR_SYNTAX, 14 + JS_ERR_REFERENCE, 15 + JS_ERR_RANGE, 16 + JS_ERR_EVAL, 17 + JS_ERR_URI, 18 + JS_ERR_INTERNAL, 19 + JS_ERR_AGGREGATE, 20 + } js_err_type_t; 21 + 22 + js_err_type_t get_error_type(ant_t *js); 23 + void js_print_stack_trace(FILE *stream); 24 + 25 + __attribute__((format(printf, 4, 5))) 26 + jsval_t js_create_error(ant_t *js, js_err_type_t err_type, jsval_t props, const char *fmt, ...); 27 + jsval_t js_throw(ant_t *js, jsval_t value); 28 + 29 + #define js_mkerr(js, ...) js_create_error(js, JS_ERR_TYPE, js_mkundef(), __VA_ARGS__) 30 + #define js_mkerr_typed(js, err_type, ...) js_create_error(js, err_type, js_mkundef(), __VA_ARGS__) 31 + #define js_mkerr_props(js, err_type, props, ...) js_create_error(js, err_type, props, __VA_ARGS__) 32 + 33 + #endif
+6
include/internal.h
··· 95 95 bool js_has_pending_coroutines(void); 96 96 bool is_internal_prop(const char *key, jsoff_t klen); 97 97 98 + jsoff_t lkp(struct js *js, jsval_t obj, const char *buf, size_t len); 99 + jsoff_t vstr(struct js *js, jsval_t value, jsoff_t *len); 100 + 101 + jsval_t mkval(uint8_t type, uint64_t data); 102 + jsval_t resolveprop(struct js *js, jsval_t v); 103 + 98 104 #define is_non_numeric(v) ((1u << vtype(v)) & T_NON_NUMERIC_MASK) 99 105 100 106 #endif
+30
include/stack.h
··· 1 + #ifndef ANT_STACK_H 2 + #define ANT_STACK_H 3 + 4 + #include <stdbool.h> 5 + #include <stdint.h> 6 + 7 + typedef struct call_frame { 8 + const char *filename; 9 + const char *function_name; 10 + const char *code; 11 + uint32_t pos; int line; int col; 12 + } call_frame_t; 13 + 14 + typedef struct { 15 + call_frame_t *frames; 16 + int depth; int capacity; 17 + } call_stack_t; 18 + 19 + extern call_stack_t global_call_stack; 20 + 21 + void pop_call_frame(void); 22 + 23 + bool push_call_frame( 24 + const char *filename, 25 + const char *function_name, 26 + const char *code, 27 + uint32_t pos 28 + ); 29 + 30 + #endif
+64
include/tokens.h
··· 1 + #ifndef TOKENS_H 2 + #define TOKENS_H 3 + 4 + #include <stdint.h> 5 + 6 + enum { 7 + TOK_ERR, TOK_EOF, TOK_NUMBER, TOK_STRING, TOK_SEMICOLON, TOK_BIGINT, 8 + TOK_LPAREN, TOK_RPAREN, TOK_LBRACE, TOK_RBRACE, TOK_LBRACKET, TOK_RBRACKET, 9 + 10 + // identifier-like 11 + TOK_IDENTIFIER = 50, 12 + TOK_ASYNC, TOK_AWAIT, TOK_BREAK, TOK_CASE, TOK_CATCH, TOK_CLASS, TOK_CONST, TOK_CONTINUE, 13 + TOK_DEFAULT, TOK_DELETE, TOK_DO, TOK_DEBUGGER, TOK_ELSE, TOK_EXPORT, TOK_FINALLY, TOK_FOR, 14 + TOK_FROM, TOK_FUNC, TOK_IF, TOK_IMPORT, TOK_IN, TOK_INSTANCEOF, TOK_LET, TOK_NEW, TOK_OF, 15 + TOK_RETURN, TOK_SUPER, TOK_SWITCH, TOK_THIS, TOK_THROW, TOK_TRY, TOK_VAR, TOK_VOID, TOK_WHILE, TOK_WITH, 16 + TOK_YIELD, TOK_UNDEF, TOK_NULL, TOK_TRUE, TOK_FALSE, TOK_AS, TOK_STATIC, TOK_TYPEOF, 17 + TOK_WINDOW, TOK_GLOBAL_THIS, 18 + TOK_IDENT_LIKE_END, 19 + 20 + // operators 21 + TOK_DOT = 100, TOK_CALL, TOK_BRACKET, TOK_POSTINC, TOK_POSTDEC, TOK_NOT, TOK_TILDA, 22 + TOK_UPLUS, TOK_UMINUS, TOK_EXP, TOK_MUL, TOK_DIV, TOK_REM, 23 + TOK_OPTIONAL_CHAIN, TOK_REST, 24 + TOK_PLUS, TOK_MINUS, TOK_SHL, TOK_SHR, TOK_ZSHR, TOK_LT, TOK_LE, TOK_GT, 25 + TOK_GE, TOK_EQ, TOK_NE, TOK_SEQ, TOK_SNE, TOK_AND, TOK_XOR, TOK_OR, TOK_LAND, TOK_LOR, TOK_NULLISH, 26 + TOK_COLON, TOK_Q, TOK_ASSIGN, TOK_PLUS_ASSIGN, TOK_MINUS_ASSIGN, 27 + TOK_MUL_ASSIGN, TOK_DIV_ASSIGN, TOK_REM_ASSIGN, TOK_SHL_ASSIGN, 28 + TOK_SHR_ASSIGN, TOK_ZSHR_ASSIGN, TOK_AND_ASSIGN, TOK_XOR_ASSIGN, 29 + TOK_OR_ASSIGN, TOK_LOR_ASSIGN, TOK_LAND_ASSIGN, TOK_NULLISH_ASSIGN, 30 + TOK_COMMA, TOK_TEMPLATE, TOK_ARROW, TOK_HASH, 31 + TOK_MAX 32 + }; 33 + 34 + static const uint8_t prec_table[TOK_MAX] = { 35 + [TOK_LOR] = 4, 36 + [TOK_LAND] = 5, 37 + [TOK_NULLISH] = 5, 38 + [TOK_OR] = 6, 39 + [TOK_XOR] = 7, 40 + [TOK_AND] = 8, 41 + [TOK_EQ] = 9, [TOK_NE] = 9, [TOK_SEQ] = 9, [TOK_SNE] = 9, 42 + [TOK_LT] = 10, [TOK_LE] = 10, [TOK_GT] = 10, [TOK_GE] = 10, 43 + [TOK_INSTANCEOF] = 10, [TOK_IN] = 10, 44 + [TOK_SHL] = 11, [TOK_SHR] = 11, [TOK_ZSHR] = 11, 45 + [TOK_PLUS] = 12, [TOK_MINUS] = 12, 46 + [TOK_MUL] = 13, [TOK_DIV] = 13, [TOK_REM] = 13, 47 + [TOK_EXP] = 14, 48 + }; 49 + 50 + static const uint8_t body_end_tok[TOK_MAX] = { 51 + [TOK_RPAREN] = 1, [TOK_RBRACE] = 1, [TOK_RBRACKET] = 1, 52 + [TOK_SEMICOLON] = 1, [TOK_COMMA] = 1, [TOK_EOF] = 1, 53 + }; 54 + 55 + static const uint8_t expr_context_tok[TOK_MAX] = { 56 + [TOK_ASSIGN] = 1, [TOK_LPAREN] = 1, [TOK_COLON] = 1, [TOK_LBRACKET] = 1, 57 + [TOK_COMMA] = 1, [TOK_NOT] = 1, [TOK_Q] = 1, [TOK_OR] = 1, [TOK_AND] = 1, 58 + [TOK_RETURN] = 1, [TOK_ARROW] = 1, [TOK_LAND] = 1, [TOK_LOR] = 1, 59 + [TOK_PLUS_ASSIGN] = 1, [TOK_MINUS_ASSIGN] = 1, [TOK_MUL_ASSIGN] = 1, 60 + [TOK_DIV_ASSIGN] = 1, [TOK_REM_ASSIGN] = 1, [TOK_AND_ASSIGN] = 1, 61 + [TOK_OR_ASSIGN] = 1, [TOK_XOR_ASSIGN] = 1, [TOK_NULLISH] = 1, 62 + }; 63 + 64 + #endif
+15
include/types.h
··· 1 + #ifndef TYPES_H 2 + #define TYPES_H 3 + 4 + #include <stdint.h> 5 + 6 + struct js; 7 + 8 + typedef struct js ant_t; 9 + typedef unsigned long long u64; 10 + 11 + typedef int jshdl_t; 12 + typedef uint64_t jsoff_t; 13 + typedef uint64_t jsval_t; 14 + 15 + #endif
+2
libant/meson.build
··· 25 25 '../src/roots.c', 26 26 '../src/utils.c', 27 27 '../src/ant.c', 28 + '../src/errors.c', 29 + '../src/stack.c', 28 30 '../src/gc.c', 29 31 '../src/repl.c', 30 32 '../src/runtime.c',
+2
meson.build
··· 24 24 'src/roots.c', 25 25 'src/utils.c', 26 26 'src/ant.c', 27 + 'src/errors.c', 28 + 'src/stack.c', 27 29 'src/gc.c', 28 30 'src/repl.c', 29 31 'src/runtime.c',
+18 -507
src/ant.c
··· 5 5 #include <compat.h> // IWYU pragma: keep 6 6 7 7 #include "ant.h" 8 + #include "tokens.h" 8 9 #include "common.h" 9 10 #include "arena.h" 10 11 #include "utils.h" 11 12 #include "runtime.h" 12 13 #include "internal.h" 14 + #include "stack.h" 15 + #include "errors.h" 13 16 14 17 #include <uv.h> 15 18 #include <oxc.h> ··· 74 77 int capacity; 75 78 } this_stack_t; 76 79 77 - typedef struct call_frame { 78 - const char *filename; 79 - const char *function_name; 80 - const char *code; 81 - uint32_t pos; 82 - int line; 83 - int col; 84 - } call_frame_t; 85 - 86 - typedef struct { 87 - call_frame_t *frames; 88 - int depth; 89 - int capacity; 90 - } call_stack_t; 91 - 92 80 typedef enum { 93 81 CORO_ASYNC_AWAIT, 94 82 CORO_GENERATOR, ··· 155 143 156 144 static UT_array *global_scope_stack = NULL; 157 145 static UT_array *saved_scope_stack = NULL; 158 - 159 146 static this_stack_t global_this_stack = {NULL, 0, 0}; 160 - static call_stack_t global_call_stack = {NULL, 0, 0}; 161 147 162 148 static uint32_t coros_this_tick = 0; 163 149 static coroutine_queue_t pending_coroutines = {NULL, NULL}; ··· 410 396 return lib; 411 397 } 412 398 413 - enum { 414 - TOK_ERR, TOK_EOF, TOK_NUMBER, TOK_STRING, TOK_SEMICOLON, TOK_BIGINT, 415 - TOK_LPAREN, TOK_RPAREN, TOK_LBRACE, TOK_RBRACE, TOK_LBRACKET, TOK_RBRACKET, 416 - 417 - // identifier-like 418 - TOK_IDENTIFIER = 50, 419 - TOK_ASYNC, TOK_AWAIT, TOK_BREAK, TOK_CASE, TOK_CATCH, TOK_CLASS, TOK_CONST, TOK_CONTINUE, 420 - TOK_DEFAULT, TOK_DELETE, TOK_DO, TOK_DEBUGGER, TOK_ELSE, TOK_EXPORT, TOK_FINALLY, TOK_FOR, 421 - TOK_FROM, TOK_FUNC, TOK_IF, TOK_IMPORT, TOK_IN, TOK_INSTANCEOF, TOK_LET, TOK_NEW, TOK_OF, 422 - TOK_RETURN, TOK_SUPER, TOK_SWITCH, TOK_THIS, TOK_THROW, TOK_TRY, TOK_VAR, TOK_VOID, TOK_WHILE, TOK_WITH, 423 - TOK_YIELD, TOK_UNDEF, TOK_NULL, TOK_TRUE, TOK_FALSE, TOK_AS, TOK_STATIC, TOK_TYPEOF, 424 - TOK_WINDOW, TOK_GLOBAL_THIS, 425 - TOK_IDENT_LIKE_END, 426 - 427 - // operators 428 - TOK_DOT = 100, TOK_CALL, TOK_BRACKET, TOK_POSTINC, TOK_POSTDEC, TOK_NOT, TOK_TILDA, 429 - TOK_UPLUS, TOK_UMINUS, TOK_EXP, TOK_MUL, TOK_DIV, TOK_REM, 430 - TOK_OPTIONAL_CHAIN, TOK_REST, 431 - TOK_PLUS, TOK_MINUS, TOK_SHL, TOK_SHR, TOK_ZSHR, TOK_LT, TOK_LE, TOK_GT, 432 - TOK_GE, TOK_EQ, TOK_NE, TOK_SEQ, TOK_SNE, TOK_AND, TOK_XOR, TOK_OR, TOK_LAND, TOK_LOR, TOK_NULLISH, 433 - TOK_COLON, TOK_Q, TOK_ASSIGN, TOK_PLUS_ASSIGN, TOK_MINUS_ASSIGN, 434 - TOK_MUL_ASSIGN, TOK_DIV_ASSIGN, TOK_REM_ASSIGN, TOK_SHL_ASSIGN, 435 - TOK_SHR_ASSIGN, TOK_ZSHR_ASSIGN, TOK_AND_ASSIGN, TOK_XOR_ASSIGN, 436 - TOK_OR_ASSIGN, TOK_LOR_ASSIGN, TOK_LAND_ASSIGN, TOK_NULLISH_ASSIGN, 437 - TOK_COMMA, TOK_TEMPLATE, TOK_ARROW, TOK_HASH, 438 - TOK_MAX 439 - }; 440 - 441 - static const uint8_t prec_table[TOK_MAX] = { 442 - [TOK_LOR] = 4, 443 - [TOK_LAND] = 5, 444 - [TOK_NULLISH] = 5, 445 - [TOK_OR] = 6, 446 - [TOK_XOR] = 7, 447 - [TOK_AND] = 8, 448 - [TOK_EQ] = 9, [TOK_NE] = 9, [TOK_SEQ] = 9, [TOK_SNE] = 9, 449 - [TOK_LT] = 10, [TOK_LE] = 10, [TOK_GT] = 10, [TOK_GE] = 10, 450 - [TOK_INSTANCEOF] = 10, [TOK_IN] = 10, 451 - [TOK_SHL] = 11, [TOK_SHR] = 11, [TOK_ZSHR] = 11, 452 - [TOK_PLUS] = 12, [TOK_MINUS] = 12, 453 - [TOK_MUL] = 13, [TOK_DIV] = 13, [TOK_REM] = 13, 454 - [TOK_EXP] = 14, 455 - }; 456 - 457 - static const uint8_t body_end_tok[TOK_MAX] = { 458 - [TOK_RPAREN] = 1, [TOK_RBRACE] = 1, [TOK_RBRACKET] = 1, 459 - [TOK_SEMICOLON] = 1, [TOK_COMMA] = 1, [TOK_EOF] = 1, 460 - }; 461 - 462 - static const uint8_t expr_context_tok[TOK_MAX] = { 463 - [TOK_ASSIGN] = 1, [TOK_LPAREN] = 1, [TOK_COLON] = 1, [TOK_LBRACKET] = 1, 464 - [TOK_COMMA] = 1, [TOK_NOT] = 1, [TOK_Q] = 1, [TOK_OR] = 1, [TOK_AND] = 1, 465 - [TOK_RETURN] = 1, [TOK_ARROW] = 1, [TOK_LAND] = 1, [TOK_LOR] = 1, 466 - [TOK_PLUS_ASSIGN] = 1, [TOK_MINUS_ASSIGN] = 1, [TOK_MUL_ASSIGN] = 1, 467 - [TOK_DIV_ASSIGN] = 1, [TOK_REM_ASSIGN] = 1, [TOK_AND_ASSIGN] = 1, 468 - [TOK_OR_ASSIGN] = 1, [TOK_XOR_ASSIGN] = 1, [TOK_NULLISH] = 1, 469 - }; 470 - 471 399 static const char *typestr_raw(uint8_t t) { 472 400 const char *names[] = { 473 401 "object", "prop", "string", "undefined", "null", "number", ··· 582 510 return is_tagged(v) ? ((v >> NANBOX_TYPE_SHIFT) & NANBOX_TYPE_MASK) : (uint8_t)T_NUM; 583 511 } 584 512 585 - static jsval_t mkval(uint8_t type, uint64_t data) { 513 + jsval_t mkval(uint8_t type, uint64_t data) { 586 514 return NANBOX_PREFIX | ((jsval_t)(type & NANBOX_TYPE_MASK) << NANBOX_TYPE_SHIFT) | (data & NANBOX_DATA_MASK); 587 515 } 588 516 ··· 804 732 (js)->consumed = (state).consumed; \ 805 733 } while(0) 806 734 807 - static jsoff_t vstr(struct js *js, jsval_t value, jsoff_t *len); 808 735 static size_t strstring(struct js *js, jsval_t value, char *buf, size_t len); 809 736 static size_t strkey(struct js *js, jsval_t value, char *buf, size_t len); 810 737 ··· 871 798 static jsval_t do_op(struct js *, uint8_t op, jsval_t l, jsval_t r); 872 799 static jsval_t do_instanceof(struct js *js, jsval_t l, jsval_t r); 873 800 static jsval_t do_in(struct js *js, jsval_t l, jsval_t r); 874 - static jsval_t resolveprop(struct js *js, jsval_t v); 875 - 876 - static jsoff_t lkp(struct js *js, jsval_t obj, const char *buf, size_t len); 877 - static jsoff_t lkp_interned(struct js *js, jsval_t obj, const char *search_intern, size_t len); 878 801 879 802 static inline bool is_slot_prop(jsoff_t header); 880 803 static inline jsoff_t next_prop(jsoff_t header); ··· 898 821 static inline jsval_t pop_this(void); 899 822 900 823 static jsoff_t lkp_proto(struct js *js, jsval_t obj, const char *key, size_t len); 824 + static jsoff_t lkp_interned(struct js *js, jsval_t obj, const char *search_intern, size_t len); 825 + 901 826 static jsval_t get_prototype_for_type(struct js *js, uint8_t type); 902 827 static jsval_t get_ctor_proto(struct js *js, const char *name, size_t len); 903 828 static jsval_t setprop(struct js *js, jsval_t obj, jsval_t k, jsval_t v); ··· 1484 1409 return loadval(js, prop + (jsoff_t) (sizeof(prop) + sizeof(koff))); 1485 1410 } 1486 1411 1412 + const char *get_str_prop(struct js *js, jsval_t obj, const char *key, jsoff_t klen, jsoff_t *out_len) { 1413 + jsoff_t off = lkp(js, obj, key, klen); 1414 + if (off <= 0) return NULL; 1415 + jsval_t v = resolveprop(js, mkval(T_PROP, off)); 1416 + if (vtype(v) != T_STR) return NULL; 1417 + return (const char *)&js->mem[vstr(js, v, out_len)]; 1418 + } 1419 + 1487 1420 static bool is_small_array(struct js *js, jsval_t obj, int *elem_count) { 1488 1421 int count = 0; 1489 1422 bool has_nested = false; ··· 2267 2200 return cpy(buf, len, temp, strlen(temp)); 2268 2201 } 2269 2202 2270 - static jsoff_t vstr(struct js *js, jsval_t value, jsoff_t *len) { 2203 + jsoff_t vstr(struct js *js, jsval_t value, jsoff_t *len) { 2271 2204 jsoff_t off = (jsoff_t) vdata(value); 2272 2205 if (len) *len = offtolen(loadoff(js, off)); 2273 2206 return (jsoff_t) (off + sizeof(off)); ··· 2403 2336 return cpy(buf, len, fmt->anon, fmt->anon_len); 2404 2337 } 2405 2338 2406 - static void get_line_col(const char *code, jsoff_t pos, int *line, int *col) { 2407 - int l = 1, c = 1; 2408 - for (jsoff_t i = 0; i < pos && code[i]; i++) 2409 - code[i] == '\n' ? (l++, c = 1) : c++; 2410 - *line = l; 2411 - *col = c; 2412 - } 2413 - 2414 - static void get_error_line(const char *code, jsoff_t clen, jsoff_t pos, char *buf, size_t bufsize, int *line_start_col) { 2415 - if (!code || bufsize == 0) { 2416 - if (bufsize > 0) buf[0] = '\0'; 2417 - if (line_start_col) *line_start_col = 1; 2418 - return; 2419 - } 2420 - 2421 - if (pos > clen) pos = clen; 2422 - 2423 - if (clen == 0) { 2424 - buf[0] = '\0'; 2425 - if (line_start_col) *line_start_col = 1; 2426 - return; 2427 - } 2428 - 2429 - jsoff_t line_start = pos; 2430 - while (line_start > 0 && code[line_start - 1] != '\n') { 2431 - line_start--; 2432 - } 2433 - 2434 - jsoff_t line_end = pos; 2435 - while (line_end < clen && code[line_end] != '\n' && code[line_end] != '\0') { 2436 - line_end++; 2437 - } 2438 - 2439 - jsoff_t line_len = line_end - line_start; 2440 - if (line_len >= bufsize) line_len = (jsoff_t)(bufsize - 1); 2441 - 2442 - memcpy(buf, &code[line_start], line_len); 2443 - buf[line_len] = '\0'; 2444 - *line_start_col = (int)(pos - line_start) + 1; 2445 - } 2446 - 2447 - static bool ensure_errmsg_capacity(struct js *js, size_t needed) { 2448 - if (js->errmsg_size == 0) js->errmsg_size = 4096; 2449 - 2450 - if (!js->errmsg) { 2451 - js->errmsg = (char *)malloc(js->errmsg_size); 2452 - if (!js->errmsg) return false; 2453 - js->errmsg[0] = '\0'; 2454 - } 2455 - 2456 - if (needed <= js->errmsg_size) return true; 2457 - 2458 - size_t new_size = js->errmsg_size; 2459 - while (new_size < needed) { 2460 - size_t next = new_size * 2; 2461 - if (next < new_size) return false; 2462 - new_size = next; 2463 - } 2464 - 2465 - char *next_buf = (char *)realloc(js->errmsg, new_size); 2466 - if (!next_buf) return false; 2467 - js->errmsg = next_buf; 2468 - js->errmsg_size = new_size; 2469 - return true; 2470 - } 2471 - 2472 - __attribute__((format(printf, 3, 4))) 2473 - static size_t append_errmsg_fmt(struct js *js, size_t used, const char *fmt, ...) { 2474 - for (;;) { 2475 - if (!ensure_errmsg_capacity(js, used + 1)) return used; 2476 - 2477 - size_t remaining = js->errmsg_size - used; 2478 - va_list ap; 2479 - va_start(ap, fmt); 2480 - int written = vsnprintf(js->errmsg + used, remaining, fmt, ap); 2481 - va_end(ap); 2482 - 2483 - if (written < 0) return used; 2484 - if ((size_t)written < remaining) return used + (size_t)written; 2485 - 2486 - if (!ensure_errmsg_capacity(js, used + (size_t)written + 1)) { 2487 - return js->errmsg_size ? js->errmsg_size - 1 : used; 2488 - } 2489 - } 2490 - } 2491 - 2492 - #define ERR_FMT "\x1b[31m%.*s\x1b[0m: \x1b[1m%.*s\x1b[0m" 2493 - #define ERR_NAME_ONLY "\x1b[31m%.*s\x1b[0m" 2494 - 2495 - static inline size_t remaining_capacity(size_t used, size_t total) { 2496 - return used >= total ? 0 : total - used; 2497 - } 2498 - 2499 - static size_t append_error_header(struct js *js, size_t used, int line) { 2500 - if (js->filename) return append_errmsg_fmt(js, used, "%s:%d\n", js->filename, line); 2501 - return append_errmsg_fmt(js, used, "<eval>:%d\n", line); 2502 - } 2503 - 2504 - static const char *get_str_prop(struct js *js, jsval_t obj, const char *key, jsoff_t klen, jsoff_t *out_len) { 2505 - jsoff_t off = lkp(js, obj, key, klen); 2506 - if (off <= 0) return NULL; 2507 - jsval_t v = resolveprop(js, mkval(T_PROP, off)); 2508 - if (vtype(v) != T_STR) return NULL; 2509 - return (const char *)&js->mem[vstr(js, v, out_len)]; 2510 - } 2511 - 2512 - static size_t append_error_value(struct js *js, size_t used, jsval_t value) { 2513 - const char *name = "Error"; 2514 - const char *msg = NULL; 2515 - 2516 - jsoff_t name_len = 5; 2517 - jsoff_t msg_len = 0; 2518 - 2519 - static const void *type_dispatch[] = { 2520 - [T_STR] = &&l_type_str, 2521 - [T_OBJ] = &&l_type_obj, 2522 - [T_FUNC] = &&l_type_default, 2523 - [T_ARR] = &&l_type_default, 2524 - [T_PROMISE] = &&l_type_default, 2525 - [T_GENERATOR] = &&l_type_default, 2526 - [T_PROP] = &&l_type_default, 2527 - [T_BIGINT] = &&l_type_default, 2528 - [T_NUM] = &&l_type_default, 2529 - [T_BOOL] = &&l_type_default, 2530 - [T_SYMBOL] = &&l_type_default, 2531 - [T_CFUNC] = &&l_type_default, 2532 - [T_FFI] = &&l_type_default, 2533 - [T_TYPEDARRAY] = &&l_type_default, 2534 - [T_CODEREF] = &&l_type_default, 2535 - [T_PROPREF] = &&l_type_default, 2536 - [T_ERR] = &&l_type_default, 2537 - [T_UNDEF] = &&l_type_default, 2538 - [T_NULL] = &&l_type_default, 2539 - }; 2540 - 2541 - uint8_t t = vtype(value); 2542 - if (t < sizeof(type_dispatch) / sizeof(type_dispatch[0]) && type_dispatch[t]) { 2543 - goto *type_dispatch[t]; 2544 - } 2545 - goto l_type_default; 2546 - 2547 - l_type_str: 2548 - msg = (const char *)&js->mem[vstr(js, value, &msg_len)]; 2549 - goto l_type_done; 2550 - 2551 - l_type_obj: 2552 - name = get_str_prop(js, value, "name", 4, &name_len); 2553 - if (!name) { 2554 - name = "Error"; 2555 - name_len = 5; 2556 - } 2557 - msg = get_str_prop(js, value, "message", 7, &msg_len); 2558 - goto l_type_done; 2559 - 2560 - l_type_default: 2561 - msg = js_str(js, value); 2562 - msg_len = msg ? (jsoff_t)strlen(msg) : 0; 2563 - goto l_type_done; 2564 - 2565 - l_type_done: 2566 - 2567 - static const void *dispatch[] = { &&l_with_msg, &&l_name_only }; 2568 - int key = msg ? 0 : 1; 2569 - goto *dispatch[key]; 2570 - 2571 - l_with_msg: 2572 - return append_errmsg_fmt(js, used, 2573 - ERR_FMT, 2574 - (int)name_len, name, (int)msg_len, msg 2575 - ); 2576 - 2577 - l_name_only: 2578 - return append_errmsg_fmt(js, used, 2579 - ERR_NAME_ONLY, 2580 - (int)name_len, name 2581 - ); 2582 - } 2583 - 2584 - static void append_error_caret(struct js *js, size_t *n, int error_col) { 2585 - if (!ensure_errmsg_capacity(js, *n + (size_t)error_col + 2)) return; 2586 - if (*n >= js->errmsg_size - 1) return; 2587 - 2588 - size_t remaining = js->errmsg_size - *n; 2589 - for (int i = 1; i < error_col && remaining > 1; i++) { 2590 - js->errmsg[(*n)++] = ' '; 2591 - remaining--; 2592 - } 2593 - if (remaining > 1) { 2594 - js->errmsg[(*n)++] = '^'; 2595 - } 2596 - js->errmsg[*n] = '\0'; 2597 - } 2598 - 2599 - static void format_error_stack(struct js *js, size_t *n, int line, int col, bool include_source_line, const char *error_line, int error_col) { 2600 - if (!ensure_errmsg_capacity(js, *n + 1)) return; 2601 - 2602 - const char *dim = "\x1b[90m"; 2603 - const char *reset = "\x1b[0m"; 2604 - 2605 - if (include_source_line && error_line && *n < js->errmsg_size) { 2606 - *n = append_errmsg_fmt(js, *n, "\n%s\n", error_line); 2607 - append_error_caret(js, n, error_col); 2608 - } 2609 - 2610 - size_t remaining = remaining_capacity(*n, js->errmsg_size); 2611 - if (remaining > 20) { 2612 - const char *file = js->filename ? js->filename : "<eval>"; 2613 - 2614 - for (int i = global_call_stack.depth - 1; i >= 0 && remaining > 20; i--) { 2615 - call_frame_t *frame = &global_call_stack.frames[i]; 2616 - const char *fname = frame->function_name ? frame->function_name : "<anonymous>"; 2617 - const char *ffile = frame->filename ? frame->filename : "<eval>"; 2618 - 2619 - if (frame->line < 0 && frame->code) { 2620 - get_line_col(frame->code, frame->pos, &frame->line, &frame->col); 2621 - } 2622 - int fline = frame->line > 0 ? frame->line : 1; 2623 - int fcol = frame->col > 0 ? frame->col : 1; 2624 - 2625 - *n = append_errmsg_fmt(js, *n, 2626 - "\n at %s %s(%s:%d:%d)%s", 2627 - fname, dim, ffile, fline, fcol, reset 2628 - ); 2629 - remaining = remaining_capacity(*n, js->errmsg_size); 2630 - } 2631 - 2632 - if (global_call_stack.depth > 0 && remaining > 60) { 2633 - *n = append_errmsg_fmt(js, *n, 2634 - "\n at Object.<anonymous> %s(%s:1:1)%s", 2635 - dim, file, reset 2636 - ); 2637 - remaining = remaining_capacity(*n, js->errmsg_size); 2638 - } 2639 - 2640 - if (global_call_stack.depth == 0 && remaining > 20) { 2641 - *n = append_errmsg_fmt(js, *n, 2642 - "\n at %s%s:%d:%d%s", 2643 - dim, file, line, col, reset 2644 - ); 2645 - remaining = remaining_capacity(*n, js->errmsg_size); 2646 - } 2647 - 2648 - if (remaining > 60 && js->filename && strcmp(js->filename, "[eval]") != 0) { 2649 - *n = append_errmsg_fmt(js, *n, 2650 - "\n at Module.executeUserEntryPoint [as runMain] %s(ant:internal/modules/run_main:149:5)%s", 2651 - dim, reset 2652 - ); 2653 - remaining = remaining_capacity(*n, js->errmsg_size); 2654 - } 2655 - 2656 - if (remaining > 40 && js->filename && strcmp(js->filename, "[eval]") != 0) { 2657 - *n = append_errmsg_fmt(js, *n, 2658 - "\n at %sant:internal/call:21728:23%s", 2659 - dim, reset 2660 - ); 2661 - } 2662 - } 2663 - 2664 - js->errmsg[js->errmsg_size - 1] = '\0'; 2665 - } 2666 - 2667 - static const char *get_error_type_name(js_err_type_t err_type) { 2668 - switch (err_type) { 2669 - case JS_ERR_TYPE: return "TypeError"; 2670 - case JS_ERR_SYNTAX: return "SyntaxError"; 2671 - case JS_ERR_REFERENCE: return "ReferenceError"; 2672 - case JS_ERR_RANGE: return "RangeError"; 2673 - case JS_ERR_EVAL: return "EvalError"; 2674 - case JS_ERR_URI: return "URIError"; 2675 - case JS_ERR_INTERNAL: return "InternalError"; 2676 - case JS_ERR_AGGREGATE: return "AggregateError"; 2677 - case JS_ERR_GENERIC: return "Error"; 2678 - default: return "Error"; 2679 - } 2680 - } 2681 - 2682 - static inline js_err_type_t get_error_type(struct js *js) { 2683 - if (!(js->flags & F_THROW)) return JS_ERR_GENERIC; 2684 - jsval_t err_type = get_slot(js, js->thrown_value, SLOT_ERR_TYPE); 2685 - if (vtype(err_type) != T_NUM) return JS_ERR_GENERIC; 2686 - return (js_err_type_t)(int)js_getnum(err_type); 2687 - } 2688 - 2689 - __attribute__((format(printf, 4, 5))) 2690 - jsval_t js_create_error(struct js *js, js_err_type_t err_type, jsval_t props, const char *xx, ...) { 2691 - va_list ap; 2692 - int line = 0, col = 0; 2693 - char error_line[256] = {0}; 2694 - int error_col = 0; 2695 - char error_msg[256] = {0}; 2696 - 2697 - bool no_stack = (err_type & JS_ERR_NO_STACK) != 0; 2698 - err_type = (js_err_type_t)(err_type & ~JS_ERR_NO_STACK); 2699 - 2700 - if (!js->errmsg) { 2701 - js->errmsg_size = 4096; 2702 - js->errmsg = (char *)malloc(js->errmsg_size); 2703 - if (!js->errmsg) return mkval(T_ERR, 0); 2704 - } 2705 - 2706 - get_line_col(js->code, js->toff > 0 ? js->toff : js->pos, &line, &col); 2707 - get_error_line(js->code, js->clen, js->toff > 0 ? js->toff : js->pos, error_line, sizeof(error_line), &error_col); 2708 - 2709 - va_start(ap, xx); 2710 - vsnprintf(error_msg, sizeof(error_msg), xx, ap); 2711 - va_end(ap); 2712 - 2713 - const char *err_name = get_error_type_name(err_type); 2714 - size_t err_name_len = strlen(err_name); 2715 - size_t msg_len = strlen(error_msg); 2716 - 2717 - jsval_t err_obj = js_mkobj(js); 2718 - js_set(js, err_obj, "name", js_mkstr(js, err_name, err_name_len)); 2719 - js_set(js, err_obj, "message", js_mkstr(js, error_msg, msg_len)); 2720 - set_slot(js, err_obj, SLOT_ERR_TYPE, js_mknum((double)err_type)); 2721 - 2722 - if (vtype(props) == T_OBJ) js_merge_obj(js, err_obj, props); 2723 - jsval_t proto = js_get_ctor_proto(js, err_name, err_name_len); 2724 - if (vtype(proto) == T_OBJ) js_set_proto(js, err_obj, proto); 2725 - 2726 - js->flags |= F_THROW; 2727 - js->thrown_value = err_obj; 2728 - 2729 - size_t n = 0; 2730 - n = append_error_header(js, 0, line); 2731 - 2732 - if (n < js->errmsg_size - 1) n = append_errmsg_fmt( 2733 - js, n, 2734 - "\x1b[31m%s\x1b[0m: \x1b[1m%s\x1b[0m", 2735 - err_name, error_msg 2736 - ); 2737 - 2738 - if (!no_stack) { 2739 - format_error_stack(js, &n, line, col, true, error_line, error_col); 2740 - } 2741 - 2742 - js->pos = js->clen, js->tok = TOK_EOF, js->consumed = 0; 2743 - return mkval(T_ERR, 0); 2744 - } 2745 - 2746 - static jsval_t js_throw(struct js *js, jsval_t value) { 2747 - int line = 0, col = 0; 2748 - char error_line[256] = {0}; 2749 - int error_col = 0; 2750 - 2751 - get_line_col(js->code, js->toff > 0 ? js->toff : js->pos, &line, &col); 2752 - get_error_line(js->code, js->clen, js->toff > 0 ? js->toff : js->pos, error_line, sizeof(error_line), &error_col); 2753 - 2754 - if (!js->errmsg) { 2755 - js->errmsg_size = 4096; 2756 - js->errmsg = (char *)malloc(js->errmsg_size); 2757 - if (!js->errmsg) return mkval(T_ERR, 0); 2758 - } 2759 - 2760 - size_t n = 0; 2761 - 2762 - n = append_error_header(js, 0, line); 2763 - n = append_error_value(js, n, value); 2764 - 2765 - format_error_stack(js, &n, line, col, true, error_line, error_col); 2766 - 2767 - js->flags |= F_THROW; 2768 - js->thrown_value = value; 2769 - js->pos = js->clen; 2770 - js->tok = TOK_EOF; 2771 - js->consumed = 0; 2772 - return mkval(T_ERR, 0); 2773 - } 2774 - 2775 2339 static size_t tostr(struct js *js, jsval_t value, char *buf, size_t len) { 2776 2340 switch (vtype(value)) { 2777 2341 case T_UNDEF: return ANT_COPY(buf, len, "undefined"); ··· 5204 4768 return js_mkundef(); 5205 4769 } 5206 4770 5207 - static inline bool push_call_frame(const char *filename, const char *function_name, const char *code, uint32_t pos) { 5208 - if (global_call_stack.depth >= global_call_stack.capacity) { 5209 - int new_capacity = global_call_stack.capacity == 0 ? 32 : global_call_stack.capacity * 2; 5210 - call_frame_t *new_stack = (call_frame_t *) realloc(global_call_stack.frames, new_capacity * sizeof(call_frame_t)); 5211 - if (!new_stack) return false; 5212 - global_call_stack.frames = new_stack; 5213 - global_call_stack.capacity = new_capacity; 5214 - } 5215 - 5216 - global_call_stack.frames[global_call_stack.depth].filename = filename; 5217 - global_call_stack.frames[global_call_stack.depth].function_name = function_name; 5218 - global_call_stack.frames[global_call_stack.depth].code = code; 5219 - global_call_stack.frames[global_call_stack.depth].pos = pos; 5220 - global_call_stack.frames[global_call_stack.depth].line = -1; 5221 - global_call_stack.frames[global_call_stack.depth].col = -1; 5222 - global_call_stack.depth++; 5223 - 5224 - return true; 5225 - } 5226 - 5227 - static inline void pop_call_frame() { 5228 - if (global_call_stack.depth > 0) { 5229 - global_call_stack.depth--; 5230 - } 5231 - } 5232 - 5233 4771 static jsval_t js_func_decl(struct js *js); 5234 4772 static jsval_t js_func_decl_async(struct js *js); 5235 4773 ··· 5418 4956 return result; 5419 4957 } 5420 4958 5421 - static inline jsoff_t lkp(struct js *js, jsval_t obj, const char *buf, size_t len) { 4959 + inline jsoff_t lkp(struct js *js, jsval_t obj, const char *buf, size_t len) { 5422 4960 const char *search_intern = intern_string(buf, len); 5423 4961 if (!search_intern) return 0; 5424 4962 return lkp_interned(js, obj, search_intern, len); ··· 5794 5332 return false; 5795 5333 } 5796 5334 5797 - static jsval_t resolveprop(struct js *js, jsval_t v) { 5335 + jsval_t resolveprop(struct js *js, jsval_t v) { 5798 5336 if (vtype(v) == T_PROPREF) { 5799 5337 if (is_prim_propref(v)) { 5800 5338 prim_propref_data_t *prim_data = prim_propref_get(v); ··· 23889 23427 entry->has_setter = true; 23890 23428 entry->getter = getter; 23891 23429 entry->setter = setter; 23892 - } 23893 - 23894 - void js_print_stack_trace(FILE *stream) { 23895 - if (global_call_stack.depth > 0) { 23896 - for (int i = global_call_stack.depth - 1; i >= 0; i--) { 23897 - call_frame_t *frame = &global_call_stack.frames[i]; 23898 - fprintf(stream, " at "); 23899 - 23900 - if (frame->function_name) { 23901 - fprintf(stream, "%s", frame->function_name); 23902 - } else fprintf(stream, "<anonymous>"); 23903 - 23904 - fprintf(stream, " (\x1b[90m"); 23905 - 23906 - if (frame->line < 0 && frame->code) { 23907 - get_line_col(frame->code, frame->pos, &frame->line, &frame->col); 23908 - } 23909 - int fline = frame->line > 0 ? frame->line : 1; 23910 - int fcol = frame->col > 0 ? frame->col : 1; 23911 - 23912 - if (frame->filename) { 23913 - fprintf(stream, "%s:%d:%d", frame->filename, fline, fcol); 23914 - } else fprintf(stream, "<unknown>"); 23915 - 23916 - fprintf(stream, "\x1b[0m)\n"); 23917 - } 23918 - } 23919 - } 23430 + }
+387
src/errors.c
··· 1 + #include "tokens.h" 2 + #include "stack.h" 3 + #include "errors.h" 4 + #include "internal.h" 5 + 6 + #include <stdlib.h> 7 + #include <string.h> 8 + #include <stdarg.h> 9 + 10 + static const char *get_error_type_name(js_err_type_t err_type) { 11 + static const char *names[] = { 12 + [JS_ERR_GENERIC] = "Error", 13 + [JS_ERR_TYPE] = "TypeError", 14 + [JS_ERR_SYNTAX] = "SyntaxError", 15 + [JS_ERR_REFERENCE] = "ReferenceError", 16 + [JS_ERR_RANGE] = "RangeError", 17 + [JS_ERR_EVAL] = "EvalError", 18 + [JS_ERR_URI] = "URIError", 19 + [JS_ERR_INTERNAL] = "InternalError", 20 + [JS_ERR_AGGREGATE] = "AggregateError", 21 + }; 22 + 23 + return names[err_type] ?: "Error"; 24 + } 25 + 26 + static bool ensure_errmsg_capacity(struct js *js, size_t needed) { 27 + if (js->errmsg_size == 0) js->errmsg_size = 4096; 28 + 29 + if (!js->errmsg) { 30 + js->errmsg = (char *)malloc(js->errmsg_size); 31 + if (!js->errmsg) return false; 32 + js->errmsg[0] = '\0'; 33 + } 34 + 35 + if (needed <= js->errmsg_size) return true; 36 + 37 + size_t new_size = js->errmsg_size; 38 + while (new_size < needed) { 39 + size_t next = new_size * 2; 40 + if (next < new_size) return false; 41 + new_size = next; 42 + } 43 + 44 + char *next_buf = (char *)realloc(js->errmsg, new_size); 45 + if (!next_buf) return false; 46 + js->errmsg = next_buf; 47 + js->errmsg_size = new_size; 48 + return true; 49 + } 50 + 51 + __attribute__((format(printf, 3, 4))) 52 + static size_t append_errmsg_fmt(struct js *js, size_t used, const char *fmt, ...) { 53 + for (;;) { 54 + if (!ensure_errmsg_capacity(js, used + 1)) return used; 55 + 56 + size_t remaining = js->errmsg_size - used; 57 + va_list ap; 58 + va_start(ap, fmt); 59 + int written = vsnprintf(js->errmsg + used, remaining, fmt, ap); 60 + va_end(ap); 61 + 62 + if (written < 0) return used; 63 + if ((size_t)written < remaining) return used + (size_t)written; 64 + 65 + if (!ensure_errmsg_capacity(js, used + (size_t)written + 1)) { 66 + return js->errmsg_size ? js->errmsg_size - 1 : used; 67 + } 68 + } 69 + } 70 + 71 + static inline size_t remaining_capacity(size_t used, size_t total) { 72 + return used >= total ? 0 : total - used; 73 + } 74 + 75 + static size_t append_error_header(struct js *js, size_t used, int line) { 76 + if (js->filename) return append_errmsg_fmt(js, used, "%s:%d\n", js->filename, line); 77 + return append_errmsg_fmt(js, used, "<eval>:%d\n", line); 78 + } 79 + 80 + static void get_line_col(const char *code, jsoff_t pos, int *line, int *col) { 81 + int l = 1, c = 1; 82 + for (jsoff_t i = 0; i < pos && code[i]; i++) code[i] == '\n' ? (l++, c = 1) : c++; 83 + *line = l; *col = c; 84 + } 85 + 86 + static void get_error_line(const char *code, jsoff_t clen, jsoff_t pos, char *buf, size_t bufsize, int *line_start_col) { 87 + if (!code || bufsize == 0) { 88 + if (bufsize > 0) buf[0] = '\0'; 89 + if (line_start_col) *line_start_col = 1; 90 + return; 91 + } 92 + 93 + if (pos > clen) pos = clen; 94 + 95 + if (clen == 0) { 96 + buf[0] = '\0'; 97 + if (line_start_col) *line_start_col = 1; 98 + return; 99 + } 100 + 101 + jsoff_t line_start = pos; 102 + while (line_start > 0 && code[line_start - 1] != '\n') { 103 + line_start--; 104 + } 105 + 106 + jsoff_t line_end = pos; 107 + while (line_end < clen && code[line_end] != '\n' && code[line_end] != '\0') { 108 + line_end++; 109 + } 110 + 111 + jsoff_t line_len = line_end - line_start; 112 + if (line_len >= bufsize) line_len = (jsoff_t)(bufsize - 1); 113 + 114 + memcpy(buf, &code[line_start], line_len); 115 + buf[line_len] = '\0'; 116 + *line_start_col = (int)(pos - line_start) + 1; 117 + } 118 + 119 + static size_t append_error_value(struct js *js, size_t used, jsval_t value) { 120 + const char *name = "Error"; 121 + const char *msg = NULL; 122 + 123 + jsoff_t name_len = 5; 124 + jsoff_t msg_len = 0; 125 + 126 + static const void *type_dispatch[] = { 127 + [T_STR] = &&l_type_str, 128 + [T_OBJ] = &&l_type_obj, 129 + [T_FUNC] = &&l_type_default, 130 + [T_ARR] = &&l_type_default, 131 + [T_PROMISE] = &&l_type_default, 132 + [T_GENERATOR] = &&l_type_default, 133 + [T_PROP] = &&l_type_default, 134 + [T_BIGINT] = &&l_type_default, 135 + [T_NUM] = &&l_type_default, 136 + [T_BOOL] = &&l_type_default, 137 + [T_SYMBOL] = &&l_type_default, 138 + [T_CFUNC] = &&l_type_default, 139 + [T_FFI] = &&l_type_default, 140 + [T_TYPEDARRAY] = &&l_type_default, 141 + [T_CODEREF] = &&l_type_default, 142 + [T_PROPREF] = &&l_type_default, 143 + [T_ERR] = &&l_type_default, 144 + [T_UNDEF] = &&l_type_default, 145 + [T_NULL] = &&l_type_default, 146 + }; 147 + 148 + uint8_t t = vtype(value); 149 + if (t < sizeof(type_dispatch) / sizeof(type_dispatch[0]) && type_dispatch[t]) { 150 + goto *type_dispatch[t]; 151 + } 152 + goto l_type_default; 153 + 154 + l_type_str: 155 + msg = (const char *)&js->mem[vstr(js, value, &msg_len)]; 156 + goto l_type_done; 157 + 158 + l_type_obj: 159 + name = get_str_prop(js, value, "name", 4, &name_len); 160 + if (!name) { 161 + name = "Error"; 162 + name_len = 5; 163 + } 164 + msg = get_str_prop(js, value, "message", 7, &msg_len); 165 + goto l_type_done; 166 + 167 + l_type_default: 168 + msg = js_str(js, value); 169 + msg_len = msg ? (jsoff_t)strlen(msg) : 0; 170 + goto l_type_done; 171 + 172 + l_type_done: 173 + 174 + static const void *dispatch[] = { &&l_with_msg, &&l_name_only }; 175 + int key = msg ? 0 : 1; 176 + goto *dispatch[key]; 177 + 178 + l_with_msg: 179 + return append_errmsg_fmt(js, used, 180 + ERR_FMT, 181 + (int)name_len, name, (int)msg_len, msg 182 + ); 183 + 184 + l_name_only: 185 + return append_errmsg_fmt(js, used, 186 + ERR_NAME_ONLY, 187 + (int)name_len, name 188 + ); 189 + } 190 + 191 + static void append_error_caret(struct js *js, size_t *n, int error_col) { 192 + if (!ensure_errmsg_capacity(js, *n + (size_t)error_col + 2)) return; 193 + if (*n >= js->errmsg_size - 1) return; 194 + 195 + size_t remaining = js->errmsg_size - *n; 196 + for (int i = 1; i < error_col && remaining > 1; i++) { 197 + js->errmsg[(*n)++] = ' '; 198 + remaining--; 199 + } 200 + if (remaining > 1) { 201 + js->errmsg[(*n)++] = '^'; 202 + } 203 + js->errmsg[*n] = '\0'; 204 + } 205 + 206 + static void format_error_stack(struct js *js, size_t *n, int line, int col, bool include_source_line, const char *error_line, int error_col) { 207 + if (!ensure_errmsg_capacity(js, *n + 1)) return; 208 + 209 + const char *dim = "\x1b[90m"; 210 + const char *reset = "\x1b[0m"; 211 + 212 + if (include_source_line && error_line && *n < js->errmsg_size) { 213 + *n = append_errmsg_fmt(js, *n, "\n%s\n", error_line); 214 + append_error_caret(js, n, error_col); 215 + } 216 + 217 + size_t remaining = remaining_capacity(*n, js->errmsg_size); 218 + if (remaining > 20) { 219 + const char *file = js->filename ? js->filename : "<eval>"; 220 + 221 + for (int i = global_call_stack.depth - 1; i >= 0 && remaining > 20; i--) { 222 + call_frame_t *frame = &global_call_stack.frames[i]; 223 + const char *fname = frame->function_name ? frame->function_name : "<anonymous>"; 224 + const char *ffile = frame->filename ? frame->filename : "<eval>"; 225 + 226 + if (frame->line < 0 && frame->code) { 227 + get_line_col(frame->code, frame->pos, &frame->line, &frame->col); 228 + } 229 + int fline = frame->line > 0 ? frame->line : 1; 230 + int fcol = frame->col > 0 ? frame->col : 1; 231 + 232 + *n = append_errmsg_fmt(js, *n, 233 + "\n at %s %s(%s:%d:%d)%s", 234 + fname, dim, ffile, fline, fcol, reset 235 + ); 236 + remaining = remaining_capacity(*n, js->errmsg_size); 237 + } 238 + 239 + if (global_call_stack.depth > 0 && remaining > 60) { 240 + *n = append_errmsg_fmt(js, *n, 241 + "\n at Object.<anonymous> %s(%s:1:1)%s", 242 + dim, file, reset 243 + ); 244 + remaining = remaining_capacity(*n, js->errmsg_size); 245 + } 246 + 247 + if (global_call_stack.depth == 0 && remaining > 20) { 248 + *n = append_errmsg_fmt(js, *n, 249 + "\n at %s%s:%d:%d%s", 250 + dim, file, line, col, reset 251 + ); 252 + remaining = remaining_capacity(*n, js->errmsg_size); 253 + } 254 + 255 + if (remaining > 60 && js->filename && strcmp(js->filename, "[eval]") != 0) { 256 + *n = append_errmsg_fmt(js, *n, 257 + "\n at Module.executeUserEntryPoint [as runMain] %s(ant:internal/modules/run_main:149:5)%s", 258 + dim, reset 259 + ); 260 + remaining = remaining_capacity(*n, js->errmsg_size); 261 + } 262 + 263 + if (remaining > 40 && js->filename && strcmp(js->filename, "[eval]") != 0) { 264 + *n = append_errmsg_fmt(js, *n, 265 + "\n at %sant:internal/call:21728:23%s", 266 + dim, reset 267 + ); 268 + } 269 + } 270 + 271 + js->errmsg[js->errmsg_size - 1] = '\0'; 272 + } 273 + 274 + js_err_type_t get_error_type(struct js *js) { 275 + if (!(js->flags & F_THROW)) return JS_ERR_GENERIC; 276 + jsval_t err_type = js_get_slot(js, js->thrown_value, SLOT_ERR_TYPE); 277 + if (vtype(err_type) != T_NUM) return JS_ERR_GENERIC; 278 + return (js_err_type_t)(int)js_getnum(err_type); 279 + } 280 + 281 + __attribute__((format(printf, 4, 5))) 282 + jsval_t js_create_error(struct js *js, js_err_type_t err_type, jsval_t props, const char *xx, ...) { 283 + va_list ap; 284 + int line = 0, col = 0; 285 + char error_line[256] = {0}; 286 + int error_col = 0; 287 + char error_msg[256] = {0}; 288 + 289 + bool no_stack = (err_type & JS_ERR_NO_STACK) != 0; 290 + err_type = (js_err_type_t)(err_type & ~JS_ERR_NO_STACK); 291 + 292 + if (!js->errmsg) { 293 + js->errmsg_size = 4096; 294 + js->errmsg = (char *)malloc(js->errmsg_size); 295 + if (!js->errmsg) return mkval(T_ERR, 0); 296 + } 297 + 298 + get_line_col(js->code, js->toff > 0 ? js->toff : js->pos, &line, &col); 299 + get_error_line(js->code, js->clen, js->toff > 0 ? js->toff : js->pos, error_line, sizeof(error_line), &error_col); 300 + 301 + va_start(ap, xx); 302 + vsnprintf(error_msg, sizeof(error_msg), xx, ap); 303 + va_end(ap); 304 + 305 + const char *err_name = get_error_type_name(err_type); 306 + size_t err_name_len = strlen(err_name); 307 + size_t msg_len = strlen(error_msg); 308 + 309 + jsval_t err_obj = js_mkobj(js); 310 + js_set(js, err_obj, "name", js_mkstr(js, err_name, err_name_len)); 311 + js_set(js, err_obj, "message", js_mkstr(js, error_msg, msg_len)); 312 + js_set_slot(js, err_obj, SLOT_ERR_TYPE, js_mknum((double)err_type)); 313 + 314 + if (vtype(props) == T_OBJ) js_merge_obj(js, err_obj, props); 315 + jsval_t proto = js_get_ctor_proto(js, err_name, err_name_len); 316 + if (vtype(proto) == T_OBJ) js_set_proto(js, err_obj, proto); 317 + 318 + js->flags |= F_THROW; 319 + js->thrown_value = err_obj; 320 + 321 + size_t n = 0; 322 + n = append_error_header(js, 0, line); 323 + 324 + if (n < js->errmsg_size - 1) n = append_errmsg_fmt( 325 + js, n, 326 + "\x1b[31m%s\x1b[0m: \x1b[1m%s\x1b[0m", 327 + err_name, error_msg 328 + ); 329 + 330 + if (!no_stack) { 331 + format_error_stack(js, &n, line, col, true, error_line, error_col); 332 + } 333 + 334 + js->pos = js->clen, js->tok = TOK_EOF, js->consumed = 0; 335 + return mkval(T_ERR, 0); 336 + } 337 + 338 + jsval_t js_throw(struct js *js, jsval_t value) { 339 + int line = 0, col = 0; 340 + char error_line[256] = {0}; 341 + int error_col = 0; 342 + 343 + get_line_col(js->code, js->toff > 0 ? js->toff : js->pos, &line, &col); 344 + get_error_line(js->code, js->clen, js->toff > 0 ? js->toff : js->pos, error_line, sizeof(error_line), &error_col); 345 + 346 + if (!js->errmsg) { 347 + js->errmsg_size = 4096; 348 + js->errmsg = (char *)malloc(js->errmsg_size); 349 + if (!js->errmsg) return mkval(T_ERR, 0); 350 + } 351 + 352 + size_t n = 0; 353 + 354 + n = append_error_header(js, 0, line); 355 + n = append_error_value(js, n, value); 356 + 357 + format_error_stack(js, &n, line, col, true, error_line, error_col); 358 + 359 + js->flags |= F_THROW; 360 + js->thrown_value = value; 361 + js->pos = js->clen; 362 + js->tok = TOK_EOF; 363 + js->consumed = 0; 364 + return mkval(T_ERR, 0); 365 + } 366 + 367 + void js_print_stack_trace(FILE *stream) { 368 + int i = global_call_stack.depth; 369 + 370 + loop: 371 + if (--i < 0) goto done; 372 + call_frame_t *frame = &global_call_stack.frames[i]; 373 + 374 + if (frame->line >= 0 || !frame->code) goto print; 375 + get_line_col(frame->code, frame->pos, &frame->line, &frame->col); 376 + 377 + print: 378 + fprintf(stream, " at %s (\x1b[90m%s:%d:%d\x1b[0m)\n", 379 + frame->function_name ?: "<anonymous>", 380 + frame->filename ?: "<unknown>", 381 + frame->line > 0 ? frame->line : 1, 382 + frame->col > 0 ? frame->col : 1); 383 + goto loop; 384 + 385 + done: 386 + return; 387 + }
+1
src/modules/atomics.c
··· 7 7 #include <errno.h> 8 8 9 9 #include "ant.h" 10 + #include "errors.h" 10 11 #include "runtime.h" 11 12 12 13 #include "modules/buffer.h"
+1
src/modules/buffer.c
··· 10 10 #endif 11 11 12 12 #include "ant.h" 13 + #include "errors.h" 13 14 #include "arena.h" 14 15 #include "runtime.h" 15 16
+2 -1
src/modules/builtin.c
··· 1 - #include "ant.h" 2 1 #include <compat.h> // IWYU pragma: keep 3 2 4 3 #include <stdlib.h> ··· 14 13 #include <sys/resource.h> 15 14 #endif 16 15 16 + #include "ant.h" 17 + #include "errors.h" 17 18 #include "runtime.h" 18 19 #include "internal.h" 19 20 #include "modules/builtin.h"
+2 -2
src/modules/child_process.c
··· 23 23 #endif 24 24 25 25 #include "ant.h" 26 + #include "errors.h" 26 27 #include "modules/child_process.h" 27 28 #include "modules/symbol.h" 28 29 ··· 783 784 if (exit_code != 0) { 784 785 char err_msg[256]; 785 786 snprintf(err_msg, sizeof(err_msg), "Command failed with exit code %d", exit_code); 786 - free(output); 787 - return js_mkerr(js, err_msg); 787 + free(output); return js_mkerr(js, "%s", err_msg); 788 788 } 789 789 790 790 jsval_t result = js_mkstr(js, output, output_len);
+1
src/modules/crypto.c
··· 14 14 #endif 15 15 16 16 #include "ant.h" 17 + #include "errors.h" 17 18 #include "runtime.h" 18 19 #include "modules/crypto.h" 19 20 #include "modules/buffer.h"
+1
src/modules/events.c
··· 5 5 #include <uthash.h> 6 6 7 7 #include "ant.h" 8 + #include "errors.h" 8 9 #include "arena.h" 9 10 #include "runtime.h" 10 11
+1
src/modules/fetch.c
··· 9 9 #include <utarray.h> 10 10 11 11 #include "ant.h" 12 + #include "errors.h" 12 13 #include "config.h" 13 14 #include "common.h" 14 15 #include "runtime.h"
+1
src/modules/ffi.c
··· 15 15 #include <utarray.h> 16 16 #include <uthash.h> 17 17 18 + #include "errors.h" 18 19 #include "modules/ffi.h" 19 20 #include "modules/symbol.h" 20 21
+14 -20
src/modules/fs.c
··· 11 11 #include <errno.h> 12 12 13 13 #include "ant.h" 14 + #include "errors.h" 14 15 #include "internal.h" 15 16 #include "runtime.h" 16 17 ··· 372 373 if (!file) { 373 374 char err_msg[256]; 374 375 snprintf(err_msg, sizeof(err_msg), "Failed to open file: %s", strerror(errno)); 375 - free(path_cstr); 376 - return js_mkerr(js, err_msg); 376 + free(path_cstr); return js_mkerr(js, "%s", err_msg); 377 377 } 378 378 379 379 fseek(file, 0, SEEK_END); ··· 424 424 if (!file) { 425 425 char err_msg[256]; 426 426 snprintf(err_msg, sizeof(err_msg), "Failed to open file: %s", strerror(errno)); 427 - free(path_cstr); 428 - return js_mkerr(js, err_msg); 427 + free(path_cstr); return js_mkerr(js, "%s", err_msg); 429 428 } 430 429 431 430 fseek(file, 0, SEEK_END); ··· 545 544 if (!file) { 546 545 char err_msg[256]; 547 546 snprintf(err_msg, sizeof(err_msg), "Failed to open file: %s", strerror(errno)); 548 - free(path_cstr); 549 - return js_mkerr(js, err_msg); 547 + free(path_cstr); return js_mkerr(js, "%s", err_msg); 550 548 } 551 549 552 550 size_t bytes_written = fwrite(data, 1, data_len, file); ··· 584 582 if (!in) { 585 583 char err_msg[256]; 586 584 snprintf(err_msg, sizeof(err_msg), "Failed to open source file: %s", strerror(errno)); 587 - free(src_cstr); 588 - free(dest_cstr); 589 - return js_mkerr(js, err_msg); 585 + free(src_cstr); free(dest_cstr); 586 + return js_mkerr(js, "%s", err_msg); 590 587 } 591 588 592 589 FILE *out = fopen(dest_cstr, "wb"); ··· 594 591 char err_msg[256]; 595 592 snprintf(err_msg, sizeof(err_msg), "Failed to open dest file: %s", strerror(errno)); 596 593 fclose(in); 597 - free(src_cstr); 598 - free(dest_cstr); 599 - return js_mkerr(js, err_msg); 594 + free(src_cstr); free(dest_cstr); 595 + return js_mkerr(js, "%s", err_msg); 600 596 } 601 597 602 598 char buf[8192]; ··· 646 642 if (result != 0) { 647 643 char err_msg[256]; 648 644 snprintf(err_msg, sizeof(err_msg), "Failed to rename: %s", strerror(errno)); 649 - return js_mkerr(js, err_msg); 645 + return js_mkerr(js, "%s", err_msg); 650 646 } 651 647 652 648 return js_mkundef(); ··· 671 667 if (!file) { 672 668 char err_msg[256]; 673 669 snprintf(err_msg, sizeof(err_msg), "Failed to open file: %s", strerror(errno)); 674 - free(path_cstr); 675 - return js_mkerr(js, err_msg); 670 + free(path_cstr); return js_mkerr(js, "%s", err_msg); 676 671 } 677 672 678 673 size_t bytes_written = fwrite(data, 1, data_len, file); ··· 749 744 if (result != 0) { 750 745 char err_msg[256]; 751 746 snprintf(err_msg, sizeof(err_msg), "Failed to unlink file: %s", strerror(errno)); 752 - return js_mkerr(js, err_msg); 747 + return js_mkerr(js, "%s", err_msg); 753 748 } 754 749 755 750 return js_mkundef(); ··· 834 829 } 835 830 char err_msg[256]; 836 831 snprintf(err_msg, sizeof(err_msg), "Failed to create directory: %s", strerror(errno)); 837 - return js_mkerr(js, err_msg); 832 + return js_mkerr(js, "%s", err_msg); 838 833 } 839 834 840 835 return js_mkundef(); ··· 900 895 if (result != 0) { 901 896 char err_msg[256]; 902 897 snprintf(err_msg, sizeof(err_msg), "Failed to remove directory: %s", strerror(errno)); 903 - return js_mkerr(js, err_msg); 898 + return js_mkerr(js, "%s", err_msg); 904 899 } 905 900 906 901 return js_mkundef(); ··· 1199 1194 if (result < 0) { 1200 1195 char err_msg[256]; 1201 1196 snprintf(err_msg, sizeof(err_msg), "Failed to read directory: %s", uv_strerror(result)); 1202 - uv_fs_req_cleanup(&req); 1203 - return js_mkerr(js, err_msg); 1197 + uv_fs_req_cleanup(&req); return js_mkerr(js, "%s", err_msg); 1204 1198 } 1205 1199 1206 1200 jsval_t arr = js_mkarr(js);
+1
src/modules/io.c
··· 9 9 #include <uv.h> 10 10 11 11 #include "common.h" 12 + #include "errors.h" 12 13 #include "internal.h" 13 14 #include "runtime.h" 14 15 #include "modules/io.h"
+1
src/modules/json.c
··· 5 5 #include <yyjson.h> 6 6 #include <uthash.h> 7 7 8 + #include "errors.h" 8 9 #include "runtime.h" 9 10 #include "internal.h" 10 11 #include "modules/json.h"
+1
src/modules/localstorage.c
··· 5 5 #include <yyjson.h> 6 6 7 7 #include "ant.h" 8 + #include "errors.h" 8 9 #include "arena.h" 9 10 #include "runtime.h" 10 11
+1
src/modules/navigator.c
··· 12 12 #endif 13 13 14 14 #include "ant.h" 15 + #include "errors.h" 15 16 #include "config.h" 16 17 #include "runtime.h" 17 18 #include "modules/navigator.h"
+1
src/modules/observable.c
··· 2 2 #include <stdio.h> 3 3 #include <string.h> 4 4 5 + #include "errors.h" 5 6 #include "internal.h" 6 7 #include "runtime.h" 7 8
+1
src/modules/os.c
··· 34 34 #endif 35 35 36 36 #include "ant.h" 37 + #include "errors.h" 37 38 #include "modules/symbol.h" 38 39 39 40 #ifdef _WIN32
+1
src/modules/path.c
··· 5 5 #include <string.h> 6 6 7 7 #include "ant.h" 8 + #include "errors.h" 8 9 #include "modules/symbol.h" 9 10 10 11 #ifndef PATH_MAX
+2
src/modules/process.c
··· 27 27 #endif 28 28 29 29 #include "ant.h" 30 + #include "errors.h" 30 31 #include "config.h" 31 32 #include "internal.h" 32 33 #include "runtime.h" 34 + 33 35 #include "modules/process.h" 34 36 #include "modules/symbol.h" 35 37
+1
src/modules/readline.c
··· 22 22 #endif 23 23 24 24 #include "ant.h" 25 + #include "errors.h" 25 26 #include "runtime.h" 26 27 #include "modules/readline.h" 27 28 #include "modules/symbol.h"
+1
src/modules/reflect.c
··· 2 2 #include <string.h> 3 3 4 4 #include "ant.h" 5 + #include "errors.h" 5 6 #include "runtime.h" 6 7 #include "modules/reflect.h" 7 8 #include "modules/symbol.h"
+1
src/modules/sessionstorage.c
··· 3 3 #include <uthash.h> 4 4 5 5 #include "ant.h" 6 + #include "errors.h" 6 7 #include "arena.h" 7 8 #include "runtime.h" 8 9
+1
src/modules/shell.c
··· 12 12 #endif 13 13 14 14 #include "ant.h" 15 + #include "errors.h" 15 16 #include "modules/symbol.h" 16 17 17 18 static jsval_t builtin_shell_text(struct js *js, jsval_t *args, int nargs);
+1
src/modules/symbol.c
··· 3 3 #include <stdio.h> 4 4 5 5 #include "ant.h" 6 + #include "errors.h" 6 7 #include "runtime.h" 7 8 #include "modules/symbol.h" 8 9
+1
src/modules/textcodec.c
··· 3 3 #include <string.h> 4 4 5 5 #include "runtime.h" 6 + #include "errors.h" 6 7 #include "modules/textcodec.h" 7 8 #include "modules/buffer.h" 8 9 #include "modules/symbol.h"
+1
src/modules/timer.c
··· 12 12 #endif 13 13 14 14 #include "arena.h" 15 + #include "errors.h" 15 16 #include "runtime.h" 16 17 #include "modules/timer.h" 17 18
+1
src/modules/uri.c
··· 3 3 #include <string.h> 4 4 5 5 #include "ant.h" 6 + #include "errors.h" 6 7 #include "runtime.h" 7 8 #include "modules/uri.h" 8 9
+1
src/modules/url.c
··· 6 6 #include <ctype.h> 7 7 8 8 #include "ant.h" 9 + #include "errors.h" 9 10 #include "runtime.h" 10 11 #include "modules/url.h" 11 12
+1
src/snapshot.c
··· 1 1 #include <string.h> 2 2 3 3 #include "ant.h" 4 + #include "errors.h" 4 5 #include "snapshot.h" 5 6 #include "snapshot_data.h" 6 7
+37
src/stack.c
··· 1 + #include "stack.h" 2 + #include "arena.h" 3 + 4 + #include <stdint.h> 5 + #include <stdlib.h> 6 + 7 + call_stack_t global_call_stack = {NULL, 0, 0}; 8 + 9 + void pop_call_frame(void) { 10 + if (global_call_stack.depth > 0) global_call_stack.depth--; 11 + } 12 + 13 + bool push_call_frame(const char *filename, const char *function_name, const char *code, uint32_t pos) { 14 + if (global_call_stack.depth >= global_call_stack.capacity) { 15 + int new_capacity = global_call_stack.capacity == 0 ? 32 : global_call_stack.capacity * 2; 16 + if ((size_t)new_capacity > SIZE_MAX / sizeof(call_frame_t)) return false; 17 + 18 + call_frame_t *new_stack = (call_frame_t *)ant_realloc(global_call_stack.frames, new_capacity * sizeof(call_frame_t)); 19 + if (!new_stack) return false; 20 + 21 + global_call_stack.frames = new_stack; 22 + global_call_stack.capacity = new_capacity; 23 + } 24 + 25 + call_frame_t *frame = &global_call_stack.frames[global_call_stack.depth++]; 26 + 27 + *frame = (call_frame_t) { 28 + .filename = filename, 29 + .function_name = function_name, 30 + .code = code, 31 + .pos = pos, 32 + .line = -1, 33 + .col = -1, 34 + }; 35 + 36 + return true; 37 + }