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.

strict mode

+304 -2
+1 -1
meson.build
··· 41 41 build_date = run_command('date', '+%Y-%m-%d', check: true).stdout().strip() 42 42 43 43 version_conf = configuration_data() 44 - version_conf.set('ANT_VERSION', '0.0.5.50') 44 + version_conf.set('ANT_VERSION', '0.0.5.51') 45 45 version_conf.set('ANT_GIT_HASH', git_hash) 46 46 version_conf.set('ANT_BUILD_DATE', build_date) 47 47
+82 -1
src/ant.c
··· 859 859 return n == len && memcmp(buf, p, len) == 0; 860 860 } 861 861 862 + static bool is_strict_reserved(const char *buf, size_t len) { 863 + switch (len) { 864 + case 3: return streq(buf, len, "let", 3); 865 + case 5: return streq(buf, len, "yield", 5); 866 + case 6: return streq(buf, len, "static", 6) || streq(buf, len, "public", 6); 867 + case 7: return streq(buf, len, "private", 7) || streq(buf, len, "package", 7); 868 + case 9: return streq(buf, len, "interface", 9) || streq(buf, len, "protected", 9); 869 + case 10: return streq(buf, len, "implements", 10); 870 + default: return false; 871 + } 872 + } 873 + 874 + static bool is_strict_restricted(const char *buf, size_t len) { 875 + return (len == 4 && streq(buf, len, "eval", 4)) || (len == 9 && streq(buf, len, "arguments", 9)); 876 + } 877 + 862 878 static uint8_t parsekeyword(const char *buf, size_t len) { 863 879 switch (buf[0]) { 864 880 case 'a': if (streq("async", 5, buf, len)) return TOK_ASYNC; if (streq("await", 5, buf, len)) return TOK_AWAIT; break; ··· 957 973 if (buf[0] == buf[js->tlen]) js->tok = TOK_STRING, js->tlen++; 958 974 break; 959 975 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { 976 + if ((js->flags & F_STRICT) && buf[0] == '0' && js->toff + 1 < js->clen && 977 + is_digit(buf[1]) && buf[1] != 'x' && buf[1] != 'X' && buf[1] != 'b' && buf[1] != 'B' && buf[1] != 'o' && buf[1] != 'O') { 978 + js->tok = TOK_ERR; 979 + js->tlen = 1; 980 + break; 981 + } 960 982 char *end; 961 983 js->tval = tov(strtod(buf, &end)); 962 984 TOK(TOK_NUMBER, (jsoff_t) (end - buf)); ··· 1085 1107 scope = mkval(T_OBJ, loadoff(js, (jsoff_t) (vdata(scope) + sizeof(jsoff_t)))); 1086 1108 } 1087 1109 1110 + if (js->flags & F_STRICT) { 1111 + return js_mkerr(js, "ReferenceError: '%.*s' is not defined", (int) len, buf); 1112 + } 1113 + 1088 1114 return js_mkerr(js, "'%.*s' not found", (int) len, buf); 1089 1115 } 1090 1116 ··· 1098 1124 if (is_const_prop(js, propoff)) { 1099 1125 return js_mkerr(js, "assignment to constant"); 1100 1126 } 1127 + 1128 + if (js->flags & F_STRICT) { 1129 + jsval_t prop_val = loadval(js, (jsoff_t) (propoff + sizeof(jsoff_t) * 2)); 1130 + uint8_t prop_type = vtype(prop_val); 1131 + 1132 + if (prop_type == T_STR || prop_type == T_NUM || prop_type == T_BOOL || 1133 + prop_type == T_NULL || prop_type == T_UNDEF) { 1134 + return js_mkerr(js, "TypeError: cannot set property on primitive value in strict mode"); 1135 + } 1136 + } 1137 + 1101 1138 saveval(js, (jsoff_t) ((vdata(lhs) & ~3U) + sizeof(jsoff_t) * 2), val); 1102 1139 return lhs; 1103 1140 } ··· 2061 2098 } 2062 2099 2063 2100 static bool parse_func_params(struct js *js, uint8_t *flags) { 2101 + const char *param_names[32]; 2102 + size_t param_lens[32]; 2103 + int param_count = 0; 2104 + 2064 2105 for (bool comma = false; next(js) != TOK_EOF; comma = true) { 2065 2106 if (!comma && next(js) == TOK_RPAREN) break; 2066 2107 ··· 2076 2117 js_mkerr(js, "identifier expected"); 2077 2118 return false; 2078 2119 } 2120 + 2121 + const char *param_name = &js->code[js->toff]; 2122 + size_t param_len = js->tlen; 2123 + 2124 + if ((js->flags & F_STRICT) && is_strict_restricted(param_name, param_len)) { 2125 + if (flags) js->flags = *flags; 2126 + js_mkerr(js, "cannot use '%.*s' as parameter name in strict mode", (int) param_len, param_name); 2127 + return false; 2128 + } 2129 + 2130 + if (js->flags & F_STRICT) { 2131 + for (int i = 0; i < param_count; i++) { 2132 + if (param_lens[i] == param_len && memcmp(param_names[i], param_name, param_len) == 0) { 2133 + if (flags) js->flags = *flags; 2134 + js_mkerr(js, "duplicate parameter name '%.*s' in strict mode", (int) param_len, param_name); 2135 + return false; 2136 + } 2137 + } 2138 + } 2139 + 2140 + if (param_count < 32) { 2141 + param_names[param_count] = param_name; 2142 + param_lens[param_count] = param_len; 2143 + param_count++; 2144 + } 2145 + 2079 2146 js->consumed = 1; 2080 2147 2081 2148 if (is_rest && next(js) != TOK_RPAREN) { ··· 2187 2254 js->consumed = 1; 2188 2255 2189 2256 switch (js->tok) { 2190 - case TOK_ERR: return js_mkerr(js, "parse error"); 2257 + case TOK_ERR: 2258 + if ((js->flags & F_STRICT) && js->toff < js->clen && js->code[js->toff] == '0' && 2259 + js->toff + 1 < js->clen && is_digit(js->code[js->toff + 1])) { 2260 + return js_mkerr(js, "octal literals are not allowed in strict mode"); 2261 + } 2262 + return js_mkerr(js, "parse error"); 2191 2263 case TOK_NUMBER: return js->tval; 2192 2264 case TOK_STRING: return js_str_literal(js); 2193 2265 case TOK_TEMPLATE: return js_template_literal(js); ··· 2994 3066 js->consumed = 0; 2995 3067 jsoff_t noff = js->toff, nlen = js->tlen; 2996 3068 char *name = (char *) &js->code[noff]; 3069 + 3070 + if (exe && (js->flags & F_STRICT) && is_strict_restricted(name, nlen)) { 3071 + return js_mkerr(js, "cannot use '%.*s' as variable name in strict mode", (int) nlen, name); 3072 + } 3073 + 3074 + if (exe && (js->flags & F_STRICT) && is_strict_reserved(name, nlen)) { 3075 + return js_mkerr(js, "'%.*s' is reserved in strict mode", (int) nlen, name); 3076 + } 3077 + 2997 3078 jsval_t v = js_mkundef(); 2998 3079 js->consumed = 1; 2999 3080 if (next(js) == TOK_ASSIGN) {
+110
tests/test_strict_comprehensive.cjs
··· 1 + // Comprehensive Strict Mode Tests 2 + // Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode 3 + 4 + console.log("=== Strict Mode Comprehensive Tests ===\n"); 5 + 6 + // Test 1: Converting mistakes into errors 7 + console.log("Test 1: Assigning to undeclared variables"); 8 + try { 9 + "use strict"; 10 + eval("x = 3.14;"); 11 + console.log(" FAIL: Should throw ReferenceError"); 12 + } catch (e) { 13 + console.log(" PASS: " + e); 14 + } 15 + 16 + // Test 2: Octal literals 17 + console.log("\nTest 2: Legacy octal literals"); 18 + try { 19 + "use strict"; 20 + eval("let num = 0123;"); 21 + console.log(" FAIL: Should reject octal literals"); 22 + } catch (e) { 23 + console.log(" PASS: Octal literals rejected"); 24 + } 25 + 26 + // Test 3: Reserved words as identifiers 27 + console.log("\nTest 3: Future reserved words"); 28 + const reservedWords = ["implements", "interface", "package", "private", "protected", "public", "static"]; 29 + let passedReserved = 0; 30 + for (let i = 0; i < reservedWords.length; i++) { 31 + try { 32 + eval('"use strict"; let ' + reservedWords[i] + ' = 1;'); 33 + console.log(" FAIL: '" + reservedWords[i] + "' should be reserved"); 34 + } catch (e) { 35 + passedReserved++; 36 + } 37 + } 38 + console.log(" PASS: " + passedReserved + " of " + reservedWords.length + " reserved words blocked"); 39 + 40 + // Test 4: eval and arguments restrictions 41 + console.log("\nTest 4: eval and arguments restrictions"); 42 + try { 43 + "use strict"; 44 + eval("let eval = 5;"); 45 + console.log(" FAIL: Cannot assign to 'eval'"); 46 + } catch (e) { 47 + console.log(" PASS: Cannot use 'eval' as identifier"); 48 + } 49 + 50 + try { 51 + "use strict"; 52 + eval("let arguments = 10;"); 53 + console.log(" FAIL: Cannot assign to 'arguments'"); 54 + } catch (e) { 55 + console.log(" PASS: Cannot use 'arguments' as identifier"); 56 + } 57 + 58 + // Test 5: with statement 59 + console.log("\nTest 5: with statement"); 60 + try { 61 + "use strict"; 62 + eval("with ({}) {}"); 63 + console.log(" FAIL: with statement should be disallowed"); 64 + } catch (e) { 65 + console.log(" PASS: with statement blocked"); 66 + } 67 + 68 + // Test 6: Function parameter restrictions 69 + console.log("\nTest 6: Function parameter restrictions"); 70 + try { 71 + "use strict"; 72 + eval("function f(a, b, a) {}"); 73 + console.log(" FAIL: Duplicate parameters should be disallowed"); 74 + } catch (e) { 75 + console.log(" PASS: Duplicate parameters blocked"); 76 + } 77 + 78 + try { 79 + "use strict"; 80 + eval("function f(eval) {}"); 81 + console.log(" FAIL: 'eval' as parameter should be disallowed"); 82 + } catch (e) { 83 + console.log(" PASS: Cannot use 'eval' as parameter name"); 84 + } 85 + 86 + // Test 7: Strict mode in different contexts 87 + console.log("\nTest 7: Strict mode in different contexts"); 88 + 89 + // Script-level strict mode 90 + let scriptStrictWorks = false; 91 + try { 92 + eval('"use strict"; undeclared = 1;'); 93 + } catch (e) { 94 + scriptStrictWorks = true; 95 + } 96 + console.log(" " + (scriptStrictWorks ? "PASS" : "FAIL") + ": Script-level strict mode"); 97 + 98 + // Function-level strict mode 99 + function testFunctionStrict() { 100 + "use strict"; 101 + try { 102 + undeclared2 = 2; 103 + return false; 104 + } catch (e) { 105 + return true; 106 + } 107 + } 108 + console.log(" " + (testFunctionStrict() ? "PASS" : "FAIL") + ": Function-level strict mode"); 109 + 110 + console.log("\n=== All Tests Completed ===");
+48
tests/test_strict_function.cjs
··· 1 + // Test function-level strict mode 2 + // Based on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode 3 + 4 + // Non-strict code 5 + let globalVar = 10; 6 + console.log("Non-strict global:", globalVar); 7 + 8 + // Function with strict mode 9 + function strictFunction() { 10 + "use strict"; 11 + 12 + // This should work - accessing outer scope 13 + console.log("Accessing outer scope:", globalVar); 14 + 15 + // This should fail - undeclared variable 16 + try { 17 + undeclaredVar = 20; 18 + console.log("FAIL: Should have thrown error in strict function"); 19 + } catch (e) { 20 + console.log("PASS: Strict mode in function works"); 21 + } 22 + } 23 + 24 + strictFunction(); 25 + 26 + // Non-strict function - should allow undeclared vars (though not recommended) 27 + function nonStrictFunction() { 28 + // Note: In this implementation, undeclared vars might still error 29 + // as they create implicit globals which is generally an error 30 + console.log("PASS: Non-strict function executed"); 31 + } 32 + 33 + nonStrictFunction(); 34 + 35 + // Arrow function with strict mode 36 + const strictArrow = () => { 37 + "use strict"; 38 + try { 39 + newVar = 30; 40 + console.log("FAIL: Arrow function strict mode didn't work"); 41 + } catch (e) { 42 + console.log("PASS: Strict mode in arrow function works"); 43 + } 44 + }; 45 + 46 + strictArrow(); 47 + 48 + console.log("\nFunction-level strict mode tests completed!");
+63
tests/test_strict_mode.cjs
··· 1 + // Test strict mode features 2 + // Based on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode 3 + 4 + // Test 1: Strict mode enabled at script level 5 + "use strict"; 6 + 7 + // Test 2: Assignment to undeclared variables should fail 8 + try { 9 + mistypeVariable = 17; 10 + console.log("FAIL: Should have thrown ReferenceError for undeclared variable"); 11 + } catch (e) { 12 + console.log("PASS: Caught error for undeclared variable assignment"); 13 + } 14 + 15 + // Test 3: Using eval as variable name should fail 16 + try { 17 + eval("let eval = 5;"); 18 + console.log("FAIL: Should have thrown error for using 'eval' as variable name"); 19 + } catch (e) { 20 + console.log("PASS: Cannot use 'eval' as variable name in strict mode"); 21 + } 22 + 23 + // Test 4: Using arguments as variable name should fail 24 + try { 25 + eval("let arguments = 10;"); 26 + console.log("FAIL: Should have thrown error for using 'arguments' as variable name"); 27 + } catch (e) { 28 + console.log("PASS: Cannot use 'arguments' as variable name in strict mode"); 29 + } 30 + 31 + // Test 5: Duplicate parameter names should fail 32 + try { 33 + eval("function sum(a, a, c) { return a + a + c; }"); 34 + console.log("FAIL: Should have thrown error for duplicate parameter names"); 35 + } catch (e) { 36 + console.log("PASS: Duplicate parameter names not allowed in strict mode"); 37 + } 38 + 39 + // Test 6: Octal literals should fail 40 + try { 41 + eval("let x = 0644;"); 42 + console.log("FAIL: Should have thrown error for octal literal"); 43 + } catch (e) { 44 + console.log("PASS: Octal literals not allowed in strict mode"); 45 + } 46 + 47 + // Test 7: Reserved words should not be usable as identifiers 48 + try { 49 + eval("let implements = 5;"); 50 + console.log("FAIL: Should have thrown error for using reserved word 'implements'"); 51 + } catch (e) { 52 + console.log("PASS: Reserved word 'implements' cannot be used in strict mode"); 53 + } 54 + 55 + // Test 8: with statement should fail 56 + try { 57 + eval("with (Math) { x = cos(2); }"); 58 + console.log("FAIL: Should have thrown error for 'with' statement"); 59 + } catch (e) { 60 + console.log("PASS: 'with' statement not allowed in strict mode"); 61 + } 62 + 63 + console.log("\nAll strict mode tests completed!");