Added var, const, and for statements
git-svn-id: svn://10.0.0.236/trunk@70908 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
eed09dcad3
commit
c4a32c8de3
@ -619,13 +619,15 @@ const JS::Token &JS::Lexer::peek(bool preferRegExp)
|
||||
#ifdef DEBUG
|
||||
// Change the setting of preferRegExp for an already peeked token. The token must not be one
|
||||
// for which that setting mattered.
|
||||
//
|
||||
// THIS IS A DANGEROUS FUNCTION!
|
||||
// Use it only if you can be prove that the already peeked token does not start with a slash.
|
||||
void JS::Lexer::redesignate(bool preferRegExp)
|
||||
{
|
||||
ASSERT(nTokensFwd);
|
||||
if (savedPreferRegExp[nextToken - tokens] != preferRegExp) {
|
||||
ASSERT(!(nextToken->hasKind(Token::regExp) || nextToken->hasKind(Token::divide) || nextToken->hasKind(Token::divideEquals)));
|
||||
savedPreferRegExp[nextToken - tokens] = preferRegExp;
|
||||
}
|
||||
ASSERT(savedPreferRegExp[nextToken - tokens] != preferRegExp);
|
||||
ASSERT(!(nextToken->hasKind(Token::regExp) || nextToken->hasKind(Token::divide) || nextToken->hasKind(Token::divideEquals)));
|
||||
savedPreferRegExp[nextToken - tokens] = preferRegExp;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1185,6 +1187,37 @@ void JS::Lexer::lexToken(bool preferRegExp)
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// VariableBinding
|
||||
//
|
||||
|
||||
const int32 basicIndent = 4; // Size of one level of statement indentation
|
||||
const int32 caseIndent = basicIndent/2; // Indentation before a case or default statement
|
||||
const int32 varIndent = 2; // Indentation of var or const statement bindings
|
||||
const int32 subexpressionIndent = 4; // Size of one level of expression indentation
|
||||
|
||||
|
||||
// Print this onto f.
|
||||
void JS::VariableBinding::print(PrettyPrinter &f) const
|
||||
{
|
||||
PrettyPrinter::Block b(f);
|
||||
if (name)
|
||||
f << name;
|
||||
PrettyPrinter::Indent i(f, subexpressionIndent);
|
||||
if (type) {
|
||||
f.fillBreak(0);
|
||||
f << ": ";
|
||||
f << type;
|
||||
}
|
||||
if (initializer) {
|
||||
f.linearBreak(1);
|
||||
f << "= ";
|
||||
f << initializer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// ExprNode
|
||||
//
|
||||
@ -1380,7 +1413,7 @@ void JS::InvokeExprNode::print(PrettyPrinter &f) const
|
||||
if (hasKind(New))
|
||||
f << "new ";
|
||||
f << op;
|
||||
PrettyPrinter::Indent i(f, 4);
|
||||
PrettyPrinter::Indent i(f, subexpressionIndent);
|
||||
f.fillBreak(0);
|
||||
PairListExprNode::print(f);
|
||||
}
|
||||
@ -1448,18 +1481,15 @@ void JS::TernaryExprNode::print(PrettyPrinter &f) const
|
||||
//
|
||||
|
||||
|
||||
const int32 basicIndent = 4; // Size of one level of indentation
|
||||
const int32 caseIndent = basicIndent/2; // Indentation before a case or default statement
|
||||
|
||||
|
||||
// Print statements on separate lines onto f. Do not print a line break after the last statement.
|
||||
void JS::StmtNode::printStatements(PrettyPrinter &f, const StmtNode *statements)
|
||||
{
|
||||
if (statements) {
|
||||
PrettyPrinter::Block b(f);
|
||||
while (true) {
|
||||
statements->print(f);
|
||||
statements = statements->next;
|
||||
const StmtNode *next = statements->next;
|
||||
statements->print(f, !next);
|
||||
statements = next;
|
||||
if (!statements)
|
||||
break;
|
||||
f.requiredBreak();
|
||||
@ -1479,10 +1509,10 @@ void JS::StmtNode::printBlock(PrettyPrinter &f, const StmtNode *statements)
|
||||
if (statements->hasKind(Case)) {
|
||||
PrettyPrinter::Indent i(f, caseIndent - basicIndent);
|
||||
f.requiredBreak();
|
||||
statements->print(f);
|
||||
statements->print(f, false);
|
||||
} else {
|
||||
f.requiredBreak();
|
||||
statements->print(f);
|
||||
statements->print(f, !statements->next);
|
||||
}
|
||||
statements = statements->next;
|
||||
}
|
||||
@ -1494,6 +1524,14 @@ void JS::StmtNode::printBlock(PrettyPrinter &f, const StmtNode *statements)
|
||||
}
|
||||
|
||||
|
||||
// Print a closing statement semicolon onto f unless noSemi is true.
|
||||
void JS::StmtNode::printSemi(PrettyPrinter &f, bool noSemi)
|
||||
{
|
||||
if (!noSemi)
|
||||
f << ';';
|
||||
}
|
||||
|
||||
|
||||
// Print this as a substatement of a statement such as if or with.
|
||||
// If this statement is a block without attributes, begin it on the current line and
|
||||
// do not indent it -- the block itself will provide the indent. Otherwise, begin this
|
||||
@ -1502,18 +1540,19 @@ void JS::StmtNode::printBlock(PrettyPrinter &f, const StmtNode *statements)
|
||||
// of a do-while statement. If this statement is a block without attributes, print a
|
||||
// space and the continuation after the closing brace; otherwise print the continuation
|
||||
// on a new line.
|
||||
void JS::StmtNode::printSubstatement(PrettyPrinter &f, const char *continuation) const
|
||||
// If noSemi is true, do not print the semicolon unless it is required by the statement.
|
||||
void JS::StmtNode::printSubstatement(PrettyPrinter &f, bool noSemi, const char *continuation) const
|
||||
{
|
||||
if (hasKind(block) && !static_cast<const BlockStmtNode *>(this)->attributes) {
|
||||
f << ' ';
|
||||
f << this;
|
||||
this->print(f, noSemi);
|
||||
if (continuation)
|
||||
f << ' ' << continuation;
|
||||
} else {
|
||||
{
|
||||
PrettyPrinter::Block b(f, basicIndent);
|
||||
f.requiredBreak();
|
||||
f << this;
|
||||
this->print(f, noSemi);
|
||||
}
|
||||
if (continuation) {
|
||||
f.requiredBreak();
|
||||
@ -1525,12 +1564,14 @@ void JS::StmtNode::printSubstatement(PrettyPrinter &f, const char *continuation)
|
||||
|
||||
// Print this onto f. The caller must enclose this call within the scope
|
||||
// of at least one PrettyPrinter::Block.
|
||||
void JS::StmtNode::print(PrettyPrinter &f) const
|
||||
// If noSemi is true, do not print the semicolon unless it is required by the statement.
|
||||
void JS::StmtNode::print(PrettyPrinter &f, bool /*noSemi*/) const
|
||||
{
|
||||
ASSERT(hasKind(empty));
|
||||
f << ';';
|
||||
}
|
||||
|
||||
void JS::ExprStmtNode::print(PrettyPrinter &f) const
|
||||
void JS::ExprStmtNode::print(PrettyPrinter &f, bool noSemi) const
|
||||
{
|
||||
const ExprNode *e = expr;
|
||||
|
||||
@ -1558,7 +1599,7 @@ void JS::ExprStmtNode::print(PrettyPrinter &f) const
|
||||
showExpr:
|
||||
f << e;
|
||||
showSemicolon:
|
||||
StmtNode::print(f);
|
||||
printSemi(f, noSemi);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1566,27 +1607,21 @@ void JS::ExprStmtNode::print(PrettyPrinter &f) const
|
||||
}
|
||||
}
|
||||
|
||||
void JS::AttributeStmtNode::print(PrettyPrinter &f) const
|
||||
void JS::BlockStmtNode::print(PrettyPrinter &f, bool) const
|
||||
{
|
||||
for (const IdentifierList *a = attributes; a; a = a->next)
|
||||
f << a->name << ' ';
|
||||
}
|
||||
|
||||
void JS::BlockStmtNode::print(PrettyPrinter &f) const
|
||||
{
|
||||
AttributeStmtNode::print(f);
|
||||
printAttributes(f);
|
||||
printBlock(f, statements);
|
||||
}
|
||||
|
||||
void JS::LabelStmtNode::print(PrettyPrinter &f) const
|
||||
void JS::LabelStmtNode::print(PrettyPrinter &f, bool noSemi) const
|
||||
{
|
||||
PrettyPrinter::Block b(f, basicIndent);
|
||||
f << name << ':';
|
||||
f.linearBreak(1);
|
||||
f << stmt;
|
||||
stmt->print(f, noSemi);
|
||||
}
|
||||
|
||||
void JS::UnaryStmtNode::print(PrettyPrinter &f) const
|
||||
void JS::UnaryStmtNode::print(PrettyPrinter &f, bool noSemi) const
|
||||
{
|
||||
ASSERT(stmt);
|
||||
const char *kindName = 0;
|
||||
@ -1602,9 +1637,9 @@ void JS::UnaryStmtNode::print(PrettyPrinter &f) const
|
||||
|
||||
case DoWhile:
|
||||
f << "do";
|
||||
stmt->printSubstatement(f, "while (");
|
||||
stmt->printSubstatement(f, true, "while (");
|
||||
f << expr << ')';
|
||||
StmtNode::print(f);
|
||||
printSemi(f, noSemi);
|
||||
return;
|
||||
|
||||
case With:
|
||||
@ -1617,26 +1652,55 @@ void JS::UnaryStmtNode::print(PrettyPrinter &f) const
|
||||
|
||||
f << kindName << " (";
|
||||
f << expr << ')';
|
||||
stmt->printSubstatement(f);
|
||||
stmt->printSubstatement(f, noSemi);
|
||||
}
|
||||
|
||||
void JS::BinaryStmtNode::print(PrettyPrinter &f) const
|
||||
void JS::BinaryStmtNode::print(PrettyPrinter &f, bool noSemi) const
|
||||
{
|
||||
ASSERT(stmt && stmt2 && hasKind(IfElse));
|
||||
f << "if (";
|
||||
f << expr << ')';
|
||||
stmt->printSubstatement(f, "else");
|
||||
stmt2->printSubstatement(f);
|
||||
stmt->printSubstatement(f, true, "else");
|
||||
stmt2->printSubstatement(f, noSemi);
|
||||
}
|
||||
|
||||
void JS::SwitchStmtNode::print(PrettyPrinter &f) const
|
||||
void JS::ForStmtNode::print(PrettyPrinter &f, bool noSemi) const
|
||||
{
|
||||
ASSERT(stmt && (hasKind(For) || hasKind(ForIn)));
|
||||
f << "for (";
|
||||
{
|
||||
PrettyPrinter::Block b(f);
|
||||
if (initializer)
|
||||
initializer->print(f, true);
|
||||
if (hasKind(ForIn)) {
|
||||
f.fillBreak(1);
|
||||
f << "in";
|
||||
f.fillBreak(1);
|
||||
ASSERT(expr2 && !expr3);
|
||||
f << expr2;
|
||||
} else {
|
||||
f << ';';
|
||||
f.linearBreak(1);
|
||||
if (expr2)
|
||||
f << expr2;
|
||||
f << ';';
|
||||
f.linearBreak(1);
|
||||
if (expr3)
|
||||
f << expr3;
|
||||
}
|
||||
f << ')';
|
||||
}
|
||||
stmt->printSubstatement(f, noSemi);
|
||||
}
|
||||
|
||||
void JS::SwitchStmtNode::print(PrettyPrinter &f, bool) const
|
||||
{
|
||||
f << "switch (";
|
||||
f << expr << ") ";
|
||||
printBlock(f, statements);
|
||||
}
|
||||
|
||||
void JS::GoStmtNode::print(PrettyPrinter &f) const
|
||||
void JS::GoStmtNode::print(PrettyPrinter &f, bool noSemi) const
|
||||
{
|
||||
const char *kindName = 0;
|
||||
|
||||
@ -1656,15 +1720,15 @@ void JS::GoStmtNode::print(PrettyPrinter &f) const
|
||||
f << kindName;
|
||||
if (name)
|
||||
f << " " << *name;
|
||||
StmtNode::print(f);
|
||||
printSemi(f, noSemi);
|
||||
}
|
||||
|
||||
void JS::TryStmtNode::print(PrettyPrinter &f) const
|
||||
void JS::TryStmtNode::print(PrettyPrinter &f, bool noSemi) const
|
||||
{
|
||||
f << "try";
|
||||
const StmtNode *s = stmt;
|
||||
for (const CatchClause *c = catches; c; c = c->next) {
|
||||
s->printSubstatement(f, "catch (");
|
||||
s->printSubstatement(f, true, "catch (");
|
||||
PrettyPrinter::Block b(f);
|
||||
f << c->name;
|
||||
ExprNode *t = c->type;
|
||||
@ -1677,10 +1741,39 @@ void JS::TryStmtNode::print(PrettyPrinter &f) const
|
||||
s = c->stmt;
|
||||
}
|
||||
if (finally) {
|
||||
s->printSubstatement(f, "finally");
|
||||
s->printSubstatement(f, true, "finally");
|
||||
s = finally;
|
||||
}
|
||||
s->printSubstatement(f);
|
||||
s->printSubstatement(f, noSemi);
|
||||
}
|
||||
|
||||
void JS::VariableStmtNode::print(PrettyPrinter &f, bool noSemi) const
|
||||
{
|
||||
printAttributes(f);
|
||||
ASSERT(hasKind(Const) || hasKind(Var));
|
||||
f << (hasKind(Const) ? "const" : "var");
|
||||
{
|
||||
PrettyPrinter::Block b(f, basicIndent);
|
||||
const VariableBinding *binding = bindings;
|
||||
if (binding)
|
||||
while (true) {
|
||||
f.linearBreak(1);
|
||||
binding->print(f);
|
||||
binding = binding->next;
|
||||
if (!binding)
|
||||
break;
|
||||
f << ',';
|
||||
}
|
||||
}
|
||||
printSemi(f, noSemi);
|
||||
}
|
||||
|
||||
|
||||
// Print the attributes on a single line separated with and followed by a space.
|
||||
void JS::AttributeStmtNode::printAttributes(PrettyPrinter &f) const
|
||||
{
|
||||
for (const IdentifierList *a = attributes; a; a = a->next)
|
||||
f << a->name << ' ';
|
||||
}
|
||||
|
||||
|
||||
@ -1747,10 +1840,10 @@ inline JS::String &JS::Parser::copyTokenChars(const Token &t)
|
||||
// If it is followed by one or more ::'s followed by identifiers, construct the appropriate
|
||||
// qualify parse node and return it and set foundQualifiers to true. If no ::
|
||||
// is found, return e and set foundQualifiers to false.
|
||||
// After parseIdentifierQualifiers finishes, the next token might have been peeked with preferRegExp set to false.
|
||||
JS::ExprNode *JS::Parser::parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers)
|
||||
// After parseIdentifierQualifiers finishes, the next token might have been peeked with the given preferRegExp setting.
|
||||
JS::ExprNode *JS::Parser::parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers, bool preferRegExp)
|
||||
{
|
||||
const Token *tDoubleColon = lexer.eat(false, Token::doubleColon);
|
||||
const Token *tDoubleColon = lexer.eat(preferRegExp, Token::doubleColon);
|
||||
if (!tDoubleColon) {
|
||||
foundQualifiers = false;
|
||||
return e;
|
||||
@ -1758,7 +1851,7 @@ JS::ExprNode *JS::Parser::parseIdentifierQualifiers(ExprNode *e, bool &foundQual
|
||||
|
||||
foundQualifiers = true;
|
||||
checkStackSize();
|
||||
return new(arena) BinaryExprNode(tDoubleColon->getPos(), ExprNode::qualify, e, parseQualifiedIdentifier(lexer.get(true)));
|
||||
return new(arena) BinaryExprNode(tDoubleColon->getPos(), ExprNode::qualify, e, parseQualifiedIdentifier(lexer.get(true), preferRegExp));
|
||||
}
|
||||
|
||||
|
||||
@ -1767,36 +1860,36 @@ JS::ExprNode *JS::Parser::parseIdentifierQualifiers(ExprNode *e, bool &foundQual
|
||||
// qualify parse node and return it and set foundQualifiers to true. If no ::
|
||||
// is found, return the ParenthesizedExpression and set foundQualifiers to false.
|
||||
// After parseParenthesesAndIdentifierQualifiers finishes, the next token might have been peeked with
|
||||
// preferRegExp set to false.
|
||||
JS::ExprNode *JS::Parser::parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool &foundQualifiers)
|
||||
// the given preferRegExp setting.
|
||||
JS::ExprNode *JS::Parser::parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool &foundQualifiers, bool preferRegExp)
|
||||
{
|
||||
uint32 pos = tParen.getPos();
|
||||
ExprNode *e = new(arena) UnaryExprNode(pos, ExprNode::parentheses, parseExpression(false));
|
||||
require(false, Token::closeParenthesis);
|
||||
return parseIdentifierQualifiers(e, foundQualifiers);
|
||||
return parseIdentifierQualifiers(e, foundQualifiers, preferRegExp);
|
||||
}
|
||||
|
||||
|
||||
// Parse and return a qualifiedIdentifier. The first token has already been parsed and is in t.
|
||||
// If the second token was peeked, it should be have been done with preferRegExp set to false.
|
||||
// After parseQualifiedIdentifier finishes, the next token might have been peeked with preferRegExp set to false.
|
||||
JS::ExprNode *JS::Parser::parseQualifiedIdentifier(const Token &t)
|
||||
// If the second token was peeked, it should be have been done with the given preferRegExp setting.
|
||||
// After parseQualifiedIdentifier finishes, the next token might have been peeked with the given preferRegExp setting.
|
||||
JS::ExprNode *JS::Parser::parseQualifiedIdentifier(const Token &t, bool preferRegExp)
|
||||
{
|
||||
bool foundQualifiers;
|
||||
ExprNode *e;
|
||||
|
||||
if (t.hasIdentifierKind())
|
||||
return parseIdentifierQualifiers(new(arena) IdentifierExprNode(t), foundQualifiers);
|
||||
return parseIdentifierQualifiers(new(arena) IdentifierExprNode(t), foundQualifiers, preferRegExp);
|
||||
if (t.hasKind(Token::openParenthesis)) {
|
||||
e = parseParenthesesAndIdentifierQualifiers(t, foundQualifiers);
|
||||
e = parseParenthesesAndIdentifierQualifiers(t, foundQualifiers, preferRegExp);
|
||||
goto checkQualifiers;
|
||||
}
|
||||
if (t.hasKind(Token::Super)) {
|
||||
e = parseIdentifierQualifiers(new(arena) ExprNode(t.getPos(), ExprNode::Super), foundQualifiers);
|
||||
e = parseIdentifierQualifiers(new(arena) ExprNode(t.getPos(), ExprNode::Super), foundQualifiers, preferRegExp);
|
||||
goto checkQualifiers;
|
||||
}
|
||||
if (t.hasKind(Token::Public) || t.hasKind(Token::Package) || t.hasKind(Token::Private)) {
|
||||
e = parseIdentifierQualifiers(new(arena) IdentifierExprNode(t), foundQualifiers);
|
||||
e = parseIdentifierQualifiers(new(arena) IdentifierExprNode(t), foundQualifiers, preferRegExp);
|
||||
checkQualifiers:
|
||||
if (!foundQualifiers)
|
||||
syntaxError("'::' expected", 0);
|
||||
@ -1817,7 +1910,7 @@ JS::PairListExprNode *JS::Parser::parseArrayLiteral(const Token &initialToken)
|
||||
ExprNode *element = 0;
|
||||
const Token &t = lexer.peek(true);
|
||||
if (t.hasKind(Token::comma) || t.hasKind(Token::closeBracket))
|
||||
lexer.redesignate(false);
|
||||
lexer.redesignate(false); // Safe: neither ',' nor '}' starts with a slash.
|
||||
else
|
||||
element = parseAssignmentExpression(false);
|
||||
elements += new(arena) ExprPairList(0, element);
|
||||
@ -1844,7 +1937,7 @@ JS::PairListExprNode *JS::Parser::parseObjectLiteral(const Token &initialToken)
|
||||
ExprNode *field;
|
||||
if (t.hasIdentifierKind() || t.hasKind(Token::openParenthesis) || t.hasKind(Token::Super) ||
|
||||
t.hasKind(Token::Public) || t.hasKind(Token::Package) || t.hasKind(Token::Private))
|
||||
field = parseQualifiedIdentifier(t);
|
||||
field = parseQualifiedIdentifier(t, false);
|
||||
else if (t.hasKind(Token::string))
|
||||
field = new(arena) StringExprNode(t.getPos(), ExprNode::string, copyTokenChars(t));
|
||||
else if (t.hasKind(Token::number))
|
||||
@ -1929,13 +2022,13 @@ JS::ExprNode *JS::Parser::parsePrimaryExpression()
|
||||
case Token::Private:
|
||||
case CASE_TOKEN_NONRESERVED:
|
||||
makeQualifiedIdentifierNode:
|
||||
e = parseQualifiedIdentifier(t);
|
||||
e = parseQualifiedIdentifier(t, false);
|
||||
break;
|
||||
|
||||
case Token::openParenthesis:
|
||||
{
|
||||
bool foundQualifiers;
|
||||
e = parseParenthesesAndIdentifierQualifiers(t, foundQualifiers);
|
||||
e = parseParenthesesAndIdentifierQualifiers(t, foundQualifiers, false);
|
||||
if (!foundQualifiers) {
|
||||
const Token &tUnit = lexer.peek(false);
|
||||
if (!lineBreakBefore(tUnit) && tUnit.hasKind(Token::string)) {
|
||||
@ -1979,11 +2072,11 @@ JS::BinaryExprNode *JS::Parser::parseMember(ExprNode *target, const Token &tOper
|
||||
const Token &t2 = lexer.get(true);
|
||||
if (t2.hasKind(Token::openParenthesis)) {
|
||||
bool foundQualifiers;
|
||||
member = parseParenthesesAndIdentifierQualifiers(t2, foundQualifiers);
|
||||
member = parseParenthesesAndIdentifierQualifiers(t2, foundQualifiers, false);
|
||||
if (!foundQualifiers)
|
||||
kind = parenKind;
|
||||
} else
|
||||
member = parseQualifiedIdentifier(t2);
|
||||
member = parseQualifiedIdentifier(t2, false);
|
||||
return new(arena) BinaryExprNode(pos, kind, target, member);
|
||||
}
|
||||
|
||||
@ -2085,6 +2178,15 @@ JS::ExprNode *JS::Parser::parsePostfixExpression(bool newExpression)
|
||||
}
|
||||
|
||||
|
||||
// Ensure that e is a postfix expression. If not, throw a syntax error on the current token.
|
||||
void JS::Parser::ensurePostfix(const ExprNode *e)
|
||||
{
|
||||
ASSERT(e);
|
||||
if (!e->isPostfix())
|
||||
syntaxError("Only a postfix expression can be used as the result of an assignment; enclose this expression in parentheses", 0);
|
||||
}
|
||||
|
||||
|
||||
// Parse and return a UnaryExpression.
|
||||
// If the first token was peeked, it should be have been done with preferRegExp set to true.
|
||||
// After parseUnaryExpression finishes, the next token might have been peeked with preferRegExp set to false.
|
||||
@ -2288,7 +2390,6 @@ struct JS::Parser::StackedSubexpression {
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Parse and return an Expression. If noIn is false, allow the in operator. If noAssignment is
|
||||
// false, allow the = and op= operators. If noComma is false, allow the comma operator.
|
||||
// If the first token was peeked, it should be have been done with preferRegExp set to true.
|
||||
@ -2317,11 +2418,9 @@ JS::ExprNode *JS::Parser::parseExpression(bool noIn, bool noAssignment, bool noC
|
||||
precedence = pExpression;
|
||||
}
|
||||
|
||||
if (precedence == pPostfix) {
|
||||
// Ensure that the target of an assignment is a postfix subexpression.
|
||||
if (ExprNode::isUnaryKind(e->getKind()))
|
||||
syntaxError("Cannot assign to the result of this unary expression", 0);
|
||||
} else
|
||||
if (precedence == pPostfix)
|
||||
ensurePostfix(e); // Ensure that the target of an assignment is a postfix subexpression.
|
||||
else
|
||||
// Reduce already stacked operators with precedenceLeft or higher precedence
|
||||
while (subexpressionStack.back().precedence >= precedence) {
|
||||
StackedSubexpression &s = subexpressionStack.pop_back();
|
||||
@ -2380,11 +2479,50 @@ const JS::StringAtom &JS::Parser::parseTypedIdentifier(ExprNode *&type)
|
||||
|
||||
type = 0;
|
||||
if (lexer.eat(false, Token::colon))
|
||||
type = parseAssignmentExpression(false);
|
||||
type = parseNonAssignmentExpression(false);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
// Parse and return a VariableBinding.
|
||||
// If noQualifiers is false, allow a QualifiedIdentifier as the variable name; otherwise, restrict the
|
||||
// variable name to be a simple Identifier.
|
||||
// If noIn is false, allow the in operator.
|
||||
//
|
||||
// If the first token was peeked, it should be have been done with preferRegExp set to true.
|
||||
// After parseVariableBinding finishes, the next token might have been peeked with preferRegExp set to true.
|
||||
JS::VariableBinding *JS::Parser::parseVariableBinding(bool noQualifiers, bool noIn)
|
||||
{
|
||||
const Token &t = lexer.get(true);
|
||||
uint32 pos = t.getPos();
|
||||
|
||||
ExprNode *name;
|
||||
if (noQualifiers) {
|
||||
if (!t.hasIdentifierKind())
|
||||
syntaxError("Identifier expected");
|
||||
name = new(arena) IdentifierExprNode(t);
|
||||
} else
|
||||
name = parseQualifiedIdentifier(t, true);
|
||||
|
||||
ExprNode *type = 0;
|
||||
if (lexer.eat(true, Token::colon)) {
|
||||
type = parseNonAssignmentExpression(noIn);
|
||||
if (lexer.peek(false).hasKind(Token::divideEquals))
|
||||
syntaxError("'/=' not allowed here", 0);
|
||||
lexer.redesignate(true); // Safe: a '/' would have been interpreted as an operator, so it can't be the next token;
|
||||
// a '/=' was outlawed by the check above.
|
||||
}
|
||||
|
||||
ExprNode *initializer = 0;
|
||||
if (lexer.eat(true, Token::assignment)) {
|
||||
initializer = parseAssignmentExpression(noIn);
|
||||
lexer.redesignate(true); // Safe: a '/' or a '/=' would have been interpreted as an operator, so it can't be the next token.
|
||||
}
|
||||
|
||||
return new(arena) VariableBinding(pos, name, type, initializer);
|
||||
}
|
||||
|
||||
|
||||
// Parse a list of statements ending with a '}'. Return these statements as a linked list
|
||||
// threaded through the StmtNodes' next fields. If noOpenBrace is true, the opening '{' has already been read.
|
||||
// If noCloseBrace is true, an end-of-input terminates the block; the end-of-input token is not read.
|
||||
@ -2423,6 +2561,7 @@ JS::StmtNode *JS::Parser::parseBlock(bool inSwitch, bool noOpenBrace, bool noClo
|
||||
|
||||
|
||||
// Parse and return a statement that takes zero or more initial attributes, which have already been parsed.
|
||||
// If noIn is false, allow the in operator.
|
||||
//
|
||||
// If the statement ends with an optional semicolon, that semicolon is not parsed.
|
||||
// Instead, parseAttributeStatement returns in semicolonState one of three values:
|
||||
@ -2432,18 +2571,35 @@ JS::StmtNode *JS::Parser::parseBlock(bool inSwitch, bool noOpenBrace, bool noClo
|
||||
//
|
||||
// pos is the position of the beginning of the statement (its first attribute if it has attributes).
|
||||
// The first token of the statement has already been read and is provided in t.
|
||||
// If the second token was peeked, it should be have been done with preferRegExp set to false.
|
||||
// After parseAttributeStatement finishes, the next token might have been peeked with preferRegExp set to true.
|
||||
JS::StmtNode *JS::Parser::parseAttributeStatement(uint32 pos, IdentifierList *attributes, const Token &t, SemicolonState &semicolonState)
|
||||
JS::StmtNode *JS::Parser::parseAttributeStatement(uint32 pos, IdentifierList *attributes, const Token &t,
|
||||
bool noIn, SemicolonState &semicolonState)
|
||||
{
|
||||
StmtNode *s;
|
||||
semicolonState = semiNone;
|
||||
StmtNode::Kind sKind;
|
||||
|
||||
switch (t.getKind()) {
|
||||
case Token::openBrace:
|
||||
s = new(arena) BlockStmtNode(pos, StmtNode::block, attributes, parseBlock(false, true, false));
|
||||
break;
|
||||
|
||||
case Token::Const:
|
||||
sKind = StmtNode::Const;
|
||||
goto constOrVar;
|
||||
case Token::Var:
|
||||
sKind = StmtNode::Var;
|
||||
constOrVar:
|
||||
{
|
||||
NodeQueue<VariableBinding> bindings;
|
||||
|
||||
do bindings += parseVariableBinding(false, noIn);
|
||||
while (lexer.eat(true, Token::comma));
|
||||
s = new(arena) VariableStmtNode(pos, sKind, attributes, bindings.first);
|
||||
semicolonState = semiInsertable;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
syntaxError("Bad declaration");
|
||||
s = 0;
|
||||
@ -2458,10 +2614,11 @@ JS::StmtNode *JS::Parser::parseAttributeStatement(uint32 pos, IdentifierList *at
|
||||
// as restricts the kinds of statements that are allowed after the attributes:
|
||||
// asAny Any statements that takes attributes can follow
|
||||
// asBlock Only a block can follow
|
||||
// asConstVar Only a const or var declaration can follow
|
||||
// asConstVar Only a const or var declaration can follow, and the 'in' operator is not allowed at its top level
|
||||
//
|
||||
// The first token of the statement has already been read and is provided in t.
|
||||
// If the second token was peeked, it should be have been done with preferRegExp set to false.
|
||||
// If the second token was peeked, it should be have been done with preferRegExp set to false;
|
||||
// the second token should have been peeked only if t is an attribute.
|
||||
// After parseAttributesAndStatement finishes, the next token might have been peeked with
|
||||
// preferRegExp set to true.
|
||||
JS::StmtNode *JS::Parser::parseAttributesAndStatement(const Token *t, AttributeStatement as, SemicolonState &semicolonState)
|
||||
@ -2489,7 +2646,7 @@ JS::StmtNode *JS::Parser::parseAttributesAndStatement(const Token *t, AttributeS
|
||||
syntaxError("const or var expected");
|
||||
break;
|
||||
}
|
||||
return parseAttributeStatement(pos, attributes.first, *t, semicolonState);
|
||||
return parseAttributeStatement(pos, attributes.first, *t, as == asConstVar, semicolonState);
|
||||
}
|
||||
|
||||
|
||||
@ -2506,6 +2663,83 @@ JS::StmtNode *JS::Parser::parseAnnotatedBlock()
|
||||
}
|
||||
|
||||
|
||||
// Parse and return a ForStatement. The 'for' token has already been read; its position is pos.
|
||||
// If the statement ends with an optional semicolon, that semicolon is not parsed.
|
||||
// Instead, parseFor returns a semicolonState with the same meaning as that in parseStatement.
|
||||
//
|
||||
// After parseFor finishes, the next token might have been peeked with preferRegExp set to true.
|
||||
JS::StmtNode *JS::Parser::parseFor(uint32 pos, SemicolonState &semicolonState)
|
||||
{
|
||||
require(true, Token::openParenthesis);
|
||||
const Token &t = lexer.get(true);
|
||||
uint32 tPos = t.getPos();
|
||||
const Token *t2;
|
||||
StmtNode *initializer = 0;
|
||||
ExprNode *expr1 = 0;
|
||||
ExprNode *expr2 = 0;
|
||||
ExprNode *expr3 = 0;
|
||||
StmtNode::Kind sKind = StmtNode::For;
|
||||
|
||||
switch (t.getKind()) {
|
||||
case Token::semicolon:
|
||||
goto threeExpr;
|
||||
|
||||
case Token::Const:
|
||||
case Token::Var:
|
||||
case Token::Final:
|
||||
case Token::Static:
|
||||
case Token::Volatile:
|
||||
makeAttribute:
|
||||
initializer = parseAttributesAndStatement(&t, asConstVar, semicolonState);
|
||||
break;
|
||||
|
||||
case CASE_TOKEN_ATTRIBUTE_IDENTIFIER:
|
||||
case Token::Public:
|
||||
case Token::Package:
|
||||
case Token::Private:
|
||||
t2 = &lexer.peek(false);
|
||||
if (!lineBreakBefore(*t2) && t2->getFlag(Token::canFollowAttribute))
|
||||
goto makeAttribute;
|
||||
default:
|
||||
lexer.unget();
|
||||
expr1 = parseExpression(true);
|
||||
initializer = new(arena) ExprStmtNode(tPos, StmtNode::expression, expr1);
|
||||
lexer.redesignate(true); // Safe: a '/' or a '/=' would have been interpreted as an operator, so it can't be the next token.
|
||||
break;
|
||||
}
|
||||
|
||||
if (lexer.eat(true, Token::semicolon))
|
||||
threeExpr: {
|
||||
if (!lexer.eat(true, Token::semicolon)) {
|
||||
expr2 = parseExpression(false);
|
||||
require(false, Token::semicolon);
|
||||
}
|
||||
if (lexer.peek(true).hasKind(Token::closeParenthesis))
|
||||
lexer.redesignate(false); // Safe: the token is ')'.
|
||||
else
|
||||
expr3 = parseExpression(false);
|
||||
}
|
||||
else if (lexer.eat(true, Token::In)) {
|
||||
sKind = StmtNode::ForIn;
|
||||
if (expr1) {
|
||||
ASSERT(initializer->hasKind(StmtNode::expression));
|
||||
ensurePostfix(expr1);
|
||||
} else {
|
||||
ASSERT(initializer->hasKind(StmtNode::Const) || initializer->hasKind(StmtNode::Var));
|
||||
const VariableBinding *bindings = static_cast<VariableStmtNode *>(initializer)->bindings;
|
||||
if (!bindings || bindings->next)
|
||||
syntaxError("Only one variable binding can be used in a for-in statement", 0);
|
||||
}
|
||||
expr2 = parseExpression(false);
|
||||
}
|
||||
else
|
||||
syntaxError("';' or 'in' expected", 0);
|
||||
|
||||
require(false, Token::closeParenthesis);
|
||||
return new(arena) ForStmtNode(pos, sKind, initializer, expr2, expr3, parseStatement(false, false, semicolonState));
|
||||
}
|
||||
|
||||
|
||||
// Parse and return a TryStatement. The 'try' token has already been read; its position is pos.
|
||||
// After parseTry finishes, the next token might have been peeked with preferRegExp set to true.
|
||||
JS::StmtNode *JS::Parser::parseTry(uint32 pos)
|
||||
@ -2562,7 +2796,7 @@ JS::StmtNode *JS::Parser::parseStatement(bool topLevel, bool inSwitch, Semicolon
|
||||
case Token::openBrace:
|
||||
case Token::Const:
|
||||
case Token::Var:
|
||||
s = parseAttributeStatement(pos, 0, t, semicolonState);
|
||||
s = parseAttributeStatement(pos, 0, t, false, semicolonState);
|
||||
break;
|
||||
|
||||
case Token::If:
|
||||
@ -2621,6 +2855,10 @@ JS::StmtNode *JS::Parser::parseStatement(bool topLevel, bool inSwitch, Semicolon
|
||||
s = new(arena) UnaryStmtNode(pos, sKind, e, s);
|
||||
break;
|
||||
|
||||
case Token::For:
|
||||
s = parseFor(pos, semicolonState);
|
||||
break;
|
||||
|
||||
case Token::Continue:
|
||||
sKind = StmtNode::Continue;
|
||||
goto makeGo;
|
||||
@ -2657,7 +2895,6 @@ JS::StmtNode *JS::Parser::parseStatement(bool topLevel, bool inSwitch, Semicolon
|
||||
break;
|
||||
|
||||
case Token::Final:
|
||||
case Token::Private:
|
||||
case Token::Static:
|
||||
case Token::Volatile:
|
||||
makeAttribute:
|
||||
@ -2665,6 +2902,8 @@ JS::StmtNode *JS::Parser::parseStatement(bool topLevel, bool inSwitch, Semicolon
|
||||
break;
|
||||
|
||||
case Token::Public:
|
||||
case Token::Package:
|
||||
case Token::Private:
|
||||
t2 = &lexer.peek(false);
|
||||
goto makeExpressionOrAttribute;
|
||||
|
||||
@ -2684,7 +2923,7 @@ JS::StmtNode *JS::Parser::parseStatement(bool topLevel, bool inSwitch, Semicolon
|
||||
sKind = StmtNode::expression;
|
||||
makeExpressionNode:
|
||||
e = parseExpression(false);
|
||||
lexer.redesignate(true);
|
||||
lexer.redesignate(true); // Safe: a '/' or a '/=' would have been interpreted as an operator, so it can't be the next token.
|
||||
makeExprStmtNode:
|
||||
s = new(arena) ExprStmtNode(pos, sKind, e);
|
||||
insertableSemicolon:
|
||||
|
||||
@ -348,7 +348,7 @@ namespace JavaScript {
|
||||
};
|
||||
|
||||
#ifndef DEBUG
|
||||
inline void Lexer::redesignate(bool) {}
|
||||
inline void Lexer::redesignate(bool) {} // See description for the DEBUG version inside parser.cpp
|
||||
#endif
|
||||
|
||||
// Return the position of the first character of the next token, which must have been peeked.
|
||||
@ -433,7 +433,10 @@ namespace JavaScript {
|
||||
ExprNode *type; // Type expression or nil if not provided
|
||||
ExprNode *initializer; // Initial value expression or nil if not provided
|
||||
|
||||
VariableBinding(uint32 pos): ParseNode(pos), next(0), name(0), type(0), initializer(0) {}
|
||||
VariableBinding(uint32 pos, ExprNode *name, ExprNode *type, ExprNode *initializer):
|
||||
ParseNode(pos), next(0), name(name), type(type), initializer(initializer) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
};
|
||||
|
||||
struct FunctionDefinition: FunctionName {
|
||||
@ -448,7 +451,7 @@ namespace JavaScript {
|
||||
struct ExprNode: ParseNode {
|
||||
enum Kind { // Actual class Operands // Keep synchronized with kindNames
|
||||
none,
|
||||
identifier, // IdentifierExprNode <name>
|
||||
identifier, // IdentifierExprNode <name> // Begin of isPostfix()
|
||||
number, // NumberExprNode <value>
|
||||
string, // StringExprNode <str>
|
||||
regExp, // RegExpExprNode /<re>/<flags>
|
||||
@ -474,8 +477,9 @@ namespace JavaScript {
|
||||
dot, // BinaryExprNode <op1> . <op2> // <op2> must be identifier or qualify
|
||||
dotParen, // BinaryExprNode <op1> .( <op2> )
|
||||
at, // BinaryExprNode <op1> @ <op2> or <op1> @( <op2> )
|
||||
// End of isPostfix()
|
||||
|
||||
Delete, // UnaryExprNode delete <op> // Begin of isUnaryKind()
|
||||
Delete, // UnaryExprNode delete <op>
|
||||
Typeof, // UnaryExprNode typeof <op>
|
||||
Eval, // UnaryExprNode eval <op>
|
||||
preIncrement, // UnaryExprNode ++ <op>
|
||||
@ -485,7 +489,7 @@ namespace JavaScript {
|
||||
plus, // UnaryExprNode + <op>
|
||||
minus, // UnaryExprNode - <op>
|
||||
complement, // UnaryExprNode ~ <op>
|
||||
logicalNot, // UnaryExprNode ! <op> // End of isUnaryKind()
|
||||
logicalNot, // UnaryExprNode ! <op>
|
||||
|
||||
add, // BinaryExprNode <op1> + <op2>
|
||||
subtract, // BinaryExprNode <op1> - <op2>
|
||||
@ -547,8 +551,8 @@ namespace JavaScript {
|
||||
|
||||
static bool isFieldKind(Kind kind) {return kind == identifier || kind == number || kind == string || kind == qualify;}
|
||||
static bool isAssigningKind(Kind kind) {return kind >= assignment && kind <= logicalOrEquals;}
|
||||
static bool isUnaryKind(Kind kind) {return kind >= Delete && kind <= logicalNot;}
|
||||
static const char *kindName(Kind kind) {ASSERT(uint(kind) < kindsEnd); return kindNames[kind];}
|
||||
bool isPostfix() const {return kind >= identifier && kind <= at;}
|
||||
|
||||
virtual void print(PrettyPrinter &f) const;
|
||||
};
|
||||
@ -689,9 +693,7 @@ namespace JavaScript {
|
||||
DoWhile, // UnaryStmtNode do <stmt> while ( <expr> )
|
||||
With, // UnaryStmtNode with ( <expr> ) <stmt>
|
||||
For, // ForStmtNode for ( <initializer> ; <expr2> ; <expr3> ) <stmt>
|
||||
ForExprIn, // ForExprInStmtNode for ( <varExpr> in <container> ) <stmt>
|
||||
ForConstIn, // ForVarInStmtNode for ( const <binding> in <container> ) <stmt>
|
||||
ForVarIn, // ForVarInStmtNode for ( var <binding> in <container> ) <stmt>
|
||||
ForIn, // ForStmtNode for ( <initializer> in <expr2> ) <stmt>
|
||||
Case, // ExprStmtNode case <expr> : or default : // Only occurs directly inside a Switch
|
||||
Break, // GoStmtNode break ; or break <name> ;
|
||||
Continue, // GoStmtNode continue ; or continue <name> ;
|
||||
@ -723,22 +725,20 @@ namespace JavaScript {
|
||||
Kind getKind() const {return kind;}
|
||||
bool hasKind(Kind k) const {return kind == k;}
|
||||
|
||||
virtual void print(PrettyPrinter &f) const;
|
||||
void printSubstatement(PrettyPrinter &f, const char *continuation = 0) const;
|
||||
static void printStatements(PrettyPrinter &f, const StmtNode *statements);
|
||||
static void printBlock(PrettyPrinter &f, const StmtNode *statements);
|
||||
static void printSemi(PrettyPrinter &f, bool noSemi);
|
||||
void printSubstatement(PrettyPrinter &f, bool noSemi, const char *continuation = 0) const;
|
||||
virtual void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
// Print s onto f.
|
||||
inline PrettyPrinter &operator<<(PrettyPrinter &f, const StmtNode *s) {ASSERT(s); s->print(f); return f;}
|
||||
|
||||
|
||||
struct ExprStmtNode: StmtNode {
|
||||
ExprNode *expr; // The expression statement's expression. May be nil for default: or return-with-no-expression statements.
|
||||
|
||||
ExprStmtNode(uint32 pos, Kind kind, ExprNode *expr): StmtNode(pos, kind), expr(expr) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct IdentifierList: ArenaObject {
|
||||
@ -753,7 +753,7 @@ namespace JavaScript {
|
||||
|
||||
AttributeStmtNode(uint32 pos, Kind kind, IdentifierList *attributes): StmtNode(pos, kind), attributes(attributes) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void printAttributes(PrettyPrinter &f) const;
|
||||
};
|
||||
|
||||
struct BlockStmtNode: AttributeStmtNode {
|
||||
@ -762,7 +762,7 @@ namespace JavaScript {
|
||||
BlockStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, StmtNode *statements):
|
||||
AttributeStmtNode(pos, kind, attributes), statements(statements) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct LabelStmtNode: StmtNode {
|
||||
@ -772,7 +772,7 @@ namespace JavaScript {
|
||||
LabelStmtNode(uint32 pos, const StringAtom &name, StmtNode *stmt):
|
||||
StmtNode(pos, label), name(name), stmt(stmt) {ASSERT(stmt);}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct UnaryStmtNode: ExprStmtNode {
|
||||
@ -781,7 +781,7 @@ namespace JavaScript {
|
||||
UnaryStmtNode(uint32 pos, Kind kind, ExprNode *expr, StmtNode *stmt):
|
||||
ExprStmtNode(pos, kind, expr), stmt(stmt) {ASSERT(stmt);}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct BinaryStmtNode: UnaryStmtNode {
|
||||
@ -790,39 +790,22 @@ namespace JavaScript {
|
||||
BinaryStmtNode(uint32 pos, Kind kind, ExprNode *expr, StmtNode *stmt1, StmtNode *stmt2):
|
||||
UnaryStmtNode(pos, kind, expr, stmt1), stmt2(stmt2) {ASSERT(stmt2);}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct ForStmtNode: StmtNode {
|
||||
StmtNode *initializer; // First item in parentheses; either nil (if not provided), an expression, or a Var, or a Const.
|
||||
ExprNode *expr2; // Second item in parentheses; nil if not provided
|
||||
ExprNode *expr3; // Third item in parentheses; nil if not provided
|
||||
StmtNode *initializer; // For: First item in parentheses; either nil (if not provided), an expression, or a Var, or a Const.
|
||||
// ForIn: Expression or declaration before 'in'; either an expression, or a Var or a Const with exactly one binding.
|
||||
ExprNode *expr2; // For: Second item in parentheses; nil if not provided
|
||||
// ForIn: Subexpression after 'in'; non-nil only
|
||||
ExprNode *expr3; // For: Third item in parentheses; nil if not provided
|
||||
// ForIn: nil
|
||||
StmtNode *stmt; // Substatement; non-nil only
|
||||
|
||||
ForStmtNode(uint32 pos, Kind kind, StmtNode *stmt):
|
||||
StmtNode(pos, kind), stmt(stmt) {ASSERT(stmt);}
|
||||
};
|
||||
|
||||
struct ForInStmtNode: StmtNode {
|
||||
ExprNode *container; // Subexpression after 'in'; non-nil only
|
||||
StmtNode *stmt; // Substatement; non-nil only
|
||||
ForStmtNode(uint32 pos, Kind kind, StmtNode *initializer, ExprNode *expr2, ExprNode *expr3, StmtNode *stmt):
|
||||
StmtNode(pos, kind), initializer(initializer), expr2(expr2), expr3(expr3), stmt(stmt) {ASSERT(stmt);}
|
||||
|
||||
ForInStmtNode(uint32 pos, Kind kind, ExprNode *container, StmtNode *stmt):
|
||||
StmtNode(pos, kind), container(container), stmt(stmt) {ASSERT(container && stmt);}
|
||||
};
|
||||
|
||||
struct ForExprInStmtNode: ForInStmtNode {
|
||||
ExprNode *varExpr; // Subexpression before 'in'; non-nil only
|
||||
|
||||
ForExprInStmtNode(uint32 pos, Kind kind, ExprNode *container, StmtNode *stmt, ExprNode *varExpr):
|
||||
ForInStmtNode(pos, kind, container, stmt), varExpr(varExpr) {ASSERT(varExpr);}
|
||||
};
|
||||
|
||||
struct ForVarInStmtNode: ForInStmtNode {
|
||||
VariableBinding *binding; // Var or const binding before 'in'; non-nil only
|
||||
|
||||
ForVarInStmtNode(uint32 pos, Kind kind, ExprNode *container, StmtNode *stmt, VariableBinding *binding):
|
||||
ForInStmtNode(pos, kind, container, stmt), binding(binding) {ASSERT(binding);}
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct SwitchStmtNode: ExprStmtNode {
|
||||
@ -830,7 +813,7 @@ namespace JavaScript {
|
||||
|
||||
SwitchStmtNode(uint32 pos, ExprNode *expr, StmtNode *statements): ExprStmtNode(pos, Switch, expr), statements(statements) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct GoStmtNode: StmtNode {
|
||||
@ -838,7 +821,7 @@ namespace JavaScript {
|
||||
|
||||
GoStmtNode(uint32 pos, Kind kind, const StringAtom *name): StmtNode(pos, kind), name(name) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct CatchClause: ParseNode {
|
||||
@ -859,7 +842,7 @@ namespace JavaScript {
|
||||
TryStmtNode(uint32 pos, StmtNode *stmt, CatchClause *catches, StmtNode *finally):
|
||||
StmtNode(pos, Try), stmt(stmt), catches(catches), finally(finally) {ASSERT(stmt);}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct PackageName: ArenaObject { // Either idList or str may be null, but not both
|
||||
@ -918,6 +901,8 @@ namespace JavaScript {
|
||||
|
||||
VariableStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, VariableBinding *bindings):
|
||||
AttributeStmtNode(pos, kind, attributes), bindings(bindings) {}
|
||||
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct FunctionStmtNode: AttributeStmtNode {
|
||||
@ -980,15 +965,16 @@ namespace JavaScript {
|
||||
bool lineBreakBefore(const Token &t) const {return lineBreaksSignificant && t.getLineBreak();}
|
||||
bool lineBreakBefore() {return lineBreaksSignificant && lexer.peek(true).getLineBreak();}
|
||||
|
||||
ExprNode *parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers);
|
||||
ExprNode *parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool &foundQualifiers);
|
||||
ExprNode *parseQualifiedIdentifier(const Token &t);
|
||||
ExprNode *parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers, bool preferRegExp);
|
||||
ExprNode *parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool &foundQualifiers, bool preferRegExp);
|
||||
ExprNode *parseQualifiedIdentifier(const Token &t, bool preferRegExp);
|
||||
PairListExprNode *parseArrayLiteral(const Token &initialToken);
|
||||
PairListExprNode *parseObjectLiteral(const Token &initialToken);
|
||||
ExprNode *parsePrimaryExpression();
|
||||
BinaryExprNode *parseMember(ExprNode *target, const Token &tOperator, ExprNode::Kind kind, ExprNode::Kind parenKind);
|
||||
InvokeExprNode *parseInvoke(ExprNode *target, uint32 pos, Token::Kind closingTokenKind, ExprNode::Kind invokeKind);
|
||||
ExprNode *parsePostfixExpression(bool newExpression = false);
|
||||
void ensurePostfix(const ExprNode *e);
|
||||
ExprNode *parseUnaryExpression();
|
||||
|
||||
enum Precedence {
|
||||
@ -1026,13 +1012,15 @@ namespace JavaScript {
|
||||
private:
|
||||
ExprNode *parseParenthesizedExpression();
|
||||
const StringAtom &parseTypedIdentifier(ExprNode *&type);
|
||||
VariableBinding *parseVariableBinding(bool noQualifiers, bool noIn);
|
||||
|
||||
enum SemicolonState {semiNone, semiNoninsertable, semiInsertable};
|
||||
enum AttributeStatement {asAny, asBlock, asConstVar};
|
||||
StmtNode *parseBlock(bool inSwitch, bool noOpenBrace, bool noCloseBrace);
|
||||
StmtNode *parseAttributeStatement(uint32 pos, IdentifierList *attributes, const Token &t, SemicolonState &semicolonState);
|
||||
StmtNode *parseAttributeStatement(uint32 pos, IdentifierList *attributes, const Token &t, bool noIn, SemicolonState &semicolonState);
|
||||
StmtNode *parseAttributesAndStatement(const Token *t, AttributeStatement as, SemicolonState &semicolonState);
|
||||
StmtNode *parseAnnotatedBlock();
|
||||
StmtNode *parseFor(uint32 pos, SemicolonState &semicolonState);
|
||||
StmtNode *parseTry(uint32 pos);
|
||||
public:
|
||||
StmtNode *parseStatement(bool topLevel, bool inSwitch, SemicolonState &semicolonState);
|
||||
|
||||
@ -619,13 +619,15 @@ const JS::Token &JS::Lexer::peek(bool preferRegExp)
|
||||
#ifdef DEBUG
|
||||
// Change the setting of preferRegExp for an already peeked token. The token must not be one
|
||||
// for which that setting mattered.
|
||||
//
|
||||
// THIS IS A DANGEROUS FUNCTION!
|
||||
// Use it only if you can be prove that the already peeked token does not start with a slash.
|
||||
void JS::Lexer::redesignate(bool preferRegExp)
|
||||
{
|
||||
ASSERT(nTokensFwd);
|
||||
if (savedPreferRegExp[nextToken - tokens] != preferRegExp) {
|
||||
ASSERT(!(nextToken->hasKind(Token::regExp) || nextToken->hasKind(Token::divide) || nextToken->hasKind(Token::divideEquals)));
|
||||
savedPreferRegExp[nextToken - tokens] = preferRegExp;
|
||||
}
|
||||
ASSERT(savedPreferRegExp[nextToken - tokens] != preferRegExp);
|
||||
ASSERT(!(nextToken->hasKind(Token::regExp) || nextToken->hasKind(Token::divide) || nextToken->hasKind(Token::divideEquals)));
|
||||
savedPreferRegExp[nextToken - tokens] = preferRegExp;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1185,6 +1187,37 @@ void JS::Lexer::lexToken(bool preferRegExp)
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// VariableBinding
|
||||
//
|
||||
|
||||
const int32 basicIndent = 4; // Size of one level of statement indentation
|
||||
const int32 caseIndent = basicIndent/2; // Indentation before a case or default statement
|
||||
const int32 varIndent = 2; // Indentation of var or const statement bindings
|
||||
const int32 subexpressionIndent = 4; // Size of one level of expression indentation
|
||||
|
||||
|
||||
// Print this onto f.
|
||||
void JS::VariableBinding::print(PrettyPrinter &f) const
|
||||
{
|
||||
PrettyPrinter::Block b(f);
|
||||
if (name)
|
||||
f << name;
|
||||
PrettyPrinter::Indent i(f, subexpressionIndent);
|
||||
if (type) {
|
||||
f.fillBreak(0);
|
||||
f << ": ";
|
||||
f << type;
|
||||
}
|
||||
if (initializer) {
|
||||
f.linearBreak(1);
|
||||
f << "= ";
|
||||
f << initializer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// ExprNode
|
||||
//
|
||||
@ -1380,7 +1413,7 @@ void JS::InvokeExprNode::print(PrettyPrinter &f) const
|
||||
if (hasKind(New))
|
||||
f << "new ";
|
||||
f << op;
|
||||
PrettyPrinter::Indent i(f, 4);
|
||||
PrettyPrinter::Indent i(f, subexpressionIndent);
|
||||
f.fillBreak(0);
|
||||
PairListExprNode::print(f);
|
||||
}
|
||||
@ -1448,18 +1481,15 @@ void JS::TernaryExprNode::print(PrettyPrinter &f) const
|
||||
//
|
||||
|
||||
|
||||
const int32 basicIndent = 4; // Size of one level of indentation
|
||||
const int32 caseIndent = basicIndent/2; // Indentation before a case or default statement
|
||||
|
||||
|
||||
// Print statements on separate lines onto f. Do not print a line break after the last statement.
|
||||
void JS::StmtNode::printStatements(PrettyPrinter &f, const StmtNode *statements)
|
||||
{
|
||||
if (statements) {
|
||||
PrettyPrinter::Block b(f);
|
||||
while (true) {
|
||||
statements->print(f);
|
||||
statements = statements->next;
|
||||
const StmtNode *next = statements->next;
|
||||
statements->print(f, !next);
|
||||
statements = next;
|
||||
if (!statements)
|
||||
break;
|
||||
f.requiredBreak();
|
||||
@ -1479,10 +1509,10 @@ void JS::StmtNode::printBlock(PrettyPrinter &f, const StmtNode *statements)
|
||||
if (statements->hasKind(Case)) {
|
||||
PrettyPrinter::Indent i(f, caseIndent - basicIndent);
|
||||
f.requiredBreak();
|
||||
statements->print(f);
|
||||
statements->print(f, false);
|
||||
} else {
|
||||
f.requiredBreak();
|
||||
statements->print(f);
|
||||
statements->print(f, !statements->next);
|
||||
}
|
||||
statements = statements->next;
|
||||
}
|
||||
@ -1494,6 +1524,14 @@ void JS::StmtNode::printBlock(PrettyPrinter &f, const StmtNode *statements)
|
||||
}
|
||||
|
||||
|
||||
// Print a closing statement semicolon onto f unless noSemi is true.
|
||||
void JS::StmtNode::printSemi(PrettyPrinter &f, bool noSemi)
|
||||
{
|
||||
if (!noSemi)
|
||||
f << ';';
|
||||
}
|
||||
|
||||
|
||||
// Print this as a substatement of a statement such as if or with.
|
||||
// If this statement is a block without attributes, begin it on the current line and
|
||||
// do not indent it -- the block itself will provide the indent. Otherwise, begin this
|
||||
@ -1502,18 +1540,19 @@ void JS::StmtNode::printBlock(PrettyPrinter &f, const StmtNode *statements)
|
||||
// of a do-while statement. If this statement is a block without attributes, print a
|
||||
// space and the continuation after the closing brace; otherwise print the continuation
|
||||
// on a new line.
|
||||
void JS::StmtNode::printSubstatement(PrettyPrinter &f, const char *continuation) const
|
||||
// If noSemi is true, do not print the semicolon unless it is required by the statement.
|
||||
void JS::StmtNode::printSubstatement(PrettyPrinter &f, bool noSemi, const char *continuation) const
|
||||
{
|
||||
if (hasKind(block) && !static_cast<const BlockStmtNode *>(this)->attributes) {
|
||||
f << ' ';
|
||||
f << this;
|
||||
this->print(f, noSemi);
|
||||
if (continuation)
|
||||
f << ' ' << continuation;
|
||||
} else {
|
||||
{
|
||||
PrettyPrinter::Block b(f, basicIndent);
|
||||
f.requiredBreak();
|
||||
f << this;
|
||||
this->print(f, noSemi);
|
||||
}
|
||||
if (continuation) {
|
||||
f.requiredBreak();
|
||||
@ -1525,12 +1564,14 @@ void JS::StmtNode::printSubstatement(PrettyPrinter &f, const char *continuation)
|
||||
|
||||
// Print this onto f. The caller must enclose this call within the scope
|
||||
// of at least one PrettyPrinter::Block.
|
||||
void JS::StmtNode::print(PrettyPrinter &f) const
|
||||
// If noSemi is true, do not print the semicolon unless it is required by the statement.
|
||||
void JS::StmtNode::print(PrettyPrinter &f, bool /*noSemi*/) const
|
||||
{
|
||||
ASSERT(hasKind(empty));
|
||||
f << ';';
|
||||
}
|
||||
|
||||
void JS::ExprStmtNode::print(PrettyPrinter &f) const
|
||||
void JS::ExprStmtNode::print(PrettyPrinter &f, bool noSemi) const
|
||||
{
|
||||
const ExprNode *e = expr;
|
||||
|
||||
@ -1558,7 +1599,7 @@ void JS::ExprStmtNode::print(PrettyPrinter &f) const
|
||||
showExpr:
|
||||
f << e;
|
||||
showSemicolon:
|
||||
StmtNode::print(f);
|
||||
printSemi(f, noSemi);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1566,27 +1607,21 @@ void JS::ExprStmtNode::print(PrettyPrinter &f) const
|
||||
}
|
||||
}
|
||||
|
||||
void JS::AttributeStmtNode::print(PrettyPrinter &f) const
|
||||
void JS::BlockStmtNode::print(PrettyPrinter &f, bool) const
|
||||
{
|
||||
for (const IdentifierList *a = attributes; a; a = a->next)
|
||||
f << a->name << ' ';
|
||||
}
|
||||
|
||||
void JS::BlockStmtNode::print(PrettyPrinter &f) const
|
||||
{
|
||||
AttributeStmtNode::print(f);
|
||||
printAttributes(f);
|
||||
printBlock(f, statements);
|
||||
}
|
||||
|
||||
void JS::LabelStmtNode::print(PrettyPrinter &f) const
|
||||
void JS::LabelStmtNode::print(PrettyPrinter &f, bool noSemi) const
|
||||
{
|
||||
PrettyPrinter::Block b(f, basicIndent);
|
||||
f << name << ':';
|
||||
f.linearBreak(1);
|
||||
f << stmt;
|
||||
stmt->print(f, noSemi);
|
||||
}
|
||||
|
||||
void JS::UnaryStmtNode::print(PrettyPrinter &f) const
|
||||
void JS::UnaryStmtNode::print(PrettyPrinter &f, bool noSemi) const
|
||||
{
|
||||
ASSERT(stmt);
|
||||
const char *kindName = 0;
|
||||
@ -1602,9 +1637,9 @@ void JS::UnaryStmtNode::print(PrettyPrinter &f) const
|
||||
|
||||
case DoWhile:
|
||||
f << "do";
|
||||
stmt->printSubstatement(f, "while (");
|
||||
stmt->printSubstatement(f, true, "while (");
|
||||
f << expr << ')';
|
||||
StmtNode::print(f);
|
||||
printSemi(f, noSemi);
|
||||
return;
|
||||
|
||||
case With:
|
||||
@ -1617,26 +1652,55 @@ void JS::UnaryStmtNode::print(PrettyPrinter &f) const
|
||||
|
||||
f << kindName << " (";
|
||||
f << expr << ')';
|
||||
stmt->printSubstatement(f);
|
||||
stmt->printSubstatement(f, noSemi);
|
||||
}
|
||||
|
||||
void JS::BinaryStmtNode::print(PrettyPrinter &f) const
|
||||
void JS::BinaryStmtNode::print(PrettyPrinter &f, bool noSemi) const
|
||||
{
|
||||
ASSERT(stmt && stmt2 && hasKind(IfElse));
|
||||
f << "if (";
|
||||
f << expr << ')';
|
||||
stmt->printSubstatement(f, "else");
|
||||
stmt2->printSubstatement(f);
|
||||
stmt->printSubstatement(f, true, "else");
|
||||
stmt2->printSubstatement(f, noSemi);
|
||||
}
|
||||
|
||||
void JS::SwitchStmtNode::print(PrettyPrinter &f) const
|
||||
void JS::ForStmtNode::print(PrettyPrinter &f, bool noSemi) const
|
||||
{
|
||||
ASSERT(stmt && (hasKind(For) || hasKind(ForIn)));
|
||||
f << "for (";
|
||||
{
|
||||
PrettyPrinter::Block b(f);
|
||||
if (initializer)
|
||||
initializer->print(f, true);
|
||||
if (hasKind(ForIn)) {
|
||||
f.fillBreak(1);
|
||||
f << "in";
|
||||
f.fillBreak(1);
|
||||
ASSERT(expr2 && !expr3);
|
||||
f << expr2;
|
||||
} else {
|
||||
f << ';';
|
||||
f.linearBreak(1);
|
||||
if (expr2)
|
||||
f << expr2;
|
||||
f << ';';
|
||||
f.linearBreak(1);
|
||||
if (expr3)
|
||||
f << expr3;
|
||||
}
|
||||
f << ')';
|
||||
}
|
||||
stmt->printSubstatement(f, noSemi);
|
||||
}
|
||||
|
||||
void JS::SwitchStmtNode::print(PrettyPrinter &f, bool) const
|
||||
{
|
||||
f << "switch (";
|
||||
f << expr << ") ";
|
||||
printBlock(f, statements);
|
||||
}
|
||||
|
||||
void JS::GoStmtNode::print(PrettyPrinter &f) const
|
||||
void JS::GoStmtNode::print(PrettyPrinter &f, bool noSemi) const
|
||||
{
|
||||
const char *kindName = 0;
|
||||
|
||||
@ -1656,15 +1720,15 @@ void JS::GoStmtNode::print(PrettyPrinter &f) const
|
||||
f << kindName;
|
||||
if (name)
|
||||
f << " " << *name;
|
||||
StmtNode::print(f);
|
||||
printSemi(f, noSemi);
|
||||
}
|
||||
|
||||
void JS::TryStmtNode::print(PrettyPrinter &f) const
|
||||
void JS::TryStmtNode::print(PrettyPrinter &f, bool noSemi) const
|
||||
{
|
||||
f << "try";
|
||||
const StmtNode *s = stmt;
|
||||
for (const CatchClause *c = catches; c; c = c->next) {
|
||||
s->printSubstatement(f, "catch (");
|
||||
s->printSubstatement(f, true, "catch (");
|
||||
PrettyPrinter::Block b(f);
|
||||
f << c->name;
|
||||
ExprNode *t = c->type;
|
||||
@ -1677,10 +1741,39 @@ void JS::TryStmtNode::print(PrettyPrinter &f) const
|
||||
s = c->stmt;
|
||||
}
|
||||
if (finally) {
|
||||
s->printSubstatement(f, "finally");
|
||||
s->printSubstatement(f, true, "finally");
|
||||
s = finally;
|
||||
}
|
||||
s->printSubstatement(f);
|
||||
s->printSubstatement(f, noSemi);
|
||||
}
|
||||
|
||||
void JS::VariableStmtNode::print(PrettyPrinter &f, bool noSemi) const
|
||||
{
|
||||
printAttributes(f);
|
||||
ASSERT(hasKind(Const) || hasKind(Var));
|
||||
f << (hasKind(Const) ? "const" : "var");
|
||||
{
|
||||
PrettyPrinter::Block b(f, basicIndent);
|
||||
const VariableBinding *binding = bindings;
|
||||
if (binding)
|
||||
while (true) {
|
||||
f.linearBreak(1);
|
||||
binding->print(f);
|
||||
binding = binding->next;
|
||||
if (!binding)
|
||||
break;
|
||||
f << ',';
|
||||
}
|
||||
}
|
||||
printSemi(f, noSemi);
|
||||
}
|
||||
|
||||
|
||||
// Print the attributes on a single line separated with and followed by a space.
|
||||
void JS::AttributeStmtNode::printAttributes(PrettyPrinter &f) const
|
||||
{
|
||||
for (const IdentifierList *a = attributes; a; a = a->next)
|
||||
f << a->name << ' ';
|
||||
}
|
||||
|
||||
|
||||
@ -1747,10 +1840,10 @@ inline JS::String &JS::Parser::copyTokenChars(const Token &t)
|
||||
// If it is followed by one or more ::'s followed by identifiers, construct the appropriate
|
||||
// qualify parse node and return it and set foundQualifiers to true. If no ::
|
||||
// is found, return e and set foundQualifiers to false.
|
||||
// After parseIdentifierQualifiers finishes, the next token might have been peeked with preferRegExp set to false.
|
||||
JS::ExprNode *JS::Parser::parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers)
|
||||
// After parseIdentifierQualifiers finishes, the next token might have been peeked with the given preferRegExp setting.
|
||||
JS::ExprNode *JS::Parser::parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers, bool preferRegExp)
|
||||
{
|
||||
const Token *tDoubleColon = lexer.eat(false, Token::doubleColon);
|
||||
const Token *tDoubleColon = lexer.eat(preferRegExp, Token::doubleColon);
|
||||
if (!tDoubleColon) {
|
||||
foundQualifiers = false;
|
||||
return e;
|
||||
@ -1758,7 +1851,7 @@ JS::ExprNode *JS::Parser::parseIdentifierQualifiers(ExprNode *e, bool &foundQual
|
||||
|
||||
foundQualifiers = true;
|
||||
checkStackSize();
|
||||
return new(arena) BinaryExprNode(tDoubleColon->getPos(), ExprNode::qualify, e, parseQualifiedIdentifier(lexer.get(true)));
|
||||
return new(arena) BinaryExprNode(tDoubleColon->getPos(), ExprNode::qualify, e, parseQualifiedIdentifier(lexer.get(true), preferRegExp));
|
||||
}
|
||||
|
||||
|
||||
@ -1767,36 +1860,36 @@ JS::ExprNode *JS::Parser::parseIdentifierQualifiers(ExprNode *e, bool &foundQual
|
||||
// qualify parse node and return it and set foundQualifiers to true. If no ::
|
||||
// is found, return the ParenthesizedExpression and set foundQualifiers to false.
|
||||
// After parseParenthesesAndIdentifierQualifiers finishes, the next token might have been peeked with
|
||||
// preferRegExp set to false.
|
||||
JS::ExprNode *JS::Parser::parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool &foundQualifiers)
|
||||
// the given preferRegExp setting.
|
||||
JS::ExprNode *JS::Parser::parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool &foundQualifiers, bool preferRegExp)
|
||||
{
|
||||
uint32 pos = tParen.getPos();
|
||||
ExprNode *e = new(arena) UnaryExprNode(pos, ExprNode::parentheses, parseExpression(false));
|
||||
require(false, Token::closeParenthesis);
|
||||
return parseIdentifierQualifiers(e, foundQualifiers);
|
||||
return parseIdentifierQualifiers(e, foundQualifiers, preferRegExp);
|
||||
}
|
||||
|
||||
|
||||
// Parse and return a qualifiedIdentifier. The first token has already been parsed and is in t.
|
||||
// If the second token was peeked, it should be have been done with preferRegExp set to false.
|
||||
// After parseQualifiedIdentifier finishes, the next token might have been peeked with preferRegExp set to false.
|
||||
JS::ExprNode *JS::Parser::parseQualifiedIdentifier(const Token &t)
|
||||
// If the second token was peeked, it should be have been done with the given preferRegExp setting.
|
||||
// After parseQualifiedIdentifier finishes, the next token might have been peeked with the given preferRegExp setting.
|
||||
JS::ExprNode *JS::Parser::parseQualifiedIdentifier(const Token &t, bool preferRegExp)
|
||||
{
|
||||
bool foundQualifiers;
|
||||
ExprNode *e;
|
||||
|
||||
if (t.hasIdentifierKind())
|
||||
return parseIdentifierQualifiers(new(arena) IdentifierExprNode(t), foundQualifiers);
|
||||
return parseIdentifierQualifiers(new(arena) IdentifierExprNode(t), foundQualifiers, preferRegExp);
|
||||
if (t.hasKind(Token::openParenthesis)) {
|
||||
e = parseParenthesesAndIdentifierQualifiers(t, foundQualifiers);
|
||||
e = parseParenthesesAndIdentifierQualifiers(t, foundQualifiers, preferRegExp);
|
||||
goto checkQualifiers;
|
||||
}
|
||||
if (t.hasKind(Token::Super)) {
|
||||
e = parseIdentifierQualifiers(new(arena) ExprNode(t.getPos(), ExprNode::Super), foundQualifiers);
|
||||
e = parseIdentifierQualifiers(new(arena) ExprNode(t.getPos(), ExprNode::Super), foundQualifiers, preferRegExp);
|
||||
goto checkQualifiers;
|
||||
}
|
||||
if (t.hasKind(Token::Public) || t.hasKind(Token::Package) || t.hasKind(Token::Private)) {
|
||||
e = parseIdentifierQualifiers(new(arena) IdentifierExprNode(t), foundQualifiers);
|
||||
e = parseIdentifierQualifiers(new(arena) IdentifierExprNode(t), foundQualifiers, preferRegExp);
|
||||
checkQualifiers:
|
||||
if (!foundQualifiers)
|
||||
syntaxError("'::' expected", 0);
|
||||
@ -1817,7 +1910,7 @@ JS::PairListExprNode *JS::Parser::parseArrayLiteral(const Token &initialToken)
|
||||
ExprNode *element = 0;
|
||||
const Token &t = lexer.peek(true);
|
||||
if (t.hasKind(Token::comma) || t.hasKind(Token::closeBracket))
|
||||
lexer.redesignate(false);
|
||||
lexer.redesignate(false); // Safe: neither ',' nor '}' starts with a slash.
|
||||
else
|
||||
element = parseAssignmentExpression(false);
|
||||
elements += new(arena) ExprPairList(0, element);
|
||||
@ -1844,7 +1937,7 @@ JS::PairListExprNode *JS::Parser::parseObjectLiteral(const Token &initialToken)
|
||||
ExprNode *field;
|
||||
if (t.hasIdentifierKind() || t.hasKind(Token::openParenthesis) || t.hasKind(Token::Super) ||
|
||||
t.hasKind(Token::Public) || t.hasKind(Token::Package) || t.hasKind(Token::Private))
|
||||
field = parseQualifiedIdentifier(t);
|
||||
field = parseQualifiedIdentifier(t, false);
|
||||
else if (t.hasKind(Token::string))
|
||||
field = new(arena) StringExprNode(t.getPos(), ExprNode::string, copyTokenChars(t));
|
||||
else if (t.hasKind(Token::number))
|
||||
@ -1929,13 +2022,13 @@ JS::ExprNode *JS::Parser::parsePrimaryExpression()
|
||||
case Token::Private:
|
||||
case CASE_TOKEN_NONRESERVED:
|
||||
makeQualifiedIdentifierNode:
|
||||
e = parseQualifiedIdentifier(t);
|
||||
e = parseQualifiedIdentifier(t, false);
|
||||
break;
|
||||
|
||||
case Token::openParenthesis:
|
||||
{
|
||||
bool foundQualifiers;
|
||||
e = parseParenthesesAndIdentifierQualifiers(t, foundQualifiers);
|
||||
e = parseParenthesesAndIdentifierQualifiers(t, foundQualifiers, false);
|
||||
if (!foundQualifiers) {
|
||||
const Token &tUnit = lexer.peek(false);
|
||||
if (!lineBreakBefore(tUnit) && tUnit.hasKind(Token::string)) {
|
||||
@ -1979,11 +2072,11 @@ JS::BinaryExprNode *JS::Parser::parseMember(ExprNode *target, const Token &tOper
|
||||
const Token &t2 = lexer.get(true);
|
||||
if (t2.hasKind(Token::openParenthesis)) {
|
||||
bool foundQualifiers;
|
||||
member = parseParenthesesAndIdentifierQualifiers(t2, foundQualifiers);
|
||||
member = parseParenthesesAndIdentifierQualifiers(t2, foundQualifiers, false);
|
||||
if (!foundQualifiers)
|
||||
kind = parenKind;
|
||||
} else
|
||||
member = parseQualifiedIdentifier(t2);
|
||||
member = parseQualifiedIdentifier(t2, false);
|
||||
return new(arena) BinaryExprNode(pos, kind, target, member);
|
||||
}
|
||||
|
||||
@ -2085,6 +2178,15 @@ JS::ExprNode *JS::Parser::parsePostfixExpression(bool newExpression)
|
||||
}
|
||||
|
||||
|
||||
// Ensure that e is a postfix expression. If not, throw a syntax error on the current token.
|
||||
void JS::Parser::ensurePostfix(const ExprNode *e)
|
||||
{
|
||||
ASSERT(e);
|
||||
if (!e->isPostfix())
|
||||
syntaxError("Only a postfix expression can be used as the result of an assignment; enclose this expression in parentheses", 0);
|
||||
}
|
||||
|
||||
|
||||
// Parse and return a UnaryExpression.
|
||||
// If the first token was peeked, it should be have been done with preferRegExp set to true.
|
||||
// After parseUnaryExpression finishes, the next token might have been peeked with preferRegExp set to false.
|
||||
@ -2288,7 +2390,6 @@ struct JS::Parser::StackedSubexpression {
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Parse and return an Expression. If noIn is false, allow the in operator. If noAssignment is
|
||||
// false, allow the = and op= operators. If noComma is false, allow the comma operator.
|
||||
// If the first token was peeked, it should be have been done with preferRegExp set to true.
|
||||
@ -2317,11 +2418,9 @@ JS::ExprNode *JS::Parser::parseExpression(bool noIn, bool noAssignment, bool noC
|
||||
precedence = pExpression;
|
||||
}
|
||||
|
||||
if (precedence == pPostfix) {
|
||||
// Ensure that the target of an assignment is a postfix subexpression.
|
||||
if (ExprNode::isUnaryKind(e->getKind()))
|
||||
syntaxError("Cannot assign to the result of this unary expression", 0);
|
||||
} else
|
||||
if (precedence == pPostfix)
|
||||
ensurePostfix(e); // Ensure that the target of an assignment is a postfix subexpression.
|
||||
else
|
||||
// Reduce already stacked operators with precedenceLeft or higher precedence
|
||||
while (subexpressionStack.back().precedence >= precedence) {
|
||||
StackedSubexpression &s = subexpressionStack.pop_back();
|
||||
@ -2380,11 +2479,50 @@ const JS::StringAtom &JS::Parser::parseTypedIdentifier(ExprNode *&type)
|
||||
|
||||
type = 0;
|
||||
if (lexer.eat(false, Token::colon))
|
||||
type = parseAssignmentExpression(false);
|
||||
type = parseNonAssignmentExpression(false);
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
// Parse and return a VariableBinding.
|
||||
// If noQualifiers is false, allow a QualifiedIdentifier as the variable name; otherwise, restrict the
|
||||
// variable name to be a simple Identifier.
|
||||
// If noIn is false, allow the in operator.
|
||||
//
|
||||
// If the first token was peeked, it should be have been done with preferRegExp set to true.
|
||||
// After parseVariableBinding finishes, the next token might have been peeked with preferRegExp set to true.
|
||||
JS::VariableBinding *JS::Parser::parseVariableBinding(bool noQualifiers, bool noIn)
|
||||
{
|
||||
const Token &t = lexer.get(true);
|
||||
uint32 pos = t.getPos();
|
||||
|
||||
ExprNode *name;
|
||||
if (noQualifiers) {
|
||||
if (!t.hasIdentifierKind())
|
||||
syntaxError("Identifier expected");
|
||||
name = new(arena) IdentifierExprNode(t);
|
||||
} else
|
||||
name = parseQualifiedIdentifier(t, true);
|
||||
|
||||
ExprNode *type = 0;
|
||||
if (lexer.eat(true, Token::colon)) {
|
||||
type = parseNonAssignmentExpression(noIn);
|
||||
if (lexer.peek(false).hasKind(Token::divideEquals))
|
||||
syntaxError("'/=' not allowed here", 0);
|
||||
lexer.redesignate(true); // Safe: a '/' would have been interpreted as an operator, so it can't be the next token;
|
||||
// a '/=' was outlawed by the check above.
|
||||
}
|
||||
|
||||
ExprNode *initializer = 0;
|
||||
if (lexer.eat(true, Token::assignment)) {
|
||||
initializer = parseAssignmentExpression(noIn);
|
||||
lexer.redesignate(true); // Safe: a '/' or a '/=' would have been interpreted as an operator, so it can't be the next token.
|
||||
}
|
||||
|
||||
return new(arena) VariableBinding(pos, name, type, initializer);
|
||||
}
|
||||
|
||||
|
||||
// Parse a list of statements ending with a '}'. Return these statements as a linked list
|
||||
// threaded through the StmtNodes' next fields. If noOpenBrace is true, the opening '{' has already been read.
|
||||
// If noCloseBrace is true, an end-of-input terminates the block; the end-of-input token is not read.
|
||||
@ -2423,6 +2561,7 @@ JS::StmtNode *JS::Parser::parseBlock(bool inSwitch, bool noOpenBrace, bool noClo
|
||||
|
||||
|
||||
// Parse and return a statement that takes zero or more initial attributes, which have already been parsed.
|
||||
// If noIn is false, allow the in operator.
|
||||
//
|
||||
// If the statement ends with an optional semicolon, that semicolon is not parsed.
|
||||
// Instead, parseAttributeStatement returns in semicolonState one of three values:
|
||||
@ -2432,18 +2571,35 @@ JS::StmtNode *JS::Parser::parseBlock(bool inSwitch, bool noOpenBrace, bool noClo
|
||||
//
|
||||
// pos is the position of the beginning of the statement (its first attribute if it has attributes).
|
||||
// The first token of the statement has already been read and is provided in t.
|
||||
// If the second token was peeked, it should be have been done with preferRegExp set to false.
|
||||
// After parseAttributeStatement finishes, the next token might have been peeked with preferRegExp set to true.
|
||||
JS::StmtNode *JS::Parser::parseAttributeStatement(uint32 pos, IdentifierList *attributes, const Token &t, SemicolonState &semicolonState)
|
||||
JS::StmtNode *JS::Parser::parseAttributeStatement(uint32 pos, IdentifierList *attributes, const Token &t,
|
||||
bool noIn, SemicolonState &semicolonState)
|
||||
{
|
||||
StmtNode *s;
|
||||
semicolonState = semiNone;
|
||||
StmtNode::Kind sKind;
|
||||
|
||||
switch (t.getKind()) {
|
||||
case Token::openBrace:
|
||||
s = new(arena) BlockStmtNode(pos, StmtNode::block, attributes, parseBlock(false, true, false));
|
||||
break;
|
||||
|
||||
case Token::Const:
|
||||
sKind = StmtNode::Const;
|
||||
goto constOrVar;
|
||||
case Token::Var:
|
||||
sKind = StmtNode::Var;
|
||||
constOrVar:
|
||||
{
|
||||
NodeQueue<VariableBinding> bindings;
|
||||
|
||||
do bindings += parseVariableBinding(false, noIn);
|
||||
while (lexer.eat(true, Token::comma));
|
||||
s = new(arena) VariableStmtNode(pos, sKind, attributes, bindings.first);
|
||||
semicolonState = semiInsertable;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
syntaxError("Bad declaration");
|
||||
s = 0;
|
||||
@ -2458,10 +2614,11 @@ JS::StmtNode *JS::Parser::parseAttributeStatement(uint32 pos, IdentifierList *at
|
||||
// as restricts the kinds of statements that are allowed after the attributes:
|
||||
// asAny Any statements that takes attributes can follow
|
||||
// asBlock Only a block can follow
|
||||
// asConstVar Only a const or var declaration can follow
|
||||
// asConstVar Only a const or var declaration can follow, and the 'in' operator is not allowed at its top level
|
||||
//
|
||||
// The first token of the statement has already been read and is provided in t.
|
||||
// If the second token was peeked, it should be have been done with preferRegExp set to false.
|
||||
// If the second token was peeked, it should be have been done with preferRegExp set to false;
|
||||
// the second token should have been peeked only if t is an attribute.
|
||||
// After parseAttributesAndStatement finishes, the next token might have been peeked with
|
||||
// preferRegExp set to true.
|
||||
JS::StmtNode *JS::Parser::parseAttributesAndStatement(const Token *t, AttributeStatement as, SemicolonState &semicolonState)
|
||||
@ -2489,7 +2646,7 @@ JS::StmtNode *JS::Parser::parseAttributesAndStatement(const Token *t, AttributeS
|
||||
syntaxError("const or var expected");
|
||||
break;
|
||||
}
|
||||
return parseAttributeStatement(pos, attributes.first, *t, semicolonState);
|
||||
return parseAttributeStatement(pos, attributes.first, *t, as == asConstVar, semicolonState);
|
||||
}
|
||||
|
||||
|
||||
@ -2506,6 +2663,83 @@ JS::StmtNode *JS::Parser::parseAnnotatedBlock()
|
||||
}
|
||||
|
||||
|
||||
// Parse and return a ForStatement. The 'for' token has already been read; its position is pos.
|
||||
// If the statement ends with an optional semicolon, that semicolon is not parsed.
|
||||
// Instead, parseFor returns a semicolonState with the same meaning as that in parseStatement.
|
||||
//
|
||||
// After parseFor finishes, the next token might have been peeked with preferRegExp set to true.
|
||||
JS::StmtNode *JS::Parser::parseFor(uint32 pos, SemicolonState &semicolonState)
|
||||
{
|
||||
require(true, Token::openParenthesis);
|
||||
const Token &t = lexer.get(true);
|
||||
uint32 tPos = t.getPos();
|
||||
const Token *t2;
|
||||
StmtNode *initializer = 0;
|
||||
ExprNode *expr1 = 0;
|
||||
ExprNode *expr2 = 0;
|
||||
ExprNode *expr3 = 0;
|
||||
StmtNode::Kind sKind = StmtNode::For;
|
||||
|
||||
switch (t.getKind()) {
|
||||
case Token::semicolon:
|
||||
goto threeExpr;
|
||||
|
||||
case Token::Const:
|
||||
case Token::Var:
|
||||
case Token::Final:
|
||||
case Token::Static:
|
||||
case Token::Volatile:
|
||||
makeAttribute:
|
||||
initializer = parseAttributesAndStatement(&t, asConstVar, semicolonState);
|
||||
break;
|
||||
|
||||
case CASE_TOKEN_ATTRIBUTE_IDENTIFIER:
|
||||
case Token::Public:
|
||||
case Token::Package:
|
||||
case Token::Private:
|
||||
t2 = &lexer.peek(false);
|
||||
if (!lineBreakBefore(*t2) && t2->getFlag(Token::canFollowAttribute))
|
||||
goto makeAttribute;
|
||||
default:
|
||||
lexer.unget();
|
||||
expr1 = parseExpression(true);
|
||||
initializer = new(arena) ExprStmtNode(tPos, StmtNode::expression, expr1);
|
||||
lexer.redesignate(true); // Safe: a '/' or a '/=' would have been interpreted as an operator, so it can't be the next token.
|
||||
break;
|
||||
}
|
||||
|
||||
if (lexer.eat(true, Token::semicolon))
|
||||
threeExpr: {
|
||||
if (!lexer.eat(true, Token::semicolon)) {
|
||||
expr2 = parseExpression(false);
|
||||
require(false, Token::semicolon);
|
||||
}
|
||||
if (lexer.peek(true).hasKind(Token::closeParenthesis))
|
||||
lexer.redesignate(false); // Safe: the token is ')'.
|
||||
else
|
||||
expr3 = parseExpression(false);
|
||||
}
|
||||
else if (lexer.eat(true, Token::In)) {
|
||||
sKind = StmtNode::ForIn;
|
||||
if (expr1) {
|
||||
ASSERT(initializer->hasKind(StmtNode::expression));
|
||||
ensurePostfix(expr1);
|
||||
} else {
|
||||
ASSERT(initializer->hasKind(StmtNode::Const) || initializer->hasKind(StmtNode::Var));
|
||||
const VariableBinding *bindings = static_cast<VariableStmtNode *>(initializer)->bindings;
|
||||
if (!bindings || bindings->next)
|
||||
syntaxError("Only one variable binding can be used in a for-in statement", 0);
|
||||
}
|
||||
expr2 = parseExpression(false);
|
||||
}
|
||||
else
|
||||
syntaxError("';' or 'in' expected", 0);
|
||||
|
||||
require(false, Token::closeParenthesis);
|
||||
return new(arena) ForStmtNode(pos, sKind, initializer, expr2, expr3, parseStatement(false, false, semicolonState));
|
||||
}
|
||||
|
||||
|
||||
// Parse and return a TryStatement. The 'try' token has already been read; its position is pos.
|
||||
// After parseTry finishes, the next token might have been peeked with preferRegExp set to true.
|
||||
JS::StmtNode *JS::Parser::parseTry(uint32 pos)
|
||||
@ -2562,7 +2796,7 @@ JS::StmtNode *JS::Parser::parseStatement(bool topLevel, bool inSwitch, Semicolon
|
||||
case Token::openBrace:
|
||||
case Token::Const:
|
||||
case Token::Var:
|
||||
s = parseAttributeStatement(pos, 0, t, semicolonState);
|
||||
s = parseAttributeStatement(pos, 0, t, false, semicolonState);
|
||||
break;
|
||||
|
||||
case Token::If:
|
||||
@ -2621,6 +2855,10 @@ JS::StmtNode *JS::Parser::parseStatement(bool topLevel, bool inSwitch, Semicolon
|
||||
s = new(arena) UnaryStmtNode(pos, sKind, e, s);
|
||||
break;
|
||||
|
||||
case Token::For:
|
||||
s = parseFor(pos, semicolonState);
|
||||
break;
|
||||
|
||||
case Token::Continue:
|
||||
sKind = StmtNode::Continue;
|
||||
goto makeGo;
|
||||
@ -2657,7 +2895,6 @@ JS::StmtNode *JS::Parser::parseStatement(bool topLevel, bool inSwitch, Semicolon
|
||||
break;
|
||||
|
||||
case Token::Final:
|
||||
case Token::Private:
|
||||
case Token::Static:
|
||||
case Token::Volatile:
|
||||
makeAttribute:
|
||||
@ -2665,6 +2902,8 @@ JS::StmtNode *JS::Parser::parseStatement(bool topLevel, bool inSwitch, Semicolon
|
||||
break;
|
||||
|
||||
case Token::Public:
|
||||
case Token::Package:
|
||||
case Token::Private:
|
||||
t2 = &lexer.peek(false);
|
||||
goto makeExpressionOrAttribute;
|
||||
|
||||
@ -2684,7 +2923,7 @@ JS::StmtNode *JS::Parser::parseStatement(bool topLevel, bool inSwitch, Semicolon
|
||||
sKind = StmtNode::expression;
|
||||
makeExpressionNode:
|
||||
e = parseExpression(false);
|
||||
lexer.redesignate(true);
|
||||
lexer.redesignate(true); // Safe: a '/' or a '/=' would have been interpreted as an operator, so it can't be the next token.
|
||||
makeExprStmtNode:
|
||||
s = new(arena) ExprStmtNode(pos, sKind, e);
|
||||
insertableSemicolon:
|
||||
|
||||
@ -348,7 +348,7 @@ namespace JavaScript {
|
||||
};
|
||||
|
||||
#ifndef DEBUG
|
||||
inline void Lexer::redesignate(bool) {}
|
||||
inline void Lexer::redesignate(bool) {} // See description for the DEBUG version inside parser.cpp
|
||||
#endif
|
||||
|
||||
// Return the position of the first character of the next token, which must have been peeked.
|
||||
@ -433,7 +433,10 @@ namespace JavaScript {
|
||||
ExprNode *type; // Type expression or nil if not provided
|
||||
ExprNode *initializer; // Initial value expression or nil if not provided
|
||||
|
||||
VariableBinding(uint32 pos): ParseNode(pos), next(0), name(0), type(0), initializer(0) {}
|
||||
VariableBinding(uint32 pos, ExprNode *name, ExprNode *type, ExprNode *initializer):
|
||||
ParseNode(pos), next(0), name(name), type(type), initializer(initializer) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
};
|
||||
|
||||
struct FunctionDefinition: FunctionName {
|
||||
@ -448,7 +451,7 @@ namespace JavaScript {
|
||||
struct ExprNode: ParseNode {
|
||||
enum Kind { // Actual class Operands // Keep synchronized with kindNames
|
||||
none,
|
||||
identifier, // IdentifierExprNode <name>
|
||||
identifier, // IdentifierExprNode <name> // Begin of isPostfix()
|
||||
number, // NumberExprNode <value>
|
||||
string, // StringExprNode <str>
|
||||
regExp, // RegExpExprNode /<re>/<flags>
|
||||
@ -474,8 +477,9 @@ namespace JavaScript {
|
||||
dot, // BinaryExprNode <op1> . <op2> // <op2> must be identifier or qualify
|
||||
dotParen, // BinaryExprNode <op1> .( <op2> )
|
||||
at, // BinaryExprNode <op1> @ <op2> or <op1> @( <op2> )
|
||||
// End of isPostfix()
|
||||
|
||||
Delete, // UnaryExprNode delete <op> // Begin of isUnaryKind()
|
||||
Delete, // UnaryExprNode delete <op>
|
||||
Typeof, // UnaryExprNode typeof <op>
|
||||
Eval, // UnaryExprNode eval <op>
|
||||
preIncrement, // UnaryExprNode ++ <op>
|
||||
@ -485,7 +489,7 @@ namespace JavaScript {
|
||||
plus, // UnaryExprNode + <op>
|
||||
minus, // UnaryExprNode - <op>
|
||||
complement, // UnaryExprNode ~ <op>
|
||||
logicalNot, // UnaryExprNode ! <op> // End of isUnaryKind()
|
||||
logicalNot, // UnaryExprNode ! <op>
|
||||
|
||||
add, // BinaryExprNode <op1> + <op2>
|
||||
subtract, // BinaryExprNode <op1> - <op2>
|
||||
@ -547,8 +551,8 @@ namespace JavaScript {
|
||||
|
||||
static bool isFieldKind(Kind kind) {return kind == identifier || kind == number || kind == string || kind == qualify;}
|
||||
static bool isAssigningKind(Kind kind) {return kind >= assignment && kind <= logicalOrEquals;}
|
||||
static bool isUnaryKind(Kind kind) {return kind >= Delete && kind <= logicalNot;}
|
||||
static const char *kindName(Kind kind) {ASSERT(uint(kind) < kindsEnd); return kindNames[kind];}
|
||||
bool isPostfix() const {return kind >= identifier && kind <= at;}
|
||||
|
||||
virtual void print(PrettyPrinter &f) const;
|
||||
};
|
||||
@ -689,9 +693,7 @@ namespace JavaScript {
|
||||
DoWhile, // UnaryStmtNode do <stmt> while ( <expr> )
|
||||
With, // UnaryStmtNode with ( <expr> ) <stmt>
|
||||
For, // ForStmtNode for ( <initializer> ; <expr2> ; <expr3> ) <stmt>
|
||||
ForExprIn, // ForExprInStmtNode for ( <varExpr> in <container> ) <stmt>
|
||||
ForConstIn, // ForVarInStmtNode for ( const <binding> in <container> ) <stmt>
|
||||
ForVarIn, // ForVarInStmtNode for ( var <binding> in <container> ) <stmt>
|
||||
ForIn, // ForStmtNode for ( <initializer> in <expr2> ) <stmt>
|
||||
Case, // ExprStmtNode case <expr> : or default : // Only occurs directly inside a Switch
|
||||
Break, // GoStmtNode break ; or break <name> ;
|
||||
Continue, // GoStmtNode continue ; or continue <name> ;
|
||||
@ -723,22 +725,20 @@ namespace JavaScript {
|
||||
Kind getKind() const {return kind;}
|
||||
bool hasKind(Kind k) const {return kind == k;}
|
||||
|
||||
virtual void print(PrettyPrinter &f) const;
|
||||
void printSubstatement(PrettyPrinter &f, const char *continuation = 0) const;
|
||||
static void printStatements(PrettyPrinter &f, const StmtNode *statements);
|
||||
static void printBlock(PrettyPrinter &f, const StmtNode *statements);
|
||||
static void printSemi(PrettyPrinter &f, bool noSemi);
|
||||
void printSubstatement(PrettyPrinter &f, bool noSemi, const char *continuation = 0) const;
|
||||
virtual void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
// Print s onto f.
|
||||
inline PrettyPrinter &operator<<(PrettyPrinter &f, const StmtNode *s) {ASSERT(s); s->print(f); return f;}
|
||||
|
||||
|
||||
struct ExprStmtNode: StmtNode {
|
||||
ExprNode *expr; // The expression statement's expression. May be nil for default: or return-with-no-expression statements.
|
||||
|
||||
ExprStmtNode(uint32 pos, Kind kind, ExprNode *expr): StmtNode(pos, kind), expr(expr) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct IdentifierList: ArenaObject {
|
||||
@ -753,7 +753,7 @@ namespace JavaScript {
|
||||
|
||||
AttributeStmtNode(uint32 pos, Kind kind, IdentifierList *attributes): StmtNode(pos, kind), attributes(attributes) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void printAttributes(PrettyPrinter &f) const;
|
||||
};
|
||||
|
||||
struct BlockStmtNode: AttributeStmtNode {
|
||||
@ -762,7 +762,7 @@ namespace JavaScript {
|
||||
BlockStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, StmtNode *statements):
|
||||
AttributeStmtNode(pos, kind, attributes), statements(statements) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct LabelStmtNode: StmtNode {
|
||||
@ -772,7 +772,7 @@ namespace JavaScript {
|
||||
LabelStmtNode(uint32 pos, const StringAtom &name, StmtNode *stmt):
|
||||
StmtNode(pos, label), name(name), stmt(stmt) {ASSERT(stmt);}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct UnaryStmtNode: ExprStmtNode {
|
||||
@ -781,7 +781,7 @@ namespace JavaScript {
|
||||
UnaryStmtNode(uint32 pos, Kind kind, ExprNode *expr, StmtNode *stmt):
|
||||
ExprStmtNode(pos, kind, expr), stmt(stmt) {ASSERT(stmt);}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct BinaryStmtNode: UnaryStmtNode {
|
||||
@ -790,39 +790,22 @@ namespace JavaScript {
|
||||
BinaryStmtNode(uint32 pos, Kind kind, ExprNode *expr, StmtNode *stmt1, StmtNode *stmt2):
|
||||
UnaryStmtNode(pos, kind, expr, stmt1), stmt2(stmt2) {ASSERT(stmt2);}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct ForStmtNode: StmtNode {
|
||||
StmtNode *initializer; // First item in parentheses; either nil (if not provided), an expression, or a Var, or a Const.
|
||||
ExprNode *expr2; // Second item in parentheses; nil if not provided
|
||||
ExprNode *expr3; // Third item in parentheses; nil if not provided
|
||||
StmtNode *initializer; // For: First item in parentheses; either nil (if not provided), an expression, or a Var, or a Const.
|
||||
// ForIn: Expression or declaration before 'in'; either an expression, or a Var or a Const with exactly one binding.
|
||||
ExprNode *expr2; // For: Second item in parentheses; nil if not provided
|
||||
// ForIn: Subexpression after 'in'; non-nil only
|
||||
ExprNode *expr3; // For: Third item in parentheses; nil if not provided
|
||||
// ForIn: nil
|
||||
StmtNode *stmt; // Substatement; non-nil only
|
||||
|
||||
ForStmtNode(uint32 pos, Kind kind, StmtNode *stmt):
|
||||
StmtNode(pos, kind), stmt(stmt) {ASSERT(stmt);}
|
||||
};
|
||||
|
||||
struct ForInStmtNode: StmtNode {
|
||||
ExprNode *container; // Subexpression after 'in'; non-nil only
|
||||
StmtNode *stmt; // Substatement; non-nil only
|
||||
ForStmtNode(uint32 pos, Kind kind, StmtNode *initializer, ExprNode *expr2, ExprNode *expr3, StmtNode *stmt):
|
||||
StmtNode(pos, kind), initializer(initializer), expr2(expr2), expr3(expr3), stmt(stmt) {ASSERT(stmt);}
|
||||
|
||||
ForInStmtNode(uint32 pos, Kind kind, ExprNode *container, StmtNode *stmt):
|
||||
StmtNode(pos, kind), container(container), stmt(stmt) {ASSERT(container && stmt);}
|
||||
};
|
||||
|
||||
struct ForExprInStmtNode: ForInStmtNode {
|
||||
ExprNode *varExpr; // Subexpression before 'in'; non-nil only
|
||||
|
||||
ForExprInStmtNode(uint32 pos, Kind kind, ExprNode *container, StmtNode *stmt, ExprNode *varExpr):
|
||||
ForInStmtNode(pos, kind, container, stmt), varExpr(varExpr) {ASSERT(varExpr);}
|
||||
};
|
||||
|
||||
struct ForVarInStmtNode: ForInStmtNode {
|
||||
VariableBinding *binding; // Var or const binding before 'in'; non-nil only
|
||||
|
||||
ForVarInStmtNode(uint32 pos, Kind kind, ExprNode *container, StmtNode *stmt, VariableBinding *binding):
|
||||
ForInStmtNode(pos, kind, container, stmt), binding(binding) {ASSERT(binding);}
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct SwitchStmtNode: ExprStmtNode {
|
||||
@ -830,7 +813,7 @@ namespace JavaScript {
|
||||
|
||||
SwitchStmtNode(uint32 pos, ExprNode *expr, StmtNode *statements): ExprStmtNode(pos, Switch, expr), statements(statements) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct GoStmtNode: StmtNode {
|
||||
@ -838,7 +821,7 @@ namespace JavaScript {
|
||||
|
||||
GoStmtNode(uint32 pos, Kind kind, const StringAtom *name): StmtNode(pos, kind), name(name) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct CatchClause: ParseNode {
|
||||
@ -859,7 +842,7 @@ namespace JavaScript {
|
||||
TryStmtNode(uint32 pos, StmtNode *stmt, CatchClause *catches, StmtNode *finally):
|
||||
StmtNode(pos, Try), stmt(stmt), catches(catches), finally(finally) {ASSERT(stmt);}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct PackageName: ArenaObject { // Either idList or str may be null, but not both
|
||||
@ -918,6 +901,8 @@ namespace JavaScript {
|
||||
|
||||
VariableStmtNode(uint32 pos, Kind kind, IdentifierList *attributes, VariableBinding *bindings):
|
||||
AttributeStmtNode(pos, kind, attributes), bindings(bindings) {}
|
||||
|
||||
void print(PrettyPrinter &f, bool noSemi) const;
|
||||
};
|
||||
|
||||
struct FunctionStmtNode: AttributeStmtNode {
|
||||
@ -980,15 +965,16 @@ namespace JavaScript {
|
||||
bool lineBreakBefore(const Token &t) const {return lineBreaksSignificant && t.getLineBreak();}
|
||||
bool lineBreakBefore() {return lineBreaksSignificant && lexer.peek(true).getLineBreak();}
|
||||
|
||||
ExprNode *parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers);
|
||||
ExprNode *parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool &foundQualifiers);
|
||||
ExprNode *parseQualifiedIdentifier(const Token &t);
|
||||
ExprNode *parseIdentifierQualifiers(ExprNode *e, bool &foundQualifiers, bool preferRegExp);
|
||||
ExprNode *parseParenthesesAndIdentifierQualifiers(const Token &tParen, bool &foundQualifiers, bool preferRegExp);
|
||||
ExprNode *parseQualifiedIdentifier(const Token &t, bool preferRegExp);
|
||||
PairListExprNode *parseArrayLiteral(const Token &initialToken);
|
||||
PairListExprNode *parseObjectLiteral(const Token &initialToken);
|
||||
ExprNode *parsePrimaryExpression();
|
||||
BinaryExprNode *parseMember(ExprNode *target, const Token &tOperator, ExprNode::Kind kind, ExprNode::Kind parenKind);
|
||||
InvokeExprNode *parseInvoke(ExprNode *target, uint32 pos, Token::Kind closingTokenKind, ExprNode::Kind invokeKind);
|
||||
ExprNode *parsePostfixExpression(bool newExpression = false);
|
||||
void ensurePostfix(const ExprNode *e);
|
||||
ExprNode *parseUnaryExpression();
|
||||
|
||||
enum Precedence {
|
||||
@ -1026,13 +1012,15 @@ namespace JavaScript {
|
||||
private:
|
||||
ExprNode *parseParenthesizedExpression();
|
||||
const StringAtom &parseTypedIdentifier(ExprNode *&type);
|
||||
VariableBinding *parseVariableBinding(bool noQualifiers, bool noIn);
|
||||
|
||||
enum SemicolonState {semiNone, semiNoninsertable, semiInsertable};
|
||||
enum AttributeStatement {asAny, asBlock, asConstVar};
|
||||
StmtNode *parseBlock(bool inSwitch, bool noOpenBrace, bool noCloseBrace);
|
||||
StmtNode *parseAttributeStatement(uint32 pos, IdentifierList *attributes, const Token &t, SemicolonState &semicolonState);
|
||||
StmtNode *parseAttributeStatement(uint32 pos, IdentifierList *attributes, const Token &t, bool noIn, SemicolonState &semicolonState);
|
||||
StmtNode *parseAttributesAndStatement(const Token *t, AttributeStatement as, SemicolonState &semicolonState);
|
||||
StmtNode *parseAnnotatedBlock();
|
||||
StmtNode *parseFor(uint32 pos, SemicolonState &semicolonState);
|
||||
StmtNode *parseTry(uint32 pos);
|
||||
public:
|
||||
StmtNode *parseStatement(bool topLevel, bool inSwitch, SemicolonState &semicolonState);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user