[ES6] Implement tagged templates
https://bugs.webkit.org/show_bug.cgi?id=143183
Reviewed by Oliver Hunt.
This patch implements ES6 tagged templates.
In tagged templates, the function takes the template object.
The template object contains the raw and cooked template strings,
so when parsing the tagged templates, we need to tokenize the raw and cooked strings.
While tagged templates require the both strings, the template literal only requires
the cooked strings. So when tokenizing under the template literal context,
we only builds the cooked strings.
As per ES6 spec, the template objects for the same raw strings are shared in the same realm.
The template objects is cached. And every time we evaluate the same tagged templates,
the same (cached) template objects are used.
Since the spec freezes this template objects completely,
we cannot attach some properties to it.
So we can say that it behaves as if the template objects are the primitive values (like JSString).
Since we cannot attach properties, the only way to test the identity of the template object is comparing. (===)
As the result, when there is no reference to the template object, we can garbage collect it
because the user has no way to test that the newly created template object does not equal
to the already collected template object.
So, to implement tagged templates, we implement the following components.
1. JSTemplateRegistryKey
It holds the template registry key and it does not exposed to users.
TemplateRegistryKey holds the vector of raw and cooked strings with the pre-computed hash value.
When obtaining the template object for the (statically, a.k.a. at the parsing time) given raw string vectors,
we use this JSTemplateRegistryKey as a key to the map and look up the template object from
TemplateRegistry.
JSTemplateRegistryKey is created at the bytecode compiling time and
stored in the CodeBlock as like as JSString content values.
2. TemplateRegistry
This manages the cached template objects.
It holds the weak map (JSTemplateRegistryKey -> the template object).
The template object is weakly referenced.
So if there is no reference to the template object,
the template object is automatically GC-ed.
When looking up the template object, it searches the cached template object.
If it is found, it is returned to the users.
If there is no cached template objects, it creates the new template object and
stores it with the given template registry key.
* CMakeLists.txt:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj:
* JavaScriptCore.vcxproj/JavaScriptCore.vcxproj.filters:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::addTemplateRegistryKeyConstant):
(JSC::BytecodeGenerator::emitGetTemplateObject):
* bytecompiler/BytecodeGenerator.h:
* bytecompiler/NodesCodegen.cpp:
(JSC::TaggedTemplateNode::emitBytecode):
(JSC::TemplateLiteralNode::emitBytecode): Deleted.
* parser/ASTBuilder.h:
(JSC::ASTBuilder::createTaggedTemplate):
(JSC::ASTBuilder::createTemplateLiteral): Deleted.
* parser/Lexer.cpp:
(JSC::Lexer<T>::setCode):
(JSC::Lexer<T>::parseTemplateLiteral):
(JSC::Lexer<T>::lex):
(JSC::Lexer<T>::scanTrailingTemplateString):
(JSC::Lexer<T>::clear):
* parser/Lexer.h:
(JSC::Lexer<T>::makeEmptyIdentifier):
* parser/NodeConstructors.h:
(JSC::TaggedTemplateNode::TaggedTemplateNode):
(JSC::TemplateLiteralNode::TemplateLiteralNode): Deleted.
* parser/Nodes.h:
(JSC::TemplateLiteralNode::templateStrings):
(JSC::TemplateLiteralNode::templateExpressions):
(JSC::TaggedTemplateNode::templateLiteral):
* parser/Parser.cpp:
(JSC::Parser<LexerType>::parseTemplateString):
(JSC::Parser<LexerType>::parseTemplateLiteral):
(JSC::Parser<LexerType>::parsePrimaryExpression):
(JSC::Parser<LexerType>::parseMemberExpression):
* parser/Parser.h:
* parser/ParserArena.h:
(JSC::IdentifierArena::makeEmptyIdentifier):
* parser/SyntaxChecker.h:
(JSC::SyntaxChecker::createTaggedTemplate):
(JSC::SyntaxChecker::createTemplateLiteral): Deleted.
* runtime/CommonIdentifiers.h:
* runtime/JSGlobalObject.cpp:
(JSC::getTemplateObject):
(JSC::JSGlobalObject::JSGlobalObject):
(JSC::JSGlobalObject::init):
* runtime/JSGlobalObject.h:
(JSC::JSGlobalObject::templateRegistry):
* runtime/JSTemplateRegistryKey.cpp: Added.
(JSC::JSTemplateRegistryKey::JSTemplateRegistryKey):
(JSC::JSTemplateRegistryKey::create):
(JSC::JSTemplateRegistryKey::destroy):
* runtime/JSTemplateRegistryKey.h: Added.
* runtime/ObjectConstructor.cpp:
(JSC::objectConstructorFreeze):
* runtime/ObjectConstructor.h:
* runtime/TemplateRegistry.cpp: Added.
(JSC::TemplateRegistry::TemplateRegistry):
(JSC::TemplateRegistry::getTemplateObject):
* runtime/TemplateRegistry.h: Added.
* runtime/TemplateRegistryKey.h: Added.
(JSC::TemplateRegistryKey::isDeletedValue):
(JSC::TemplateRegistryKey::isEmptyValue):
(JSC::TemplateRegistryKey::hash):
(JSC::TemplateRegistryKey::rawStrings):
(JSC::TemplateRegistryKey::cookedStrings):
(JSC::TemplateRegistryKey::operator==):
(JSC::TemplateRegistryKey::operator!=):
(JSC::TemplateRegistryKey::Hasher::hash):
(JSC::TemplateRegistryKey::Hasher::equal):
(JSC::TemplateRegistryKey::TemplateRegistryKey):
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:
* tests/stress/tagged-templates-identity.js: Added.
(shouldBe):
* tests/stress/tagged-templates-raw-strings.js: Added.
(shouldBe):
(tag):
(testEval):
* tests/stress/tagged-templates-syntax.js: Added.
(tag):
(testSyntax):
(testSyntaxError):
* tests/stress/tagged-templates-template-object.js: Added.
(shouldBe):
(tag):
* tests/stress/tagged-templates-this.js: Added.
(shouldBe):
(tag):
* tests/stress/tagged-templates.js: Added.
(shouldBe):
(raw):
(cooked):
(Counter):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@184337 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/parser/ASTBuilder.h b/Source/JavaScriptCore/parser/ASTBuilder.h
index c494536..fbcbe26 100644
--- a/Source/JavaScriptCore/parser/ASTBuilder.h
+++ b/Source/JavaScriptCore/parser/ASTBuilder.h
@@ -288,6 +288,13 @@
{
return new (m_parserArena) TemplateLiteralNode(location, templateStringList, templateExpressionList);
}
+
+ ExpressionNode* createTaggedTemplate(const JSTokenLocation& location, ExpressionNode* base, TemplateLiteralNode* templateLiteral, const JSTextPosition& start, const JSTextPosition& divot, const JSTextPosition& end)
+ {
+ auto node = new (m_parserArena) TaggedTemplateNode(location, base, templateLiteral);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
#endif
ExpressionNode* createRegExp(const JSTokenLocation& location, const Identifier& pattern, const Identifier& flags, const JSTextPosition& start)
diff --git a/Source/JavaScriptCore/parser/Lexer.cpp b/Source/JavaScriptCore/parser/Lexer.cpp
index 96eb7aa..7b119ba 100644
--- a/Source/JavaScriptCore/parser/Lexer.cpp
+++ b/Source/JavaScriptCore/parser/Lexer.cpp
@@ -569,6 +569,7 @@
m_buffer8.reserveInitialCapacity(initialReadBufferCapacity);
m_buffer16.reserveInitialCapacity((m_codeEnd - m_code) / 2);
+ m_bufferForRawTemplateString16.reserveInitialCapacity(initialReadBufferCapacity);
if (LIKELY(m_code < m_codeEnd))
m_current = *m_code;
@@ -1374,7 +1375,7 @@
};
template <typename T>
-template <bool shouldBuildStrings> typename Lexer<T>::StringParseResult Lexer<T>::parseTemplateLiteral(JSTokenData* tokenData)
+template <bool shouldBuildStrings> typename Lexer<T>::StringParseResult Lexer<T>::parseTemplateLiteral(JSTokenData* tokenData, RawStringsBuildMode rawStringsBuildMode)
{
const T* stringStart = currentSourcePtr();
const T* rawStringStart = currentSourcePtr();
@@ -1435,10 +1436,16 @@
if (isLineTerminator(m_current)) {
if (m_current == '\r') {
// Normalize <CR>, <CR><LF> to <LF>.
- if (stringStart != currentSourcePtr() && shouldBuildStrings)
- append16(stringStart, currentSourcePtr() - stringStart);
- if (shouldBuildStrings)
+ if (shouldBuildStrings) {
+ if (stringStart != currentSourcePtr())
+ append16(stringStart, currentSourcePtr() - stringStart);
+ if (rawStringStart != currentSourcePtr() && rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
+ m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart);
+
record16('\n');
+ if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
+ m_bufferForRawTemplateString16.append('\n');
+ }
lineNumberAdder.add(m_current);
shift();
if (m_current == '\n') {
@@ -1446,6 +1453,7 @@
shift();
}
stringStart = currentSourcePtr();
+ rawStringStart = currentSourcePtr();
} else {
lineNumberAdder.add(m_current);
shift();
@@ -1461,24 +1469,28 @@
bool isTail = m_current == '`';
- if (currentSourcePtr() != stringStart && shouldBuildStrings)
- append16(stringStart, currentSourcePtr() - stringStart);
+ if (shouldBuildStrings) {
+ if (currentSourcePtr() != stringStart)
+ append16(stringStart, currentSourcePtr() - stringStart);
+ if (rawStringStart != currentSourcePtr() && rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
+ m_bufferForRawTemplateString16.append(rawStringStart, currentSourcePtr() - rawStringStart);
+ }
if (shouldBuildStrings) {
tokenData->cooked = makeIdentifier(m_buffer16.data(), m_buffer16.size());
- // TODO: While line terminator normalization (e.g. <CR> => <LF>) should be applied to both the raw and cooked representations,
- // this raw implementation just slices the source string. As a result, line terminators appear in the raw representation without normalization.
- // For example, when parsing `<CR>`, <CR> appears in the raw representation.
- // While non-tagged template literals don't use the raw representation, tagged templates use the raw representation.
- // So line terminator normalization should be applied to the raw representation when implementing tagged templates.
- tokenData->raw = makeIdentifier(rawStringStart, currentSourcePtr() - rawStringStart);
+ // Line terminator normalization (e.g. <CR> => <LF>) should be applied to both the raw and cooked representations.
+ if (rawStringsBuildMode == RawStringsBuildMode::BuildRawStrings)
+ tokenData->raw = makeIdentifier(m_bufferForRawTemplateString16.data(), m_bufferForRawTemplateString16.size());
+ else
+ tokenData->raw = makeEmptyIdentifier();
} else {
- tokenData->cooked = nullptr;
- tokenData->raw = nullptr;
+ tokenData->cooked = makeEmptyIdentifier();
+ tokenData->raw = makeEmptyIdentifier();
}
tokenData->isTail = isTail;
m_buffer16.shrink(0);
+ m_bufferForRawTemplateString16.shrink(0);
if (isTail) {
// Skip `
@@ -2125,9 +2137,9 @@
shift();
StringParseResult result = StringCannotBeParsed;
if (lexerFlags & LexerFlagsDontBuildStrings)
- result = parseTemplateLiteral<false>(tokenData);
+ result = parseTemplateLiteral<false>(tokenData, RawStringsBuildMode::BuildRawStrings);
else
- result = parseTemplateLiteral<true>(tokenData);
+ result = parseTemplateLiteral<true>(tokenData, RawStringsBuildMode::BuildRawStrings);
if (UNLIKELY(result != StringParsedSuccessfully)) {
token = result == StringUnterminated ? UNTERMINATED_TEMPLATE_LITERAL_ERRORTOK : INVALID_TEMPLATE_LITERAL_ERRORTOK;
@@ -2331,7 +2343,7 @@
#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
template <typename T>
-JSTokenType Lexer<T>::scanTrailingTemplateString(JSToken* tokenRecord)
+JSTokenType Lexer<T>::scanTrailingTemplateString(JSToken* tokenRecord, RawStringsBuildMode rawStringsBuildMode)
{
JSTokenData* tokenData = &tokenRecord->m_data;
JSTokenLocation* tokenLocation = &tokenRecord->m_location;
@@ -2340,7 +2352,7 @@
// Leading closing brace } is already shifted in the previous token scan.
// So in this re-scan phase, shift() is not needed here.
- StringParseResult result = parseTemplateLiteral<true>(tokenData);
+ StringParseResult result = parseTemplateLiteral<true>(tokenData, rawStringsBuildMode);
JSTokenType token = ERRORTOK;
if (UNLIKELY(result != StringParsedSuccessfully)) {
token = result == StringUnterminated ? UNTERMINATED_TEMPLATE_LITERAL_ERRORTOK : INVALID_TEMPLATE_LITERAL_ERRORTOK;
@@ -2374,6 +2386,9 @@
Vector<UChar> newBuffer16;
m_buffer16.swap(newBuffer16);
+ Vector<UChar> newBufferForRawTemplateString16;
+ m_bufferForRawTemplateString16.swap(newBufferForRawTemplateString16);
+
m_isReparsing = false;
}
diff --git a/Source/JavaScriptCore/parser/Lexer.h b/Source/JavaScriptCore/parser/Lexer.h
index 8afef26..cab7d52 100644
--- a/Source/JavaScriptCore/parser/Lexer.h
+++ b/Source/JavaScriptCore/parser/Lexer.h
@@ -102,7 +102,8 @@
bool prevTerminator() const { return m_terminator; }
bool scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar patternPrefix = 0);
#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
- JSTokenType scanTrailingTemplateString(JSToken*);
+ enum class RawStringsBuildMode { BuildRawStrings, DontBuildRawStrings };
+ JSTokenType scanTrailingTemplateString(JSToken*, RawStringsBuildMode);
#endif
bool skipRegExp();
@@ -166,6 +167,7 @@
ALWAYS_INLINE const Identifier* makeLCharIdentifier(const UChar* characters, size_t length);
ALWAYS_INLINE const Identifier* makeRightSizedIdentifier(const UChar* characters, size_t length, UChar orAllChars);
ALWAYS_INLINE const Identifier* makeIdentifierLCharFromUChar(const UChar* characters, size_t length);
+ ALWAYS_INLINE const Identifier* makeEmptyIdentifier();
ALWAYS_INLINE bool lastTokenWasRestrKeyword() const;
@@ -184,7 +186,7 @@
enum class EscapeParseMode { Template, String };
template <bool shouldBuildStrings> ALWAYS_INLINE StringParseResult parseComplexEscape(EscapeParseMode, bool strictMode, T stringQuoteCharacter);
#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
- template <bool shouldBuildStrings> ALWAYS_INLINE StringParseResult parseTemplateLiteral(JSTokenData*);
+ template <bool shouldBuildStrings> ALWAYS_INLINE StringParseResult parseTemplateLiteral(JSTokenData*, RawStringsBuildMode);
#endif
ALWAYS_INLINE void parseHex(double& returnValue);
ALWAYS_INLINE bool parseBinary(double& returnValue);
@@ -201,6 +203,7 @@
Vector<LChar> m_buffer8;
Vector<UChar> m_buffer16;
+ Vector<UChar> m_bufferForRawTemplateString16;
bool m_terminator;
int m_lastToken;
@@ -289,6 +292,12 @@
return &m_arena->makeIdentifier(m_vm, characters, length);
}
+template <typename T>
+ALWAYS_INLINE const Identifier* Lexer<T>::makeEmptyIdentifier()
+{
+ return &m_arena->makeEmptyIdentifier(m_vm);
+}
+
template <>
ALWAYS_INLINE void Lexer<LChar>::setCodeStart(const StringImpl* sourceString)
{
diff --git a/Source/JavaScriptCore/parser/NodeConstructors.h b/Source/JavaScriptCore/parser/NodeConstructors.h
index d4b3355..9546b71 100644
--- a/Source/JavaScriptCore/parser/NodeConstructors.h
+++ b/Source/JavaScriptCore/parser/NodeConstructors.h
@@ -143,6 +143,13 @@
, m_templateExpressions(templateExpressions)
{
}
+
+ inline TaggedTemplateNode::TaggedTemplateNode(const JSTokenLocation& location, ExpressionNode* tag, TemplateLiteralNode* templateLiteral)
+ : ExpressionNode(location)
+ , m_tag(tag)
+ , m_templateLiteral(templateLiteral)
+ {
+ }
#endif
inline RegExpNode::RegExpNode(const JSTokenLocation& location, const Identifier& pattern, const Identifier& flags)
diff --git a/Source/JavaScriptCore/parser/Nodes.h b/Source/JavaScriptCore/parser/Nodes.h
index 3a19005..f98fc4c 100644
--- a/Source/JavaScriptCore/parser/Nodes.h
+++ b/Source/JavaScriptCore/parser/Nodes.h
@@ -473,12 +473,28 @@
TemplateLiteralNode(const JSTokenLocation&, TemplateStringListNode*);
TemplateLiteralNode(const JSTokenLocation&, TemplateStringListNode*, TemplateExpressionListNode*);
+ TemplateStringListNode* templateStrings() const { return m_templateStrings; }
+ TemplateExpressionListNode* templateExpressions() const { return m_templateExpressions; }
+
private:
virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
TemplateStringListNode* m_templateStrings;
TemplateExpressionListNode* m_templateExpressions;
};
+
+ class TaggedTemplateNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ TaggedTemplateNode(const JSTokenLocation&, ExpressionNode*, TemplateLiteralNode*);
+
+ TemplateLiteralNode* templateLiteral() const { return m_templateLiteral; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) override;
+
+ ExpressionNode* m_tag;
+ TemplateLiteralNode* m_templateLiteral;
+ };
#endif
class RegExpNode : public ExpressionNode, public ThrowableExpressionData {
diff --git a/Source/JavaScriptCore/parser/Parser.cpp b/Source/JavaScriptCore/parser/Parser.cpp
index 95e988d..10a04bc 100644
--- a/Source/JavaScriptCore/parser/Parser.cpp
+++ b/Source/JavaScriptCore/parser/Parser.cpp
@@ -2282,12 +2282,12 @@
#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
template <typename LexerType>
-template <class TreeBuilder> typename TreeBuilder::TemplateString Parser<LexerType>::parseTemplateString(TreeBuilder& context, bool isTemplateHead, bool& elementIsTail)
+template <class TreeBuilder> typename TreeBuilder::TemplateString Parser<LexerType>::parseTemplateString(TreeBuilder& context, bool isTemplateHead, typename LexerType::RawStringsBuildMode rawStringsBuildMode, bool& elementIsTail)
{
if (!isTemplateHead) {
matchOrFail(CLOSEBRACE, "Expected a closing '}' following an expression in template literal");
// Re-scan the token to recognize it as Template Element.
- m_token.m_type = m_lexer->scanTrailingTemplateString(&m_token);
+ m_token.m_type = m_lexer->scanTrailingTemplateString(&m_token, rawStringsBuildMode);
}
matchOrFail(TEMPLATE, "Expected an template element");
const Identifier* cooked = m_token.m_data.cooked;
@@ -2299,12 +2299,12 @@
}
template <typename LexerType>
-template <class TreeBuilder> typename TreeBuilder::TemplateLiteral Parser<LexerType>::parseTemplateLiteral(TreeBuilder& context)
+template <class TreeBuilder> typename TreeBuilder::TemplateLiteral Parser<LexerType>::parseTemplateLiteral(TreeBuilder& context, typename LexerType::RawStringsBuildMode rawStringsBuildMode)
{
JSTokenLocation location(tokenLocation());
bool elementIsTail = false;
- auto headTemplateString = parseTemplateString(context, true, elementIsTail);
+ auto headTemplateString = parseTemplateString(context, true, rawStringsBuildMode, elementIsTail);
failIfFalse(headTemplateString, "Cannot parse head template element");
typename TreeBuilder::TemplateStringList templateStringList = context.createTemplateStringList(headTemplateString);
@@ -2320,7 +2320,7 @@
typename TreeBuilder::TemplateExpressionList templateExpressionList = context.createTemplateExpressionList(expression);
typename TreeBuilder::TemplateExpressionList templateExpressionTail = templateExpressionList;
- auto templateString = parseTemplateString(context, false, elementIsTail);
+ auto templateString = parseTemplateString(context, false, rawStringsBuildMode, elementIsTail);
failIfFalse(templateString, "Cannot parse template element");
templateStringTail = context.createTemplateStringList(templateStringTail, templateString);
@@ -2331,7 +2331,7 @@
templateExpressionTail = context.createTemplateExpressionList(templateExpressionTail, expression);
- auto templateString = parseTemplateString(context, false, elementIsTail);
+ auto templateString = parseTemplateString(context, false, rawStringsBuildMode, elementIsTail);
failIfFalse(templateString, "Cannot parse template element");
templateStringTail = context.createTemplateStringList(templateStringTail, templateString);
}
@@ -2444,7 +2444,7 @@
}
#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
case TEMPLATE:
- return parseTemplateLiteral(context);
+ return parseTemplateLiteral(context, LexerType::RawStringsBuildMode::DontBuildRawStrings);
#endif
default:
failDueToUnexpectedToken();
@@ -2568,6 +2568,16 @@
next();
break;
}
+ case TEMPLATE: {
+ semanticFailIfTrue(baseIsSuper, "Cannot use super as tag for tagged templates");
+ JSTextPosition expressionEnd = lastTokenEndPosition();
+ int nonLHSCount = m_nonLHSCount;
+ typename TreeBuilder::TemplateLiteral templateLiteral = parseTemplateLiteral(context, LexerType::RawStringsBuildMode::BuildRawStrings);
+ failIfFalse(templateLiteral, "Cannot parse template literal");
+ base = context.createTaggedTemplate(location, base, templateLiteral, expressionStart, expressionEnd, lastTokenEndPosition());
+ m_nonLHSCount = nonLHSCount;
+ break;
+ }
default:
goto endMemberExpression;
}
diff --git a/Source/JavaScriptCore/parser/Parser.h b/Source/JavaScriptCore/parser/Parser.h
index 2883daa..dfe0429 100644
--- a/Source/JavaScriptCore/parser/Parser.h
+++ b/Source/JavaScriptCore/parser/Parser.h
@@ -777,8 +777,8 @@
template <class TreeBuilder> NEVER_INLINE TreeClassExpression parseClass(TreeBuilder&, FunctionRequirements, ParserClassInfo<TreeBuilder>&);
#endif
#if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX)
- template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::TemplateString parseTemplateString(TreeBuilder& context, bool isTemplateHead, bool& elementIsTail);
- template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::TemplateLiteral parseTemplateLiteral(TreeBuilder&);
+ template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::TemplateString parseTemplateString(TreeBuilder& context, bool isTemplateHead, typename LexerType::RawStringsBuildMode, bool& elementIsTail);
+ template <class TreeBuilder> NEVER_INLINE typename TreeBuilder::TemplateLiteral parseTemplateLiteral(TreeBuilder&, typename LexerType::RawStringsBuildMode);
#endif
ALWAYS_INLINE int isBinaryOperator(JSTokenType);
diff --git a/Source/JavaScriptCore/parser/ParserArena.h b/Source/JavaScriptCore/parser/ParserArena.h
index 40ece53..2a7d44d 100644
--- a/Source/JavaScriptCore/parser/ParserArena.h
+++ b/Source/JavaScriptCore/parser/ParserArena.h
@@ -45,6 +45,7 @@
template <typename T>
ALWAYS_INLINE const Identifier& makeIdentifier(VM*, const T* characters, size_t length);
+ ALWAYS_INLINE const Identifier& makeEmptyIdentifier(VM*);
ALWAYS_INLINE const Identifier& makeIdentifierLCharFromUChar(VM*, const UChar* characters, size_t length);
const Identifier& makeNumericIdentifier(VM*, double number);
@@ -91,6 +92,11 @@
return m_identifiers.last();
}
+ ALWAYS_INLINE const Identifier& IdentifierArena::makeEmptyIdentifier(VM* vm)
+ {
+ return vm->propertyNames->emptyIdentifier;
+ }
+
ALWAYS_INLINE const Identifier& IdentifierArena::makeIdentifierLCharFromUChar(VM* vm, const UChar* characters, size_t length)
{
if (!length)
diff --git a/Source/JavaScriptCore/parser/SyntaxChecker.h b/Source/JavaScriptCore/parser/SyntaxChecker.h
index f045397..31d3fe4 100644
--- a/Source/JavaScriptCore/parser/SyntaxChecker.h
+++ b/Source/JavaScriptCore/parser/SyntaxChecker.h
@@ -82,7 +82,9 @@
PropertyListResult, ArgumentsListResult, ElementsListResult,
StatementResult, FormalParameterListResult, ClauseResult,
ClauseListResult, CommaExpr, DeconstructingAssignment,
- TemplateStringResult, TemplateStringListResult, TemplateExpressionListResult, TemplateExpr
+ TemplateStringResult, TemplateStringListResult,
+ TemplateExpressionListResult, TemplateExpr,
+ TaggedTemplateExpr
};
typedef int ExpressionType;
@@ -188,6 +190,7 @@
TemplateExpressionList createTemplateExpressionList(TemplateExpressionList, Expression) { return TemplateExpressionListResult; }
TemplateLiteral createTemplateLiteral(const JSTokenLocation&, TemplateStringList) { return TemplateExpr; }
TemplateLiteral createTemplateLiteral(const JSTokenLocation&, TemplateStringList, TemplateExpressionList) { return TemplateExpr; }
+ ExpressionType createTaggedTemplate(const JSTokenLocation&, ExpressionType, TemplateLiteral, int, int, int) { return TaggedTemplateExpr; }
#endif
int createArgumentsList(const JSTokenLocation&, int) { return ArgumentsListResult; }