mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-31 22:29:56 +00:00
import changes from rmottola/Arctic-Fox:
- Bug 1101903 - Part 1: Convert SharedContext::strict to a method. (c419cb895) - Bug 1101903 - Part 2: Allow parsing and emitting strict mode code in smaller than script-sized units. (d00819026) - Bug 1124362 - Allow strict-reserved names to be method names. (6fd24146f) - Bug 1066227 - Part 1: Create a clean way to create lexical bindings at initalizer sites. (2305b65c6) - Bug 1066227 - Part 2: Rename objectLiteral() propertyList() in preparation for classes. (e53b9cf12) - Bug 1066227 - Part 3: Parser support for basic ES6 ClassStatements (Nightly Only). (5ff4cb3b9) - Bug 1066227 - Part 4: Reflect.parse support for ClassStatements (a67bae8a3) - Bug 1066227 - Tests. (ebe27243e) - Bug 1066229 - Part 1: Create a clean way to emit lexical initializers (2d4900e5b) - Bug 1066229 - Part 2: Factor EmitPropertyList() out of EmitObject(). (09b97b557) - Bug 1066229 - Part 3: Create JSOP_INITLOCKEDDPROP, which adds non-configurable non-writable non-enumerable properties. (80d4961b4) - Bug 1066229 - Part 4: Create JSOP_INITHIDDENPROP, which adds non-enumerable properties. (1c79190e4) - Bug 1066229 - Follow up: Enable |let| in ecma_6/Class/ in browser JS reftests. (12a117456) - Bug 1066229 - Tests. (8577d220a) - Bug 1066229 - Tests. (957f4fead)
This commit is contained in:
+338
-175
@@ -757,7 +757,7 @@ Parser<ParseHandler>::reportBadReturn(Node pn, ParseReportKind kind,
|
||||
} else {
|
||||
errnum = anonerrnum;
|
||||
}
|
||||
return report(kind, pc->sc->strict, pn, errnum, name.ptr());
|
||||
return report(kind, pc->sc->strict(), pn, errnum, name.ptr());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -780,7 +780,7 @@ Parser<ParseHandler>::checkStrictAssignment(Node lhs)
|
||||
if (!AtomToPrintableString(context, atom, &name))
|
||||
return false;
|
||||
|
||||
if (!report(ParseStrictError, pc->sc->strict, lhs, JSMSG_BAD_STRICT_ASSIGN, name.ptr()))
|
||||
if (!report(ParseStrictError, pc->sc->strict(), lhs, JSMSG_BAD_STRICT_ASSIGN, name.ptr()))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -803,7 +803,7 @@ Parser<ParseHandler>::checkStrictBinding(PropertyName* name, Node pn)
|
||||
JSAutoByteString bytes;
|
||||
if (!AtomToPrintableString(context, name, &bytes))
|
||||
return false;
|
||||
return report(ParseStrictError, pc->sc->strict, pn,
|
||||
return report(ParseStrictError, pc->sc->strict(), pn,
|
||||
JSMSG_BAD_BINDING, bytes.ptr());
|
||||
}
|
||||
|
||||
@@ -1479,7 +1479,7 @@ Parser<ParseHandler>::defineArg(Node funcpn, HandlePropertyName name,
|
||||
JSAutoByteString bytes;
|
||||
if (!AtomToPrintableString(context, name, &bytes))
|
||||
return false;
|
||||
if (!report(ParseStrictError, pc->sc->strict, pn,
|
||||
if (!report(ParseStrictError, pc->sc->strict(), pn,
|
||||
JSMSG_DUPLICATE_FORMAL, bytes.ptr()))
|
||||
{
|
||||
return false;
|
||||
@@ -1866,7 +1866,7 @@ Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
|
||||
* statements (e.g., functions in an "if" or "while" block) are
|
||||
* dynamically bound when control flow reaches the statement.
|
||||
*/
|
||||
MOZ_ASSERT(!pc->sc->strict);
|
||||
MOZ_ASSERT(!pc->sc->strict());
|
||||
MOZ_ASSERT(pn->pn_cookie.isFree());
|
||||
if (pc->sc->isFunctionBox()) {
|
||||
FunctionBox* funbox = pc->sc->asFunctionBox();
|
||||
@@ -2254,7 +2254,7 @@ Parser<SyntaxParseHandler>::finishFunctionDefinition(Node pn, FunctionBox* funbo
|
||||
for (size_t i = 0; i < numInnerFunctions; i++)
|
||||
innerFunctions[i].init(pc->innerFunctions[i]);
|
||||
|
||||
if (pc->sc->strict)
|
||||
if (pc->sc->strict())
|
||||
lazy->setStrict();
|
||||
lazy->setGeneratorKind(funbox->generatorKind());
|
||||
if (funbox->usesArguments && funbox->usesApply && funbox->usesThis)
|
||||
@@ -2446,7 +2446,7 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, unsigned st
|
||||
if (!funpc.init(tokenStream))
|
||||
return null();
|
||||
|
||||
if (!functionArgsAndBodyGeneric(pn, fun, Normal, Statement)) {
|
||||
if (!functionArgsAndBodyGeneric(pn, fun, Normal, Lazy)) {
|
||||
MOZ_ASSERT(directives == newDirectives);
|
||||
return null();
|
||||
}
|
||||
@@ -2530,8 +2530,11 @@ Parser<ParseHandler>::functionArgsAndBodyGeneric(Node pn, HandleFunction fun, Fu
|
||||
if (!body)
|
||||
return false;
|
||||
|
||||
if (fun->name() && !checkStrictBinding(fun->name(), pn))
|
||||
if (kind != Method && kind != Lazy &&
|
||||
fun->name() && !checkStrictBinding(fun->name(), pn))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bodyType == StatementListBody) {
|
||||
bool matched;
|
||||
@@ -2549,7 +2552,7 @@ Parser<ParseHandler>::functionArgsAndBodyGeneric(Node pn, HandleFunction fun, Fu
|
||||
if (tokenStream.hadError())
|
||||
return false;
|
||||
funbox->bufEnd = pos().end;
|
||||
if (kind == Statement && !MatchOrInsertSemicolon(tokenStream))
|
||||
if ((kind == Statement || kind == Lazy) && !MatchOrInsertSemicolon(tokenStream))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2562,7 +2565,7 @@ Parser<ParseHandler>::checkYieldNameValidity()
|
||||
{
|
||||
// In star generators and in JS >= 1.7, yield is a keyword. Otherwise in
|
||||
// strict mode, yield is a future reserved word.
|
||||
if (pc->isStarGenerator() || versionNumber() >= JSVERSION_1_7 || pc->sc->strict) {
|
||||
if (pc->isStarGenerator() || versionNumber() >= JSVERSION_1_7 || pc->sc->strict()) {
|
||||
report(ParseError, false, null(), JSMSG_RESERVED_ID, "yield");
|
||||
return false;
|
||||
}
|
||||
@@ -2601,7 +2604,7 @@ Parser<ParseHandler>::functionStmt()
|
||||
|
||||
/* We forbid function statements in strict mode code. */
|
||||
if (!pc->atBodyLevel() && pc->sc->needStrictChecks() &&
|
||||
!report(ParseStrictError, pc->sc->strict, null(), JSMSG_STRICT_FUNCTION_STATEMENT))
|
||||
!report(ParseStrictError, pc->sc->strict(), null(), JSMSG_STRICT_FUNCTION_STATEMENT))
|
||||
return null();
|
||||
|
||||
return functionDef(name, Normal, Statement, generatorKind);
|
||||
@@ -2754,7 +2757,7 @@ Parser<ParseHandler>::maybeParseDirective(Node list, Node pn, bool* cont)
|
||||
// We're going to be in strict mode. Note that this scope explicitly
|
||||
// had "use strict";
|
||||
pc->sc->setExplicitUseStrict();
|
||||
if (!pc->sc->strict) {
|
||||
if (!pc->sc->strict()) {
|
||||
if (pc->sc->isFunctionBox()) {
|
||||
// Request that this function be reparsed as strict.
|
||||
pc->newDirectives->setStrict();
|
||||
@@ -2767,7 +2770,7 @@ Parser<ParseHandler>::maybeParseDirective(Node list, Node pn, bool* cont)
|
||||
report(ParseError, false, null(), JSMSG_DEPRECATED_OCTAL);
|
||||
return false;
|
||||
}
|
||||
pc->sc->strict = true;
|
||||
pc->sc->strictScript = true;
|
||||
}
|
||||
}
|
||||
} else if (directive == context->names().useAsm) {
|
||||
@@ -3238,7 +3241,7 @@ Parser<FullParseHandler>::makeSetCall(ParseNode* pn, unsigned msg)
|
||||
pn->isOp(JSOP_SPREADEVAL) || pn->isOp(JSOP_STRICTSPREADEVAL) ||
|
||||
pn->isOp(JSOP_FUNCALL) || pn->isOp(JSOP_FUNAPPLY));
|
||||
|
||||
if (!report(ParseStrictError, pc->sc->strict, pn, msg))
|
||||
if (!report(ParseStrictError, pc->sc->strict(), pn, msg))
|
||||
return false;
|
||||
handler.markAsSetCall(pn);
|
||||
return true;
|
||||
@@ -3297,7 +3300,7 @@ Parser<ParseHandler>::noteNameUse(HandlePropertyName name, Node pn)
|
||||
|
||||
template <>
|
||||
bool
|
||||
Parser<FullParseHandler>::bindDestructuringVar(BindData<FullParseHandler>* data, ParseNode* pn)
|
||||
Parser<FullParseHandler>::bindInitialized(BindData<FullParseHandler> *data, ParseNode *pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isKind(PNK_NAME));
|
||||
|
||||
@@ -3357,7 +3360,7 @@ Parser<FullParseHandler>::checkDestructuringObject(BindData<FullParseHandler>* d
|
||||
report(ParseError, false, expr, JSMSG_NO_VARIABLE_NAME);
|
||||
return false;
|
||||
}
|
||||
ok = bindDestructuringVar(data, expr);
|
||||
ok = bindInitialized(data, expr);
|
||||
} else {
|
||||
ok = checkAndMarkAsAssignmentLhs(expr, KeyedDestructuringAssignment);
|
||||
}
|
||||
@@ -3405,7 +3408,7 @@ Parser<FullParseHandler>::checkDestructuringArray(BindData<FullParseHandler>* da
|
||||
report(ParseError, false, target, JSMSG_NO_VARIABLE_NAME);
|
||||
return false;
|
||||
}
|
||||
ok = bindDestructuringVar(data, target);
|
||||
ok = bindInitialized(data, target);
|
||||
} else {
|
||||
ok = checkAndMarkAsAssignmentLhs(target, KeyedDestructuringAssignment);
|
||||
}
|
||||
@@ -3817,135 +3820,168 @@ Parser<ParseHandler>::variables(ParseNodeKind kind, bool* psimple,
|
||||
}
|
||||
|
||||
template <>
|
||||
ParseNode*
|
||||
bool
|
||||
Parser<FullParseHandler>::checkAndPrepareLexical(bool isConst, const TokenPos &errorPos)
|
||||
{
|
||||
/*
|
||||
* This is a lexical declaration. We must be directly under a block per the
|
||||
* proposed ES4 specs, but not an implicit block created due to
|
||||
* 'for (let ...)'. If we pass this error test, make the enclosing
|
||||
* StmtInfoPC be our scope. Further let declarations in this block will
|
||||
* find this scope statement and use the same block object.
|
||||
*
|
||||
* If we are the first let declaration in this block (i.e., when the
|
||||
* enclosing maybe-scope StmtInfoPC isn't yet a scope statement) then
|
||||
* we also need to set pc->blockNode to be our PNK_LEXICALSCOPE.
|
||||
*/
|
||||
StmtInfoPC *stmt = pc->topStmt;
|
||||
if (stmt && (!stmt->maybeScope() || stmt->isForLetBlock)) {
|
||||
reportWithOffset(ParseError, false, errorPos.begin, JSMSG_LEXICAL_DECL_NOT_IN_BLOCK,
|
||||
isConst ? "const" : "lexical");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (stmt && stmt->isBlockScope) {
|
||||
MOZ_ASSERT(pc->staticScope == stmt->staticScope);
|
||||
} else {
|
||||
if (pc->atBodyLevel()) {
|
||||
/*
|
||||
* When bug 589199 is fixed, let variables will be stored in
|
||||
* the slots of a new scope chain object, encountered just
|
||||
* before the global object in the overall chain. This extra
|
||||
* object is present in the scope chain for all code in that
|
||||
* global, including self-hosted code. But self-hosted code
|
||||
* must be usable against *any* global object, including ones
|
||||
* with other let variables -- variables possibly placed in
|
||||
* conflicting slots. Forbid top-level let declarations to
|
||||
* prevent such conflicts from ever occurring.
|
||||
*/
|
||||
bool isGlobal = !pc->sc->isFunctionBox() && stmt == pc->topScopeStmt;
|
||||
if (options().selfHostingMode && isGlobal) {
|
||||
report(ParseError, false, null(), JSMSG_SELFHOSTED_TOP_LEVEL_LEXICAL,
|
||||
isConst ? "'const'" : "'let'");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some obvious assertions here, but they may help clarify the
|
||||
* situation. This stmt is not yet a scope, so it must not be a
|
||||
* catch block (catch is a lexical scope by definition).
|
||||
*/
|
||||
MOZ_ASSERT(!stmt->isBlockScope);
|
||||
MOZ_ASSERT(stmt != pc->topScopeStmt);
|
||||
MOZ_ASSERT(stmt->type == STMT_BLOCK ||
|
||||
stmt->type == STMT_SWITCH ||
|
||||
stmt->type == STMT_TRY ||
|
||||
stmt->type == STMT_FINALLY);
|
||||
MOZ_ASSERT(!stmt->downScope);
|
||||
|
||||
/* Convert the block statement into a scope statement. */
|
||||
StaticBlockObject *blockObj = StaticBlockObject::create(context);
|
||||
if (!blockObj)
|
||||
return false;
|
||||
|
||||
ObjectBox *blockbox = newObjectBox(blockObj);
|
||||
if (!blockbox)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Insert stmt on the pc->topScopeStmt/stmtInfo.downScope linked
|
||||
* list stack, if it isn't already there. If it is there, but it
|
||||
* lacks the SIF_SCOPE flag, it must be a try, catch, or finally
|
||||
* block.
|
||||
*/
|
||||
stmt->isBlockScope = stmt->isNestedScope = true;
|
||||
stmt->downScope = pc->topScopeStmt;
|
||||
pc->topScopeStmt = stmt;
|
||||
|
||||
blockObj->initEnclosingNestedScopeFromParser(pc->staticScope);
|
||||
pc->staticScope = blockObj;
|
||||
stmt->staticScope = blockObj;
|
||||
|
||||
#ifdef DEBUG
|
||||
ParseNode *tmp = pc->blockNode;
|
||||
MOZ_ASSERT(!tmp || !tmp->isKind(PNK_LEXICALSCOPE));
|
||||
#endif
|
||||
|
||||
/* Create a new lexical scope node for these statements. */
|
||||
ParseNode *pn1 = handler.new_<LexicalScopeNode>(blockbox, pc->blockNode);
|
||||
if (!pn1)
|
||||
return false;;
|
||||
pc->blockNode = pn1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static StaticBlockObject *
|
||||
CurrentLexicalStaticBlock(ParseContext<FullParseHandler> *pc)
|
||||
{
|
||||
return pc->atBodyLevel() ? nullptr :
|
||||
&pc->staticScope->as<StaticBlockObject>();
|
||||
}
|
||||
|
||||
template <>
|
||||
ParseNode *
|
||||
Parser<FullParseHandler>::makeInitializedLexicalBinding(HandlePropertyName name, bool isConst,
|
||||
const TokenPos &pos)
|
||||
{
|
||||
// Handle the silliness of global and body level lexical decls.
|
||||
BindData<FullParseHandler> data(context);
|
||||
if (pc->atGlobalLevel()) {
|
||||
data.initVarOrGlobalConst(isConst ? JSOP_DEFCONST : JSOP_DEFVAR);
|
||||
} else {
|
||||
if (!checkAndPrepareLexical(isConst, pos))
|
||||
return null();
|
||||
data.initLexical(HoistVars, CurrentLexicalStaticBlock(pc), JSMSG_TOO_MANY_LOCALS, isConst);
|
||||
}
|
||||
ParseNode *dn = newBindingNode(name, pc->atGlobalLevel());
|
||||
if (!dn)
|
||||
return null();
|
||||
handler.setPosition(dn, pos);
|
||||
|
||||
if (!bindInitialized(&data, dn))
|
||||
return null();
|
||||
|
||||
return dn;
|
||||
}
|
||||
|
||||
template <>
|
||||
ParseNode *
|
||||
Parser<FullParseHandler>::lexicalDeclaration(bool isConst)
|
||||
{
|
||||
handler.disableSyntaxParser();
|
||||
|
||||
ParseNode* pn;
|
||||
if (!checkAndPrepareLexical(isConst, pos()))
|
||||
return null();
|
||||
|
||||
do {
|
||||
/*
|
||||
* This is a let declaration. We must be directly under a block per the
|
||||
* proposed ES4 specs, but not an implicit block created due to
|
||||
* 'for (let ...)'. If we pass this error test, make the enclosing
|
||||
* StmtInfoPC be our scope. Further let declarations in this block will
|
||||
* find this scope statement and use the same block object.
|
||||
*
|
||||
* If we are the first let declaration in this block (i.e., when the
|
||||
* enclosing maybe-scope StmtInfoPC isn't yet a scope statement) then
|
||||
* we also need to set pc->blockNode to be our PNK_LEXICALSCOPE.
|
||||
*/
|
||||
StmtInfoPC* stmt = pc->topStmt;
|
||||
if (stmt && (!stmt->maybeScope() || stmt->isForLetBlock)) {
|
||||
report(ParseError, false, null(), JSMSG_LEXICAL_DECL_NOT_IN_BLOCK,
|
||||
isConst ? "const" : "let");
|
||||
return null();
|
||||
}
|
||||
|
||||
if (stmt && stmt->isBlockScope) {
|
||||
MOZ_ASSERT(pc->staticScope == stmt->staticScope);
|
||||
} else {
|
||||
if (pc->atBodyLevel()) {
|
||||
/*
|
||||
* When bug 589199 is fixed, let variables will be stored in
|
||||
* the slots of a new scope chain object, encountered just
|
||||
* before the global object in the overall chain. This extra
|
||||
* object is present in the scope chain for all code in that
|
||||
* global, including self-hosted code. But self-hosted code
|
||||
* must be usable against *any* global object, including ones
|
||||
* with other let variables -- variables possibly placed in
|
||||
* conflicting slots. Forbid top-level let declarations to
|
||||
* prevent such conflicts from ever occurring.
|
||||
*/
|
||||
bool isGlobal = !pc->sc->isFunctionBox() && stmt == pc->topScopeStmt;
|
||||
if (options().selfHostingMode && isGlobal) {
|
||||
report(ParseError, false, null(), JSMSG_SELFHOSTED_TOP_LEVEL_LEXICAL,
|
||||
isConst ? "'const'" : "'let'");
|
||||
return null();
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse body-level lets without a new block object. ES6 specs
|
||||
* that an execution environment's initial lexical environment
|
||||
* is the VariableEnvironment, i.e., body-level lets are in
|
||||
* the same environment record as vars.
|
||||
*
|
||||
* However, they cannot be parsed exactly as vars, as ES6
|
||||
* requires that uninitialized lets throw ReferenceError on use.
|
||||
*
|
||||
* See 8.1.1.1.6 and the note in 13.2.1.
|
||||
*
|
||||
* FIXME global-level lets are still considered vars until
|
||||
* other bugs are fixed.
|
||||
*/
|
||||
ParseNodeKind kind = PNK_LET;
|
||||
if (isGlobal)
|
||||
kind = isConst ? PNK_GLOBALCONST : PNK_VAR;
|
||||
else if (isConst)
|
||||
kind = PNK_CONST;
|
||||
pn = variables(kind);
|
||||
if (!pn)
|
||||
return null();
|
||||
pn->pn_xflags |= PNX_POPVAR;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some obvious assertions here, but they may help clarify the
|
||||
* situation. This stmt is not yet a scope, so it must not be a
|
||||
* catch block (catch is a lexical scope by definition).
|
||||
*/
|
||||
MOZ_ASSERT(!stmt->isBlockScope);
|
||||
MOZ_ASSERT(stmt != pc->topScopeStmt);
|
||||
MOZ_ASSERT(stmt->type == STMT_BLOCK ||
|
||||
stmt->type == STMT_SWITCH ||
|
||||
stmt->type == STMT_TRY ||
|
||||
stmt->type == STMT_FINALLY);
|
||||
MOZ_ASSERT(!stmt->downScope);
|
||||
|
||||
/* Convert the block statement into a scope statement. */
|
||||
StaticBlockObject* blockObj = StaticBlockObject::create(context);
|
||||
if (!blockObj)
|
||||
return null();
|
||||
|
||||
ObjectBox* blockbox = newObjectBox(blockObj);
|
||||
if (!blockbox)
|
||||
return null();
|
||||
|
||||
/*
|
||||
* Insert stmt on the pc->topScopeStmt/stmtInfo.downScope linked
|
||||
* list stack, if it isn't already there. If it is there, but it
|
||||
* lacks the SIF_SCOPE flag, it must be a try, catch, or finally
|
||||
* block.
|
||||
*/
|
||||
stmt->isBlockScope = stmt->isNestedScope = true;
|
||||
stmt->downScope = pc->topScopeStmt;
|
||||
pc->topScopeStmt = stmt;
|
||||
|
||||
blockObj->initEnclosingNestedScopeFromParser(pc->staticScope);
|
||||
pc->staticScope = blockObj;
|
||||
stmt->staticScope = blockObj;
|
||||
|
||||
#ifdef DEBUG
|
||||
ParseNode* tmp = pc->blockNode;
|
||||
MOZ_ASSERT(!tmp || !tmp->isKind(PNK_LEXICALSCOPE));
|
||||
#endif
|
||||
|
||||
/* Create a new lexical scope node for these statements. */
|
||||
ParseNode* pn1 = handler.new_<LexicalScopeNode>(blockbox, pc->blockNode);
|
||||
if (!pn1)
|
||||
return null();
|
||||
pc->blockNode = pn1;
|
||||
}
|
||||
|
||||
pn = variables(isConst ? PNK_CONST : PNK_LET, nullptr,
|
||||
&pc->staticScope->as<StaticBlockObject>(), HoistVars);
|
||||
if (!pn)
|
||||
return null();
|
||||
pn->pn_xflags = PNX_POPVAR;
|
||||
} while (0);
|
||||
/*
|
||||
* Parse body-level lets without a new block object. ES6 specs
|
||||
* that an execution environment's initial lexical environment
|
||||
* is the VariableEnvironment, i.e., body-level lets are in
|
||||
* the same environment record as vars.
|
||||
*
|
||||
* However, they cannot be parsed exactly as vars, as ES6
|
||||
* requires that uninitialized lets throw ReferenceError on use.
|
||||
*
|
||||
* See 8.1.1.1.6 and the note in 13.2.1.
|
||||
*
|
||||
* FIXME global-level lets are still considered vars until
|
||||
* other bugs are fixed.
|
||||
*/
|
||||
ParseNodeKind kind = PNK_LET;
|
||||
if (pc->atGlobalLevel())
|
||||
kind = isConst ? PNK_GLOBALCONST : PNK_VAR;
|
||||
else if (isConst)
|
||||
kind = PNK_CONST;
|
||||
|
||||
ParseNode *pn = variables(kind, nullptr,
|
||||
CurrentLexicalStaticBlock(pc),
|
||||
HoistVars);
|
||||
if (!pn)
|
||||
return null();
|
||||
pn->pn_xflags = PNX_POPVAR;
|
||||
return MatchOrInsertSemicolon(tokenStream) ? pn : nullptr;
|
||||
}
|
||||
|
||||
@@ -4436,7 +4472,7 @@ Parser<FullParseHandler>::forStatement()
|
||||
iflags = JSITER_FOREACH;
|
||||
isForEach = true;
|
||||
if (versionNumber() < JSVERSION_LATEST) {
|
||||
if (!report(ParseWarning, pc->sc->strict, null(), JSMSG_DEPRECATED_FOR_EACH))
|
||||
if (!report(ParseWarning, pc->sc->strict(), null(), JSMSG_DEPRECATED_FOR_EACH))
|
||||
return null();
|
||||
}
|
||||
}
|
||||
@@ -5356,7 +5392,7 @@ Parser<FullParseHandler>::withStatement()
|
||||
// construct that is forbidden in strict mode code, but doesn't even merit a
|
||||
// warning under JSOPTION_EXTRA_WARNINGS. See
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=514576#c1.
|
||||
if (pc->sc->strict && !report(ParseStrictError, true, null(), JSMSG_STRICT_CODE_WITH))
|
||||
if (pc->sc->strict() && !report(ParseStrictError, true, null(), JSMSG_STRICT_CODE_WITH))
|
||||
return null();
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH);
|
||||
@@ -5659,6 +5695,80 @@ Parser<ParseHandler>::debuggerStatement()
|
||||
return handler.newDebuggerStatement(p);
|
||||
}
|
||||
|
||||
template <>
|
||||
ParseNode *
|
||||
Parser<FullParseHandler>::classStatement()
|
||||
{
|
||||
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_CLASS));
|
||||
|
||||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
|
||||
RootedPropertyName name(context);
|
||||
if (tt == TOK_NAME) {
|
||||
name = tokenStream.currentName();
|
||||
} else if (tt == TOK_YIELD) {
|
||||
if (!checkYieldNameValidity())
|
||||
return null();
|
||||
name = tokenStream.currentName();
|
||||
} else {
|
||||
// Class statements must have a bound name
|
||||
report(ParseError, false, null(), JSMSG_UNNAMED_CLASS_STMT);
|
||||
return null();
|
||||
}
|
||||
|
||||
if (name == context->names().let) {
|
||||
report(ParseError, false, null(), JSMSG_LET_CLASS_BINDING);
|
||||
return null();
|
||||
}
|
||||
|
||||
// Because the binding definitions keep track of their blockId, we need to
|
||||
// create at least the inner binding later. Keep track of the name's position
|
||||
// in order to provide it for the nodes created later.
|
||||
TokenPos namePos = pos();
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CLASS);
|
||||
|
||||
bool savedStrictness = setLocalStrictMode(true);
|
||||
|
||||
StmtInfoPC classStmt(context);
|
||||
ParseNode *classBlock = pushLexicalScope(&classStmt);
|
||||
if (!classBlock)
|
||||
return null();
|
||||
|
||||
ParseNode *classMethods = propertyList(ClassBody);
|
||||
if (!classMethods)
|
||||
return null();
|
||||
handler.setLexicalScopeBody(classBlock, classMethods);
|
||||
|
||||
ParseNode *innerBinding = makeInitializedLexicalBinding(name, true, namePos);
|
||||
if (!innerBinding)
|
||||
return null();
|
||||
|
||||
PopStatementPC(tokenStream, pc);
|
||||
|
||||
ParseNode *outerBinding = makeInitializedLexicalBinding(name, false, namePos);
|
||||
if (!outerBinding)
|
||||
return null();
|
||||
|
||||
ParseNode *nameNode = handler.newClassNames(outerBinding, innerBinding, namePos);
|
||||
if (!nameNode)
|
||||
return null();
|
||||
|
||||
MOZ_ALWAYS_TRUE(setLocalStrictMode(savedStrictness));
|
||||
|
||||
return handler.newClass(nameNode, null(), classBlock);
|
||||
}
|
||||
|
||||
template <>
|
||||
SyntaxParseHandler::Node
|
||||
Parser<SyntaxParseHandler>::classStatement()
|
||||
{
|
||||
JS_ALWAYS_FALSE(abortIfSyntaxParser());
|
||||
return SyntaxParseHandler::NodeFailure;
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::statement(bool canHaveDirectives)
|
||||
@@ -5729,6 +5839,11 @@ Parser<ParseHandler>::statement(bool canHaveDirectives)
|
||||
return functionStmt();
|
||||
case TOK_DEBUGGER:
|
||||
return debuggerStatement();
|
||||
case TOK_CLASS:
|
||||
if (!abortIfSyntaxParser())
|
||||
return null();
|
||||
return classStatement();
|
||||
|
||||
|
||||
/* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */
|
||||
case TOK_CATCH:
|
||||
@@ -6285,7 +6400,7 @@ Parser<ParseHandler>::unaryExpr(InvokedPrediction invoked)
|
||||
// Per spec, deleting any unary expression is valid -- it simply
|
||||
// returns true -- except for one case that is illegal in strict mode.
|
||||
if (handler.isName(expr)) {
|
||||
if (!report(ParseStrictError, pc->sc->strict, expr, JSMSG_DEPRECATED_DELETE_OPERAND))
|
||||
if (!report(ParseStrictError, pc->sc->strict(), expr, JSMSG_DEPRECATED_DELETE_OPERAND))
|
||||
return null();
|
||||
pc->sc->setBindingsAccessedDynamically();
|
||||
}
|
||||
@@ -6690,7 +6805,7 @@ Parser<FullParseHandler>::legacyComprehensionTail(ParseNode* bodyExpr, unsigned
|
||||
if (matched) {
|
||||
pn2->pn_iflags |= JSITER_FOREACH;
|
||||
if (versionNumber() < JSVERSION_LATEST) {
|
||||
if (!report(ParseWarning, pc->sc->strict, pn2, JSMSG_DEPRECATED_FOR_EACH))
|
||||
if (!report(ParseWarning, pc->sc->strict(), pn2, JSMSG_DEPRECATED_FOR_EACH))
|
||||
return null();
|
||||
}
|
||||
}
|
||||
@@ -6946,7 +7061,7 @@ Parser<ParseHandler>::generatorComprehensionLambda(GeneratorKind comprehensionKi
|
||||
return null();
|
||||
|
||||
// Create box for fun->object early to root it.
|
||||
Directives directives(/* strict = */ outerpc->sc->strict);
|
||||
Directives directives(/* strict = */ outerpc->sc->strict());
|
||||
FunctionBox* genFunbox = newFunctionBox(genfn, fun, outerpc, directives, comprehensionKind);
|
||||
if (!genFunbox)
|
||||
return null();
|
||||
@@ -7466,7 +7581,7 @@ Parser<ParseHandler>::memberExpr(TokenKind tt, bool allowCallSyntax, InvokedPred
|
||||
if (JSAtom* atom = handler.isName(lhs)) {
|
||||
if (tt == TOK_LP && atom == context->names().eval) {
|
||||
/* Select JSOP_EVAL and flag pc as heavyweight. */
|
||||
op = pc->sc->strict ? JSOP_STRICTEVAL : JSOP_EVAL;
|
||||
op = pc->sc->strict() ? JSOP_STRICTEVAL : JSOP_EVAL;
|
||||
pc->sc->setBindingsAccessedDynamically();
|
||||
pc->sc->setHasDirectEval();
|
||||
|
||||
@@ -7474,7 +7589,7 @@ Parser<ParseHandler>::memberExpr(TokenKind tt, bool allowCallSyntax, InvokedPred
|
||||
* In non-strict mode code, direct calls to eval can add
|
||||
* variables to the call object.
|
||||
*/
|
||||
if (pc->sc->isFunctionBox() && !pc->sc->strict)
|
||||
if (pc->sc->isFunctionBox() && !pc->sc->strict())
|
||||
pc->sc->asFunctionBox()->setHasExtensibleScope();
|
||||
}
|
||||
} else if (JSAtom* atom = handler.isGetProp(lhs)) {
|
||||
@@ -7761,15 +7876,27 @@ Parser<ParseHandler>::computedPropertyName(Node literal)
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::objectLiteral()
|
||||
Parser<ParseHandler>::newPropertyListNode(PropListType type)
|
||||
{
|
||||
if (type == ClassBody)
|
||||
return handler.newClassMethodList(pos().begin);
|
||||
|
||||
MOZ_ASSERT(type == ObjectLiteral);
|
||||
return handler.newObjectLiteral(pos().begin);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
typename ParseHandler::Node
|
||||
Parser<ParseHandler>::propertyList(PropListType type)
|
||||
{
|
||||
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_LC));
|
||||
|
||||
Node literal = handler.newObjectLiteral(pos().begin);
|
||||
if (!literal)
|
||||
Node propList = newPropertyListNode(type);
|
||||
if (!propList)
|
||||
return null();
|
||||
|
||||
bool seenPrototypeMutation = false;
|
||||
bool seenConstructor = false;
|
||||
RootedAtom atom(context);
|
||||
for (;;) {
|
||||
TokenKind ltok;
|
||||
@@ -7778,6 +7905,9 @@ Parser<ParseHandler>::objectLiteral()
|
||||
if (ltok == TOK_RC)
|
||||
break;
|
||||
|
||||
if (type == ClassBody && ltok == TOK_SEMI)
|
||||
continue;
|
||||
|
||||
bool isGenerator = false;
|
||||
if (ltok == TOK_MUL) {
|
||||
isGenerator = true;
|
||||
@@ -7800,7 +7930,7 @@ Parser<ParseHandler>::objectLiteral()
|
||||
break;
|
||||
|
||||
case TOK_LB: {
|
||||
propname = computedPropertyName(literal);
|
||||
propname = computedPropertyName(propList);
|
||||
if (!propname)
|
||||
return null();
|
||||
break;
|
||||
@@ -7856,7 +7986,7 @@ Parser<ParseHandler>::objectLiteral()
|
||||
if (!propname)
|
||||
return null();
|
||||
} else if (tt == TOK_LB) {
|
||||
propname = computedPropertyName(literal);
|
||||
propname = computedPropertyName(propList);
|
||||
if (!propname)
|
||||
return null();
|
||||
} else {
|
||||
@@ -7893,12 +8023,30 @@ Parser<ParseHandler>::objectLiteral()
|
||||
return null();
|
||||
}
|
||||
|
||||
if (type == ClassBody) {
|
||||
if (atom == context->names().constructor) {
|
||||
if (isGenerator || op != JSOP_INITPROP) {
|
||||
report(ParseError, false, propname, JSMSG_BAD_METHOD_DEF);
|
||||
return null();
|
||||
}
|
||||
if (seenConstructor) {
|
||||
report(ParseError, false, propname, JSMSG_DUPLICATE_PROPERTY, "constructor");
|
||||
return null();
|
||||
}
|
||||
seenConstructor = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (op == JSOP_INITPROP) {
|
||||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
|
||||
if (tt == TOK_COLON) {
|
||||
if (type == ClassBody) {
|
||||
report(ParseError, false, null(), JSMSG_BAD_METHOD_DEF);
|
||||
return null();
|
||||
}
|
||||
if (isGenerator) {
|
||||
report(ParseError, false, null(), JSMSG_BAD_PROP_ID);
|
||||
return null();
|
||||
@@ -7923,13 +8071,13 @@ Parser<ParseHandler>::objectLiteral()
|
||||
// method/generator definitions, computed property name
|
||||
// versions of all of these, and shorthands do not.
|
||||
uint32_t begin = handler.getPosition(propname).begin;
|
||||
if (!handler.addPrototypeMutation(literal, begin, propexpr))
|
||||
if (!handler.addPrototypeMutation(propList, begin, propexpr))
|
||||
return null();
|
||||
} else {
|
||||
if (!handler.isConstant(propexpr))
|
||||
handler.setListFlag(literal, PNX_NONCONST);
|
||||
handler.setListFlag(propList, PNX_NONCONST);
|
||||
|
||||
if (!handler.addPropertyDefinition(literal, propname, propexpr))
|
||||
if (!handler.addPropertyDefinition(propList, propname, propexpr))
|
||||
return null();
|
||||
}
|
||||
} else if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC)) {
|
||||
@@ -7937,6 +8085,10 @@ Parser<ParseHandler>::objectLiteral()
|
||||
* Support, e.g., |var {x, y} = o| as destructuring shorthand
|
||||
* for |var {x: x, y: y} = o|, per proposed JS2/ES4 for JS1.8.
|
||||
*/
|
||||
if (type == ClassBody) {
|
||||
report(ParseError, false, null(), JSMSG_BAD_METHOD_DEF);
|
||||
return null();
|
||||
}
|
||||
if (isGenerator) {
|
||||
report(ParseError, false, null(), JSMSG_BAD_PROP_ID);
|
||||
return null();
|
||||
@@ -7950,11 +8102,11 @@ Parser<ParseHandler>::objectLiteral()
|
||||
if (!nameExpr)
|
||||
return null();
|
||||
|
||||
if (!handler.addShorthand(literal, propname, nameExpr))
|
||||
if (!handler.addShorthand(propList, propname, nameExpr))
|
||||
return null();
|
||||
} else if (tt == TOK_LP) {
|
||||
tokenStream.ungetToken();
|
||||
if (!methodDefinition(literal, propname, Normal, Method,
|
||||
if (!methodDefinition(type, propList, propname, Normal, Method,
|
||||
isGenerator ? StarGenerator : NotGenerator, op)) {
|
||||
return null();
|
||||
}
|
||||
@@ -7964,32 +8116,40 @@ Parser<ParseHandler>::objectLiteral()
|
||||
}
|
||||
} else {
|
||||
/* NB: Getter function in { get x(){} } is unnamed. */
|
||||
if (!methodDefinition(literal, propname, op == JSOP_INITPROP_GETTER ? Getter : Setter,
|
||||
if (!methodDefinition(type, propList, propname, op == JSOP_INITPROP_GETTER ? Getter : Setter,
|
||||
Expression, NotGenerator, op)) {
|
||||
return null();
|
||||
}
|
||||
}
|
||||
|
||||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
if (tt == TOK_RC)
|
||||
break;
|
||||
if (tt != TOK_COMMA) {
|
||||
report(ParseError, false, null(), JSMSG_CURLY_AFTER_LIST);
|
||||
return null();
|
||||
if (type == ObjectLiteral) {
|
||||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
if (tt == TOK_RC)
|
||||
break;
|
||||
if (tt != TOK_COMMA) {
|
||||
report(ParseError, false, null(), JSMSG_CURLY_AFTER_LIST);
|
||||
return null();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handler.setEndPosition(literal, pos().end);
|
||||
return literal;
|
||||
// Default constructors not yet implemented. See bug 1105463
|
||||
if (type == ClassBody && !seenConstructor) {
|
||||
report(ParseError, false, null(), JSMSG_NO_CLASS_CONSTRUCTOR);
|
||||
return null();
|
||||
}
|
||||
|
||||
handler.setEndPosition(propList, pos().end);
|
||||
return propList;
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
bool
|
||||
Parser<ParseHandler>::methodDefinition(Node literal, Node propname, FunctionType type,
|
||||
FunctionSyntaxKind kind, GeneratorKind generatorKind,
|
||||
JSOp op)
|
||||
Parser<ParseHandler>::methodDefinition(PropListType listType, Node propList, Node propname,
|
||||
FunctionType type, FunctionSyntaxKind kind,
|
||||
GeneratorKind generatorKind, JSOp op)
|
||||
{
|
||||
RootedPropertyName funName(context);
|
||||
if (kind == Method && tokenStream.isCurrentTokenType(TOK_NAME))
|
||||
@@ -8000,9 +8160,12 @@ Parser<ParseHandler>::methodDefinition(Node literal, Node propname, FunctionType
|
||||
Node fn = functionDef(funName, type, kind, generatorKind);
|
||||
if (!fn)
|
||||
return false;
|
||||
if (!handler.addMethodDefinition(literal, propname, fn, op))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
if (listType == ClassBody)
|
||||
return handler.addClassMethodDefinition(propList, propname, fn, op);
|
||||
|
||||
MOZ_ASSERT(listType == ObjectLiteral);
|
||||
return handler.addObjectMethodDefinition(propList, propname, fn, op);
|
||||
}
|
||||
|
||||
template <typename ParseHandler>
|
||||
@@ -8020,7 +8183,7 @@ Parser<ParseHandler>::primaryExpr(TokenKind tt, InvokedPrediction invoked)
|
||||
return arrayInitializer();
|
||||
|
||||
case TOK_LC:
|
||||
return objectLiteral();
|
||||
return propertyList(ObjectLiteral);
|
||||
|
||||
case TOK_LP: {
|
||||
TokenKind next;
|
||||
|
||||
Reference in New Issue
Block a user