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.

default params

+420 -14
+1 -1
meson.build
··· 67 67 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 68 68 69 69 version_conf = configuration_data() 70 - version_conf.set('ANT_VERSION', '0.0.6.34') 70 + version_conf.set('ANT_VERSION', '0.0.6.35') 71 71 version_conf.set('ANT_GIT_HASH', git_hash) 72 72 version_conf.set('ANT_BUILD_DATE', build_date) 73 73
+172 -8
src/ant.c
··· 1769 1769 return res; 1770 1770 } 1771 1771 1772 + static jsoff_t extract_default_param_value(const char *fn, jsoff_t fnlen, jsoff_t start_pos, jsoff_t *out_start, jsoff_t *out_len) { 1773 + jsoff_t after_ident = skiptonext(fn, fnlen, start_pos); 1774 + if (after_ident >= fnlen || fn[after_ident] != '=') { 1775 + *out_start = 0; 1776 + *out_len = 0; 1777 + return after_ident; 1778 + } 1779 + 1780 + jsoff_t default_start = skiptonext(fn, fnlen, after_ident + 1); 1781 + jsoff_t default_len = 0; 1782 + jsoff_t depth = 0; 1783 + bool in_string = false; 1784 + char string_char = 0; 1785 + 1786 + for (jsoff_t i = default_start; i < fnlen; i++) { 1787 + if (in_string) { 1788 + if (fn[i] == '\\' && i + 1 < fnlen) { 1789 + default_len += 2; 1790 + i++; 1791 + continue; 1792 + } 1793 + if (fn[i] == string_char) { 1794 + in_string = false; 1795 + } 1796 + default_len++; 1797 + } else { 1798 + if (fn[i] == '"' || fn[i] == '\'' || fn[i] == '`') { 1799 + in_string = true; 1800 + string_char = fn[i]; 1801 + default_len++; 1802 + } else if (fn[i] == '(' || fn[i] == '[' || fn[i] == '{') { 1803 + depth++; 1804 + default_len++; 1805 + } else if (fn[i] == ')' || fn[i] == ']' || fn[i] == '}') { 1806 + if (depth == 0 && fn[i] == ')') break; 1807 + depth--; 1808 + default_len++; 1809 + } else if (depth == 0 && fn[i] == ',') { 1810 + break; 1811 + } else { 1812 + default_len++; 1813 + } 1814 + } 1815 + } 1816 + 1817 + *out_start = default_start; 1818 + *out_len = default_len; 1819 + return skiptonext(fn, fnlen, default_start + default_len); 1820 + } 1821 + 1772 1822 static jsval_t call_js(struct js *js, const char *fn, jsoff_t fnlen, jsval_t closure_scope) { 1773 1823 jsoff_t fnpos = 1; 1774 1824 jsval_t saved_scope = js->scope; ··· 1808 1858 break; 1809 1859 } 1810 1860 1861 + jsoff_t param_name_pos = fnpos; 1862 + jsoff_t default_start = 0, default_len = 0; 1863 + fnpos = extract_default_param_value(fn, fnlen, fnpos + identlen, &default_start, &default_len); 1864 + 1811 1865 js->pos = skiptonext(js->code, js->clen, js->pos); 1812 1866 js->consumed = 1; 1813 - jsval_t v = js->code[js->pos] == ')' ? js_mkundef() : js_expr(js); 1814 - setprop(js, function_scope, js_mkstr(js, &fn[fnpos], identlen), v); 1867 + jsval_t v; 1868 + if (js->code[js->pos] == ')' || js->code[js->pos] == ',') { 1869 + if (default_len > 0) { 1870 + const char *saved_code = js->code; 1871 + jsoff_t saved_clen = js->clen, saved_pos = js->pos; 1872 + js->code = &fn[default_start]; 1873 + js->clen = default_len; 1874 + js->pos = 0; 1875 + js->consumed = 1; 1876 + v = js_expr(js); 1877 + js->code = saved_code; 1878 + js->clen = saved_clen; 1879 + js->pos = saved_pos; 1880 + } else { 1881 + v = js_mkundef(); 1882 + } 1883 + } else { 1884 + v = js_expr(js); 1885 + } 1886 + setprop(js, function_scope, js_mkstr(js, &fn[param_name_pos], identlen), v); 1815 1887 js->pos = skiptonext(js->code, js->clen, js->pos); 1816 1888 if (js->pos < js->clen && js->code[js->pos] == ',') js->pos++; 1817 - fnpos = skiptonext(fn, fnlen, fnpos + identlen); 1818 1889 if (fnpos < fnlen && fn[fnpos] == ',') fnpos++; 1819 1890 } 1820 1891 ··· 1936 2007 break; 1937 2008 } 1938 2009 1939 - jsval_t v = arg_idx < nargs ? args[arg_idx] : js_mkundef(); 1940 - setprop(js, function_scope, js_mkstr(js, &fn[fnpos], identlen), v); 2010 + jsoff_t param_name_pos = fnpos; 2011 + jsoff_t default_start = 0, default_len = 0; 2012 + fnpos = extract_default_param_value(fn, fnlen, fnpos + identlen, &default_start, &default_len); 2013 + 2014 + jsval_t v; 2015 + if (arg_idx < nargs) { 2016 + v = args[arg_idx]; 2017 + } else if (default_len > 0) { 2018 + const char *saved_code = js->code; 2019 + jsoff_t saved_clen = js->clen, saved_pos = js->pos; 2020 + uint8_t saved_consumed = js->consumed; 2021 + js->code = &fn[default_start]; 2022 + js->clen = default_len; 2023 + js->pos = 0; 2024 + js->consumed = 1; 2025 + v = js_expr(js); 2026 + js->code = saved_code; 2027 + js->clen = saved_clen; 2028 + js->pos = saved_pos; 2029 + js->consumed = saved_consumed; 2030 + } else { 2031 + v = js_mkundef(); 2032 + } 2033 + setprop(js, function_scope, js_mkstr(js, &fn[param_name_pos], identlen), v); 1941 2034 arg_idx++; 1942 - fnpos = skiptonext(fn, fnlen, fnpos + identlen); 1943 2035 if (fnpos < fnlen && fn[fnpos] == ',') fnpos++; 1944 2036 } 1945 2037 ··· 2533 2625 2534 2626 js->consumed = 1; 2535 2627 2628 + if (next(js) == TOK_ASSIGN) { 2629 + js->consumed = 1; 2630 + int depth = 0; 2631 + bool done = false; 2632 + while (!done && next(js) != TOK_EOF) { 2633 + uint8_t tok = next(js); 2634 + if (depth == 0 && (tok == TOK_RPAREN || tok == TOK_COMMA)) { 2635 + done = true; 2636 + } else if (tok == TOK_LPAREN || tok == TOK_LBRACKET || tok == TOK_LBRACE) { 2637 + depth++; 2638 + js->consumed = 1; 2639 + } else if (tok == TOK_RPAREN || tok == TOK_RBRACKET || tok == TOK_RBRACE) { 2640 + depth--; 2641 + js->consumed = 1; 2642 + } else { 2643 + js->consumed = 1; 2644 + } 2645 + } 2646 + } 2647 + 2536 2648 if (is_rest && next(js) != TOK_RPAREN) { 2537 2649 if (flags) js->flags = *flags; 2538 2650 js_mkerr(js, "rest parameter must be last"); ··· 2894 3006 else if (js->tok == TOK_RPAREN) paren_depth--; 2895 3007 2896 3008 if (paren_depth > 0) { 2897 - if (js->tok != TOK_IDENTIFIER && js->tok != TOK_COMMA && js->tok != TOK_REST) could_be_arrow = false; 3009 + if (js->tok != TOK_IDENTIFIER && js->tok != TOK_COMMA && js->tok != TOK_REST && 3010 + js->tok != TOK_ASSIGN && js->tok != TOK_NUMBER && js->tok != TOK_STRING && 3011 + js->tok != TOK_TRUE && js->tok != TOK_FALSE && js->tok != TOK_NULL && 3012 + js->tok != TOK_UNDEF && js->tok != TOK_LBRACKET && js->tok != TOK_RBRACKET && 3013 + js->tok != TOK_LBRACE && js->tok != TOK_RBRACE && js->tok != TOK_DOT && 3014 + js->tok != TOK_PLUS && js->tok != TOK_MINUS && js->tok != TOK_MUL && js->tok != TOK_DIV) { 3015 + could_be_arrow = false; 3016 + } 2898 3017 } 2899 3018 js->consumed = 1; 2900 3019 } ··· 3530 3649 if (next(js) != TOK_IDENTIFIER) return js_mkerr(js, "identifier expected"); 3531 3650 js->consumed = 1; 3532 3651 3652 + if (next(js) == TOK_ASSIGN) { 3653 + js->consumed = 1; 3654 + int depth = 0; 3655 + bool done = false; 3656 + while (!done && next(js) != TOK_EOF) { 3657 + uint8_t tok = next(js); 3658 + if (depth == 0 && (tok == TOK_RPAREN || tok == TOK_COMMA)) { 3659 + done = true; 3660 + } else if (tok == TOK_LPAREN || tok == TOK_LBRACKET || tok == TOK_LBRACE) { 3661 + depth++; 3662 + js->consumed = 1; 3663 + } else if (tok == TOK_RPAREN || tok == TOK_RBRACKET || tok == TOK_RBRACE) { 3664 + depth--; 3665 + js->consumed = 1; 3666 + } else { 3667 + js->consumed = 1; 3668 + } 3669 + } 3670 + } 3671 + 3533 3672 if (is_rest && next(js) != TOK_RPAREN) { 3534 3673 return js_mkerr(js, "rest parameter must be last"); 3535 3674 } ··· 4577 4716 is_async_method = true; 4578 4717 js->consumed = 1; 4579 4718 } 4580 - EXPECT(TOK_IDENTIFIER, js->flags = save_flags); 4719 + if (next(js) != TOK_IDENTIFIER && (next(js) < TOK_ASYNC || next(js) > TOK_STATIC)) { 4720 + js->flags = save_flags; 4721 + return js_mkerr(js, "method name expected"); 4722 + } 4581 4723 jsoff_t method_name_off = js->toff, method_name_len = js->tlen; 4582 4724 js->consumed = 1; 4583 4725 EXPECT(TOK_LPAREN, js->flags = save_flags); ··· 4585 4727 for (bool comma = false; next(js) != TOK_EOF; comma = true) { 4586 4728 if (!comma && next(js) == TOK_RPAREN) break; 4587 4729 EXPECT(TOK_IDENTIFIER, js->flags = save_flags); 4730 + js->consumed = 1; 4731 + 4732 + if (next(js) == TOK_ASSIGN) { 4733 + js->consumed = 1; 4734 + int depth = 0; 4735 + bool done = false; 4736 + while (!done && next(js) != TOK_EOF) { 4737 + uint8_t tok = next(js); 4738 + if (depth == 0 && (tok == TOK_RPAREN || tok == TOK_COMMA)) { 4739 + done = true; 4740 + } else if (tok == TOK_LPAREN || tok == TOK_LBRACKET || tok == TOK_LBRACE) { 4741 + depth++; 4742 + js->consumed = 1; 4743 + } else if (tok == TOK_RPAREN || tok == TOK_RBRACKET || tok == TOK_RBRACE) { 4744 + depth--; 4745 + js->consumed = 1; 4746 + } else { 4747 + js->consumed = 1; 4748 + } 4749 + } 4750 + } 4751 + 4588 4752 if (next(js) == TOK_RPAREN) break; 4589 4753 EXPECT(TOK_COMMA, js->flags = save_flags); 4590 4754 }
+76 -5
src/modules/server.c
··· 65 65 } 66 66 } 67 67 68 + static const char* get_status_text(int status) { 69 + switch (status) { 70 + case 100: return "Continue"; 71 + case 101: return "Switching Protocols"; 72 + case 102: return "Processing"; 73 + case 103: return "Early Hints"; 74 + 75 + case 200: return "OK"; 76 + case 201: return "Created"; 77 + case 202: return "Accepted"; 78 + case 203: return "Non-Authoritative Information"; 79 + case 204: return "No Content"; 80 + case 205: return "Reset Content"; 81 + case 206: return "Partial Content"; 82 + case 207: return "Multi-Status"; 83 + case 208: return "Already Reported"; 84 + case 226: return "IM Used"; 85 + 86 + case 300: return "Multiple Choices"; 87 + case 301: return "Moved Permanently"; 88 + case 302: return "Found"; 89 + case 303: return "See Other"; 90 + case 304: return "Not Modified"; 91 + case 305: return "Use Proxy"; 92 + case 306: return "Switch Proxy"; 93 + case 307: return "Temporary Redirect"; 94 + case 308: return "Permanent Redirect"; 95 + 96 + case 400: return "Bad Request"; 97 + case 401: return "Unauthorized"; 98 + case 402: return "Payment Required"; 99 + case 403: return "Forbidden"; 100 + case 404: return "Not Found"; 101 + case 405: return "Method Not Allowed"; 102 + case 406: return "Not Acceptable"; 103 + case 407: return "Proxy Authentication Required"; 104 + case 408: return "Request Timeout"; 105 + case 409: return "Conflict"; 106 + case 410: return "Gone"; 107 + case 411: return "Length Required"; 108 + case 412: return "Precondition Failed"; 109 + case 413: return "Payload Too Large"; 110 + case 414: return "URI Too Long"; 111 + case 415: return "Unsupported Media Type"; 112 + case 416: return "Range Not Satisfiable"; 113 + case 417: return "Expectation Failed"; 114 + case 418: return "I'm a Teapot"; 115 + case 421: return "Misdirected Request"; 116 + case 422: return "Unprocessable Entity"; 117 + case 423: return "Locked"; 118 + case 424: return "Failed Dependency"; 119 + case 425: return "Too Early"; 120 + case 426: return "Upgrade Required"; 121 + case 428: return "Precondition Required"; 122 + case 429: return "Too Many Requests"; 123 + case 431: return "Request Header Fields Too Large"; 124 + case 451: return "Unavailable For Legal Reasons"; 125 + 126 + case 500: return "Internal Server Error"; 127 + case 501: return "Not Implemented"; 128 + case 502: return "Bad Gateway"; 129 + case 503: return "Service Unavailable"; 130 + case 504: return "Gateway Timeout"; 131 + case 505: return "HTTP Version Not Supported"; 132 + case 506: return "Variant Also Negotiates"; 133 + case 507: return "Insufficient Storage"; 134 + case 508: return "Loop Detected"; 135 + case 510: return "Not Extended"; 136 + case 511: return "Network Authentication Required"; 137 + 138 + default: return "Unknown"; 139 + } 140 + } 141 + 68 142 typedef struct { 69 143 char method[16]; 70 144 char uri[2048]; ··· 133 207 134 208 static void on_close(uv_handle_t *handle); 135 209 static void send_response(uv_stream_t *client, response_ctx_t *res_ctx); 136 - 137 - 138 210 139 211 static jsval_t res_status(struct js *js, jsval_t *args, int nargs) { 140 212 if (nargs < 1) return js_mkundef(); ··· 254 326 "Connection: close\r\n" 255 327 "\r\n", 256 328 res_ctx->status, 257 - res_ctx->status == 200 ? "OK" : 258 - res_ctx->status == 404 ? "Not Found" : 259 - res_ctx->status == 500 ? "Internal Server Error" : "Unknown", 329 + get_status_text(res_ctx->status), 260 330 res_ctx->content_type ? res_ctx->content_type : "text/plain", 261 331 res_ctx->body ? strlen(res_ctx->body) : 0 262 332 ); ··· 323 393 if (js_type(result) == JS_ERR) { 324 394 fprintf(stderr, "Handler error: %s\n", js_str(server->js, result)); 325 395 res_ctx->status = 500; 396 + // pass error of throw in server into "internal server error" message 326 397 res_ctx->body = "internal server error\nant http v" ANT_VERSION " (" ANT_GIT_HASH ")"; 327 398 res_ctx->content_type = "text/plain"; 328 399 res_ctx->sent = 1;
+151
tests/test_default_params.cjs
··· 1 + // Test default parameters in function definitions 2 + 3 + // Test 1: Basic default parameter 4 + function greet(name = 'World') { 5 + return 'Hello, ' + name; 6 + } 7 + 8 + console.log("Test 1 - Basic default param:"); 9 + console.log(greet()); // Should print "Hello, World" 10 + console.log(greet('Alice')); // Should print "Hello, Alice" 11 + 12 + // Test 2: Multiple default parameters 13 + function multiply(a = 1, b = 1, c = 1) { 14 + return a * b * c; 15 + } 16 + 17 + console.log("\nTest 2 - Multiple default params:"); 18 + console.log(multiply()); // Should print 1 19 + console.log(multiply(2)); // Should print 2 20 + console.log(multiply(2, 3)); // Should print 6 21 + console.log(multiply(2, 3, 4)); // Should print 24 22 + 23 + // Test 3: Mix of regular and default parameters 24 + function describe(name, age = 25, city = 'Unknown') { 25 + return name + ' is ' + age + ' years old and lives in ' + city; 26 + } 27 + 28 + console.log("\nTest 3 - Mix of regular and default params:"); 29 + console.log(describe('Alice')); // Should print "Alice is 25 years old and lives in Unknown" 30 + console.log(describe('Bob', 30)); // Should print "Bob is 30 years old and lives in Unknown" 31 + console.log(describe('Charlie', 35, 'NYC')); // Should print "Charlie is 35 years old and lives in NYC" 32 + 33 + // Test 4: Default parameter with number 34 + function power(base = 2, exponent = 2) { 35 + let result = 1; 36 + for (let i = 0; i < exponent; i++) { 37 + result = result * base; 38 + } 39 + return result; 40 + } 41 + 42 + console.log("\nTest 4 - Default params with numbers:"); 43 + console.log(power()); // Should print 4 (2^2) 44 + console.log(power(3)); // Should print 9 (3^2) 45 + console.log(power(2, 3)); // Should print 8 (2^3) 46 + 47 + // Test 5: Arrow function with default parameters 48 + const add = (a = 0, b = 0) => a + b; 49 + 50 + console.log("\nTest 5 - Arrow function with default params:"); 51 + console.log(add()); // Should print 0 52 + console.log(add(5)); // Should print 5 53 + console.log(add(5, 3)); // Should print 8 54 + 55 + // Test 6: Class methods with default parameters 56 + class Calculator { 57 + add(x = 0, y = 0) { 58 + return x + y; 59 + } 60 + 61 + subtract(x = 0, y = 0) { 62 + return x - y; 63 + } 64 + 65 + multiply(x = 1, y = 1) { 66 + return x * y; 67 + } 68 + } 69 + 70 + console.log("\nTest 6 - Class methods with default params:"); 71 + const calc = new Calculator(); 72 + console.log(calc.add()); // Should print 0 73 + console.log(calc.add(10)); // Should print 10 74 + console.log(calc.add(10, 5)); // Should print 15 75 + console.log(calc.multiply()); // Should print 1 76 + console.log(calc.multiply(3)); // Should print 3 77 + console.log(calc.multiply(3, 4)); // Should print 12 78 + 79 + // Test 7: Default params with special characters in strings 80 + function wrap(text, left = '(', right = ')') { 81 + return left + text + right; 82 + } 83 + 84 + console.log("\nTest 7 - Default params with parens in strings:"); 85 + console.log(wrap('hello')); // Should print "(hello)" 86 + console.log(wrap('hello', '<', '>')); // Should print "<hello>" 87 + console.log(wrap('hello', '[')); // Should print "[hello)" 88 + 89 + // Test 8: Default with undefined explicitly passed 90 + function testUndefined(a = 'default') { 91 + return a; 92 + } 93 + 94 + console.log("\nTest 8 - Explicit undefined uses default:"); 95 + console.log(testUndefined()); // Should print "default" 96 + console.log(testUndefined(undefined)); // Should print "default" 97 + console.log(testUndefined('value')); // Should print "value" 98 + 99 + // Test 9: Complex default expressions 100 + function createArray(size = 5, fill = 'x') { 101 + let arr = []; 102 + for (let i = 0; i < size; i++) { 103 + arr.push(fill); 104 + } 105 + return arr; 106 + } 107 + 108 + console.log("\nTest 9 - Default params with expressions:"); 109 + console.log(createArray().length); // Should print 5 110 + console.log(createArray(3).length); // Should print 3 111 + console.log(createArray(2, 'o').join('')); // Should print "oo" 112 + 113 + // Test 10: Async function with default parameters 114 + async function asyncGreet(name = 'Async World') { 115 + return 'Hello, ' + name; 116 + } 117 + 118 + console.log("\nTest 10 - Async function with default params:"); 119 + asyncGreet().then(result => console.log(result)); // Should print "Hello, Async World" 120 + asyncGreet('Async Alice').then(result => console.log(result)); // Should print "Hello, Async Alice" 121 + 122 + // Test 11: Default parameters in constructor 123 + class Person { 124 + constructor(name = 'Anonymous', age = 0) { 125 + this.name = name; 126 + this.age = age; 127 + } 128 + 129 + introduce() { 130 + return this.name + ' is ' + this.age; 131 + } 132 + } 133 + 134 + console.log("\nTest 11 - Constructor with default params:"); 135 + const p1 = new Person(); 136 + console.log(p1.introduce()); // Should print "Anonymous is 0" 137 + const p2 = new Person('Dave'); 138 + console.log(p2.introduce()); // Should print "Dave is 0" 139 + const p3 = new Person('Eve', 28); 140 + console.log(p3.introduce()); // Should print "Eve is 28" 141 + 142 + // Test 12: Only last parameters have defaults 143 + function compute(required, optional = 10) { 144 + return required + optional; 145 + } 146 + 147 + console.log("\nTest 12 - Required param then default:"); 148 + console.log(compute(5)); // Should print 15 149 + console.log(compute(5, 20)); // Should print 25 150 + 151 + console.log("\nโœ“ All default parameter tests completed!");
+20
tests/test_three_params.js
··· 1 + // Test method with 3 parameters where last 2 have defaults 2 + class Formatter { 3 + wrap(text, left = '(', right = ')') { 4 + console.log('wrap called with:', text, left, right); 5 + return left + text + right; 6 + } 7 + } 8 + 9 + console.log("Test 1 - All 3 params provided:"); 10 + const fmt = new Formatter(); 11 + const result1 = fmt.wrap('test', '<', '>'); 12 + console.log('Result:', result1); 13 + 14 + console.log("\nTest 2 - Only first param (2 defaults):"); 15 + const result2 = fmt.wrap('test'); 16 + console.log('Result:', result2); 17 + 18 + console.log("\nTest 3 - First 2 params (1 default):"); 19 + const result3 = fmt.wrap('test', '['); 20 + console.log('Result:', result3);