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.

nullish coalescing operator

+288 -4
+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.47') 44 + version_conf.set('ANT_VERSION', '0.0.5.48') 45 45 version_conf.set('ANT_GIT_HASH', git_hash) 46 46 version_conf.set('ANT_BUILD_DATE', build_date) 47 47
+24 -3
src/ant.c
··· 117 117 TOK_TYPEOF, TOK_UPLUS, TOK_UMINUS, TOK_EXP, TOK_MUL, TOK_DIV, TOK_REM, 118 118 TOK_OPTIONAL_CHAIN, TOK_REST, 119 119 TOK_PLUS, TOK_MINUS, TOK_SHL, TOK_SHR, TOK_ZSHR, TOK_LT, TOK_LE, TOK_GT, 120 - TOK_GE, TOK_EQ, TOK_NE, TOK_AND, TOK_XOR, TOK_OR, TOK_LAND, TOK_LOR, 120 + TOK_GE, TOK_EQ, TOK_NE, TOK_AND, TOK_XOR, TOK_OR, TOK_LAND, TOK_LOR, TOK_NULLISH, 121 121 TOK_COLON, TOK_Q, TOK_ASSIGN, TOK_PLUS_ASSIGN, TOK_MINUS_ASSIGN, 122 122 TOK_MUL_ASSIGN, TOK_DIV_ASSIGN, TOK_REM_ASSIGN, TOK_SHL_ASSIGN, 123 123 TOK_SHR_ASSIGN, TOK_ZSHR_ASSIGN, TOK_AND_ASSIGN, TOK_XOR_ASSIGN, ··· 904 904 #define LOOK(OFS, CH) js->toff + OFS < js->clen && buf[OFS] == CH 905 905 906 906 switch (buf[0]) { 907 - case '?': if (LOOK(1, '.')) TOK(TOK_OPTIONAL_CHAIN, 2); TOK(TOK_Q, 1); 907 + case '?': if (LOOK(1, '?')) TOK(TOK_NULLISH, 2); if (LOOK(1, '.')) TOK(TOK_OPTIONAL_CHAIN, 2); TOK(TOK_Q, 1); 908 908 case ':': TOK(TOK_COLON, 1); 909 909 case '(': TOK(TOK_LPAREN, 1); 910 910 case ')': TOK(TOK_RPAREN, 1); ··· 2740 2740 LTR_BINOP(js_bitwise_xor, (next(js) == TOK_OR)); 2741 2741 } 2742 2742 2743 + static jsval_t js_nullish_coalesce(struct js *js) { 2744 + jsval_t res = js_bitwise_or(js); 2745 + if (is_err(res)) return res; 2746 + uint8_t flags = js->flags; 2747 + while (next(js) == TOK_NULLISH) { 2748 + js->consumed = 1; 2749 + res = resolveprop(js, res); 2750 + uint8_t res_type = vtype(res); 2751 + if (res_type != T_NULL && res_type != T_UNDEF) { 2752 + js->flags |= F_NOEXEC; 2753 + } 2754 + if (js->flags & F_NOEXEC) { 2755 + js_nullish_coalesce(js); 2756 + } else { 2757 + res = js_nullish_coalesce(js); 2758 + } 2759 + } 2760 + js->flags = flags; 2761 + return res; 2762 + } 2763 + 2743 2764 static jsval_t js_logical_and(struct js *js) { 2744 - jsval_t res = js_bitwise_or(js); 2765 + jsval_t res = js_nullish_coalesce(js); 2745 2766 if (is_err(res)) return res; 2746 2767 uint8_t flags = js->flags; 2747 2768 while (next(js) == TOK_LAND) {
+263
tests/test_ternary_and_operators.cjs
··· 1 + // Test ternary operator (?:), logical OR (||), and nullish coalescing (??) 2 + 3 + console.log("=== Ternary, Logical OR, and Nullish Coalescing Test ===\n"); 4 + 5 + // Test 1: Basic ternary operator 6 + console.log("Test 1: Basic ternary operator"); 7 + let x = 10; 8 + let y = 5; 9 + 10 + let result1 = x > y ? "x is greater" : "y is greater or equal"; 11 + console.log(" 10 > 5 ? 'x is greater' : 'y is greater or equal' =>", result1); 12 + 13 + let result2 = x < y ? "x is less" : "x is greater or equal"; 14 + console.log(" 10 < 5 ? 'x is less' : 'x is greater or equal' =>", result2); 15 + 16 + let result3 = true ? "yes" : "no"; 17 + console.log(" true ? 'yes' : 'no' =>", result3); 18 + 19 + let result4 = false ? "yes" : "no"; 20 + console.log(" false ? 'yes' : 'no' =>", result4); 21 + 22 + // Test 2: Nested ternary operators 23 + console.log("\nTest 2: Nested ternary operators"); 24 + let age = 25; 25 + let category = age < 18 ? "minor" : age < 65 ? "adult" : "senior"; 26 + console.log(" age = 25, category:", category); 27 + 28 + age = 15; 29 + category = age < 18 ? "minor" : age < 65 ? "adult" : "senior"; 30 + console.log(" age = 15, category:", category); 31 + 32 + age = 70; 33 + category = age < 18 ? "minor" : age < 65 ? "adult" : "senior"; 34 + console.log(" age = 70, category:", category); 35 + 36 + // Test 3: Ternary with various types 37 + console.log("\nTest 3: Ternary with various types"); 38 + let score = 85; 39 + let grade = score >= 90 ? "A" : score >= 80 ? "B" : score >= 70 ? "C" : "F"; 40 + console.log(" score = 85, grade:", grade); 41 + 42 + let hasPermission = true; 43 + let status = hasPermission ? 200 : 403; 44 + console.log(" hasPermission = true, status:", status); 45 + 46 + let value = null; 47 + let output = value ? value : "default"; 48 + console.log(" null ? null : 'default' =>", output); 49 + 50 + // Test 4: Logical OR (||) operator 51 + console.log("\nTest 4: Logical OR (||) operator"); 52 + 53 + // With boolean values 54 + let bool1 = true || false; 55 + let bool2 = false || true; 56 + let bool3 = false || false; 57 + let bool4 = true || true; 58 + console.log(" true || false =>", bool1); 59 + console.log(" false || true =>", bool2); 60 + console.log(" false || false =>", bool3); 61 + console.log(" true || true =>", bool4); 62 + 63 + // Test 5: Logical OR with truthy/falsy values 64 + console.log("\nTest 5: Logical OR with truthy/falsy values"); 65 + let val1 = null || "default"; 66 + let val2 = undefined || "fallback"; 67 + let val3 = "" || "empty string fallback"; 68 + let val4 = 0 || 42; 69 + let val5 = false || true; 70 + let val6 = "first" || "second"; 71 + let val7 = 100 || 200; 72 + 73 + console.log(" null || 'default' =>", val1); 74 + console.log(" undefined || 'fallback' =>", val2); 75 + console.log(" '' || 'empty string fallback' =>", val3); 76 + console.log(" 0 || 42 =>", val4); 77 + console.log(" false || true =>", val5); 78 + console.log(" 'first' || 'second' =>", val6); 79 + console.log(" 100 || 200 =>", val7); 80 + 81 + // Test 6: Chained logical OR 82 + console.log("\nTest 6: Chained logical OR"); 83 + let option1 = null; 84 + let option2 = undefined; 85 + let option3 = ""; 86 + let option4 = "valid value"; 87 + let finalValue = option1 || option2 || option3 || option4 || "ultimate fallback"; 88 + console.log(" null || undefined || '' || 'valid value' || 'ultimate fallback' =>", finalValue); 89 + 90 + let allFalsy = null || undefined || false || 0 || ""; 91 + console.log(" null || undefined || false || 0 || '' =>", allFalsy); 92 + 93 + // Test 7: Nullish coalescing (??) operator 94 + console.log("\nTest 7: Nullish coalescing (??) operator"); 95 + 96 + // Basic nullish coalescing 97 + let nc1 = null ?? "default"; 98 + let nc2 = undefined ?? "fallback"; 99 + let nc3 = "" ?? "empty string fallback"; 100 + let nc4 = 0 ?? 42; 101 + let nc5 = false ?? true; 102 + let nc6 = "value" ?? "default"; 103 + 104 + console.log(" null ?? 'default' =>", nc1); 105 + console.log(" undefined ?? 'fallback' =>", nc2); 106 + console.log(" '' ?? 'empty string fallback' =>", nc3); 107 + console.log(" 0 ?? 42 =>", nc4); 108 + console.log(" false ?? true =>", nc5); 109 + console.log(" 'value' ?? 'default' =>", nc6); 110 + 111 + // Test 8: Difference between || and ?? 112 + console.log("\nTest 8: Difference between || and ??"); 113 + console.log(" Comparing || and ?? with various values:"); 114 + 115 + let testVal = 0; 116 + console.log(" 0 || 'fallback' =>", testVal || "fallback"); 117 + console.log(" 0 ?? 'fallback' =>", testVal ?? "fallback"); 118 + 119 + testVal = ""; 120 + console.log(" '' || 'fallback' =>", testVal || "fallback"); 121 + console.log(" '' ?? 'fallback' =>", testVal ?? "fallback"); 122 + 123 + testVal = false; 124 + console.log(" false || 'fallback' =>", testVal || "fallback"); 125 + console.log(" false ?? 'fallback' =>", testVal ?? "fallback"); 126 + 127 + testVal = null; 128 + console.log(" null || 'fallback' =>", testVal || "fallback"); 129 + console.log(" null ?? 'fallback' =>", testVal ?? "fallback"); 130 + 131 + testVal = undefined; 132 + console.log(" undefined || 'fallback' =>", testVal || "fallback"); 133 + console.log(" undefined ?? 'fallback' =>", testVal ?? "fallback"); 134 + 135 + // Test 9: Chained nullish coalescing 136 + console.log("\nTest 9: Chained nullish coalescing"); 137 + let config1 = null; 138 + let config2 = undefined; 139 + let config3 = "configured"; 140 + let config = config1 ?? config2 ?? config3 ?? "default config"; 141 + console.log(" null ?? undefined ?? 'configured' ?? 'default config' =>", config); 142 + 143 + let allNull = null ?? undefined ?? null; 144 + console.log(" null ?? undefined ?? null =>", allNull); 145 + 146 + // Test 10: Ternary with || and ?? 147 + console.log("\nTest 10: Combining ternary with || and ??"); 148 + let username = null; 149 + let displayName = username ? username : "Guest"; 150 + console.log(" username = null, ternary result:", displayName); 151 + 152 + displayName = username || "Guest (using ||)"; 153 + console.log(" username = null, || result:", displayName); 154 + 155 + displayName = username ?? "Guest (using ??)"; 156 + console.log(" username = null, ?? result:", displayName); 157 + 158 + username = ""; 159 + displayName = username || "Guest (using ||)"; 160 + console.log(" username = '', || result:", displayName); 161 + 162 + displayName = username ?? "Guest (using ??)"; 163 + console.log(" username = '', ?? result:", displayName); 164 + 165 + // Test 11: In conditional expressions 166 + console.log("\nTest 11: In conditional expressions"); 167 + let a = 5; 168 + let b = 10; 169 + 170 + if (a > b ? true : false) { 171 + console.log(" a > b: true"); 172 + } else { 173 + console.log(" a > b: false"); 174 + } 175 + 176 + let condition = null || undefined || "has value"; 177 + if (condition) { 178 + console.log(" Condition with || is truthy:", condition); 179 + } 180 + 181 + let ncCondition = null ?? undefined ?? "has value"; 182 + if (ncCondition) { 183 + console.log(" Condition with ?? is truthy:", ncCondition); 184 + } 185 + 186 + // Test 12: In function returns 187 + console.log("\nTest 12: In function returns"); 188 + function getMax(x, y) { 189 + return x > y ? x : y; 190 + } 191 + 192 + console.log(" getMax(15, 20):", getMax(15, 20)); 193 + console.log(" getMax(30, 10):", getMax(30, 10)); 194 + 195 + function getFirstValid(a, b, c) { 196 + return a || b || c || "none"; 197 + } 198 + 199 + console.log(" getFirstValid(null, '', 'value'):", getFirstValid(null, "", "value")); 200 + console.log(" getFirstValid(null, undefined, false):", getFirstValid(null, undefined, false)); 201 + 202 + function getFirstNonNullish(a, b, c) { 203 + return a ?? b ?? c ?? "none"; 204 + } 205 + 206 + console.log(" getFirstNonNullish(null, '', 'value'):", getFirstNonNullish(null, "", "value")); 207 + console.log(" getFirstNonNullish(null, undefined, false):", getFirstNonNullish(null, undefined, false)); 208 + 209 + // Test 13: Assignment with operators 210 + console.log("\nTest 13: Assignment with operators"); 211 + let setting = null; 212 + let finalSetting = setting ?? "default"; 213 + console.log(" setting = null, finalSetting:", finalSetting); 214 + 215 + setting = undefined; 216 + finalSetting = setting ?? "default"; 217 + console.log(" setting = undefined, finalSetting:", finalSetting); 218 + 219 + setting = 0; 220 + finalSetting = setting ?? "default"; 221 + console.log(" setting = 0, finalSetting:", finalSetting); 222 + 223 + // Test 14: With objects and arrays 224 + console.log("\nTest 14: With objects and arrays"); 225 + let user = null; 226 + let defaultUser = { name: "Guest", id: 0 }; 227 + let currentUser = user ?? defaultUser; 228 + console.log(" user = null, currentUser:", currentUser); 229 + 230 + let items = null; 231 + let defaultItems = [1, 2, 3]; 232 + let currentItems = items ?? defaultItems; 233 + console.log(" items = null, currentItems:", currentItems); 234 + 235 + let emptyArray = []; 236 + let arrayResult = emptyArray || [1, 2, 3]; 237 + console.log(" [] || [1,2,3] =>", arrayResult); 238 + 239 + arrayResult = emptyArray ?? [1, 2, 3]; 240 + console.log(" [] ?? [1,2,3] =>", arrayResult); 241 + 242 + // Test 15: Complex expressions 243 + console.log("\nTest 15: Complex expressions"); 244 + let min = 10; 245 + let max = 100; 246 + let input = 50; 247 + let clamped = input < min ? min : input > max ? max : input; 248 + console.log(" Clamping 50 to [10, 100]:", clamped); 249 + 250 + input = 5; 251 + clamped = input < min ? min : input > max ? max : input; 252 + console.log(" Clamping 5 to [10, 100]:", clamped); 253 + 254 + input = 150; 255 + clamped = input < min ? min : input > max ? max : input; 256 + console.log(" Clamping 150 to [10, 100]:", clamped); 257 + 258 + let priority = null; 259 + let defaultPriority = 5; 260 + let finalPriority = (priority ?? defaultPriority) > 10 ? 10 : (priority ?? defaultPriority); 261 + console.log(" priority = null, clamped to max 10:", finalPriority); 262 + 263 + console.log("\n=== All tests completed ===");