diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h index 26407ad2ed6..02d5f6925a5 100644 --- a/js/src/frontend/FullParseHandler.h +++ b/js/src/frontend/FullParseHandler.h @@ -250,12 +250,12 @@ class FullParseHandler return new_(expr ? PNK_CASE : PNK_DEFAULT, JSOP_NOP, pos, expr, body); } - ParseNode *newContinue(PropertyName *label, uint32_t begin, uint32_t end) { - return new_(label, begin, end); + ParseNode *newContinueStatement(PropertyName *label, const TokenPos &pos) { + return new_(label, pos); } - ParseNode *newBreak(PropertyName *label, uint32_t begin, uint32_t end) { - return new_(label, begin, end); + ParseNode *newBreakStatement(PropertyName *label, const TokenPos &pos) { + return new_(label, pos); } ParseNode *newReturnStatement(ParseNode *expr, const TokenPos &pos) { diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h index b93d4438a54..03f9cd81d92 100644 --- a/js/src/frontend/ParseNode.h +++ b/js/src/frontend/ParseNode.h @@ -1026,8 +1026,8 @@ class LabeledStatement : public ParseNode class LoopControlStatement : public ParseNode { protected: - LoopControlStatement(ParseNodeKind kind, PropertyName *label, uint32_t begin, uint32_t end) - : ParseNode(kind, JSOP_NOP, PN_NULLARY, TokenPos::make(begin, end)) + LoopControlStatement(ParseNodeKind kind, PropertyName *label, const TokenPos &pos) + : ParseNode(kind, JSOP_NOP, PN_NULLARY, pos) { JS_ASSERT(kind == PNK_BREAK || kind == PNK_CONTINUE); pn_u.loopControl.label = label; @@ -1050,8 +1050,8 @@ class LoopControlStatement : public ParseNode class BreakStatement : public LoopControlStatement { public: - BreakStatement(PropertyName *label, uint32_t begin, uint32_t end) - : LoopControlStatement(PNK_BREAK, label, begin, end) + BreakStatement(PropertyName *label, const TokenPos &pos) + : LoopControlStatement(PNK_BREAK, label, pos) { } static bool test(const ParseNode &node) { @@ -1065,8 +1065,8 @@ class BreakStatement : public LoopControlStatement class ContinueStatement : public LoopControlStatement { public: - ContinueStatement(PropertyName *label, uint32_t begin, uint32_t end) - : LoopControlStatement(PNK_CONTINUE, label, begin, end) + ContinueStatement(PropertyName *label, const TokenPos &pos) + : LoopControlStatement(PNK_CONTINUE, label, pos) { } static bool test(const ParseNode &node) { diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index ddac0f3abab..948f0cc591e 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -4315,6 +4315,90 @@ Parser::switchStatement() return handler.newSwitchStatement(begin, discriminant, caseList); } +template +typename ParseHandler::Node +Parser::continueStatement() +{ + JS_ASSERT(tokenStream.isCurrentTokenType(TOK_CONTINUE)); + uint32_t begin = pos().begin; + + RootedPropertyName label(context); + if (!MatchLabel(context, &tokenStream, &label)) + return null(); + + StmtInfoPC *stmt = pc->topStmt; + if (label) { + for (StmtInfoPC *stmt2 = NULL; ; stmt = stmt->down) { + if (!stmt) { + report(ParseError, false, null(), JSMSG_LABEL_NOT_FOUND); + return null(); + } + if (stmt->type == STMT_LABEL) { + if (stmt->label == label) { + if (!stmt2 || !stmt2->isLoop()) { + report(ParseError, false, null(), JSMSG_BAD_CONTINUE); + return null(); + } + break; + } + } else { + stmt2 = stmt; + } + } + } else { + for (; ; stmt = stmt->down) { + if (!stmt) { + report(ParseError, false, null(), JSMSG_BAD_CONTINUE); + return null(); + } + if (stmt->isLoop()) + break; + } + } + + if (!MatchOrInsertSemicolon(context, &tokenStream)) + return null(); + + return handler.newContinueStatement(label, TokenPos::make(begin, pos().end)); +} + +template +typename ParseHandler::Node +Parser::breakStatement() +{ + JS_ASSERT(tokenStream.isCurrentTokenType(TOK_BREAK)); + uint32_t begin = pos().begin; + + RootedPropertyName label(context); + if (!MatchLabel(context, &tokenStream, &label)) + return null(); + StmtInfoPC *stmt = pc->topStmt; + if (label) { + for (; ; stmt = stmt->down) { + if (!stmt) { + report(ParseError, false, null(), JSMSG_LABEL_NOT_FOUND); + return null(); + } + if (stmt->type == STMT_LABEL && stmt->label == label) + break; + } + } else { + for (; ; stmt = stmt->down) { + if (!stmt) { + report(ParseError, false, null(), JSMSG_TOUGH_BREAK); + return null(); + } + if (stmt->isLoop() || stmt->type == STMT_SWITCH) + break; + } + } + + if (!MatchOrInsertSemicolon(context, &tokenStream)) + return null(); + + return handler.newBreakStatement(label, TokenPos::make(begin, pos().end)); +} + template typename ParseHandler::Node Parser::returnOrYield(bool useAssignExpr) @@ -4735,78 +4819,11 @@ Parser::statement(bool canHaveDirectives) case TOK_SWITCH: return switchStatement(); - case TOK_BREAK: - { - uint32_t begin = pos().begin; - RootedPropertyName label(context); - if (!MatchLabel(context, &tokenStream, &label)) - return null(); - pn = handler.newBreak(label, begin, pos().end); - if (!pn) - return null(); - StmtInfoPC *stmt = pc->topStmt; - if (label) { - for (; ; stmt = stmt->down) { - if (!stmt) { - report(ParseError, false, null(), JSMSG_LABEL_NOT_FOUND); - return null(); - } - if (stmt->type == STMT_LABEL && stmt->label == label) - break; - } - } else { - for (; ; stmt = stmt->down) { - if (!stmt) { - report(ParseError, false, null(), JSMSG_TOUGH_BREAK); - return null(); - } - if (stmt->isLoop() || stmt->type == STMT_SWITCH) - break; - } - } - break; - } - case TOK_CONTINUE: - { - uint32_t begin = pos().begin; - RootedPropertyName label(context); - if (!MatchLabel(context, &tokenStream, &label)) - return null(); - pn = handler.newContinue(label, begin, pos().end); - if (!pn) - return null(); - StmtInfoPC *stmt = pc->topStmt; - if (label) { - for (StmtInfoPC *stmt2 = NULL; ; stmt = stmt->down) { - if (!stmt) { - report(ParseError, false, null(), JSMSG_LABEL_NOT_FOUND); - return null(); - } - if (stmt->type == STMT_LABEL) { - if (stmt->label == label) { - if (!stmt2 || !stmt2->isLoop()) { - report(ParseError, false, null(), JSMSG_BAD_CONTINUE); - return null(); - } - break; - } - } else { - stmt2 = stmt; - } - } - } else { - for (; ; stmt = stmt->down) { - if (!stmt) { - report(ParseError, false, null(), JSMSG_BAD_CONTINUE); - return null(); - } - if (stmt->isLoop()) - break; - } - } - break; - } + return continueStatement(); + + case TOK_BREAK: + return breakStatement(); case TOK_RETURN: pn = returnOrYield(false); diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h index de4d3b2a0e4..7e9da042061 100644 --- a/js/src/frontend/Parser.h +++ b/js/src/frontend/Parser.h @@ -422,6 +422,8 @@ struct Parser : private AutoGCRooter, public StrictModeGetter Node whileStatement(); Node forStatement(); Node switchStatement(); + Node continueStatement(); + Node breakStatement(); Node withStatement(); Node labeledStatement(); Node tryStatement(); diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h index d4f87702650..83c3af62fc7 100644 --- a/js/src/frontend/SyntaxParseHandler.h +++ b/js/src/frontend/SyntaxParseHandler.h @@ -111,8 +111,8 @@ class SyntaxParseHandler Node newWhileStatement(uint32_t begin, Node cond, Node body) { return NodeGeneric; } Node newSwitchStatement(uint32_t begin, Node discriminant, Node caseList) { return NodeGeneric; } Node newCaseOrDefault(uint32_t begin, Node expr, Node body) { return NodeGeneric; } - Node newContinue(PropertyName *label, uint32_t begin, uint32_t end) { return NodeGeneric; } - Node newBreak(PropertyName *label, uint32_t begin, uint32_t end) { return NodeGeneric; } + Node newContinueStatement(PropertyName *label, const TokenPos &pos) { return NodeGeneric; } + Node newBreakStatement(PropertyName *label, const TokenPos &pos) { return NodeGeneric; } Node newReturnStatement(Node expr, const TokenPos &pos) { return NodeGeneric; } Node newLabeledStatement(PropertyName *label, Node stmt, uint32_t begin) {