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 NaN and Infinity

+220 -25
+4 -2
meson.build
··· 1 1 project('ant', 'c', default_options: [ 2 2 'optimization=2', 3 - 'c_std=c23', 3 + 'c_std=c11', 4 4 'default_library=static' 5 5 ]) 6 6 ··· 40 40 tlsuv_opts.add_cmake_defines({'BUILD_TESTING': 'OFF'}) 41 41 tlsuv_dep = cmake.subproject('tlsuv', options: tlsuv_opts).dependency('tlsuv') 42 42 43 + bdwgc_dep = subproject('bdwgc').get_variable('bdwgc_dep') 43 44 uthash_dep = subproject('uthash').get_variable('uthash_dep') 44 45 yyjson_dep = subproject('yyjson').get_variable('yyjson_dep') 45 46 uuidv7_dep = subproject('uuidv7').get_variable('uuidv7_dep') ··· 67 68 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 68 69 69 70 version_conf = configuration_data() 70 - version_conf.set('ANT_VERSION', '0.0.6.40') 71 + version_conf.set('ANT_VERSION', '0.0.6.41') 71 72 version_conf.set('ANT_GIT_HASH', git_hash) 72 73 version_conf.set('ANT_BUILD_DATE', build_date) 73 74 ··· 104 105 ) 105 106 106 107 ant_deps = [ 108 + bdwgc_dep, 107 109 llhttp, mongoose_dep, 108 110 libuv_dep, argtable3_dep, 109 111 tlsuv_dep, libsodium_dep,
+100 -21
src/ant.c
··· 202 202 203 203 static jsval_t tov(double d) { union { double d; jsval_t v; } u = {d}; return u.v; } 204 204 static double tod(jsval_t v) { union { jsval_t v; double d; } u = {v}; return u.d; } 205 - static jsval_t mkval(uint8_t type, uint64_t data) { return ((jsval_t) 0x7ff0U << 48U) | ((jsval_t) (type) << 48) | (data & 0xffffffffffffUL); } 206 - static bool is_nan(jsval_t v) { return (v >> 52U) == 0x7ffU; } 205 + static jsval_t mkval(uint8_t type, uint64_t data) { return ((jsval_t) 0x7fe0U << 48U) | ((jsval_t) (type) << 48) | (data & 0xffffffffffffUL); } 206 + static bool is_nan(jsval_t v) { return (v >> 52U) == 0x7feU; } 207 207 static uint8_t vtype(jsval_t v) { return is_nan(v) ? ((v >> 48U) & 15U) : (uint8_t) T_NUM; } 208 208 static size_t vdata(jsval_t v) { return (size_t) (v & ~((jsval_t) 0x7fffUL << 48U)); } 209 209 static jsval_t mkcoderef(jsval_t off, jsoff_t len) { return mkval(T_CODEREF, (off & 0xffffffU) | ((jsval_t)(len & 0xffffffU) << 24U)); } ··· 741 741 static size_t strnum(jsval_t value, char *buf, size_t len) { 742 742 double dv = tod(value), iv; 743 743 double frac = modf(dv, &iv); 744 + 745 + if (isnan(dv)) return cpy(buf, len, "NaN", 3); 746 + if (isinf(dv)) return cpy(buf, len, dv > 0 ? "Infinity" : "-Infinity", dv > 0 ? 8 : 9); 744 747 745 748 if (dv >= -9007199254740991.0 && dv <= 9007199254740991.0) { 746 749 if (frac == 0.0) { ··· 2242 2245 return do_string_op(js, op, l_str, r_str); 2243 2246 } 2244 2247 if (vtype(l) == T_STR && vtype(r) == T_STR) return do_string_op(js, op, l, r); 2245 - if (is_unary(op) && vtype(r) != T_NUM) return js_mkerr(js, "type mismatch"); 2246 - if (!is_unary(op) && op != TOK_DOT && op != TOK_OPTIONAL_CHAIN && op != TOK_INSTANCEOF && (vtype(l) != T_NUM || vtype(r) != T_NUM)) return js_mkerr(js, "type mismatch"); 2248 + 2249 + double a = 0.0, b = 0.0; 2250 + 2251 + if (vtype(l) == T_NUM) { 2252 + a = tod(l); 2253 + } else if (vtype(l) == T_STR) { 2254 + jsoff_t slen, off = vstr(js, l, &slen); 2255 + char *endptr; 2256 + char temp[256]; 2257 + size_t copy_len = slen < sizeof(temp) - 1 ? slen : sizeof(temp) - 1; 2258 + memcpy(temp, &js->mem[off], copy_len); 2259 + temp[copy_len] = '\0'; 2260 + a = strtod(temp, &endptr); 2261 + if (endptr == temp || *endptr != '\0') a = NAN; 2262 + } else if (vtype(l) == T_BOOL) { 2263 + a = vdata(l) ? 1.0 : 0.0; 2264 + } else if (vtype(l) == T_NULL) { 2265 + a = 0.0; 2266 + } else if (vtype(l) == T_UNDEF) { 2267 + a = NAN; 2268 + } else { 2269 + a = NAN; 2270 + } 2271 + 2272 + if (vtype(r) == T_NUM) { 2273 + b = tod(r); 2274 + } else if (vtype(r) == T_STR) { 2275 + jsoff_t slen, off = vstr(js, r, &slen); 2276 + char *endptr; 2277 + char temp[256]; 2278 + size_t copy_len = slen < sizeof(temp) - 1 ? slen : sizeof(temp) - 1; 2279 + memcpy(temp, &js->mem[off], copy_len); 2280 + temp[copy_len] = '\0'; 2281 + b = strtod(temp, &endptr); 2282 + if (endptr == temp || *endptr != '\0') b = NAN; 2283 + } else if (vtype(r) == T_BOOL) { 2284 + b = vdata(r) ? 1.0 : 0.0; 2285 + } else if (vtype(r) == T_NULL) { 2286 + b = 0.0; 2287 + } else if (vtype(r) == T_UNDEF) { 2288 + b = NAN; 2289 + } else { 2290 + b = NAN; 2291 + } 2247 2292 2248 - double a = tod(l), b = tod(r); 2249 2293 switch (op) { 2250 - case TOK_DIV: return tod(r) == 0 ? js_mkerr(js, "div by zero") : tov(a / b); 2294 + case TOK_DIV: return tov(a / b); 2251 2295 case TOK_REM: return tov(a - b * ((double) (long) (a / b))); 2252 2296 case TOK_MUL: return tov(a * b); 2253 2297 case TOK_PLUS: return tov(a + b); ··· 5017 5061 return js_mkstr(js, str, strlen(str)); 5018 5062 } 5019 5063 5064 + static jsval_t builtin_Number_isNaN(struct js *js, jsval_t *args, int nargs) { 5065 + if (nargs == 0) return mkval(T_BOOL, 0); 5066 + jsval_t arg = args[0]; 5067 + 5068 + if (vtype(arg) != T_NUM) return mkval(T_BOOL, 0); 5069 + 5070 + double val = tod(arg); 5071 + return mkval(T_BOOL, isnan(val) ? 1 : 0); 5072 + } 5073 + 5074 + static jsval_t builtin_Number_isFinite(struct js *js, jsval_t *args, int nargs) { 5075 + if (nargs == 0) return mkval(T_BOOL, 0); 5076 + jsval_t arg = args[0]; 5077 + 5078 + if (vtype(arg) != T_NUM) return mkval(T_BOOL, 0); 5079 + 5080 + double val = tod(arg); 5081 + return mkval(T_BOOL, isfinite(val) ? 1 : 0); 5082 + } 5083 + 5020 5084 static jsval_t builtin_Number(struct js *js, jsval_t *args, int nargs) { 5021 5085 if (nargs == 0) return tov(0.0); 5022 5086 jsval_t arg = args[0]; ··· 5473 5537 const char *sep = ","; 5474 5538 jsoff_t sep_len = 1; 5475 5539 5476 - if (nargs >= 1 && vtype(args[0]) == T_STR) { 5477 - sep_len = 0; 5478 - jsoff_t sep_off = vstr(js, args[0], &sep_len); 5479 - sep = (const char *) &js->mem[sep_off]; 5540 + if (nargs >= 1) { 5541 + if (vtype(args[0]) == T_STR) { 5542 + sep_len = 0; 5543 + jsoff_t sep_off = vstr(js, args[0], &sep_len); 5544 + sep = (const char *) &js->mem[sep_off]; 5545 + } else if (vtype(args[0]) != T_UNDEF) { 5546 + const char *sep_str = js_str(js, args[0]); 5547 + sep = sep_str; 5548 + sep_len = (jsoff_t) strlen(sep_str); 5549 + } 5480 5550 } 5481 5551 5482 5552 jsoff_t off = lkp(js, arr, "length", 6); ··· 6012 6082 static jsval_t builtin_string_charCodeAt(struct js *js, jsval_t *args, int nargs) { 6013 6083 jsval_t str = js->this_val; 6014 6084 if (vtype(str) != T_STR) return js_mkerr(js, "charCodeAt called on non-string"); 6015 - if (nargs < 1 || vtype(args[0]) != T_NUM) return tov(NAN); 6085 + if (nargs < 1 || vtype(args[0]) != T_NUM) return tov(-NAN); 6016 6086 6017 6087 double idx_d = tod(args[0]); 6018 - if (idx_d < 0 || idx_d != (double)(long)idx_d) return tov(NAN); 6088 + if (idx_d < 0 || idx_d != (double)(long)idx_d) return tov(-NAN); 6019 6089 6020 6090 jsoff_t idx = (jsoff_t) idx_d; 6021 6091 jsoff_t str_len = offtolen(loadoff(js, (jsoff_t) vdata(str))); 6022 6092 6023 - if (idx >= str_len) return tov(NAN); 6093 + if (idx >= str_len) return tov(-NAN); 6024 6094 6025 6095 jsoff_t str_off = (jsoff_t) vdata(str) + sizeof(jsoff_t); 6026 6096 unsigned char ch = (unsigned char) js->mem[str_off + idx]; ··· 6270 6340 } 6271 6341 6272 6342 static jsval_t builtin_parseInt(struct js *js, jsval_t *args, int nargs) { 6273 - if (nargs < 1) return tov(NAN); 6343 + if (nargs < 1) return tov(-NAN); 6274 6344 6275 6345 jsval_t str_val = args[0]; 6276 6346 if (vtype(str_val) != T_STR) { ··· 6284 6354 int radix = 10; 6285 6355 if (nargs >= 2 && vtype(args[1]) == T_NUM) { 6286 6356 radix = (int) tod(args[1]); 6287 - if (radix < 2 || radix > 36) return tov(NAN); 6357 + if (radix < 2 || radix > 36) return tov(-NAN); 6288 6358 } 6289 6359 6290 6360 jsoff_t i = 0; 6291 6361 while (i < str_len && is_space(str[i])) i++; 6292 6362 6293 - if (i >= str_len) return tov(NAN); 6363 + if (i >= str_len) return tov(-NAN); 6294 6364 6295 6365 int sign = 1; 6296 6366 if (str[i] == '-') { ··· 6326 6396 i++; 6327 6397 } 6328 6398 6329 - if (!found_digit) return tov(NAN); 6399 + if (!found_digit) return tov(-NAN); 6330 6400 6331 6401 return tov(sign * result); 6332 6402 } 6333 6403 6334 6404 static jsval_t builtin_parseFloat(struct js *js, jsval_t *args, int nargs) { 6335 - if (nargs < 1) return tov(NAN); 6405 + if (nargs < 1) return tov(-NAN); 6336 6406 6337 6407 jsval_t str_val = args[0]; 6338 6408 if (vtype(str_val) != T_STR) { ··· 6346 6416 jsoff_t i = 0; 6347 6417 while (i < str_len && is_space(str[i])) i++; 6348 6418 6349 - if (i >= str_len) return tov(NAN); 6419 + if (i >= str_len) return tov(-NAN); 6350 6420 6351 6421 char *end; 6352 6422 double result = strtod(&str[i], &end); 6353 6423 6354 - if (end == &str[i]) return tov(NAN); 6424 + if (end == &str[i]) return tov(-NAN); 6355 6425 6356 6426 return tov(result); 6357 6427 } ··· 7715 7785 setprop(js, glob, js_mkstr(js, "eval", 4), js_mkfun(builtin_eval)); 7716 7786 setprop(js, glob, js_mkstr(js, "Function", 8), js_mkfun(builtin_Function)); 7717 7787 setprop(js, glob, js_mkstr(js, "String", 6), js_mkfun(builtin_String)); 7718 - setprop(js, glob, js_mkstr(js, "Number", 6), js_mkfun(builtin_Number)); 7788 + 7789 + jsval_t number_ctor_obj = mkobj(js, 0); 7790 + setprop(js, number_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Number)); 7791 + setprop(js, number_ctor_obj, js_mkstr(js, "isNaN", 5), js_mkfun(builtin_Number_isNaN)); 7792 + setprop(js, number_ctor_obj, js_mkstr(js, "isFinite", 8), js_mkfun(builtin_Number_isFinite)); 7793 + setprop(js, glob, js_mkstr(js, "Number", 6), mkval(T_FUNC, vdata(number_ctor_obj))); 7794 + 7719 7795 setprop(js, glob, js_mkstr(js, "Boolean", 7), js_mkfun(builtin_Boolean)); 7720 7796 setprop(js, glob, js_mkstr(js, "Array", 5), js_mkfun(builtin_Array)); 7721 7797 setprop(js, glob, js_mkstr(js, "Error", 5), js_mkfun(builtin_Error)); 7722 7798 setprop(js, glob, js_mkstr(js, "RegExp", 6), js_mkfun(builtin_RegExp)); 7723 7799 setprop(js, glob, js_mkstr(js, "parseInt", 8), js_mkfun(builtin_parseInt)); 7724 7800 setprop(js, glob, js_mkstr(js, "parseFloat", 10), js_mkfun(builtin_parseFloat)); 7801 + 7802 + setprop(js, glob, js_mkstr(js, "NaN", 3), tov(NAN)); 7803 + setprop(js, glob, js_mkstr(js, "Infinity", 8), tov(INFINITY)); 7725 7804 7726 7805 jsval_t date_ctor_obj = mkobj(js, 0); 7727 7806 setprop(js, date_ctor_obj, js_mkstr(js, "__native_func", 13), js_mkfun(builtin_Date));
+2 -2
src/modules/fetch.c
··· 68 68 js_set(js, json_obj, "__code", json_str); 69 69 jsval_t json_func = js_mknum(0); 70 70 memcpy(&json_func, &json_obj, sizeof(jsval_t)); 71 - json_func = (json_func & 0xFFFFFFFFFFFFULL) | (0x7FF0000000000000ULL | ((uint64_t)7 << 48)); 71 + json_func = (json_func & 0xFFFFFFFFFFFFULL) | (0x7FE0000000000000ULL | ((uint64_t)7 << 48)); 72 72 js_set(js, response_obj, "json", json_func); 73 73 74 74 return response_obj; ··· 304 304 305 305 jsval_t wrapper_func = js_mknum(0); 306 306 memcpy(&wrapper_func, &wrapper_obj, sizeof(jsval_t)); 307 - wrapper_func = (wrapper_func & 0xFFFFFFFFFFFFULL) | (0x7FF0000000000000ULL | ((uint64_t)7 << 48)); 307 + wrapper_func = (wrapper_func & 0xFFFFFFFFFFFFULL) | (0x7FE0000000000000ULL | ((uint64_t)7 << 48)); 308 308 queue_microtask(js, wrapper_func); 309 309 310 310 return promise;
+13
subprojects/bdwgc.wrap
··· 1 + [wrap-file] 2 + directory = gc-8.2.10 3 + source_url = https://github.com/bdwgc/bdwgc/releases/download/v8.2.10/gc-8.2.10.tar.gz 4 + source_filename = gc-8.2.10.tar.gz 5 + source_hash = 832cf4f7cf676b59582ed3b1bbd90a8d0e0ddbc3b11cb3b2096c5177ce39cc47 6 + source_fallback_url = https://github.com/mesonbuild/wrapdb/releases/download/bdwgc_8.2.10-1/gc-8.2.10.tar.gz 7 + patch_filename = bdwgc_8.2.10-1_patch.zip 8 + patch_url = https://wrapdb.mesonbuild.com/v2/bdwgc_8.2.10-1/get_patch 9 + patch_hash = 6e789989cb6c96738bb896f6167c1b6cb976a4734fc191e7fd84896a2966ab97 10 + wrapdb_version = 8.2.10-1 11 + 12 + [provide] 13 + dependency_names = bdw-gc
+22
test_minimal.cjs
··· 1 + console.log('Testing recursive string assignment with objects'); 2 + 3 + function testRecursion(depth, params) { 4 + if (depth >= 10) return 'done'; 5 + 6 + let paramValue = ''; 7 + // This assignment causes parser corruption in certain contexts 8 + paramValue = 'test'; 9 + 10 + if (paramValue !== '') { 11 + params['test' + depth] = paramValue; 12 + const result = testRecursion(depth + 1, params); 13 + delete params['test' + depth]; 14 + return result; 15 + } 16 + 17 + return 'failed'; 18 + } 19 + 20 + const params = {}; 21 + const result = testRecursion(0, params); 22 + console.log('Result:', result);
+79
tests/test_nan_infinity.cjs
··· 1 + // Test NaN and Infinity values 2 + console.log('=== NaN Tests ==='); 3 + 4 + // Basic NaN value 5 + console.log('NaN:', NaN); 6 + console.log('typeof NaN:', typeof NaN); 7 + 8 + // Type coercion resulting in NaN 9 + console.log('"wat" - 1:', "wat" - 1); 10 + console.log('"hello" * 2:', "hello" * 2); 11 + console.log('undefined + 5:', undefined + 5); 12 + console.log('10 / "abc":', 10 / "abc"); 13 + console.log('0/0:', 0/0); 14 + 15 + // Valid string to number coercion 16 + console.log('"5" - 2:', "5" - 2); 17 + console.log('"10" * 2:', "10" * 2); 18 + 19 + // Boolean and null coercion 20 + console.log('true + 1:', true + 1); 21 + console.log('false + 1:', false + 1); 22 + console.log('null + 5:', null + 5); 23 + 24 + // NaN properties 25 + console.log('NaN === NaN:', NaN === NaN); // Should be false 26 + console.log('NaN !== NaN:', NaN !== NaN); // Should be true 27 + 28 + // Number.isNaN tests 29 + console.log('\n=== Number.isNaN Tests ==='); 30 + console.log('Number.isNaN(NaN):', Number.isNaN(NaN)); 31 + console.log('Number.isNaN("wat" - 1):', Number.isNaN("wat" - 1)); 32 + console.log('Number.isNaN(123):', Number.isNaN(123)); 33 + console.log('Number.isNaN("hello"):', Number.isNaN("hello")); // Should be false (not a number type) 34 + console.log('Number.isNaN(undefined):', Number.isNaN(undefined)); // Should be false 35 + console.log('Number.isNaN(null):', Number.isNaN(null)); // Should be false 36 + 37 + // parseInt/parseFloat with invalid input 38 + console.log('\n=== parseInt/parseFloat NaN ==='); 39 + console.log('parseInt("notanumber"):', parseInt("notanumber")); 40 + console.log('parseInt("123abc"):', parseInt("123abc")); 41 + console.log('parseFloat("xyz"):', parseFloat("xyz")); 42 + 43 + // Infinity tests 44 + console.log('\n=== Infinity Tests ==='); 45 + console.log('Infinity:', Infinity); 46 + console.log('typeof Infinity:', typeof Infinity); 47 + console.log('1/0:', 1/0); 48 + console.log('-1/0:', -1/0); 49 + 50 + // Number.isFinite tests 51 + console.log('\n=== Number.isFinite Tests ==='); 52 + console.log('Number.isFinite(123):', Number.isFinite(123)); 53 + console.log('Number.isFinite(1/0):', Number.isFinite(1/0)); 54 + console.log('Number.isFinite(-1/0):', Number.isFinite(-1/0)); 55 + console.log('Number.isFinite(NaN):', Number.isFinite(NaN)); 56 + console.log('Number.isFinite(Infinity):', Number.isFinite(Infinity)); 57 + console.log('Number.isFinite("123"):', Number.isFinite("123")); // Should be false (not a number type) 58 + 59 + // Array.join with NaN 60 + console.log('\n=== Array.join with NaN ==='); 61 + console.log('[1,2,3].join(NaN):', [1,2,3].join(NaN)); 62 + console.log('[1,2,3].join(0/0):', [1,2,3].join(0/0)); 63 + console.log('Array(16).join("wat" - 1) + " Batman!":', Array(16).join("wat" - 1) + " Batman!"); 64 + 65 + // String operations with NaN 66 + console.log('\n=== String operations ==='); 67 + console.log('"Result: " + NaN:', "Result: " + NaN); 68 + console.log('"Value: " + (0/0):', "Value: " + (0/0)); 69 + 70 + // Arithmetic with Infinity 71 + console.log('\n=== Arithmetic with Infinity ==='); 72 + console.log('Infinity + 1:', Infinity + 1); 73 + console.log('Infinity - 1:', Infinity - 1); 74 + console.log('Infinity * 2:', Infinity * 2); 75 + console.log('Infinity / 2:', Infinity / 2); 76 + console.log('Infinity - Infinity:', Infinity - Infinity); 77 + console.log('Infinity * 0:', Infinity * 0); 78 + 79 + console.log('\n=== All tests completed ===');