Changeset 211319 in webkit
- Timestamp:
- Jan 27, 2017, 7:09:12 PM (10 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 21 edited
-
JSTests/ChakraCore/test/es6/unicode_6_identifier_Blue524737.baseline-jsc (modified) (1 diff)
-
JSTests/ChangeLog (modified) (1 diff)
-
JSTests/stress/lift-template-literal.js (added)
-
JSTests/stress/template-literal-syntax.js (modified) (2 diffs)
-
LayoutTests/ChangeLog (modified) (1 diff)
-
LayoutTests/inspector/runtime/parse-expected.txt (modified) (1 diff)
-
LayoutTests/js/unicode-escape-sequences-expected.txt (modified) (2 diffs)
-
Source/JavaScriptCore/ChangeLog (modified) (1 diff)
-
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp (modified) (1 diff)
-
Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp (modified) (3 diffs)
-
Source/JavaScriptCore/parser/ASTBuilder.h (modified) (1 diff)
-
Source/JavaScriptCore/parser/Lexer.cpp (modified) (19 diffs)
-
Source/JavaScriptCore/parser/Lexer.h (modified) (3 diffs)
-
Source/JavaScriptCore/parser/NodeConstructors.h (modified) (1 diff)
-
Source/JavaScriptCore/parser/Nodes.h (modified) (1 diff)
-
Source/JavaScriptCore/parser/Parser.cpp (modified) (6 diffs)
-
Source/JavaScriptCore/parser/ParserTokens.h (modified) (1 diff)
-
Source/JavaScriptCore/parser/SyntaxChecker.h (modified) (1 diff)
-
Source/JavaScriptCore/runtime/TemplateRegistry.cpp (modified) (1 diff)
-
Source/JavaScriptCore/runtime/TemplateRegistryKey.h (modified) (3 diffs)
-
Source/JavaScriptCore/runtime/TemplateRegistryKeyTable.cpp (modified) (1 diff)
-
Source/JavaScriptCore/runtime/TemplateRegistryKeyTable.h (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/JSTests/ChakraCore/test/es6/unicode_6_identifier_Blue524737.baseline-jsc
r205387 r211319 1 Exception: SyntaxError: Invalid unicode escape in identifier: '\u{13407 '1 Exception: SyntaxError: Invalid unicode escape in identifier: '\u{134071' 2 2 at unicode_6_identifier_Blue524737.js:6 -
trunk/JSTests/ChangeLog
r211246 r211319 1 2017-01-27 Yusuke Suzuki <utatane.tea@gmail.com> 2 3 Lift template escape sequence restrictions in tagged templates 4 https://bugs.webkit.org/show_bug.cgi?id=166871 5 6 Reviewed by Saam Barati. 7 8 Update the error messages and add new tests. 9 10 * ChakraCore/test/es6/unicode_6_identifier_Blue524737.baseline-jsc: 11 * stress/lift-template-literal.js: Added. 12 (dump): 13 (testTag.return.tag): 14 (testTag): 15 * stress/template-literal-syntax.js: 16 1 17 2017-01-26 Mark Lam <mark.lam@apple.com> 2 18 -
trunk/JSTests/stress/template-literal-syntax.js
r183559 r211319 47 47 testSyntax("`\\\r\n`"); 48 48 testSyntax("`\\\r`"); 49 testSyntax("Hello`bad escape sequence: \\unicode`"); 50 testSyntax("Hello`\\00`"); 51 testSyntax("Hello`\\01`"); 52 testSyntax("Hello`\\1`"); 53 testSyntax("Hello`\\xo`"); 54 testSyntax("Hello`\\x0o`"); 55 testSyntax("Hello`\\uo`"); 56 testSyntax("Hello`\\u0o`"); 57 testSyntax("Hello`\\u00o`"); 58 testSyntax("Hello`\\u000o`"); 59 testSyntax("Hello`\\u{o`"); 60 testSyntax("Hello`\\u{0o`"); 61 testSyntax("Hello`\\u{110000o`"); 49 62 50 63 testSyntaxError("`Hello", "SyntaxError: Unexpected EOF"); … … 82 95 testSyntaxError("`\\u202`", "SyntaxError: \\u can only be followed by a Unicode character sequence"); 83 96 testSyntaxError("`${expr}\\u202`", "SyntaxError: \\u can only be followed by a Unicode character sequence"); 97 98 testSyntaxError("`bad escape sequence: \\unicode`", "SyntaxError: \\u can only be followed by a Unicode character sequence"); 99 100 testSyntaxError("`\\00`", "SyntaxError: The only valid numeric escape in strict mode is '\\0'"); 101 testSyntaxError("`\\01`", "SyntaxError: The only valid numeric escape in strict mode is '\\0'"); 102 testSyntaxError("`\\1`", "SyntaxError: The only valid numeric escape in strict mode is '\\0'"); 103 testSyntaxError("`\\xo`", "SyntaxError: \\x can only be followed by a hex character sequence"); 104 testSyntaxError("`\\x0o`", "SyntaxError: \\x can only be followed by a hex character sequence"); 105 testSyntaxError("`\\uo`", "SyntaxError: \\u can only be followed by a Unicode character sequence"); 106 testSyntaxError("`\\u0o`", "SyntaxError: \\u can only be followed by a Unicode character sequence"); 107 testSyntaxError("`\\u00o`", "SyntaxError: \\u can only be followed by a Unicode character sequence"); 108 testSyntaxError("`\\u000o`", "SyntaxError: \\u can only be followed by a Unicode character sequence"); 109 testSyntaxError("`\\u{o`", "SyntaxError: \\u can only be followed by a Unicode character sequence"); 110 testSyntaxError("`\\u{0o`", "SyntaxError: \\u can only be followed by a Unicode character sequence"); 111 testSyntaxError("`\\u{110000o`", "SyntaxError: \\u can only be followed by a Unicode character sequence"); -
trunk/LayoutTests/ChangeLog
r211314 r211319 1 2017-01-27 Yusuke Suzuki <utatane.tea@gmail.com> 2 3 Lift template escape sequence restrictions in tagged templates 4 https://bugs.webkit.org/show_bug.cgi?id=166871 5 6 Reviewed by Saam Barati. 7 8 Update the error messages. 9 10 * inspector/runtime/parse-expected.txt: 11 * js/unicode-escape-sequences-expected.txt: 12 1 13 2017-01-27 Yusuke Suzuki <utatane.tea@gmail.com> 2 14 -
trunk/LayoutTests/inspector/runtime/parse-expected.txt
r200429 r211319 68 68 PASS: Should be SyntaxErrorType UnterminatedLiteral. 69 69 Source: var \u007 70 ^~ 71 Error Message: Incomplete unicode escape in identifier: '\u '72 Range: {"startOffset":4,"endOffset": 6}70 ^~~~~ 71 Error Message: Incomplete unicode escape in identifier: '\u007' 72 Range: {"startOffset":4,"endOffset":9} 73 73 74 74 -
trunk/LayoutTests/js/unicode-escape-sequences-expected.txt
r183552 r211319 59 59 PASS codeUnits(function \u{G}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{'. 60 60 PASS codeUnits(function \u{1G}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{1'. 61 PASS codeUnits(function \u{110000}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{11000 '.62 PASS codeUnits(function \u{1000000}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{100000 '.63 PASS codeUnits(function \u{100000000000000000000000}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{100000 '.61 PASS codeUnits(function \u{110000}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{110000'. 62 PASS codeUnits(function \u{1000000}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{1000000'. 63 PASS codeUnits(function \u{100000000000000000000000}(){}.name) threw exception SyntaxError: Invalid unicode escape in identifier: '\u{100000000000000000000000'. 64 64 PASS codeUnits(function x\u{41}(){}.name.substring(1)) is "0041" 65 65 PASS codeUnits(function x\u{10000}(){}.name.substring(1)) is "D800,DC00" … … 88 88 PASS codeUnits(function x\u{G}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{'. 89 89 PASS codeUnits(function x\u{1G}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{1'. 90 PASS codeUnits(function x\u{110000}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{11000 '.91 PASS codeUnits(function x\u{1000000}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{100000 '.92 PASS codeUnits(function x\u{100000000000000000000000}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{100000 '.90 PASS codeUnits(function x\u{110000}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{110000'. 91 PASS codeUnits(function x\u{1000000}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{1000000'. 92 PASS codeUnits(function x\u{100000000000000000000000}(){}.name.substring(1)) threw exception SyntaxError: Invalid unicode escape in identifier: 'x\u{100000000000000000000000'. 93 93 PASS successfullyParsed is true 94 94 -
trunk/Source/JavaScriptCore/ChangeLog
r211316 r211319 1 2017-01-27 Yusuke Suzuki <utatane.tea@gmail.com> 2 3 Lift template escape sequence restrictions in tagged templates 4 https://bugs.webkit.org/show_bug.cgi?id=166871 5 6 Reviewed by Saam Barati. 7 8 This patch implements stage 3 Lifting Template Literal Restriction[1]. 9 Prior to this patch, template literal becomes syntax error if it contains 10 invalid escape sequences. But it is too restricted; Template literal 11 can have cooked and raw representations and only cooked representation 12 can escape sequences. So even if invalid escape sequences are included, 13 the raw representation can be valid. 14 15 Lifting Template Literal Restriction relaxes the above restriction. 16 When invalid escape sequence is included, if target template literals 17 are used as tagged templates, we make the result of the template including 18 the invalid escape sequence `undefined` instead of making it SyntaxError 19 immediately. It allows us to accept the templates including invalid 20 escape sequences in the raw representations in tagged templates. 21 22 On the other hand, the raw representation is only used in tagged templates. 23 So if invalid escape sequences are included in the usual template literals, 24 we just make it SyntaxError as before. 25 26 [1]: https://github.com/tc39/proposal-template-literal-revision 27 28 * bytecompiler/BytecodeGenerator.cpp: 29 (JSC::BytecodeGenerator::emitGetTemplateObject): 30 * bytecompiler/NodesCodegen.cpp: 31 (JSC::TemplateStringNode::emitBytecode): 32 (JSC::TemplateLiteralNode::emitBytecode): 33 * parser/ASTBuilder.h: 34 (JSC::ASTBuilder::createTemplateString): 35 * parser/Lexer.cpp: 36 (JSC::Lexer<CharacterType>::parseUnicodeEscape): 37 (JSC::Lexer<T>::parseTemplateLiteral): 38 (JSC::Lexer<T>::lex): 39 (JSC::Lexer<T>::scanTemplateString): 40 (JSC::Lexer<T>::scanTrailingTemplateString): Deleted. 41 * parser/Lexer.h: 42 * parser/NodeConstructors.h: 43 (JSC::TemplateStringNode::TemplateStringNode): 44 * parser/Nodes.h: 45 (JSC::TemplateStringNode::cooked): 46 (JSC::TemplateStringNode::raw): 47 * parser/Parser.cpp: 48 (JSC::Parser<LexerType>::parseAssignmentElement): 49 (JSC::Parser<LexerType>::parseTemplateString): 50 (JSC::Parser<LexerType>::parseTemplateLiteral): 51 (JSC::Parser<LexerType>::parsePrimaryExpression): 52 (JSC::Parser<LexerType>::parseMemberExpression): 53 * parser/ParserTokens.h: 54 * parser/SyntaxChecker.h: 55 (JSC::SyntaxChecker::createTemplateString): 56 * runtime/TemplateRegistry.cpp: 57 (JSC::TemplateRegistry::getTemplateObject): 58 * runtime/TemplateRegistryKey.h: 59 (JSC::TemplateRegistryKey::cookedStrings): 60 (JSC::TemplateRegistryKey::create): 61 (JSC::TemplateRegistryKey::TemplateRegistryKey): 62 * runtime/TemplateRegistryKeyTable.cpp: 63 (JSC::TemplateRegistryKeyTable::createKey): 64 * runtime/TemplateRegistryKeyTable.h: 65 1 66 2017-01-27 Saam Barati <sbarati@apple.com> 2 67 -
trunk/Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
r210522 r211319 4254 4254 { 4255 4255 TemplateRegistryKey::StringVector rawStrings; 4256 TemplateRegistryKey:: StringVector cookedStrings;4256 TemplateRegistryKey::OptionalStringVector cookedStrings; 4257 4257 4258 4258 TemplateStringListNode* templateString = taggedTemplate->templateLiteral()->templateStrings(); 4259 4259 for (; templateString; templateString = templateString->next()) { 4260 rawStrings.append(templateString->value()->raw().impl()); 4261 cookedStrings.append(templateString->value()->cooked().impl()); 4260 auto* string = templateString->value(); 4261 ASSERT(string->raw()); 4262 rawStrings.append(string->raw()->impl()); 4263 if (!string->cooked()) 4264 cookedStrings.append(std::nullopt); 4265 else 4266 cookedStrings.append(string->cooked()->impl()); 4262 4267 } 4263 4268 4264 4269 RefPtr<RegisterID> getTemplateObject = emitGetGlobalPrivate(newTemporary(), propertyNames().builtinNames().getTemplateObjectPrivateName()); 4265 4270 CallArguments arguments(*this, nullptr); 4266 emitLoad(arguments.thisRegister(), JSValue(addTemplateRegistryKeyConstant(m_vm->templateRegistryKeyTable().createKey( rawStrings, cookedStrings))));4271 emitLoad(arguments.thisRegister(), JSValue(addTemplateRegistryKeyConstant(m_vm->templateRegistryKeyTable().createKey(WTFMove(rawStrings), WTFMove(cookedStrings))))); 4267 4272 return emitCall(dst, getTemplateObject.get(), NoExpectedFunction, arguments, taggedTemplate->divot(), taggedTemplate->divotStart(), taggedTemplate->divotEnd(), DebuggableCall::No); 4268 4273 } -
trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp
r210958 r211319 247 247 if (dst == generator.ignoredResult()) 248 248 return nullptr; 249 return generator.emitLoad(dst, JSValue(generator.addStringConstant(cooked()))); 249 ASSERT(cooked()); 250 return generator.emitLoad(dst, JSValue(generator.addStringConstant(*cooked()))); 250 251 } 251 252 … … 266 267 for (; templateExpression; templateExpression = templateExpression->next(), templateString = templateString->next()) { 267 268 // Evaluate TemplateString. 268 if (!templateString->value()->cooked().isEmpty()) { 269 ASSERT(templateString->value()->cooked()); 270 if (!templateString->value()->cooked()->isEmpty()) { 269 271 temporaryRegisters.append(generator.newTemporary()); 270 272 generator.emitNode(temporaryRegisters.last().get(), templateString->value()); … … 278 280 279 281 // Evaluate tail TemplateString. 280 if (!templateString->value()->cooked().isEmpty()) { 282 ASSERT(templateString->value()->cooked()); 283 if (!templateString->value()->cooked()->isEmpty()) { 281 284 temporaryRegisters.append(generator.newTemporary()); 282 285 generator.emitNode(temporaryRegisters.last().get(), templateString->value()); -
trunk/Source/JavaScriptCore/parser/ASTBuilder.h
r210522 r211319 276 276 } 277 277 278 TemplateStringNode* createTemplateString(const JSTokenLocation& location, const Identifier & cooked, const Identifier&raw)278 TemplateStringNode* createTemplateString(const JSTokenLocation& location, const Identifier* cooked, const Identifier* raw) 279 279 { 280 280 return new (m_parserArena) TemplateStringNode(location, cooked, raw); -
trunk/Source/JavaScriptCore/parser/Lexer.cpp
r209632 r211319 634 634 }; 635 635 636 template<typename CharacterType> ParsedUnicodeEscapeValue Lexer<CharacterType>::parseUnicodeEscape() 636 template<typename CharacterType> 637 ParsedUnicodeEscapeValue Lexer<CharacterType>::parseUnicodeEscape() 637 638 { 638 639 if (m_current == '{') { … … 643 644 return m_current ? ParsedUnicodeEscapeValue::Invalid : ParsedUnicodeEscapeValue::Incomplete; 644 645 codePoint = (codePoint << 4) | toASCIIHexValue(m_current); 645 if (codePoint > UCHAR_MAX_VALUE) 646 return ParsedUnicodeEscapeValue::Invalid; 646 if (codePoint > UCHAR_MAX_VALUE) { 647 // For raw template literal syntax, we consume `NotEscapeSequence`. 648 // Here, we consume NotCodePoint's HexDigits. 649 // 650 // NotEscapeSequence :: 651 // u { [lookahread not one of HexDigit] 652 // u { NotCodePoint 653 // u { CodePoint [lookahead != }] 654 // 655 // NotCodePoint :: 656 // HexDigits but not if MV of HexDigits <= 0x10FFFF 657 // 658 // CodePoint :: 659 // HexDigits but not if MV of HexDigits > 0x10FFFF 660 shift(); 661 while (isASCIIHexDigit(m_current)) 662 shift(); 663 664 return atEnd() ? ParsedUnicodeEscapeValue::Incomplete : ParsedUnicodeEscapeValue::Invalid; 665 } 647 666 shift(); 648 667 } while (m_current != '}'); … … 654 673 auto character3 = peek(2); 655 674 auto character4 = peek(3); 656 if (UNLIKELY(!isASCIIHexDigit(m_current) || !isASCIIHexDigit(character2) || !isASCIIHexDigit(character3) || !isASCIIHexDigit(character4))) 657 return (m_code + 4) >= m_codeEnd ? ParsedUnicodeEscapeValue::Incomplete : ParsedUnicodeEscapeValue::Invalid; 675 if (UNLIKELY(!isASCIIHexDigit(m_current) || !isASCIIHexDigit(character2) || !isASCIIHexDigit(character3) || !isASCIIHexDigit(character4))) { 676 auto result = (m_code + 4) >= m_codeEnd ? ParsedUnicodeEscapeValue::Incomplete : ParsedUnicodeEscapeValue::Invalid; 677 678 // For raw template literal syntax, we consume `NotEscapeSequence`. 679 // 680 // NotEscapeSequence :: 681 // u [lookahead not one of HexDigit][lookahead != {] 682 // u HexDigit [lookahead not one of HexDigit] 683 // u HexDigit HexDigit [lookahead not one of HexDigit] 684 // u HexDigit HexDigit HexDigit [lookahead not one of HexDigit] 685 while (isASCIIHexDigit(m_current)) 686 shift(); 687 688 return result; 689 } 690 658 691 auto result = convertUnicode(m_current, character2, character3, character4); 659 692 shift(); … … 1182 1215 1183 1216 template <typename T> 1184 template <bool shouldBuildStrings > ALWAYS_INLINE auto Lexer<T>::parseComplexEscape(EscapeParseMode escapeParseMode,bool strictMode, T stringQuoteCharacter) -> StringParseResult1217 template <bool shouldBuildStrings, LexerEscapeParseMode escapeParseMode> ALWAYS_INLINE auto Lexer<T>::parseComplexEscape(bool strictMode, T stringQuoteCharacter) -> StringParseResult 1185 1218 { 1186 1219 if (m_current == 'x') { 1187 1220 shift(); 1188 1221 if (!isASCIIHexDigit(m_current) || !isASCIIHexDigit(peek(1))) { 1222 // For raw template literal syntax, we consume `NotEscapeSequence`. 1223 // 1224 // NotEscapeSequence :: 1225 // x [lookahread not one of HexDigit] 1226 // x HexDigit [lookahread not one of HexDigit] 1227 if (isASCIIHexDigit(m_current)) 1228 shift(); 1229 ASSERT(!isASCIIHexDigit(m_current)); 1230 1189 1231 m_lexErrorMessage = ASCIILiteral("\\x can only be followed by a hex character sequence"); 1190 return StringCannotBeParsed; 1191 } 1232 return atEnd() ? StringUnterminated : StringCannotBeParsed; 1233 } 1234 1192 1235 T prev = m_current; 1193 1236 shift(); … … 1195 1238 record16(convertHex(prev, m_current)); 1196 1239 shift(); 1240 1197 1241 return StringParsedSuccessfully; 1198 1242 } … … 1201 1245 shift(); 1202 1246 1203 if (escapeParseMode == EscapeParseMode::String && m_current == stringQuoteCharacter) {1247 if (escapeParseMode == LexerEscapeParseMode::String && m_current == stringQuoteCharacter) { 1204 1248 if (shouldBuildStrings) 1205 1249 record16('u'); … … 1215 1259 1216 1260 m_lexErrorMessage = ASCIILiteral("\\u can only be followed by a Unicode character sequence"); 1217 return character.isIncomplete() ? StringUnterminated : StringCannotBeParsed;1261 return atEnd() ? StringUnterminated : StringCannotBeParsed; 1218 1262 } 1219 1263 … … 1224 1268 shift(); 1225 1269 if (character1 != '0' || isASCIIDigit(m_current)) { 1270 // For raw template literal syntax, we consume `NotEscapeSequence`. 1271 // 1272 // NotEscapeSequence :: 1273 // 0 DecimalDigit 1274 // DecimalDigit but not 0 1275 if (character1 == '0') 1276 shift(); 1277 1226 1278 m_lexErrorMessage = ASCIILiteral("The only valid numeric escape in strict mode is '\\0'"); 1227 return StringCannotBeParsed;1279 return atEnd() ? StringUnterminated : StringCannotBeParsed; 1228 1280 } 1229 1281 if (shouldBuildStrings) … … 1291 1343 shiftLineTerminator(); 1292 1344 else { 1293 StringParseResult result = parseComplexEscape<shouldBuildStrings >(EscapeParseMode::String,strictMode, stringQuoteCharacter);1345 StringParseResult result = parseComplexEscape<shouldBuildStrings, LexerEscapeParseMode::String>(strictMode, stringQuoteCharacter); 1294 1346 if (result != StringParsedSuccessfully) 1295 1347 return result; … … 1373 1425 1374 1426 template <typename T> 1375 template <bool shouldBuildStrings> typename Lexer<T>::StringParseResult Lexer<T>::parseTemplateLiteral(JSTokenData* tokenData, RawStringsBuildMode rawStringsBuildMode) 1376 { 1427 typename Lexer<T>::StringParseResult Lexer<T>::parseTemplateLiteral(JSTokenData* tokenData, RawStringsBuildMode rawStringsBuildMode) 1428 { 1429 bool parseCookedFailed = false; 1377 1430 const T* stringStart = currentSourcePtr(); 1378 1431 const T* rawStringStart = currentSourcePtr(); … … 1383 1436 if (UNLIKELY(m_current == '\\')) { 1384 1437 lineNumberAdder.clear(); 1385 if (stringStart != currentSourcePtr() && shouldBuildStrings)1438 if (stringStart != currentSourcePtr()) 1386 1439 append16(stringStart, currentSourcePtr() - stringStart); 1387 1440 shift(); … … 1391 1444 // Most common escape sequences first. 1392 1445 if (escape) { 1393 if (shouldBuildStrings) 1394 record16(escape); 1446 record16(escape); 1395 1447 shift(); 1396 1448 } else if (UNLIKELY(isLineTerminator(m_current))) { 1397 1449 // Normalize <CR>, <CR><LF> to <LF>. 1398 1450 if (m_current == '\r') { 1399 if (shouldBuildStrings) { 1400 ASSERT_WITH_MESSAGE(rawStringStart != currentSourcePtr(), "We should have at least shifted the escape."); 1401 1402 if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings) { 1403 m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart); 1404 m_bufferForRawTemplateString16.append('\n'); 1405 } 1451 ASSERT_WITH_MESSAGE(rawStringStart != currentSourcePtr(), "We should have at least shifted the escape."); 1452 1453 if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings) { 1454 m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart); 1455 m_bufferForRawTemplateString16.append('\n'); 1406 1456 } 1407 1457 … … 1420 1470 } else { 1421 1471 bool strictMode = true; 1422 StringParseResult result = parseComplexEscape<shouldBuildStrings>(EscapeParseMode::Template, strictMode, '`'); 1423 if (result != StringParsedSuccessfully) 1424 return result; 1472 StringParseResult result = parseComplexEscape<true, LexerEscapeParseMode::Template>(strictMode, '`'); 1473 if (result != StringParsedSuccessfully) { 1474 if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings && result == StringCannotBeParsed) 1475 parseCookedFailed = true; 1476 else 1477 return result; 1478 } 1425 1479 } 1426 1480 … … 1446 1500 if (m_current == '\r') { 1447 1501 // Normalize <CR>, <CR><LF> to <LF>. 1448 if (shouldBuildStrings) { 1449 if (stringStart != currentSourcePtr()) 1450 append16(stringStart, currentSourcePtr() - stringStart); 1451 if (rawStringStart != currentSourcePtr() && rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings) 1452 m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart); 1453 1454 record16('\n'); 1455 if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings) 1456 m_bufferForRawTemplateString16.append('\n'); 1457 } 1502 if (stringStart != currentSourcePtr()) 1503 append16(stringStart, currentSourcePtr() - stringStart); 1504 if (rawStringStart != currentSourcePtr() && rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings) 1505 m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart); 1506 1507 record16('\n'); 1508 if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings) 1509 m_bufferForRawTemplateString16.append('\n'); 1458 1510 lineNumberAdder.add(m_current); 1459 1511 shift(); … … 1479 1531 bool isTail = m_current == '`'; 1480 1532 1481 if (shouldBuildStrings) { 1482 if (currentSourcePtr() != stringStart) 1483 append16(stringStart, currentSourcePtr() - stringStart); 1484 if (rawStringStart != currentSourcePtr() && rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings) 1485 m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart); 1486 } 1487 1488 if (shouldBuildStrings) { 1533 if (currentSourcePtr() != stringStart) 1534 append16(stringStart, currentSourcePtr() - stringStart); 1535 if (rawStringStart != currentSourcePtr() && rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings) 1536 m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart); 1537 1538 if (!parseCookedFailed) 1489 1539 tokenData->cooked = makeIdentifier(m_buffer16.data(), m_buffer16.size()); 1490 // Line terminator normalization (e.g. <CR> => <LF>) should be applied to both the raw and cooked representations.1491 if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)1492 tokenData->raw = makeIdentifier(m_bufferForRawTemplateString16.data(), m_bufferForRawTemplateString16.size()); 1493 else1494 tokenData->raw = makeEmptyIdentifier();1495 } else {1496 tokenData->cooked = makeEmptyIdentifier();1497 tokenData->raw = makeEmptyIdentifier();1498 } 1540 else 1541 tokenData->cooked = nullptr; 1542 1543 // Line terminator normalization (e.g. <CR> => <LF>) should be applied to both the raw and cooked representations. 1544 if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings) 1545 tokenData->raw = makeIdentifier(m_bufferForRawTemplateString16.data(), m_bufferForRawTemplateString16.size()); 1546 else 1547 tokenData->raw = nullptr; 1548 1499 1549 tokenData->isTail = isTail; 1500 1550 … … 2082 2132 shift(); 2083 2133 token = SEMICOLON; 2134 break; 2135 case CharacterBackQuote: 2136 shift(); 2137 token = BACKQUOTE; 2084 2138 break; 2085 2139 case CharacterOpenBrace: … … 2235 2289 break; 2236 2290 } 2237 case CharacterBackQuote: {2238 // Skip backquote.2239 shift();2240 StringParseResult result = StringCannotBeParsed;2241 if (lexerFlags & LexerFlagsDontBuildStrings)2242 result = parseTemplateLiteral<false>(tokenData, RawStringsBuildMode::BuildRawStrings);2243 else2244 result = parseTemplateLiteral<true>(tokenData, RawStringsBuildMode::BuildRawStrings);2245 2246 if (UNLIKELY(result != StringParsedSuccessfully)) {2247 token = result == StringUnterminated ? UNTERMINATED_TEMPLATE_LITERAL_ERRORTOK : INVALID_TEMPLATE_LITERAL_ERRORTOK;2248 goto returnError;2249 }2250 token = TEMPLATE;2251 break;2252 }2253 2291 case CharacterIdentifierStart: 2254 2292 ASSERT(isIdentStart(m_current)); … … 2421 2459 2422 2460 template <typename T> 2423 JSTokenType Lexer<T>::scanT railingTemplateString(JSToken* tokenRecord, RawStringsBuildMode rawStringsBuildMode)2461 JSTokenType Lexer<T>::scanTemplateString(JSToken* tokenRecord, RawStringsBuildMode rawStringsBuildMode) 2424 2462 { 2425 2463 JSTokenData* tokenData = &tokenRecord->m_data; … … 2427 2465 ASSERT(m_buffer16.isEmpty()); 2428 2466 2429 // Leading closing brace } isalready shifted in the previous token scan.2467 // Leading backquote ` (for template head) or closing brace } (for template trailing) are already shifted in the previous token scan. 2430 2468 // So in this re-scan phase, shift() is not needed here. 2431 StringParseResult result = parseTemplateLiteral <true>(tokenData, rawStringsBuildMode);2469 StringParseResult result = parseTemplateLiteral(tokenData, rawStringsBuildMode); 2432 2470 JSTokenType token = ERRORTOK; 2433 2471 if (UNLIKELY(result != StringParsedSuccessfully)) { -
trunk/Source/JavaScriptCore/parser/Lexer.h
r207798 r211319 38 38 }; 39 39 40 enum class LexerEscapeParseMode { Template, String }; 41 40 42 struct ParsedUnicodeEscapeValue; 41 43 … … 78 80 JSTokenType scanRegExp(JSToken*, UChar patternPrefix = 0); 79 81 enum class RawStringsBuildMode { BuildRawStrings, DontBuildRawStrings }; 80 JSTokenType scanT railingTemplateString(JSToken*, RawStringsBuildMode);82 JSTokenType scanTemplateString(JSToken*, RawStringsBuildMode); 81 83 82 84 // Functions for use after parsing. … … 171 173 template <bool shouldBuildStrings> NEVER_INLINE StringParseResult parseStringSlowCase(JSTokenData*, bool strictMode); 172 174 173 enum class EscapeParseMode { Template, String }; 174 template <bool shouldBuildStrings> ALWAYS_INLINE StringParseResult parseComplexEscape(EscapeParseMode, bool strictMode, T stringQuoteCharacter); 175 template <bool shouldBuildStrings> ALWAYS_INLINE StringParseResult parseTemplateLiteral(JSTokenData*, RawStringsBuildMode); 175 template <bool shouldBuildStrings, LexerEscapeParseMode escapeParseMode> ALWAYS_INLINE StringParseResult parseComplexEscape(bool strictMode, T stringQuoteCharacter); 176 ALWAYS_INLINE StringParseResult parseTemplateLiteral(JSTokenData*, RawStringsBuildMode); 176 177 ALWAYS_INLINE void parseHex(double& returnValue); 177 178 ALWAYS_INLINE bool parseBinary(double& returnValue); -
trunk/Source/JavaScriptCore/parser/NodeConstructors.h
r210522 r211319 112 112 } 113 113 114 inline TemplateStringNode::TemplateStringNode(const JSTokenLocation& location, const Identifier & cooked, const Identifier&raw)114 inline TemplateStringNode::TemplateStringNode(const JSTokenLocation& location, const Identifier* cooked, const Identifier* raw) 115 115 : ExpressionNode(location) 116 116 , m_cooked(cooked) -
trunk/Source/JavaScriptCore/parser/Nodes.h
r210522 r211319 491 491 class TemplateStringNode : public ExpressionNode { 492 492 public: 493 TemplateStringNode(const JSTokenLocation&, const Identifier & cooked, const Identifier&raw);494 495 const Identifier &cooked() { return m_cooked; }496 const Identifier &raw() { return m_raw; }497 498 private: 499 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; 500 501 const Identifier &m_cooked;502 const Identifier &m_raw;493 TemplateStringNode(const JSTokenLocation&, const Identifier* cooked, const Identifier* raw); 494 495 const Identifier* cooked() { return m_cooked; } 496 const Identifier* raw() { return m_raw; } 497 498 private: 499 RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override; 500 501 const Identifier* m_cooked; 502 const Identifier* m_raw; 503 503 }; 504 504 -
trunk/Source/JavaScriptCore/parser/Parser.cpp
r211017 r211319 905 905 SavePoint savePoint = createSavePoint(); 906 906 assignmentTarget = parseDestructuringPattern(context, kind, exportType, duplicateIdentifier, hasDestructuringPattern, bindingContext, depth); 907 if (assignmentTarget && !match(DOT) && !match(OPENBRACKET) && !match(OPENPAREN) && !match( TEMPLATE))907 if (assignmentTarget && !match(DOT) && !match(OPENBRACKET) && !match(OPENPAREN) && !match(BACKQUOTE)) 908 908 return assignmentTarget; 909 909 restoreSavePoint(savePoint); … … 4090 4090 template <class TreeBuilder> typename TreeBuilder::TemplateString Parser<LexerType>::parseTemplateString(TreeBuilder& context, bool isTemplateHead, typename LexerType::RawStringsBuildMode rawStringsBuildMode, bool& elementIsTail) 4091 4091 { 4092 if (!isTemplateHead) { 4092 if (isTemplateHead) 4093 ASSERT(match(BACKQUOTE)); 4094 else 4093 4095 matchOrFail(CLOSEBRACE, "Expected a closing '}' following an expression in template literal"); 4094 // Re-scan the token to recognize it as Template Element. 4095 m_token.m_type = m_lexer->scanTrailingTemplateString(&m_token, rawStringsBuildMode);4096 }4096 4097 // Re-scan the token to recognize it as Template Element. 4098 m_token.m_type = m_lexer->scanTemplateString(&m_token, rawStringsBuildMode); 4097 4099 matchOrFail(TEMPLATE, "Expected an template element"); 4098 4100 const Identifier* cooked = m_token.m_data.cooked; … … 4101 4103 JSTokenLocation location(tokenLocation()); 4102 4104 next(); 4103 return context.createTemplateString(location, *cooked, *raw);4105 return context.createTemplateString(location, cooked, raw); 4104 4106 } 4105 4107 … … 4107 4109 template <class TreeBuilder> typename TreeBuilder::TemplateLiteral Parser<LexerType>::parseTemplateLiteral(TreeBuilder& context, typename LexerType::RawStringsBuildMode rawStringsBuildMode) 4108 4110 { 4111 ASSERT(match(BACKQUOTE)); 4109 4112 JSTokenLocation location(tokenLocation()); 4110 4113 bool elementIsTail = false; … … 4269 4272 return re; 4270 4273 } 4271 case TEMPLATE:4274 case BACKQUOTE: 4272 4275 return parseTemplateLiteral(context, LexerType::RawStringsBuildMode::DontBuildRawStrings); 4273 4276 case YIELD: … … 4506 4509 break; 4507 4510 } 4508 case TEMPLATE: {4511 case BACKQUOTE: { 4509 4512 semanticFailIfTrue(baseIsSuper, "Cannot use super as tag for tagged templates"); 4510 4513 JSTextPosition expressionEnd = lastTokenEndPosition(); -
trunk/Source/JavaScriptCore/parser/ParserTokens.h
r209350 r211319 110 110 COMMA, 111 111 QUESTION, 112 BACKQUOTE, 112 113 INTEGER, 113 114 DOUBLE, -
trunk/Source/JavaScriptCore/parser/SyntaxChecker.h
r210522 r211319 195 195 int createArguments(int) { return ArgumentsResult; } 196 196 ExpressionType createSpreadExpression(const JSTokenLocation&, ExpressionType, int, int, int) { return SpreadExpr; } 197 TemplateString createTemplateString(const JSTokenLocation&, const Identifier &, const Identifier&) { return TemplateStringResult; }197 TemplateString createTemplateString(const JSTokenLocation&, const Identifier*, const Identifier*) { return TemplateStringResult; } 198 198 TemplateStringList createTemplateStringList(TemplateString) { return TemplateStringListResult; } 199 199 TemplateStringList createTemplateStringList(TemplateStringList, TemplateString) { return TemplateStringListResult; } -
trunk/Source/JavaScriptCore/runtime/TemplateRegistry.cpp
r209018 r211319 59 59 60 60 for (unsigned index = 0; index < count; ++index) { 61 templateObject->putDirectIndex(exec, index, jsString(exec, templateKey.cookedStrings()[index]), ReadOnly | DontDelete, PutDirectIndexLikePutDirect); 61 auto cooked = templateKey.cookedStrings()[index]; 62 if (cooked) 63 templateObject->putDirectIndex(exec, index, jsString(exec, cooked.value()), ReadOnly | DontDelete, PutDirectIndexLikePutDirect); 64 else 65 templateObject->putDirectIndex(exec, index, jsUndefined(), ReadOnly | DontDelete, PutDirectIndexLikePutDirect); 62 66 RETURN_IF_EXCEPTION(scope, nullptr); 67 63 68 rawObject->putDirectIndex(exec, index, jsString(exec, templateKey.rawStrings()[index]), ReadOnly | DontDelete, PutDirectIndexLikePutDirect); 64 69 RETURN_IF_EXCEPTION(scope, nullptr); -
trunk/Source/JavaScriptCore/runtime/TemplateRegistryKey.h
r208953 r211319 39 39 friend class TemplateRegistryKeyTable; 40 40 typedef Vector<String, 4> StringVector; 41 typedef Vector<std::optional<String>, 4> OptionalStringVector; 41 42 42 43 enum DeletedValueTag { DeletedValue }; … … 52 53 53 54 const StringVector& rawStrings() const { return m_rawStrings; } 54 const StringVector& cookedStrings() const { return m_cookedStrings; }55 const OptionalStringVector& cookedStrings() const { return m_cookedStrings; } 55 56 56 57 bool operator==(const TemplateRegistryKey& other) const { return m_hash == other.m_hash && m_rawStrings == other.m_rawStrings; } … … 67 68 68 69 private: 69 static Ref<TemplateRegistryKey> create( const StringVector& rawStrings, const StringVector& cookedStrings)70 static Ref<TemplateRegistryKey> create(StringVector&& rawStrings, OptionalStringVector&& cookedStrings) 70 71 { 71 return adoptRef(*new TemplateRegistryKey( rawStrings, cookedStrings));72 return adoptRef(*new TemplateRegistryKey(WTFMove(rawStrings), WTFMove(cookedStrings))); 72 73 } 73 74 74 TemplateRegistryKey( const StringVector& rawStrings, const StringVector& cookedStrings);75 TemplateRegistryKey(StringVector&& rawStrings, OptionalStringVector&& cookedStrings); 75 76 76 77 TemplateRegistryKeyTable* m_table { nullptr }; 77 78 StringVector m_rawStrings; 78 StringVector m_cookedStrings;79 OptionalStringVector m_cookedStrings; 79 80 unsigned m_hash { 0 }; 80 81 }; 81 82 82 inline TemplateRegistryKey::TemplateRegistryKey( const StringVector& rawStrings, const StringVector& cookedStrings)83 : m_rawStrings( rawStrings)84 , m_cookedStrings( cookedStrings)83 inline TemplateRegistryKey::TemplateRegistryKey(StringVector&& rawStrings, OptionalStringVector&& cookedStrings) 84 : m_rawStrings(WTFMove(rawStrings)) 85 , m_cookedStrings(WTFMove(cookedStrings)) 85 86 , m_hash(calculateHash(rawStrings)) 86 87 { -
trunk/Source/JavaScriptCore/runtime/TemplateRegistryKeyTable.cpp
r208953 r211319 43 43 } 44 44 45 Ref<TemplateRegistryKey> TemplateRegistryKeyTable::createKey( const TemplateRegistryKey::StringVector& rawStrings, const TemplateRegistryKey::StringVector& cookedStrings)45 Ref<TemplateRegistryKey> TemplateRegistryKeyTable::createKey(TemplateRegistryKey::StringVector&& rawStrings, TemplateRegistryKey::OptionalStringVector&& cookedStrings) 46 46 { 47 auto key = TemplateRegistryKey::create( rawStrings, cookedStrings);47 auto key = TemplateRegistryKey::create(WTFMove(rawStrings), WTFMove(cookedStrings)); 48 48 auto addResult = m_atomicTable.add<TemplateRegistryKeyTranslator>(key.ptr()); 49 49 if (addResult.isNewEntry) -
trunk/Source/JavaScriptCore/runtime/TemplateRegistryKeyTable.h
r208953 r211319 37 37 public: 38 38 using StringVector = Vector<String, 4>; 39 using OptionalStringVector = Vector<std::optional<String>, 4>; 39 40 40 41 TemplateRegistryKeyTable() = default; 41 42 42 Ref<TemplateRegistryKey> createKey( const StringVector& rawStrings, const StringVector& cookedStrings);43 Ref<TemplateRegistryKey> createKey(StringVector&& rawStrings, OptionalStringVector&& cookedStrings); 43 44 44 45 void unregister(TemplateRegistryKey&);
Note:
See TracChangeset
for help on using the changeset viewer.