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.

throw error on weird property

+62 -6
+17 -6
src/silver/ast.c
··· 266 266 ); 267 267 } 268 268 269 + static inline sv_ast_t *parse_dot_property_name(P) { 270 + if (!is_private_ident_like_tok(TOK)) { 271 + sv_parse_unexpected_token(p); 272 + return NULL; 273 + } 274 + 275 + sv_ast_t *name = mk_ident_from_tok(p); 276 + CONSUME(); 277 + return name; 278 + } 279 + 269 280 static sv_ast_t *parse_arrow_body(P) { 270 281 if (NEXT() == TOK_LBRACE) return parse_block(p, true); 271 282 return parse_assign(p); ··· 671 682 NEXT(); 672 683 sv_ast_t *mem = mk(N_MEMBER); 673 684 mem->left = callee; 674 - mem->right = mk_ident_from_tok(p); 675 - CONSUME(); 685 + mem->right = parse_dot_property_name(p); 686 + if (!mem->right) return mk(N_EMPTY); 676 687 callee = mem; 677 688 } else if (la == TOK_LBRACKET) { 678 689 CONSUME(); ··· 1064 1075 mem->right = mk_private_ident_from_tok(p); 1065 1076 CONSUME(); 1066 1077 } else { 1067 - mem->right = mk_ident_from_tok(p); 1068 - CONSUME(); 1078 + mem->right = parse_dot_property_name(p); 1079 + if (!mem->right) return mk(N_EMPTY); 1069 1080 } 1070 1081 n = mem; 1071 1082 } else if (la == TOK_LBRACKET) { ··· 1107 1118 opt->right = mk_private_ident_from_tok(p); 1108 1119 CONSUME(); 1109 1120 } else { 1110 - opt->right = mk_ident_from_tok(p); 1111 - CONSUME(); 1121 + opt->right = parse_dot_property_name(p); 1122 + if (!opt->right) return mk(N_EMPTY); 1112 1123 } 1113 1124 n = opt; 1114 1125 } else if (la == TOK_TEMPLATE) {
+45
tests/test_dot_property_syntax.cjs
··· 1 + const { spawnSync } = require('child_process'); 2 + const fs = require('fs'); 3 + const os = require('os'); 4 + const path = require('path'); 5 + 6 + function assert(condition, message) { 7 + if (!condition) throw new Error(message); 8 + } 9 + 10 + const keywordKeys = { 11 + default: 'default value', 12 + true: 'true value', 13 + null: 'null value', 14 + class: 'class value', 15 + }; 16 + 17 + assert(keywordKeys.default === 'default value', 'dot access should allow default as property name'); 18 + assert(keywordKeys.true === 'true value', 'dot access should allow true as property name'); 19 + assert(keywordKeys.null === 'null value', 'dot access should allow null as property name'); 20 + assert(keywordKeys.class === 'class value', 'dot access should allow class as property name'); 21 + 22 + const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ant-dot-property-syntax-')); 23 + 24 + function runInvalid(file, source) { 25 + const scriptPath = path.join(tmpDir, file); 26 + fs.writeFileSync(scriptPath, source); 27 + const result = spawnSync(process.execPath, [scriptPath], { encoding: 'utf8' }); 28 + if (result.error) throw result.error; 29 + assert(result.status !== 0, `${file} should fail to parse`); 30 + assert(result.stderr.includes('SyntaxError'), `${file} should report SyntaxError\n${result.stderr}`); 31 + assert(result.stderr.includes("Unexpected token '&'"), `${file} should reject the punctuator after dot\n${result.stderr}`); 32 + assert(!result.stderr.includes('ReferenceError'), `${file} should not execute as a bitwise expression\n${result.stderr}`); 33 + } 34 + 35 + runInvalid( 36 + 'invalid-dot-property.cjs', 37 + "const person = { '&weird property': 'YYCJS' };\nperson.&weird property;\n" 38 + ); 39 + 40 + runInvalid( 41 + 'invalid-optional-dot-property.cjs', 42 + "const person = { '&weird property': 'YYCJS' };\nperson?.&weird property;\n" 43 + ); 44 + 45 + console.log('dot property syntax test passed');