1336783 - Remove TokenStream::KeywordIsName.

This commit is contained in:
Fedor 2019-09-05 20:06:12 +03:00
parent 165084547d
commit 2bb2a37638
15 changed files with 892 additions and 757 deletions

View File

@ -63,7 +63,7 @@ included_inclnames_to_ignore = set([
'devtools/Instruments.h', # we ignore devtools/ in general
'double-conversion.h', # strange MFBT case
'javascript-trace.h', # generated in $OBJDIR if HAVE_DTRACE is defined
'jsautokw.h', # generated in $OBJDIR
'frontend/ReservedWordsGenerated.h', # generated in $OBJDIR
'jscustomallocator.h', # provided by embedders; allowed to be missing
'js-config.h', # generated in $OBJDIR
'fdlibm.h', # fdlibm
@ -99,7 +99,7 @@ included_inclnames_to_ignore = set([
# ignore #includes of them when checking #include ordering.
oddly_ordered_inclnames = set([
'ctypes/typedefs.h', # Included multiple times in the body of ctypes/CTypes.h
'jsautokw.h', # Included in the body of frontend/TokenStream.h
'frontend/ReservedWordsGenerated.h', # Included in the body of frontend/TokenStream.h
'jswin.h', # Must be #included before <psapi.h>
'machine/endian.h', # Must be included after <sys/types.h> on BSD
'winbase.h', # Must precede other system headers(?)

View File

@ -0,0 +1,213 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import re
import sys
def read_reserved_word_list(filename):
macro_pat = re.compile(r"^\s*macro\(([^,]+), *[^,]+, *[^\)]+\)\s*\\?$")
reserved_word_list = []
index = 0
with open(filename, 'r') as f:
for line in f:
m = macro_pat.search(line)
if m:
reserved_word_list.append((index, m.group(1)))
index += 1
assert(len(reserved_word_list) != 0)
return reserved_word_list
def line(opt, s):
opt['output'].write('{}{}\n'.format(' ' * opt['indent_level'], s))
def indent(opt):
opt['indent_level'] += 1
def dedent(opt):
opt['indent_level'] -= 1
def span_and_count_at(reserved_word_list, column):
assert(len(reserved_word_list) != 0);
chars_dict = {}
for index, word in reserved_word_list:
chars_dict[ord(word[column])] = True
chars = sorted(chars_dict.keys())
return chars[-1] - chars[0] + 1, len(chars)
def optimal_switch_column(opt, reserved_word_list, columns, unprocessed_columns):
assert(len(reserved_word_list) != 0);
assert(unprocessed_columns != 0);
min_count = 0
min_span = 0
min_count_index = 0
min_span_index = 0
for index in range(0, unprocessed_columns):
span, count = span_and_count_at(reserved_word_list, columns[index])
assert(span != 0)
if span == 1:
assert(count == 1)
return 1, True
assert(count != 1)
if index == 0 or min_span > span:
min_span = span
min_span_index = index
if index == 0 or min_count > count:
min_count = count
min_count_index = index
if min_count <= opt['use_if_threshold']:
return min_count_index, True
return min_span_index, False
def split_list_per_column(reserved_word_list, column):
assert(len(reserved_word_list) != 0);
column_dict = {}
for item in reserved_word_list:
index, word = item
per_column = column_dict.setdefault(word[column], [])
per_column.append(item)
return sorted(column_dict.items(), key=lambda (char, word): ord(char))
def generate_letter_switch(opt, unprocessed_columns, reserved_word_list,
columns=None):
assert(len(reserved_word_list) != 0);
if not columns:
columns = range(0, unprocessed_columns)
if len(reserved_word_list) == 1:
index, word = reserved_word_list[0]
if unprocessed_columns == 0:
line(opt, 'JSRW_GOT_MATCH({}) /* {} */'.format(index, word))
return
if unprocessed_columns > opt['char_tail_test_threshold']:
line(opt, 'JSRW_TEST_GUESS({}) /* {} */'.format(index, word))
return
conds = []
for column in columns[0:unprocessed_columns]:
quoted = repr(word[column])
conds.append('JSRW_AT({})=={}'.format(column, quoted))
line(opt, 'if ({}) {{'.format(' && '.join(conds)))
indent(opt)
line(opt, 'JSRW_GOT_MATCH({}) /* {} */'.format(index, word))
dedent(opt)
line(opt, '}')
line(opt, 'JSRW_NO_MATCH()')
return
assert(unprocessed_columns != 0);
optimal_column_index, use_if = optimal_switch_column(opt, reserved_word_list,
columns,
unprocessed_columns)
optimal_column = columns[optimal_column_index]
# Make a copy to avoid breaking passed list.
columns = columns[:]
columns[optimal_column_index] = columns[unprocessed_columns - 1]
list_per_column = split_list_per_column(reserved_word_list, optimal_column)
if not use_if:
line(opt, 'switch (JSRW_AT({})) {{'.format(optimal_column))
for char, reserved_word_list_per_column in list_per_column:
quoted = repr(char)
if use_if:
line(opt, 'if (JSRW_AT({}) == {}) {{'.format(optimal_column,
quoted))
else:
line(opt, ' case {}:'.format(quoted))
indent(opt)
generate_letter_switch(opt, unprocessed_columns - 1,
reserved_word_list_per_column, columns)
dedent(opt)
if use_if:
line(opt, '}')
if not use_if:
line(opt, '}')
line(opt, 'JSRW_NO_MATCH()')
def split_list_per_length(reserved_word_list):
assert(len(reserved_word_list) != 0);
length_dict = {}
for item in reserved_word_list:
index, word = item
per_length = length_dict.setdefault(len(word), [])
per_length.append(item)
return sorted(length_dict.items(), key=lambda (length, word): length)
def generate_switch(opt, reserved_word_list):
assert(len(reserved_word_list) != 0);
line(opt, '/*')
line(opt, ' * Generating switch for the list of {} entries:'.format(len(reserved_word_list)))
for index, word in reserved_word_list:
line(opt, ' * {}'.format(word))
line(opt, ' */')
list_per_length = split_list_per_length(reserved_word_list)
use_if = False
if len(list_per_length) < opt['use_if_threshold']:
use_if = True
if not use_if:
line(opt, 'switch (JSRW_LENGTH()) {')
for length, reserved_word_list_per_length in list_per_length:
if use_if:
line(opt, 'if (JSRW_LENGTH() == {}) {{'.format(length))
else:
line(opt, ' case {}:'.format(length))
indent(opt)
generate_letter_switch(opt, length, reserved_word_list_per_length)
dedent(opt)
if use_if:
line(opt, '}')
if not use_if:
line(opt, '}')
line(opt, 'JSRW_NO_MATCH()')
def main(output, reserved_words_h):
reserved_word_list = read_reserved_word_list(reserved_words_h)
opt = {
'indent_level': 1,
'use_if_threshold': 3,
'char_tail_test_threshold': 4,
'output': output
}
generate_switch(opt, reserved_word_list)
if __name__ == '__main__':
main(sys.stdout, *sys.argv[1:])

File diff suppressed because it is too large Load Diff

View File

@ -734,6 +734,9 @@ class UsedNameTracker
}
};
template <typename ParseHandler>
class AutoAwaitIsKeyword;
class ParserBase : public StrictModeGetter
{
private:
@ -783,7 +786,13 @@ class ParserBase : public StrictModeGetter
/* Unexpected end of input, i.e. TOK_EOF not at top-level. */
bool isUnexpectedEOF_:1;
bool awaitIsKeyword_:1;
public:
bool awaitIsKeyword() const {
return awaitIsKeyword_;
}
ParserBase(ExclusiveContext* cx, LifoAlloc& alloc, const ReadOnlyCompileOptions& options,
const char16_t* chars, size_t length, bool foldConstants,
UsedNameTracker& usedNames, Parser<SyntaxParseHandler>* syntaxParser,
@ -998,6 +1007,9 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
Parser<SyntaxParseHandler>* syntaxParser, LazyScript* lazyOuterFunction);
~Parser();
friend class AutoAwaitIsKeyword<ParseHandler>;
void setAwaitIsKeyword(bool isKeyword);
bool checkOptions();
// A Parser::Mark is the extension of the LifoAlloc::Mark to the entire
@ -1047,8 +1059,6 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
void trace(JSTracer* trc);
bool checkUnescapedName();
private:
Parser* thisForCtor() { return this; }
@ -1321,17 +1331,22 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
Node classDefinition(YieldHandling yieldHandling, ClassContext classContext,
DefaultHandling defaultHandling);
PropertyName* labelOrIdentifierReference(YieldHandling yieldHandling,
bool yieldTokenizedAsName);
bool checkLabelOrIdentifierReference(HandlePropertyName ident,
uint32_t offset,
YieldHandling yieldHandling);
bool checkBindingIdentifier(HandlePropertyName ident,
uint32_t offset,
YieldHandling yieldHandling);
PropertyName* labelOrIdentifierReference(YieldHandling yieldHandling);
PropertyName* labelIdentifier(YieldHandling yieldHandling) {
return labelOrIdentifierReference(yieldHandling, false);
return labelOrIdentifierReference(yieldHandling);
}
PropertyName* identifierReference(YieldHandling yieldHandling,
bool yieldTokenizedAsName = false)
{
return labelOrIdentifierReference(yieldHandling, yieldTokenizedAsName);
PropertyName* identifierReference(YieldHandling yieldHandling) {
return labelOrIdentifierReference(yieldHandling);
}
PropertyName* importedBinding() {
@ -1393,7 +1408,6 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
private:
bool checkIncDecOperand(Node operand, uint32_t operandOffset);
bool checkStrictAssignment(Node lhs);
bool checkStrictBinding(PropertyName* name, TokenPos pos);
bool hasValidSimpleStrictParameterNames();
@ -1455,6 +1469,25 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
bool asmJS(Node list);
};
template <typename ParseHandler>
class MOZ_STACK_CLASS AutoAwaitIsKeyword
{
private:
Parser<ParseHandler>* parser_;
bool oldAwaitIsKeyword_;
public:
AutoAwaitIsKeyword(Parser<ParseHandler>* parser, bool awaitIsKeyword) {
parser_ = parser;
oldAwaitIsKeyword_ = parser_->awaitIsKeyword_;
parser_->setAwaitIsKeyword(awaitIsKeyword);
}
~AutoAwaitIsKeyword() {
parser_->setAwaitIsKeyword(oldAwaitIsKeyword_);
}
};
} /* namespace frontend */
} /* namespace js */

View File

@ -4,15 +4,16 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* A higher-order macro for enumerating keyword tokens. */
/* A higher-order macro for enumerating reserved word tokens. */
#ifndef vm_Keywords_h
#define vm_Keywords_h
#ifndef vm_ReservedWords_h
#define vm_ReservedWords_h
#define FOR_EACH_JAVASCRIPT_KEYWORD(macro) \
#define FOR_EACH_JAVASCRIPT_RESERVED_WORD(macro) \
macro(false, false_, TOK_FALSE) \
macro(true, true_, TOK_TRUE) \
macro(null, null, TOK_NULL) \
\
/* Keywords. */ \
macro(break, break_, TOK_BREAK) \
macro(case, case_, TOK_CASE) \
@ -36,31 +37,45 @@
macro(this, this_, TOK_THIS) \
macro(throw, throw_, TOK_THROW) \
macro(try, try_, TOK_TRY) \
macro(typeof, typeof, TOK_TYPEOF) \
macro(typeof, typeof_, TOK_TYPEOF) \
macro(var, var, TOK_VAR) \
macro(void, void_, TOK_VOID) \
macro(while, while_, TOK_WHILE) \
macro(with, with, TOK_WITH) \
macro(import, import, TOK_IMPORT) \
macro(export, export, TOK_EXPORT) \
macro(export, export_, TOK_EXPORT) \
macro(class, class_, TOK_CLASS) \
macro(extends, extends, TOK_EXTENDS) \
macro(super, super, TOK_SUPER) \
/* Reserved keywords. */ \
macro(enum, enum_, TOK_RESERVED) \
/* Future reserved keywords, but only in strict mode. */ \
macro(implements, implements, TOK_STRICT_RESERVED) \
macro(interface, interface, TOK_STRICT_RESERVED) \
macro(package, package, TOK_STRICT_RESERVED) \
macro(private, private_, TOK_STRICT_RESERVED) \
macro(protected, protected_, TOK_STRICT_RESERVED) \
macro(public, public_, TOK_STRICT_RESERVED) \
\
/* Future reserved words. */ \
macro(enum, enum_, TOK_ENUM) \
\
/* Future reserved words, but only in strict mode. */ \
macro(implements, implements, TOK_IMPLEMENTS) \
macro(interface, interface, TOK_INTERFACE) \
macro(package, package, TOK_PACKAGE) \
macro(private, private_, TOK_PRIVATE) \
macro(protected, protected_, TOK_PROTECTED) \
macro(public, public_, TOK_PUBLIC) \
\
/* Contextual keywords. */ \
macro(as, as, TOK_AS) \
macro(async, async, TOK_ASYNC) \
macro(await, await, TOK_AWAIT) \
macro(each, each, TOK_EACH) \
macro(from, from, TOK_FROM) \
macro(get, get, TOK_GET) \
macro(let, let, TOK_LET) \
macro(of, of, TOK_OF) \
macro(set, set, TOK_SET) \
macro(static, static_, TOK_STATIC) \
macro(target, target, TOK_TARGET) \
/* \
* Yield is a token inside function*. Outside of a function*, it is a \
* future reserved keyword in strict mode, but a keyword in JS1.7 even \
* future reserved word in strict mode, but a keyword in JS1.7 even \
* when strict. Punt logic to parser. \
*/ \
macro(yield, yield, TOK_YIELD)
#endif /* vm_Keywords_h */
#endif /* vm_ReservedWords_h */

View File

@ -81,9 +81,12 @@
\
macro(REGEXP, "regular expression literal") \
macro(TRUE, "boolean literal 'true'") \
range(RESERVED_WORD_LITERAL_FIRST, TRUE) \
macro(FALSE, "boolean literal 'false'") \
macro(NULL, "null literal") \
range(RESERVED_WORD_LITERAL_LAST, NULL) \
macro(THIS, "keyword 'this'") \
range(KEYWORD_FIRST, THIS) \
macro(FUNCTION, "keyword 'function'") \
macro(IF, "keyword 'if'") \
macro(ELSE, "keyword 'else'") \
@ -106,16 +109,43 @@
macro(FINALLY, "keyword 'finally'") \
macro(THROW, "keyword 'throw'") \
macro(DEBUGGER, "keyword 'debugger'") \
macro(YIELD, "keyword 'yield'") \
macro(AWAIT, "keyword 'await'") \
macro(EXPORT, "keyword 'export'") \
macro(IMPORT, "keyword 'import'") \
macro(CLASS, "keyword 'class'") \
macro(EXTENDS, "keyword 'extends'") \
macro(SUPER, "keyword 'super'") \
macro(RESERVED, "reserved keyword") \
/* reserved keywords in strict mode */ \
macro(STRICT_RESERVED, "reserved keyword") \
range(KEYWORD_LAST, SUPER) \
\
/* contextual keywords */ \
macro(AS, "'as'") \
range(CONTEXTUAL_KEYWORD_FIRST, AS) \
macro(ASYNC, "'async'") \
macro(AWAIT, "'await'") \
macro(EACH, "'each'") \
macro(FROM, "'from'") \
macro(GET, "'get'") \
macro(LET, "'let'") \
macro(OF, "'of'") \
macro(SET, "'set'") \
macro(STATIC, "'static'") \
macro(TARGET, "'target'") \
macro(YIELD, "'yield'") \
range(CONTEXTUAL_KEYWORD_LAST, YIELD) \
\
/* future reserved words */ \
macro(ENUM, "reserved word 'enum'") \
range(FUTURE_RESERVED_KEYWORD_FIRST, ENUM) \
range(FUTURE_RESERVED_KEYWORD_LAST, ENUM) \
\
/* reserved words in strict mode */ \
macro(IMPLEMENTS, "reserved word 'implements'") \
range(STRICT_RESERVED_KEYWORD_FIRST, IMPLEMENTS) \
macro(INTERFACE, "reserved word 'interface'") \
macro(PACKAGE, "reserved word 'package'") \
macro(PRIVATE, "reserved word 'private'") \
macro(PROTECTED, "reserved word 'protected'") \
macro(PUBLIC, "reserved word 'public'") \
range(STRICT_RESERVED_KEYWORD_LAST, PUBLIC) \
\
/* \
* The following token types occupy contiguous ranges to enable easy \
@ -149,7 +179,9 @@
range(RELOP_LAST, GE) \
\
macro(INSTANCEOF, "keyword 'instanceof'") \
range(KEYWORD_BINOP_FIRST, INSTANCEOF) \
macro(IN, "keyword 'in'") \
range(KEYWORD_BINOP_LAST, IN) \
\
/* Shift ops, per TokenKindIsShift. */ \
macro(LSH, "'<<'") \
@ -168,7 +200,9 @@
\
/* Unary operation tokens. */ \
macro(TYPEOF, "keyword 'typeof'") \
range(KEYWORD_UNOP_FIRST, TYPEOF) \
macro(VOID, "keyword 'void'") \
range(KEYWORD_UNOP_LAST, VOID) \
macro(NOT, "'!'") \
macro(BITNOT, "'~'") \
\
@ -239,6 +273,61 @@ TokenKindIsAssignment(TokenKind tt)
return TOK_ASSIGNMENT_START <= tt && tt <= TOK_ASSIGNMENT_LAST;
}
inline MOZ_MUST_USE bool
TokenKindIsKeyword(TokenKind tt)
{
return (TOK_KEYWORD_FIRST <= tt && tt <= TOK_KEYWORD_LAST) ||
(TOK_KEYWORD_BINOP_FIRST <= tt && tt <= TOK_KEYWORD_BINOP_LAST) ||
(TOK_KEYWORD_UNOP_FIRST <= tt && tt <= TOK_KEYWORD_UNOP_LAST);
}
inline MOZ_MUST_USE bool
TokenKindIsContextualKeyword(TokenKind tt)
{
return TOK_CONTEXTUAL_KEYWORD_FIRST <= tt && tt <= TOK_CONTEXTUAL_KEYWORD_LAST;
}
inline MOZ_MUST_USE bool
TokenKindIsFutureReservedWord(TokenKind tt)
{
return TOK_FUTURE_RESERVED_KEYWORD_FIRST <= tt && tt <= TOK_FUTURE_RESERVED_KEYWORD_LAST;
}
inline MOZ_MUST_USE bool
TokenKindIsStrictReservedWord(TokenKind tt)
{
return TOK_STRICT_RESERVED_KEYWORD_FIRST <= tt && tt <= TOK_STRICT_RESERVED_KEYWORD_LAST;
}
inline MOZ_MUST_USE bool
TokenKindIsReservedWordLiteral(TokenKind tt)
{
return TOK_RESERVED_WORD_LITERAL_FIRST <= tt && tt <= TOK_RESERVED_WORD_LITERAL_LAST;
}
inline MOZ_MUST_USE bool
TokenKindIsReservedWord(TokenKind tt)
{
return TokenKindIsKeyword(tt) ||
TokenKindIsFutureReservedWord(tt) ||
TokenKindIsReservedWordLiteral(tt);
}
inline MOZ_MUST_USE bool
TokenKindIsPossibleIdentifier(TokenKind tt)
{
return tt == TOK_NAME ||
TokenKindIsContextualKeyword(tt) ||
TokenKindIsStrictReservedWord(tt);
}
inline MOZ_MUST_USE bool
TokenKindIsPossibleIdentifierName(TokenKind tt)
{
return TokenKindIsPossibleIdentifier(tt) ||
TokenKindIsReservedWord(tt);
}
} // namespace frontend
} // namespace js

View File

@ -24,10 +24,10 @@
#include "jsnum.h"
#include "frontend/BytecodeCompiler.h"
#include "frontend/ReservedWords.h"
#include "js/CharacterEncoding.h"
#include "js/UniquePtr.h"
#include "vm/HelperThreads.h"
#include "vm/Keywords.h"
#include "vm/StringBuffer.h"
#include "vm/Unicode.h"
@ -40,65 +40,65 @@ using mozilla::PodAssign;
using mozilla::PodCopy;
using mozilla::PodZero;
struct KeywordInfo {
const char* chars; // C string with keyword text
struct ReservedWordInfo {
const char* chars; // C string with reserved word text
TokenKind tokentype;
};
static const KeywordInfo keywords[] = {
#define KEYWORD_INFO(keyword, name, type) \
{js_##keyword##_str, type},
FOR_EACH_JAVASCRIPT_KEYWORD(KEYWORD_INFO)
#undef KEYWORD_INFO
static const ReservedWordInfo reservedWords[] = {
#define RESERVED_WORD_INFO(word, name, type) \
{js_##word##_str, type},
FOR_EACH_JAVASCRIPT_RESERVED_WORD(RESERVED_WORD_INFO)
#undef RESERVED_WORD_INFO
};
// Returns a KeywordInfo for the specified characters, or nullptr if the string
// is not a keyword.
// Returns a ReservedWordInfo for the specified characters, or nullptr if the
// string is not a reserved word.
template <typename CharT>
static const KeywordInfo*
FindKeyword(const CharT* s, size_t length)
static const ReservedWordInfo*
FindReservedWord(const CharT* s, size_t length)
{
MOZ_ASSERT(length != 0);
size_t i;
const KeywordInfo* kw;
const ReservedWordInfo* rw;
const char* chars;
#define JSKW_LENGTH() length
#define JSKW_AT(column) s[column]
#define JSKW_GOT_MATCH(index) i = (index); goto got_match;
#define JSKW_TEST_GUESS(index) i = (index); goto test_guess;
#define JSKW_NO_MATCH() goto no_match;
#include "jsautokw.h"
#undef JSKW_NO_MATCH
#undef JSKW_TEST_GUESS
#undef JSKW_GOT_MATCH
#undef JSKW_AT
#undef JSKW_LENGTH
#define JSRW_LENGTH() length
#define JSRW_AT(column) s[column]
#define JSRW_GOT_MATCH(index) i = (index); goto got_match;
#define JSRW_TEST_GUESS(index) i = (index); goto test_guess;
#define JSRW_NO_MATCH() goto no_match;
#include "frontend/ReservedWordsGenerated.h"
#undef JSRW_NO_MATCH
#undef JSRW_TEST_GUESS
#undef JSRW_GOT_MATCH
#undef JSRW_AT
#undef JSRW_LENGTH
got_match:
return &keywords[i];
return &reservedWords[i];
test_guess:
kw = &keywords[i];
chars = kw->chars;
rw = &reservedWords[i];
chars = rw->chars;
do {
if (*s++ != (unsigned char)(*chars++))
goto no_match;
} while (--length != 0);
return kw;
return rw;
no_match:
return nullptr;
}
static const KeywordInfo*
FindKeyword(JSLinearString* str)
static const ReservedWordInfo*
FindReservedWord(JSLinearString* str)
{
JS::AutoCheckCannotGC nogc;
return str->hasLatin1Chars()
? FindKeyword(str->latin1Chars(nogc), str->length())
: FindKeyword(str->twoByteChars(nogc), str->length());
? FindReservedWord(str->latin1Chars(nogc), str->length())
: FindReservedWord(str->twoByteChars(nogc), str->length());
}
template <typename CharT>
@ -188,7 +188,68 @@ frontend::IsIdentifier(const char16_t* chars, size_t length)
bool
frontend::IsKeyword(JSLinearString* str)
{
return FindKeyword(str) != nullptr;
if (const ReservedWordInfo* rw = FindReservedWord(str))
return TokenKindIsKeyword(rw->tokentype);
return false;
}
bool
frontend::IsFutureReservedWord(JSLinearString* str)
{
if (const ReservedWordInfo* rw = FindReservedWord(str))
return TokenKindIsFutureReservedWord(rw->tokentype);
return false;
}
bool
frontend::IsStrictReservedWord(JSLinearString* str)
{
if (const ReservedWordInfo* rw = FindReservedWord(str))
return TokenKindIsStrictReservedWord(rw->tokentype);
return false;
}
bool
frontend::IsReservedWordLiteral(JSLinearString* str)
{
if (const ReservedWordInfo* rw = FindReservedWord(str))
return TokenKindIsReservedWordLiteral(rw->tokentype);
return false;
}
const char*
frontend::ReservedWordToCharZ(PropertyName* str)
{
const ReservedWordInfo* rw = FindReservedWord(str);
if (rw == nullptr)
return nullptr;
switch (rw->tokentype) {
#define EMIT_CASE(word, name, type) case type: return js_##word##_str;
FOR_EACH_JAVASCRIPT_RESERVED_WORD(EMIT_CASE)
#undef EMIT_CASE
default:
MOZ_ASSERT_UNREACHABLE("Not a reserved word PropertyName.");
}
return nullptr;
}
PropertyName*
TokenStream::reservedWordToPropertyName(TokenKind tt) const
{
MOZ_ASSERT(tt != TOK_NAME);
switch (tt) {
#define EMIT_CASE(word, name, type) case type: return cx->names().name;
FOR_EACH_JAVASCRIPT_RESERVED_WORD(EMIT_CASE)
#undef EMIT_CASE
default:
MOZ_ASSERT_UNREACHABLE("Not a reserved word TokenKind.");
}
return nullptr;
}
TokenStream::SourceCoords::SourceCoords(ExclusiveContext* cx, uint32_t ln)
@ -1169,38 +1230,6 @@ TokenStream::putIdentInTokenbuf(const char16_t* identStart)
return true;
}
bool
TokenStream::checkForKeyword(const KeywordInfo* kw, TokenKind* ttp)
{
if (!awaitIsKeyword && kw->tokentype == TOK_AWAIT) {
if (ttp)
*ttp = TOK_NAME;
return true;
}
if (kw->tokentype == TOK_RESERVED) {
error(JSMSG_RESERVED_ID, kw->chars);
return false;
}
if (kw->tokentype == TOK_STRICT_RESERVED)
return reportStrictModeError(JSMSG_RESERVED_ID, kw->chars);
// Working keyword.
*ttp = kw->tokentype;
return true;
}
bool
TokenStream::checkForKeyword(JSAtom* atom, TokenKind* ttp)
{
const KeywordInfo* kw = FindKeyword(atom);
if (!kw)
return true;
return checkForKeyword(kw, ttp);
}
enum FirstCharKind {
// A char16_t has the 'OneChar' kind if it, by itself, constitutes a valid
// token that cannot also be a prefix of a longer token. E.g. ';' has the
@ -1424,36 +1453,18 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
length = userbuf.addressOfNextRawChar() - identStart;
}
// Represent keywords as keyword tokens unless told otherwise.
if (modifier != KeywordIsName) {
if (const KeywordInfo* kw = FindKeyword(chars, length)) {
// That said, keywords can't contain escapes. (Contexts where
// keywords are treated as names, that also sometimes treat
// keywords as keywords, must manually check this requirement.)
// There are two exceptions
// 1) StrictReservedWords: These keywords need to be treated as
// names in non-strict mode.
// 2) yield is also treated as a name if it contains an escape
// sequence. The parser must handle this case separately.
if (hadUnicodeEscape && !(
(kw->tokentype == TOK_STRICT_RESERVED && !strictMode()) ||
kw->tokentype == TOK_YIELD))
{
reportError(JSMSG_ESCAPED_KEYWORD);
goto error;
}
tp->type = TOK_NAME;
if (!checkForKeyword(kw, &tp->type))
goto error;
if (tp->type != TOK_NAME && !hadUnicodeEscape)
goto out;
// Represent reserved words as reserved word tokens.
if (!hadUnicodeEscape) {
if (const ReservedWordInfo* rw = FindReservedWord(chars, length)) {
tp->type = rw->tokentype;
goto out;
}
}
JSAtom* atom = AtomizeChars(cx, chars, length);
if (!atom)
if (!atom) {
goto error;
}
tp->type = TOK_NAME;
tp->setName(atom->asPropertyName());
goto out;

View File

@ -26,14 +26,13 @@
#include "js/UniquePtr.h"
#include "js/Vector.h"
#include "vm/RegExpObject.h"
#include "vm/String.h"
struct KeywordInfo;
namespace js {
namespace frontend {
class AutoAwaitIsKeyword;
struct TokenPos {
uint32_t begin; // Offset of the token's first char.
uint32_t end; // Offset of 1 past the token's last char.
@ -120,9 +119,6 @@ struct Token
// TOK_DIV.
Operand,
// Treat keywords as names by returning TOK_NAME.
KeywordIsName,
// Treat subsequent characters as the tail of a template literal, after
// a template substitution, beginning with a "}", continuing with zero
// or more template literal characters, and ending with either "${" or
@ -164,10 +160,6 @@ struct Token
// If a semicolon is inserted automatically, the next token is already
// gotten with None, but we expect Operand.
OperandIsNone,
// If name of method definition is `get` or `set`, the next token is
// already gotten with KeywordIsName, but we expect None.
NoneIsKeywordIsName,
};
friend class TokenStream;
@ -224,11 +216,6 @@ struct Token
return u.name->JSAtom::asPropertyName(); // poor-man's type verification
}
bool nameContainsEscape() const {
PropertyName* n = name();
return pos.begin + n->length() != pos.end;
}
JSAtom* atom() const {
MOZ_ASSERT(type == TOK_STRING ||
type == TOK_TEMPLATE_HEAD ||
@ -254,10 +241,22 @@ struct Token
};
class CompileError : public JSErrorReport {
public:
public:
void throwError(JSContext* cx);
};
extern const char*
ReservedWordToCharZ(PropertyName* str);
extern MOZ_MUST_USE bool
IsFutureReservedWord(JSLinearString* str);
extern MOZ_MUST_USE bool
IsReservedWordLiteral(JSLinearString* str);
extern MOZ_MUST_USE bool
IsStrictReservedWord(JSLinearString* str);
// Ideally, tokenizing would be entirely independent of context. But the
// strict mode flag, which is in SharedContext, affects tokenizing, and
// TokenStream needs to see it.
@ -344,25 +343,26 @@ class MOZ_STACK_CLASS TokenStream
JSVersion versionNumber() const { return VersionNumber(options().version); }
JSVersion versionWithFlags() const { return options().version; }
private:
PropertyName* reservedWordToPropertyName(TokenKind tt) const;
public:
PropertyName* currentName() const {
if (isCurrentTokenType(TOK_YIELD))
return cx->names().yield;
MOZ_ASSERT(isCurrentTokenType(TOK_NAME));
return currentToken().name();
if (isCurrentTokenType(TOK_NAME)) {
return currentToken().name();
}
MOZ_ASSERT(TokenKindIsPossibleIdentifierName(currentToken().type));
return reservedWordToPropertyName(currentToken().type);
}
PropertyName* nextName() const {
if (nextToken().type == TOK_YIELD)
return cx->names().yield;
MOZ_ASSERT(nextToken().type == TOK_NAME);
return nextToken().name();
}
if (nextToken().type != TOK_NAME) {
return nextToken().name();
}
bool nextNameContainsEscape() const {
if (nextToken().type == TOK_YIELD)
return false;
MOZ_ASSERT(nextToken().type == TOK_NAME);
return nextToken().nameContainsEscape();
MOZ_ASSERT(TokenKindIsPossibleIdentifierName(nextToken().type));
return reservedWordToPropertyName(nextToken().type);
}
bool isCurrentTokenAssignment() const {
@ -498,9 +498,6 @@ class MOZ_STACK_CLASS TokenStream
{}
};
bool awaitIsKeyword = false;
friend class AutoAwaitIsKeyword;
uint32_t invalidTemplateEscapeOffset = 0;
InvalidEscapeType invalidTemplateEscapeType = InvalidEscapeType::None;
@ -508,14 +505,12 @@ class MOZ_STACK_CLASS TokenStream
typedef Token::Modifier Modifier;
static constexpr Modifier None = Token::None;
static constexpr Modifier Operand = Token::Operand;
static constexpr Modifier KeywordIsName = Token::KeywordIsName;
static constexpr Modifier TemplateTail = Token::TemplateTail;
typedef Token::ModifierException ModifierException;
static constexpr ModifierException NoException = Token::NoException;
static constexpr ModifierException NoneIsOperand = Token::NoneIsOperand;
static constexpr ModifierException OperandIsNone = Token::OperandIsNone;
static constexpr ModifierException NoneIsKeywordIsName = Token::NoneIsKeywordIsName;
void addModifierException(ModifierException modifierException) {
#ifdef DEBUG
@ -544,10 +539,6 @@ class MOZ_STACK_CLASS TokenStream
MOZ_ASSERT(next.type != TOK_DIV && next.type != TOK_REGEXP,
"next token requires contextual specifier to be parsed unambiguously");
break;
case NoneIsKeywordIsName:
MOZ_ASSERT(next.modifier == KeywordIsName);
MOZ_ASSERT(next.type != TOK_NAME);
break;
default:
MOZ_CRASH("unexpected modifier exception");
}
@ -574,12 +565,6 @@ class MOZ_STACK_CLASS TokenStream
return;
}
if (lookaheadToken.modifierException == NoneIsKeywordIsName) {
// getToken() permissibly following getToken(KeywordIsName).
if (modifier == None && lookaheadToken.modifier == KeywordIsName)
return;
}
MOZ_ASSERT_UNREACHABLE("this token was previously looked up with a "
"different modifier, potentially making "
"tokenization non-deterministic");
@ -713,36 +698,6 @@ class MOZ_STACK_CLASS TokenStream
MOZ_ALWAYS_TRUE(matched);
}
// Like matchToken(..., TOK_NAME) but further matching the name token only
// if it has the given characters, without containing escape sequences.
// If the name token has the given characters yet *does* contain an escape,
// a syntax error will be reported.
//
// This latter behavior makes this method unsuitable for use in any context
// where ASI might occur. In such places, an escaped "contextual keyword"
// on a new line is the start of an ExpressionStatement, not a continuation
// of a StatementListItem (or ImportDeclaration or ExportDeclaration, in
// modules).
MOZ_MUST_USE bool matchContextualKeyword(bool* matchedp, Handle<PropertyName*> keyword,
Modifier modifier = None)
{
TokenKind token;
if (!getToken(&token, modifier))
return false;
if (token == TOK_NAME && currentToken().name() == keyword) {
if (currentToken().nameContainsEscape()) {
reportError(JSMSG_ESCAPED_KEYWORD);
return false;
}
*matchedp = true;
} else {
*matchedp = false;
ungetToken();
}
return true;
}
MOZ_MUST_USE bool nextTokenEndsExpr(bool* endsExpr) {
TokenKind tt;
if (!peekToken(&tt))
@ -808,19 +763,6 @@ class MOZ_STACK_CLASS TokenStream
return sourceMapURL_.get();
}
// If |atom| is not a keyword in this version, return true with *ttp
// unchanged.
//
// If it is a reserved word in this version and strictness mode, and thus
// can't be present in correct code, report a SyntaxError and return false.
//
// If it is a keyword, like "if", return true with the keyword's TokenKind
// in *ttp.
MOZ_MUST_USE bool checkForKeyword(JSAtom* atom, TokenKind* ttp);
// Same semantics as above, but for the provided keyword.
MOZ_MUST_USE bool checkForKeyword(const KeywordInfo* kw, TokenKind* ttp);
// This class maps a userbuf offset (which is 0-indexed) to a line number
// (which is 1-indexed) and a column index (which is 0-indexed).
class SourceCoords
@ -1102,25 +1044,6 @@ class MOZ_STACK_CLASS TokenStream
StrictModeGetter* strictModeGetter; // used to test for strict mode
};
class MOZ_STACK_CLASS AutoAwaitIsKeyword
{
private:
TokenStream* ts_;
bool oldAwaitIsKeyword_;
public:
AutoAwaitIsKeyword(TokenStream* ts, bool awaitIsKeyword) {
ts_ = ts;
oldAwaitIsKeyword_ = ts_->awaitIsKeyword;
ts_->awaitIsKeyword = awaitIsKeyword;
}
~AutoAwaitIsKeyword() {
ts_->awaitIsKeyword = oldAwaitIsKeyword_;
ts_ = nullptr;
}
};
extern const char*
TokenKindToDesc(TokenKind tt);

View File

@ -403,9 +403,7 @@ assertThrowsInstanceOf(function() {
parseAsModule("export {,} from 'a'");
}, SyntaxError);
assertThrowsInstanceOf(function() {
parseAsModule("export { true as a } from 'b'");
}, SyntaxError);
parseAsModule("export { true as a } from 'b'");
assertThrowsInstanceOf(function () {
parseAsModule("export { a } from 'b' f();");

View File

@ -265,6 +265,7 @@ MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations
MSG_DEF(JSMSG_OF_AFTER_FOR_LOOP_DECL, 0, JSEXN_SYNTAXERR, "a declaration in the head of a for-of loop can't have an initializer")
MSG_DEF(JSMSG_IN_AFTER_LEXICAL_FOR_DECL,0,JSEXN_SYNTAXERR, "a lexical declaration in the head of a for-in loop can't have an initializer")
MSG_DEF(JSMSG_INVALID_FOR_IN_DECL_WITH_INIT,0,JSEXN_SYNTAXERR,"for-in loop head declarations may not have initializers")
MSG_DEF(JSMSG_INVALID_ID, 1, JSEXN_SYNTAXERR, "{0} is an invalid identifier")
MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found")
MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable")
MSG_DEF(JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, 1, JSEXN_SYNTAXERR, "{0} declaration not directly within block")

View File

@ -54,41 +54,9 @@ FOR_EACH_COMMON_PROPERTYNAME(CONST_CHAR_STR)
#undef CONST_CHAR_STR
/* Constant strings that are not atomized. */
const char js_break_str[] = "break";
const char js_case_str[] = "case";
const char js_catch_str[] = "catch";
const char js_class_str[] = "class";
const char js_const_str[] = "const";
const char js_continue_str[] = "continue";
const char js_debugger_str[] = "debugger";
const char js_default_str[] = "default";
const char js_do_str[] = "do";
const char js_else_str[] = "else";
const char js_enum_str[] = "enum";
const char js_export_str[] = "export";
const char js_extends_str[] = "extends";
const char js_finally_str[] = "finally";
const char js_for_str[] = "for";
const char js_getter_str[] = "getter";
const char js_if_str[] = "if";
const char js_implements_str[] = "implements";
const char js_import_str[] = "import";
const char js_in_str[] = "in";
const char js_instanceof_str[] = "instanceof";
const char js_interface_str[] = "interface";
const char js_package_str[] = "package";
const char js_private_str[] = "private";
const char js_protected_str[] = "protected";
const char js_public_str[] = "public";
const char js_send_str[] = "send";
const char js_setter_str[] = "setter";
const char js_switch_str[] = "switch";
const char js_this_str[] = "this";
const char js_try_str[] = "try";
const char js_typeof_str[] = "typeof";
const char js_void_str[] = "void";
const char js_while_str[] = "while";
const char js_with_str[] = "with";
// Use a low initial capacity for atom hash tables to avoid penalizing runtimes
// which create a small number of atoms.

View File

@ -142,44 +142,9 @@ FOR_EACH_COMMON_PROPERTYNAME(DECLARE_CONST_CHAR_STR)
#undef DECLARE_CONST_CHAR_STR
/* Constant strings that are not atomized. */
extern const char js_break_str[];
extern const char js_case_str[];
extern const char js_catch_str[];
extern const char js_class_str[];
extern const char js_close_str[];
extern const char js_const_str[];
extern const char js_continue_str[];
extern const char js_debugger_str[];
extern const char js_default_str[];
extern const char js_do_str[];
extern const char js_else_str[];
extern const char js_enum_str[];
extern const char js_export_str[];
extern const char js_extends_str[];
extern const char js_finally_str[];
extern const char js_for_str[];
extern const char js_getter_str[];
extern const char js_if_str[];
extern const char js_implements_str[];
extern const char js_import_str[];
extern const char js_in_str[];
extern const char js_instanceof_str[];
extern const char js_interface_str[];
extern const char js_package_str[];
extern const char js_private_str[];
extern const char js_protected_str[];
extern const char js_public_str[];
extern const char js_send_str[];
extern const char js_setter_str[];
extern const char js_static_str[];
extern const char js_super_str[];
extern const char js_switch_str[];
extern const char js_this_str[];
extern const char js_try_str[];
extern const char js_typeof_str[];
extern const char js_void_str[];
extern const char js_while_str[];
extern const char js_with_str[];
namespace js {

View File

@ -619,11 +619,11 @@ else:
'perf/pm_stub.cpp'
]
GENERATED_FILES += ['jsautokw.h']
jsautokw = GENERATED_FILES['jsautokw.h']
jsautokw.script = 'jsautokw.py'
jsautokw.inputs += [
'vm/Keywords.h'
GENERATED_FILES += ['frontend/ReservedWordsGenerated.h']
ReservedWordsGenerated = GENERATED_FILES['frontend/ReservedWordsGenerated.h']
ReservedWordsGenerated.script = 'frontend/GenerateReservedWords.py'
ReservedWordsGenerated.inputs += [
'frontend/ReservedWords.h'
]
# JavaScript must be built shared, even for static builds, as it is used by

View File

@ -38,6 +38,7 @@
macro(Bool32x4, Bool32x4, "Bool32x4") \
macro(Bool64x2, Bool64x2, "Bool64x2") \
macro(boundWithSpace, boundWithSpace, "bound ") \
macro(break, break_, "break") \
macro(breakdown, breakdown, "breakdown") \
macro(buffer, buffer, "buffer") \
macro(builder, builder, "builder") \
@ -52,8 +53,10 @@
macro(callee, callee, "callee") \
macro(caller, caller, "caller") \
macro(callFunction, callFunction, "callFunction") \
macro(case, case_, "case") \
macro(caseFirst, caseFirst, "caseFirst") \
macro(class_, class_, "class") \
macro(catch, catch_, "catch") \
macro(class, class_, "class") \
macro(close, close, "close") \
macro(Collator, Collator, "Collator") \
macro(CollatorCompareGet, CollatorCompareGet, "Intl_Collator_compare_get") \
@ -62,9 +65,11 @@
macro(comma, comma, ",") \
macro(compare, compare, "compare") \
macro(configurable, configurable, "configurable") \
macro(const, const_, "const") \
macro(construct, construct, "construct") \
macro(constructContentFunction, constructContentFunction, "constructContentFunction") \
macro(constructor, constructor, "constructor") \
macro(continue, continue_, "continue") \
macro(ConvertAndCopyTo, ConvertAndCopyTo, "ConvertAndCopyTo") \
macro(copyWithin, copyWithin, "copyWithin") \
macro(count, count, "count") \
@ -76,28 +81,32 @@
macro(DateTimeFormatFormatToParts, DateTimeFormatFormatToParts, "Intl_DateTimeFormat_formatToParts") \
macro(day, day, "day") \
macro(dayPeriod, dayPeriod, "dayPeriod") \
macro(debugger, debugger, "debugger") \
macro(decodeURI, decodeURI, "decodeURI") \
macro(decodeURIComponent, decodeURIComponent, "decodeURIComponent") \
macro(DefaultBaseClassConstructor, DefaultBaseClassConstructor, "DefaultBaseClassConstructor") \
macro(DefaultDerivedClassConstructor, DefaultDerivedClassConstructor, "DefaultDerivedClassConstructor") \
macro(default_, default_, "default") \
macro(default, default_, "default") \
macro(defineGetter, defineGetter, "__defineGetter__") \
macro(defineProperty, defineProperty, "defineProperty") \
macro(defineSetter, defineSetter, "__defineSetter__") \
macro(delete, delete_, "delete") \
macro(deleteProperty, deleteProperty, "deleteProperty") \
macro(displayURL, displayURL, "displayURL") \
macro(do, do_, "do") \
macro(done, done, "done") \
macro(dotGenerator, dotGenerator, ".generator") \
macro(dotThis, dotThis, ".this") \
macro(each, each, "each") \
macro(elementType, elementType, "elementType") \
macro(else, else_, "else") \
macro(empty, empty, "") \
macro(emptyRegExp, emptyRegExp, "(?:)") \
macro(encodeURI, encodeURI, "encodeURI") \
macro(encodeURIComponent, encodeURIComponent, "encodeURIComponent") \
macro(endTimestamp, endTimestamp, "endTimestamp") \
macro(entries, entries, "entries") \
macro(enum, enum_, "enum") \
macro(enumerable, enumerable, "enumerable") \
macro(enumerate, enumerate, "enumerate") \
macro(era, era, "era") \
@ -105,11 +114,14 @@
macro(escape, escape, "escape") \
macro(eval, eval, "eval") \
macro(exec, exec, "exec") \
macro(export, export_, "export") \
macro(extends, extends, "extends") \
macro(false, false_, "false") \
macro(fieldOffsets, fieldOffsets, "fieldOffsets") \
macro(fieldTypes, fieldTypes, "fieldTypes") \
macro(fileName, fileName, "fileName") \
macro(fill, fill, "fill") \
macro(finally, finally_, "finally") \
macro(find, find, "find") \
macro(findIndex, findIndex, "findIndex") \
macro(firstDayOfWeek, firstDayOfWeek, "firstDayOfWeek") \
@ -121,6 +133,7 @@
macro(Float32x4, Float32x4, "Float32x4") \
macro(float64, float64, "float64") \
macro(Float64x2, Float64x2, "Float64x2") \
macro(for, for_, "for") \
macro(forceInterpreter, forceInterpreter, "forceInterpreter") \
macro(forEach, forEach, "forEach") \
macro(format, format, "format") \
@ -146,8 +159,12 @@
macro(hasOwn, hasOwn, "hasOwn") \
macro(hasOwnProperty, hasOwnProperty, "hasOwnProperty") \
macro(hour, hour, "hour") \
macro(if, if_, "if") \
macro(ignoreCase, ignoreCase, "ignoreCase") \
macro(ignorePunctuation, ignorePunctuation, "ignorePunctuation") \
macro(implements, implements, "implements") \
macro(import, import, "import") \
macro(in, in, "in") \
macro(includes, includes, "includes") \
macro(incumbentGlobal, incumbentGlobal, "incumbentGlobal") \
macro(index, index, "index") \
@ -158,12 +175,14 @@
macro(innermost, innermost, "innermost") \
macro(inNursery, inNursery, "inNursery") \
macro(input, input, "input") \
macro(instanceof, instanceof, "instanceof") \
macro(int8, int8, "int8") \
macro(int16, int16, "int16") \
macro(int32, int32, "int32") \
macro(Int8x16, Int8x16, "Int8x16") \
macro(Int16x8, Int16x8, "Int16x8") \
macro(Int32x4, Int32x4, "Int32x4") \
macro(interface, interface, "interface") \
macro(InterpretGeneratorResume, InterpretGeneratorResume, "InterpretGeneratorResume") \
macro(isEntryPoint, isEntryPoint, "isEntryPoint") \
macro(isExtensible, isExtensible, "isExtensible") \
@ -240,13 +259,17 @@
macro(outOfMemory, outOfMemory, "out of memory") \
macro(ownKeys, ownKeys, "ownKeys") \
macro(Object_valueOf, Object_valueOf, "Object_valueOf") \
macro(package, package, "package") \
macro(parseFloat, parseFloat, "parseFloat") \
macro(parseInt, parseInt, "parseInt") \
macro(pattern, pattern, "pattern") \
macro(pending, pending, "pending") \
macro(public, public_, "public") \
macro(preventExtensions, preventExtensions, "preventExtensions") \
macro(private, private_, "private") \
macro(promise, promise, "promise") \
macro(propertyIsEnumerable, propertyIsEnumerable, "propertyIsEnumerable") \
macro(protected, protected_, "protected") \
macro(proto, proto, "__proto__") \
macro(prototype, prototype, "prototype") \
macro(proxy, proxy, "proxy") \
@ -295,10 +318,12 @@
macro(StructType, StructType, "StructType") \
macro(style, style, "style") \
macro(super, super, "super") \
macro(switch, switch_, "switch") \
macro(Symbol_iterator_fun, Symbol_iterator_fun, "[Symbol.iterator]") \
macro(target, target, "target") \
macro(test, test, "test") \
macro(then, then, "then") \
macro(this, this_, "this") \
macro(throw, throw_, "throw") \
macro(timestamp, timestamp, "timestamp") \
macro(timeZone, timeZone, "timeZone") \
@ -311,7 +336,9 @@
macro(toString, toString, "toString") \
macro(toUTCString, toUTCString, "toUTCString") \
macro(true, true_, "true") \
macro(try, try_, "try") \
macro(type, type, "type") \
macro(typeof, typeof_, "typeof") \
macro(uint8, uint8, "uint8") \
macro(uint8Clamped, uint8Clamped, "uint8Clamped") \
macro(uint16, uint16, "uint16") \
@ -331,6 +358,7 @@
macro(useAsm, useAsm, "use asm") \
macro(useGrouping, useGrouping, "useGrouping") \
macro(useStrict, useStrict, "use strict") \
macro(void, void_, "void") \
macro(value, value, "value") \
macro(valueOf, valueOf, "valueOf") \
macro(values, values, "values") \
@ -345,6 +373,8 @@
macro(weekday, weekday, "weekday") \
macro(weekendEnd, weekendEnd, "weekendEnd") \
macro(weekendStart, weekendStart, "weekendStart") \
macro(while, while_, "while") \
macro(with, with, "with") \
macro(writable, writable, "writable") \
macro(year, year, "year") \
macro(yield, yield, "yield") \

View File

@ -7057,7 +7057,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line)
TokenKind tk;
if (!tokenStream.getToken(&tk, TokenStream::Operand))
return false;
if (tk != TOK_NAME && tk != TOK_YIELD)
if (!TokenKindIsPossibleIdentifier(tk))
return false; // The regular parser will throw a SyntaxError, no need to m.fail.
RootedPropertyName name(m.cx(), m.parser().bindingIdentifier(YieldIsName));