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.

refactor: replace static buffers with dynamic allocations

+324 -149
+84 -5
README.txt
··· 5 5 and built-in APIs for HTTP servers, timers, crypto, and JSON. 6 6 Check about my blog post about Ant! https://s.tail.so/js-in-one-month 7 7 8 + INSTALL: 9 + ``` 10 + curl -fsSL https://ant.themackabu.com/install | bash 11 + 12 + # or with MbedTLS (darwin only) 13 + curl -fsSL https://ant.themackabu.com/install | MBEDTLS=1 bash 14 + ``` 15 + 8 16 BUILD: 9 17 meson setup build && meson compile -C build 10 - 11 - RUN: 12 - ./build/ant script.js 13 18 14 19 EXAMPLE: 15 20 See examples/server/server.js for a good server example using Ant.serve() ··· 20 25 HTTP & Networking: 21 26 - Ant.serve() - HTTP server with uv_tcp (TLS support via tlsuv) 22 27 - fetch() - HTTP client with TLS support (GET, POST, etc.) 28 + - URL module imports - Import directly from URLs 23 29 24 30 Timers & Scheduling (built-in): 25 31 - setTimeout() - Execute callback after delay ··· 55 61 - result.stdout - Raw stdout 56 62 - result.stderr - Raw stderr 57 63 64 + Child Process (import from 'child_process'): 65 + - spawn() - Spawn child process with async streaming 66 + - exec() - Execute command and buffer output 67 + - execSync() - Execute command synchronously 68 + - spawnSync() - Spawn synchronous child process 69 + - fork() - Fork module as child process 70 + - ChildProcess events - on('exit'), on('close'), on('error'), on('data') 71 + - kill() - Send signal to child process 72 + 73 + Readline (import from 'readline'): 74 + - createInterface() - Create readline interface 75 + - question() - Prompt for user input with promise support 76 + - on('line') - Handle line input events 77 + - on('close') - Handle interface close 78 + - pause()/resume() - Control input stream 79 + - close() - Close interface 80 + - History support - Command history with navigation 81 + 82 + OS (import from 'os'): 83 + - arch() - CPU architecture (x64, arm64, etc.) 84 + - platform() - Operating system platform 85 + - type() - Operating system name 86 + - release() - OS release version 87 + - version() - OS version string 88 + - hostname() - System hostname 89 + - homedir() - User home directory 90 + - tmpdir() - Temporary directory path 91 + - cpus() - CPU core information 92 + - totalmem() - Total system memory 93 + - freemem() - Free system memory 94 + - uptime() - System uptime in seconds 95 + - networkInterfaces() - Network interface information 96 + - userInfo() - Current user information 97 + - constants - OS signals and errno constants 98 + - EOL - Platform-specific end-of-line marker 99 + 100 + Navigator 101 + - navigator.userAgent - User agent string 102 + - navigator.platform - Platform string 103 + - navigator.hardwareConcurrency - CPU thread count 104 + - navigator.locks - Web Locks API for coordination 105 + 58 106 Cryptography (crypto): 59 107 - random() - Cryptographically secure random number 60 108 - randomBytes() - Generate random bytes ··· 81 129 - exit() - Exit process with code 82 130 - cpuUsage() - Get CPU usage statistics 83 131 132 + Performance: 133 + - performance.now() - High-resolution timestamp 134 + - performance.timeOrigin - Time origin for measurements 135 + 136 + Ant Global 137 + - Ant.version - Runtime version 138 + - Ant.target - Build target 139 + - Ant.revision - Git revision 140 + - Ant.buildDate - Build date 141 + - Ant.serve() - Start HTTP server 142 + - Ant.signal() - Register signal handlers 143 + - Ant.sleep() - Sleep in seconds 144 + - Ant.msleep() - Sleep in milliseconds 145 + - Ant.usleep() - Sleep in microseconds 146 + - Ant.gc() - Trigger garbage collection 147 + - Ant.alloc() - Get memory allocation info 148 + - Ant.stats() - Get runtime statistics 149 + - Ant.typeof() - Get internal type name 150 + 84 151 JSON: 85 152 - JSON.parse() - Parse JSON string 86 153 - JSON.stringify() - Stringify to JSON ··· 177 244 - import 'ant:path' - Import built-in path module 178 245 - import 'ant:shell' - Import built-in shell module ($`...`) 179 246 - import 'ant:ffi' - Import built-in FFI module 247 + - import 'node:*' - Node.js-style module aliases 248 + - import from URL - Import modules from HTTP/HTTPS URLs 249 + - import '.json' - Import JSON files as modules 250 + - import '.txt' - Import text files as strings 251 + 252 + TYPESCRIPT: 253 + Built-in TypeScript type stripping via oxc (no type checking, strip only): 254 + - Run .ts files directly: ./build/ant script.ts 255 + - Type annotations are stripped at parse time 256 + - Full type definitions available in src/types/ 180 257 181 258 JAVASCRIPT FEATURES: 182 259 Full ES1-ES5 compliance with ES6+ extensions: ··· 218 295 - Default parameters in functions 219 296 - Array and object destructuring with defaults 220 297 - Computed property names in object literals 298 + - Shebang support (#!/usr/bin/env ant) 221 299 222 300 CONCURRENCY: 223 301 - Minicoro-based coroutines for async/await ··· 228 306 - Virtual memory allocation for coroutine stacks 229 307 230 308 SYSTEM: 231 - - Signal handlers (SIGINT, SIGTERM, etc.) 309 + - Signal handlers (SIGINT, SIGTERM, etc.) via Ant.signal() 232 310 - Mark-copy compacting garbage collector + Boehm-Demers-Weiser 233 311 - Coroutine execution tracking for proper GC 234 312 - Forward reference tracking for memory compaction ··· 238 316 - Non-configurable properties support (Object.defineProperty) 239 317 - Native library integration via FFI 240 318 - libuv-based async I/O for files and networking 319 + - TLS support via mbedtls or tlsuv 241 320 - LTO (Link Time Optimization) build support 242 321 - Gzip compression support for HTTP responses 243 322 244 323 LICENSE: 245 - MIT License - See LICENSE.txt for details 324 + MIT License - See LICENSE.txt for details
+65
examples/demo/mandelbrot.js
··· 1 + function mandelbrot(center_x, center_y, scale, w, h, max_it) { 2 + const colors = [14, 15, 7, 8, 0, 4, 12, 5, 13, 1, 9, 3, 11, 10, 2, 6]; 3 + const numColors = colors.length; 4 + const fx = (scale * 0.5) / Math.min(w, h); 5 + const fy = fx * 2; 6 + const halfW = w * 0.5; 7 + const halfH = h * 0.5; 8 + 9 + const cxArr = new Float64Array(w); 10 + for (let x1 = 0; x1 < w; x1++) { 11 + cxArr[x1] = (x1 - halfW) * fx + center_x; 12 + } 13 + 14 + function iterate(cx, cy) { 15 + const q = (cx - 0.25) * (cx - 0.25) + cy * cy; 16 + if (q * (q + (cx - 0.25)) <= 0.25 * cy * cy) return max_it; 17 + 18 + const cx1 = cx + 1; 19 + if (cx1 * cx1 + cy * cy <= 0.0625) return max_it; 20 + 21 + let x = 0, 22 + y = 0, 23 + x2 = 0, 24 + y2 = 0; 25 + let i = 0; 26 + 27 + while (i < max_it && x2 + y2 < 4) { 28 + y = 2 * x * y + cy; 29 + x = x2 - y2 + cx; 30 + x2 = x * x; 31 + y2 = y * y; 32 + i++; 33 + } 34 + return i; 35 + } 36 + 37 + const output = []; 38 + 39 + for (let y1 = 0; y1 < h; y1++) { 40 + const cy0 = (y1 - halfH) * fy + center_y; 41 + const cy1 = (y1 + 0.5 - halfH) * fy + center_y; 42 + const chars = new Array(w + 1); 43 + 44 + for (let x1 = 0; x1 < w; x1++) { 45 + const cx = cxArr[x1]; 46 + 47 + const i0 = iterate(cx, cy0); 48 + const i1 = iterate(cx, cy1); 49 + 50 + const c0 = i0 >= max_it ? 0 : colors[i0 % numColors]; 51 + const c1 = i1 >= max_it ? 0 : colors[i1 % numColors]; 52 + 53 + const fg = c0 >= 8 ? 82 + c0 : 30 + c0; 54 + const bg = c1 >= 8 ? 92 + c1 : 40 + c1; 55 + 56 + chars[x1] = '\x1b[' + fg + ';' + bg + 'm\u2580'; 57 + } 58 + chars[w] = '\x1b[0m'; 59 + output.push(chars.join('')); 60 + } 61 + 62 + console.log(output.join('\n')); 63 + } 64 + 65 + mandelbrot(-0.75, 0.0, 2.0, 80, 25, 50);
+175 -105
src/ant.c
··· 2886 2886 const char *digits = bigint_digits(js, val, &dlen); 2887 2887 2888 2888 if (radix == 10) { 2889 - char buf[1024]; 2889 + size_t buflen = dlen + 2; 2890 + char *buf = (char *)ANT_GC_MALLOC(buflen); 2891 + if (!buf) return js_mkerr(js, "oom"); 2890 2892 size_t n = 0; 2891 2893 if (neg) buf[n++] = '-'; 2892 2894 memcpy(buf + n, digits, dlen); 2893 2895 n += dlen; 2894 - return js_mkstr(js, buf, n); 2896 + jsval_t ret = js_mkstr(js, buf, n); 2897 + ANT_GC_FREE(buf); 2898 + return ret; 2895 2899 } 2896 2900 2897 - char result[2048]; 2898 - size_t rpos = sizeof(result) - 1; 2901 + size_t result_cap = dlen * 4 + 16; 2902 + char *result = (char *)ANT_GC_MALLOC(result_cap); 2903 + if (!result) return js_mkerr(js, "oom"); 2904 + size_t rpos = result_cap - 1; 2899 2905 result[rpos] = '\0'; 2900 2906 2901 - char *num = (char *)malloc(dlen + 1); 2902 - if (!num) return js_mkerr(js, "oom"); 2907 + char *num = (char *)ANT_GC_MALLOC(dlen + 1); 2908 + if (!num) { ANT_GC_FREE(result); return js_mkerr(js, "oom"); } 2903 2909 memcpy(num, digits, dlen); 2904 2910 num[dlen] = '\0'; 2905 2911 size_t numlen = dlen; ··· 2916 2922 memmove(num, num + start, numlen - start + 1); 2917 2923 numlen -= start; 2918 2924 if (numlen == 1 && num[0] == '0') numlen = 0; 2925 + if (rpos == 0) { 2926 + size_t new_cap = result_cap * 2; 2927 + char *new_result = (char *)ANT_GC_MALLOC(new_cap); 2928 + if (!new_result) { ANT_GC_FREE(num); ANT_GC_FREE(result); return js_mkerr(js, "oom"); } 2929 + size_t used = result_cap - rpos; 2930 + memcpy(new_result + new_cap - used, result + rpos, used); 2931 + ANT_GC_FREE(result); 2932 + result = new_result; 2933 + rpos = new_cap - used; 2934 + result_cap = new_cap; 2935 + } 2919 2936 rpos--; 2920 2937 result[rpos] = remainder < 10 ? '0' + remainder : 'a' + (remainder - 10); 2921 2938 } 2922 2939 2923 - free(num); 2940 + ANT_GC_FREE(num); 2924 2941 2925 - if (rpos == sizeof(result) - 1) { 2942 + if (rpos == result_cap - 1) { 2926 2943 result[--rpos] = '0'; 2927 2944 } 2928 2945 2929 2946 if (neg) result[--rpos] = '-'; 2930 2947 2931 - return js_mkstr(js, result + rpos, sizeof(result) - 1 - rpos); 2948 + jsval_t ret = js_mkstr(js, result + rpos, result_cap - 1 - rpos); 2949 + ANT_GC_FREE(result); 2950 + return ret; 2932 2951 } 2933 2952 2934 2953 static jsval_t mkobj(struct js *js, jsoff_t parent) { ··· 14769 14788 } 14770 14789 14771 14790 if (len == 0) return js_mkstr(js, "", 0); 14772 - char result[1024] = ""; 14791 + 14792 + size_t capacity = 1024; 14773 14793 size_t result_len = 0; 14794 + char *result = (char *)ANT_GC_MALLOC(capacity); 14795 + if (!result) return js_mkerr(js, "oom"); 14774 14796 14775 14797 for (jsoff_t i = 0; i < len; i++) { 14776 14798 char idxstr[16]; 14777 14799 size_t idxlen = uint_to_str(idxstr, sizeof(idxstr), (unsigned)i); 14778 14800 jsoff_t elem_off = lkp(js, arr, idxstr, idxlen); 14779 14801 14780 - if (i > 0 && result_len + sep_len < sizeof(result)) { 14802 + if (i > 0) { 14803 + if (result_len + sep_len >= capacity) { 14804 + capacity = (result_len + sep_len + 1) * 2; 14805 + char *new_result = (char *)ANT_GC_REALLOC(result, capacity); 14806 + if (!new_result) return js_mkerr(js, "oom"); 14807 + result = new_result; 14808 + } 14781 14809 memcpy(result + result_len, sep, sep_len); 14782 14810 result_len += sep_len; 14783 14811 } ··· 14786 14814 jsval_t elem = resolveprop(js, mkval(T_PROP, elem_off)); 14787 14815 if (vtype(elem) == T_STR) { 14788 14816 jsoff_t elem_len, elem_off_str = vstr(js, elem, &elem_len); 14789 - if (result_len + elem_len < sizeof(result)) { 14790 - memcpy(result + result_len, &js->mem[elem_off_str], elem_len); 14791 - result_len += elem_len; 14817 + if (result_len + elem_len >= capacity) { 14818 + capacity = (result_len + elem_len + 1) * 2; 14819 + char *new_result = (char *)ANT_GC_REALLOC(result, capacity); 14820 + if (!new_result) return js_mkerr(js, "oom"); 14821 + result = new_result; 14792 14822 } 14823 + memcpy(result + result_len, &js->mem[elem_off_str], elem_len); 14824 + result_len += elem_len; 14793 14825 } else if (vtype(elem) == T_NUM) { 14794 14826 char numstr[32]; 14795 14827 snprintf(numstr, sizeof(numstr), "%g", tod(elem)); 14796 14828 size_t num_len = strlen(numstr); 14797 - if (result_len + num_len < sizeof(result)) { 14798 - memcpy(result + result_len, numstr, num_len); 14799 - result_len += num_len; 14829 + if (result_len + num_len >= capacity) { 14830 + capacity = (result_len + num_len + 1) * 2; 14831 + char *new_result = (char *)ANT_GC_REALLOC(result, capacity); 14832 + if (!new_result) return js_mkerr(js, "oom"); 14833 + result = new_result; 14800 14834 } 14835 + memcpy(result + result_len, numstr, num_len); 14836 + result_len += num_len; 14801 14837 } else if (vtype(elem) == T_BOOL) { 14802 14838 const char *boolstr = vdata(elem) ? "true" : "false"; 14803 14839 size_t bool_len = strlen(boolstr); 14804 - if (result_len + bool_len < sizeof(result)) { 14805 - memcpy(result + result_len, boolstr, bool_len); 14806 - result_len += bool_len; 14840 + if (result_len + bool_len >= capacity) { 14841 + capacity = (result_len + bool_len + 1) * 2; 14842 + char *new_result = (char *)ANT_GC_REALLOC(result, capacity); 14843 + if (!new_result) return js_mkerr(js, "oom"); 14844 + result = new_result; 14807 14845 } 14846 + memcpy(result + result_len, boolstr, bool_len); 14847 + result_len += bool_len; 14808 14848 } 14809 14849 } 14810 14850 } 14811 - return js_mkstr(js, result, result_len); 14851 + jsval_t ret = js_mkstr(js, result, result_len); 14852 + ANT_GC_FREE(result); 14853 + return ret; 14812 14854 } 14813 14855 14814 14856 static jsval_t builtin_array_includes(struct js *js, jsval_t *args, int nargs) { ··· 16750 16792 bool is_regex = false; 16751 16793 bool global_flag = false; 16752 16794 bool is_func_replacement = (vtype(replacement) == T_FUNC); 16753 - char pattern_buf[256]; 16795 + char *pattern_buf = NULL; 16754 16796 jsoff_t pattern_len = 0; 16755 16797 16756 16798 if (vtype(search) == T_OBJ) { ··· 16762 16804 16763 16805 is_regex = true; 16764 16806 jsoff_t plen, poff = vstr(js, pattern_val, &plen); 16765 - pattern_len = plen < sizeof(pattern_buf) - 1 ? plen : sizeof(pattern_buf) - 1; 16766 - memcpy(pattern_buf, &js->mem[poff], pattern_len); 16767 - pattern_buf[pattern_len] = '\0'; 16807 + pattern_len = plen; 16808 + pattern_buf = (char *)ANT_GC_MALLOC(plen + 1); 16809 + if (!pattern_buf) return js_mkerr(js, "oom"); 16810 + memcpy(pattern_buf, &js->mem[poff], plen); 16811 + pattern_buf[plen] = '\0'; 16768 16812 16769 16813 jsoff_t flags_off = lkp(js, search, "flags", 5); 16770 16814 if (flags_off == 0) goto not_regex; ··· 16789 16833 repl_ptr = (char *) &js->mem[repl_off]; 16790 16834 } 16791 16835 16792 - char result[4096]; 16793 - jsoff_t result_len = 0; 16836 + size_t result_cap = str_len + repl_len + 256; 16837 + size_t result_len = 0; 16838 + char *result = (char *)ANT_GC_MALLOC(result_cap); 16839 + if (!result) return js_mkerr(js, "oom"); 16840 + 16841 + #define ENSURE_RESULT_CAP(need) do { \ 16842 + if (result_len + (need) >= result_cap) { \ 16843 + result_cap = (result_len + (need) + 1) * 2; \ 16844 + char *nr = (char *)ANT_GC_REALLOC(result, result_cap); \ 16845 + if (!nr) return js_mkerr(js, "oom"); \ 16846 + result = nr; \ 16847 + } \ 16848 + } while(0) 16794 16849 16795 16850 if (is_regex) { 16796 - char pcre2_pattern[512]; 16797 - size_t pcre2_len = js_to_pcre2_pattern(pattern_buf, pattern_len, pcre2_pattern, sizeof(pcre2_pattern)); 16851 + size_t pcre2_cap = pattern_len * 2 + 16; 16852 + char *pcre2_pattern = (char *)ANT_GC_MALLOC(pcre2_cap); 16853 + if (!pcre2_pattern) return js_mkerr(js, "oom"); 16854 + size_t pcre2_len = js_to_pcre2_pattern(pattern_buf, pattern_len, pcre2_pattern, pcre2_cap); 16798 16855 16799 16856 uint32_t options = PCRE2_UTF | PCRE2_UCP | PCRE2_MATCH_UNSET_BACKREF; 16800 16857 int errcode; 16801 16858 PCRE2_SIZE erroffset; 16802 16859 pcre2_code *re = pcre2_compile((PCRE2_SPTR)pcre2_pattern, pcre2_len, options, &errcode, &erroffset, NULL); 16860 + ANT_GC_FREE(pcre2_pattern); 16803 16861 if (re == NULL) return js_mkerr(js, "invalid regex pattern"); 16804 16862 16805 16863 pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(re, NULL); ··· 16818 16876 PCRE2_SIZE match_end = ovector[1]; 16819 16877 16820 16878 PCRE2_SIZE before_len = match_start - pos; 16821 - if (result_len + before_len < sizeof(result)) { 16822 - memcpy(result + result_len, str_ptr + pos, before_len); 16823 - result_len += (jsoff_t)before_len; 16824 - } 16879 + ENSURE_RESULT_CAP(before_len); 16880 + memcpy(result + result_len, str_ptr + pos, before_len); 16881 + result_len += before_len; 16825 16882 16826 16883 if (is_func_replacement) { 16827 16884 int nargs_cb = 1 + capture_count + 2; ··· 16855 16912 16856 16913 if (vtype(cb_result) == T_STR) { 16857 16914 jsoff_t cb_len, cb_off = vstr(js, cb_result, &cb_len); 16858 - if (result_len + cb_len < sizeof(result)) { 16859 - memcpy(result + result_len, &js->mem[cb_off], cb_len); 16860 - result_len += cb_len; 16861 - } 16915 + ENSURE_RESULT_CAP(cb_len); 16916 + memcpy(result + result_len, &js->mem[cb_off], cb_len); 16917 + result_len += cb_len; 16862 16918 } else { 16863 16919 char numbuf[32]; 16864 16920 size_t n = tostr(js, cb_result, numbuf, sizeof(numbuf)); 16865 - if (result_len + n < sizeof(result)) { 16866 - memcpy(result + result_len, numbuf, n); 16867 - result_len += (jsoff_t)n; 16868 - } 16921 + ENSURE_RESULT_CAP(n); 16922 + memcpy(result + result_len, numbuf, n); 16923 + result_len += n; 16869 16924 } 16870 16925 } else { 16871 - for (jsoff_t ri = 0; ri < repl_len && result_len < sizeof(result); ) { 16926 + for (jsoff_t ri = 0; ri < repl_len; ) { 16872 16927 if (repl_ptr[ri] == '$' && ri + 1 < repl_len) { 16873 16928 char next = repl_ptr[ri + 1]; 16874 16929 if (next == '$') { 16930 + ENSURE_RESULT_CAP(1); 16875 16931 result[result_len++] = '$'; 16876 16932 ri += 2; 16877 16933 } else if (next == '&') { 16878 16934 PCRE2_SIZE mlen = match_end - match_start; 16879 - if (result_len + mlen < sizeof(result)) { 16880 - memcpy(result + result_len, str_ptr + match_start, mlen); 16881 - result_len += (jsoff_t)mlen; 16882 - } 16935 + ENSURE_RESULT_CAP(mlen); 16936 + memcpy(result + result_len, str_ptr + match_start, mlen); 16937 + result_len += mlen; 16883 16938 ri += 2; 16884 16939 } else if (next == '`') { 16885 - if (result_len + match_start < sizeof(result)) { 16886 - memcpy(result + result_len, str_ptr, match_start); 16887 - result_len += (jsoff_t)match_start; 16888 - } 16940 + ENSURE_RESULT_CAP(match_start); 16941 + memcpy(result + result_len, str_ptr, match_start); 16942 + result_len += match_start; 16889 16943 ri += 2; 16890 16944 } else if (next == '\'') { 16891 16945 PCRE2_SIZE after_len = str_len - match_end; 16892 - if (result_len + after_len < sizeof(result)) { 16893 - memcpy(result + result_len, str_ptr + match_end, after_len); 16894 - result_len += (jsoff_t)after_len; 16895 - } 16946 + ENSURE_RESULT_CAP(after_len); 16947 + memcpy(result + result_len, str_ptr + match_end, after_len); 16948 + result_len += after_len; 16896 16949 ri += 2; 16897 16950 } else if (next >= '0' && next <= '9') { 16898 16951 int group_num = next - '0'; ··· 16910 16963 PCRE2_SIZE cap_end = ovector[2*group_num+1]; 16911 16964 if (cap_start != PCRE2_UNSET) { 16912 16965 PCRE2_SIZE cap_len = cap_end - cap_start; 16913 - if (result_len + cap_len < sizeof(result)) { 16914 - memcpy(result + result_len, str_ptr + cap_start, cap_len); 16915 - result_len += (jsoff_t)cap_len; 16916 - } 16966 + ENSURE_RESULT_CAP(cap_len); 16967 + memcpy(result + result_len, str_ptr + cap_start, cap_len); 16968 + result_len += cap_len; 16917 16969 } 16918 16970 } else { 16971 + ENSURE_RESULT_CAP(2); 16919 16972 result[result_len++] = '$'; 16920 - if (result_len < sizeof(result)) result[result_len++] = next; 16973 + result[result_len++] = next; 16921 16974 } 16922 16975 } else { 16976 + ENSURE_RESULT_CAP(1); 16923 16977 result[result_len++] = repl_ptr[ri++]; 16924 16978 } 16925 16979 } else { 16980 + ENSURE_RESULT_CAP(1); 16926 16981 result[result_len++] = repl_ptr[ri++]; 16927 16982 } 16928 16983 } 16929 16984 } 16930 16985 16931 16986 if (match_start == match_end) { 16932 - if (pos < str_len && result_len < sizeof(result)) { 16987 + if (pos < str_len) { 16988 + ENSURE_RESULT_CAP(1); 16933 16989 result[result_len++] = str_ptr[pos]; 16934 16990 } 16935 16991 pos = match_end + 1; 16936 - } else { 16937 - pos = match_end; 16938 - } 16992 + } else pos = match_end; 16939 16993 16940 16994 replaced = true; 16941 16995 if (!global_flag) break; 16942 16996 } 16943 16997 16944 - if (pos < str_len && result_len + (str_len - pos) < sizeof(result)) { 16945 - memcpy(result + result_len, str_ptr + pos, str_len - pos); 16946 - result_len += (jsoff_t)(str_len - pos); 16998 + if (pos < str_len) { 16999 + size_t remaining = str_len - pos; 17000 + ENSURE_RESULT_CAP(remaining); 17001 + memcpy(result + result_len, str_ptr + pos, remaining); 17002 + result_len += remaining; 16947 17003 } 16948 17004 16949 17005 pcre2_match_data_free(match_data); 16950 17006 pcre2_code_free(re); 16951 - return replaced ? js_mkstr(js, result, result_len) : str; 17007 + jsval_t ret = replaced ? js_mkstr(js, result, result_len) : str; 17008 + ANT_GC_FREE(result); 17009 + return ret; 16952 17010 16953 17011 } else { 16954 - if (vtype(search) != T_STR) return str; 17012 + if (vtype(search) != T_STR) { ANT_GC_FREE(result); return str; } 16955 17013 jsoff_t search_len, search_off = vstr(js, search, &search_len); 16956 17014 const char *search_ptr = (char *) &js->mem[search_off]; 16957 17015 16958 - if (search_len > str_len) return str; 17016 + if (search_len > str_len) { ANT_GC_FREE(result); return str; } 16959 17017 16960 17018 for (jsoff_t i = 0; i <= str_len - search_len; i++) { 16961 17019 if (memcmp(str_ptr + i, search_ptr, search_len) == 0) { 16962 - if (result_len + i < sizeof(result)) { 16963 - memcpy(result + result_len, str_ptr, i); 16964 - result_len += i; 16965 - } 17020 + ENSURE_RESULT_CAP(i); 17021 + memcpy(result + result_len, str_ptr, i); 17022 + result_len += i; 16966 17023 16967 17024 if (is_func_replacement) { 16968 17025 jsval_t match_str = js_mkstr(js, search_ptr, search_len); 16969 17026 jsval_t cb_args[1] = { match_str }; 16970 17027 jsval_t cb_result = js_call(js, replacement, cb_args, 1); 16971 17028 16972 - if (vtype(cb_result) == T_ERR) return cb_result; 17029 + if (vtype(cb_result) == T_ERR) { ANT_GC_FREE(result); return cb_result; } 16973 17030 16974 17031 if (vtype(cb_result) == T_STR) { 16975 17032 jsoff_t cb_len, cb_off = vstr(js, cb_result, &cb_len); 16976 - if (result_len + cb_len < sizeof(result)) { 16977 - memcpy(result + result_len, &js->mem[cb_off], cb_len); 16978 - result_len += cb_len; 16979 - } 17033 + ENSURE_RESULT_CAP(cb_len); 17034 + memcpy(result + result_len, &js->mem[cb_off], cb_len); 17035 + result_len += cb_len; 16980 17036 } else { 16981 17037 char numbuf[32]; 16982 17038 size_t n = tostr(js, cb_result, numbuf, sizeof(numbuf)); 16983 - if (result_len + n < sizeof(result)) { 16984 - memcpy(result + result_len, numbuf, n); 16985 - result_len += (jsoff_t)n; 16986 - } 17039 + ENSURE_RESULT_CAP(n); 17040 + memcpy(result + result_len, numbuf, n); 17041 + result_len += n; 16987 17042 } 16988 17043 } else { 16989 - if (result_len + repl_len < sizeof(result)) { 16990 - memcpy(result + result_len, repl_ptr, repl_len); 16991 - result_len += repl_len; 16992 - } 17044 + ENSURE_RESULT_CAP(repl_len); 17045 + memcpy(result + result_len, repl_ptr, repl_len); 17046 + result_len += repl_len; 16993 17047 } 16994 17048 16995 17049 jsoff_t after_start = i + search_len; 16996 17050 jsoff_t after_len = str_len - after_start; 16997 - if (after_len > 0 && result_len + after_len < sizeof(result)) { 17051 + if (after_len > 0) { 17052 + ENSURE_RESULT_CAP(after_len); 16998 17053 memcpy(result + result_len, str_ptr + after_start, after_len); 16999 17054 result_len += after_len; 17000 17055 } 17001 - return js_mkstr(js, result, result_len); 17056 + jsval_t ret = js_mkstr(js, result, result_len); 17057 + ANT_GC_FREE(result); 17058 + return ret; 17002 17059 } 17003 17060 } 17061 + ANT_GC_FREE(result); 17004 17062 return str; 17005 17063 } 17064 + #undef ENSURE_RESULT_CAP 17006 17065 } 17007 17066 17008 17067 static jsval_t builtin_string_replaceAll(struct js *js, jsval_t *args, int nargs) { ··· 17273 17332 jsoff_t str_len, str_off = vstr(js, str, &str_len); 17274 17333 const char *str_ptr = (char *) &js->mem[str_off]; 17275 17334 17276 - char result[2048]; 17277 - jsoff_t result_len = 0; 17335 + size_t result_cap = str_len + 256; 17336 + size_t result_len = 0; 17337 + char *result = (char *)ANT_GC_MALLOC(result_cap); 17338 + if (!result) return js_mkerr(js, "oom"); 17278 17339 jsoff_t i = 0; 17340 + 17341 + #define ENSURE_CAP(need) do { \ 17342 + if (result_len + (need) >= result_cap) { \ 17343 + result_cap = (result_len + (need) + 1) * 2; \ 17344 + char *nr = (char *)ANT_GC_REALLOC(result, result_cap); \ 17345 + if (!nr) return js_mkerr(js, "oom"); \ 17346 + result = nr; \ 17347 + } \ 17348 + } while(0) 17279 17349 17280 - while (i < str_len && result_len < sizeof(result) - 1) { 17350 + while (i < str_len) { 17281 17351 if (i < str_len - 3 && str_ptr[i] == '{' && str_ptr[i + 1] == '{') { 17282 17352 jsoff_t start = i + 2; 17283 17353 jsoff_t end = start; ··· 17292 17362 jsval_t value = resolveprop(js, mkval(T_PROP, prop_off)); 17293 17363 if (vtype(value) == T_STR) { 17294 17364 jsoff_t val_len, val_off = vstr(js, value, &val_len); 17295 - if (result_len + val_len < sizeof(result)) { 17296 - memcpy(result + result_len, &js->mem[val_off], val_len); 17297 - result_len += val_len; 17298 - } 17365 + ENSURE_CAP(val_len); 17366 + memcpy(result + result_len, &js->mem[val_off], val_len); 17367 + result_len += val_len; 17299 17368 } else if (vtype(value) == T_NUM) { 17300 17369 char numstr[32]; 17301 17370 snprintf(numstr, sizeof(numstr), "%g", tod(value)); 17302 17371 size_t num_len = strlen(numstr); 17303 - if (result_len + num_len < sizeof(result)) { 17304 - memcpy(result + result_len, numstr, num_len); 17305 - result_len += num_len; 17306 - } 17372 + ENSURE_CAP(num_len); 17373 + memcpy(result + result_len, numstr, num_len); 17374 + result_len += num_len; 17307 17375 } else if (vtype(value) == T_BOOL) { 17308 17376 const char *boolstr = vdata(value) ? "true" : "false"; 17309 17377 size_t bool_len = strlen(boolstr); 17310 - if (result_len + bool_len < sizeof(result)) { 17311 - memcpy(result + result_len, boolstr, bool_len); 17312 - result_len += bool_len; 17313 - } 17378 + ENSURE_CAP(bool_len); 17379 + memcpy(result + result_len, boolstr, bool_len); 17380 + result_len += bool_len; 17314 17381 } 17315 - } else { 17316 17382 } 17317 17383 i = end + 2; 17318 17384 continue; 17319 17385 } 17320 17386 } 17387 + ENSURE_CAP(1); 17321 17388 result[result_len++] = str_ptr[i++]; 17322 17389 } 17323 - return js_mkstr(js, result, result_len); 17390 + jsval_t ret = js_mkstr(js, result, result_len); 17391 + ANT_GC_FREE(result); 17392 + return ret; 17393 + #undef ENSURE_CAP 17324 17394 } 17325 17395 17326 17396 static jsval_t builtin_string_charCodeAt(struct js *js, jsval_t *args, int nargs) {
-39
tests/mandelbrot.js
··· 1 - /* Mandelbrot display on a color terminal 2 - (c) 2025 Fabrice Bellard 3 - MIT license 4 - */ 5 - function mandelbrot(center_x, center_y, scale, w, h, max_it) 6 - { 7 - var x1, y1, y2, i, x, y, cx, cy, fx, fy, i, t, c, s, c0; 8 - var colors = [ 14, 15, 7, 8, 0, 4, 12, 5, 13, 1, 9, 3, 11, 10, 2, 6]; 9 - fx = scale * 0.5 / Math.min(w, h); 10 - fy = fx * 2; 11 - for(y1 = 0; y1 < h; y1++) { 12 - s = ""; 13 - for(x1 = 0; x1 < w; x1++) { 14 - for(y2 = 0; y2 < 2; y2++) { 15 - cx = (x1 - w * 0.5) * fx + center_x; 16 - cy = (y1 + y2 * 0.5 - h * 0.5) * fy + center_y; 17 - x = 0; 18 - y = 0; 19 - for(i = 0; i < max_it && x * x + y * y < 4; i++) { 20 - t = x * x - y * y + cx; 21 - y = 2 * x * y + cy; 22 - x = t; 23 - } 24 - if (i >= max_it) { 25 - c = 0; 26 - } else { 27 - c = colors[i % colors.length]; 28 - } 29 - if (y2 == 0) 30 - c0 = c; 31 - } 32 - s += "\x1b[" + (c0 >= 8 ? 82 + c0 : 30 + c0) + ";" + (c >= 8 ? 92 + c : 40 + c) + "m\u2580"; 33 - } 34 - s += "\x1b[0m"; /* reset the colors */ 35 - console.log(s); 36 - } 37 - } 38 - 39 - mandelbrot(-0.75, 0.0, 2.0, 80, 25, 50);