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.

unify string handling

use `js_to_cstr()` and stack buffers to prevent leaking memory

+108 -54
+1
.gitignore
··· 17 17 18 18 /test262 19 19 /javascript-zoo 20 + /game-of-life 20 21 21 22 /vendor/*/ 22 23 /vendor/.wraplock
+7
include/internal.h
··· 78 78 bool ascii_cache_init; 79 79 }; 80 80 81 + typedef struct { 82 + const char *ptr; 83 + size_t len; 84 + bool needs_free; 85 + } js_cstr_t; 86 + 81 87 enum { 82 88 T_OBJ, T_PROP, T_STR, T_UNDEF, T_NULL, T_NUM, T_BOOL, T_FUNC, 83 89 T_CODEREF, T_CFUNC, T_ERR, T_ARR, T_PROMISE, T_TYPEDARRAY, ··· 117 123 118 124 jsval_t coerce_to_str(struct js *js, jsval_t v); 119 125 jsval_t coerce_to_str_concat(struct js *js, jsval_t v); 126 + js_cstr_t js_to_cstr(struct js *js, jsval_t value, char *stack_buf, size_t stack_size); 120 127 121 128 jsoff_t lkp(struct js *js, jsval_t obj, const char *buf, size_t len); 122 129 jsoff_t lkp_proto(struct js *js, jsval_t obj, const char *buf, size_t len);
+65
src/ant.c
··· 1952 1952 return buf; 1953 1953 } 1954 1954 1955 + js_cstr_t js_to_cstr(struct js *js, jsval_t value, char *stack_buf, size_t stack_size) { 1956 + js_cstr_t out = { .ptr = "", .len = 0, .needs_free = false }; 1957 + 1958 + if (is_err(value)) { 1959 + out.ptr = js->errmsg ? js->errmsg : ""; 1960 + out.len = strlen(out.ptr); 1961 + return out; 1962 + } 1963 + 1964 + if (vtype(value) == T_STR) { 1965 + size_t len = 0; 1966 + char *str = js_getstr(js, value, &len); 1967 + out.ptr = str ? str : ""; out.len = len; 1968 + return out; 1969 + } 1970 + 1971 + multiref_count = 0; 1972 + multiref_next_id = 0; 1973 + stringify_depth = 0; 1974 + scan_refs(js, value); 1975 + 1976 + size_t capacity = stack_size; 1977 + char *buf = stack_buf; 1978 + out.needs_free = false; 1979 + 1980 + if (!buf || capacity == 0) { 1981 + capacity = 64; 1982 + buf = ant_calloc(capacity); 1983 + if (!buf) return out; 1984 + out.needs_free = true; 1985 + } 1986 + 1987 + for (;;) { 1988 + stringify_depth = 0; 1989 + stringify_indent = 0; 1990 + size_t len = tostr(js, value, buf, capacity); 1991 + 1992 + if (len < capacity - 1) { 1993 + out.ptr = buf; 1994 + out.len = len; 1995 + return out; 1996 + } 1997 + 1998 + size_t new_capacity = capacity * 2; 1999 + char *next = out.needs_free 2000 + ? ant_realloc(buf, new_capacity) 2001 + : ant_calloc(new_capacity); 2002 + 2003 + if (!next) { 2004 + if (out.needs_free) free(buf); 2005 + out.ptr = ""; out.len = 0; 2006 + out.needs_free = false; 2007 + return out; 2008 + } 2009 + 2010 + if (!out.needs_free) { 2011 + memcpy(next, buf, capacity); 2012 + out.needs_free = true; 2013 + } 2014 + 2015 + buf = next; 2016 + capacity = new_capacity; 2017 + } 2018 + } 2019 + 1955 2020 jsval_t js_tostring_val(struct js *js, jsval_t value) { 1956 2021 uint8_t t = vtype(value); 1957 2022 char *buf; size_t len, buflen;
+9 -8
src/main.c
··· 105 105 jsval_t result = js_eval(js, script, len); 106 106 js_run_event_loop(js); 107 107 108 + char cbuf_stack[512]; js_cstr_t cstr = js_to_cstr( 109 + js, result, cbuf_stack, sizeof(cbuf_stack) 110 + ); 111 + 108 112 if (vtype(result) == T_ERR) { 109 - fprintf(stderr, "%s\n", js_str(js, result)); 113 + fprintf(stderr, "%s\n", cstr.ptr); 110 114 js_result = EXIT_FAILURE; 111 115 } else if (print->count > 0) { 112 - if (vtype(result) == T_STR) { 113 - char *str = js_getstr(js, result, NULL); 114 - if (str) printf("%s\n", str); 115 - } else { 116 - const char *str = js_str(js, result); 117 - if (str && strcmp(str, "undefined") != 0) { print_value_colored(str, stdout); printf("\n"); } 116 + if (vtype(result) == T_STR) printf("%s\n", cstr.ptr ? cstr.ptr : ""); 117 + else if (cstr.ptr && strcmp(cstr.ptr, "undefined") != 0) { 118 + print_value_colored(cstr.ptr, stdout); printf("\n"); 118 119 } 119 - } 120 + } if (cstr.needs_free) free((void *)cstr.ptr); 120 121 } 121 122 122 123 static char *read_file(const char *filename, size_t *len) {
+15 -30
src/modules/io.c
··· 279 279 for (int i = 0; i < nargs; i++) { 280 280 const char *space = i == 0 ? "" : " "; 281 281 io_puts(space, stream); 282 - 283 282 if (vtype(args[i]) == T_STR) { 284 283 char *str = js_getstr(js, args[i], NULL); 285 - io_print(str, stream); 284 + io_print(str ? str : "", stream); 286 285 } else { 287 - const char *str = js_str(js, args[i]); 286 + char cbuf_stack[512]; js_cstr_t cstr = js_to_cstr( 287 + js, args[i], cbuf_stack, sizeof(cbuf_stack) 288 + ); 288 289 if (color && !io_no_color) io_puts(ANSI_RESET, stream); 289 - print_value_colored(str, stream); 290 + print_value_colored(cstr.ptr, stream); 290 291 if (color && !io_no_color) io_puts(color, stream); 292 + if (cstr.needs_free) free((void *)cstr.ptr); 291 293 } 292 294 } 293 295 ··· 316 318 bool is_truthy = js_truthy(js, args[0]); 317 319 if (is_truthy) return js_mkundef(); 318 320 319 - if (!io_no_color) io_puts(ANSI_RED, stderr); 320 321 io_puts("Assertion failed", stderr); 321 322 if (nargs > 1) { 322 323 io_puts(": ", stderr); 323 - for (int i = 1; i < nargs; i++) { 324 - const char *space = i == 1 ? "" : " "; 325 - io_puts(space, stderr); 326 - 327 - if (vtype(args[i]) == T_STR) { 328 - char *str = js_getstr(js, args[i], NULL); 329 - io_print(str, stderr); 330 - } else { 331 - const char *str = js_str(js, args[i]); 332 - io_print(str, stderr); 333 - } 334 - } 324 + console_print(js, args + 1, nargs - 1, NULL, stderr); 325 + return js_mkundef(); 335 326 } 336 - if (!io_no_color) io_puts(ANSI_RESET, stderr); 327 + 337 328 io_putc('\n', stderr); 338 - 339 329 return js_mkundef(); 340 330 } 341 331 342 332 static jsval_t js_console_trace(struct js *js, jsval_t *args, int nargs) { 343 - fprintf(stderr, "Console Trace"); 344 - if (nargs > 0 && vtype(args[0]) == T_STR) { 345 - fprintf(stderr, ": "); 346 - char *str = js_getstr(js, args[0], NULL); 347 - fprintf(stderr, "%s", str); 348 - } 333 + io_puts("Trace", stderr); 334 + if (nargs > 0) { 335 + io_puts(": ", stderr); 336 + console_print(js, args, nargs, NULL, stderr); 337 + } else io_putc('\n', stderr); 349 338 350 - fprintf(stderr, "\n"); 351 339 js_print_stack_trace(stderr); 352 - 353 340 return js_mkundef(); 354 341 } 355 342 ··· 364 351 } 365 352 366 353 static jsval_t js_console_clear(struct js *js, jsval_t *args, int nargs) { 367 - (void)args; 368 - (void)nargs; 369 354 if (!io_no_color) { 370 355 fprintf(stdout, "\033[2J\033[H"); 371 356 fflush(stdout); ··· 678 663 679 664 js_set(js, console_obj, get_toStringTag_sym_key(), js_mkstr(js, "console", 7)); 680 665 js_set(js, js_glob(js), "console", console_obj); 681 - } 666 + }
+11 -16
src/repl.c
··· 60 60 61 61 static cmd_result_t cmd_help(struct js *js, history_t *history, const char *arg); 62 62 static cmd_result_t cmd_exit(struct js *js, history_t *history, const char *arg); 63 - static cmd_result_t cmd_clear(struct js *js, history_t *history, const char *arg); 64 63 static cmd_result_t cmd_load(struct js *js, history_t *history, const char *arg); 65 64 static cmd_result_t cmd_save(struct js *js, history_t *history, const char *arg); 66 65 static cmd_result_t cmd_gc(struct js *js, history_t *history, const char *arg); ··· 69 68 static const repl_command_t commands[] = { 70 69 { "help", "Show this help message", false, cmd_help }, 71 70 { "exit", "Exit the REPL", false, cmd_exit }, 72 - { "clear", "Clear the current context", false, cmd_clear }, 73 71 { "load", "Load JS from a file into the REPL session", true, cmd_load }, 74 72 { "save", "Save all evaluated commands in this REPL session to a file", true, cmd_save }, 75 73 { "gc", "Run garbage collector", false, cmd_gc }, ··· 78 76 }; 79 77 80 78 static cmd_result_t cmd_help(struct js *js, history_t *history, const char *arg) { 81 - (void)js; (void)history; (void)arg; 82 79 for (const repl_command_t *cmd = commands; cmd->name; cmd++) { 83 80 printf(" .%-7s - %s\n", cmd->name, cmd->description); 84 81 } ··· 87 84 } 88 85 89 86 static cmd_result_t cmd_exit(struct js *js, history_t *history, const char *arg) { 90 - (void)js; (void)history; (void)arg; 91 87 return CMD_EXIT; 92 - } 93 - 94 - static cmd_result_t cmd_clear(struct js *js, history_t *history, const char *arg) { 95 - (void)js; (void)history; (void)arg; 96 - printf("Clearing context...\n"); 97 - return CMD_OK; 98 88 } 99 89 100 90 static cmd_result_t cmd_load(struct js *js, history_t *history, const char *arg) { ··· 601 591 jsval_t eval_result = js_eval(js, multiline_buf, multiline_len); 602 592 js_run_event_loop(js); 603 593 604 - if (vtype(eval_result) == T_ERR) { 605 - fprintf(stderr, "%s\n", js_str(js, eval_result)); 606 - } else { 607 - const char *str = js_str(js, eval_result); 608 - print_value_colored(str, stdout); 594 + char cbuf_stack[512]; js_cstr_t cstr = js_to_cstr( 595 + js, eval_result, cbuf_stack, sizeof(cbuf_stack) 596 + ); 597 + 598 + if (vtype(eval_result) == T_ERR) 599 + fprintf(stderr, "%s\n", cstr.ptr); 600 + else if (vtype(eval_result) == T_STR) 601 + printf("%s\n", cstr.ptr ? cstr.ptr : ""); 602 + else { 603 + print_value_colored(cstr.ptr, stdout); 609 604 printf("\n"); 610 - } 605 + } if (cstr.needs_free) free((void *)cstr.ptr); 611 606 612 607 free(multiline_buf); 613 608 multiline_buf = NULL;