}
+bool Expression::IsIdentifier() {
+ return (AsVariableProxy() != NULL && !AsVariableProxy()->is_this());
+}
+
+
+bool Expression::IsIdentifierNamed(String* name) {
+ return (AsVariableProxy() != NULL && AsVariableProxy()->name()->Equals(name));
+}
+
+
VariableProxy::VariableProxy(Zone* zone, Variable* var, int position)
: Expression(zone, position),
name_(var->name()),
// True if we can prove that the expression is the undefined literal.
bool IsUndefinedLiteral(Isolate* isolate);
+ bool IsIdentifier();
+
+ bool IsIdentifierNamed(String* name);
+
// Expression type bounds
Bounds bounds() { return bounds_; }
void set_bounds(Bounds bounds) { bounds_ = bounds; }
!scanner().HasAnyLineTerminatorBeforeNext() &&
stmt != NULL) {
ExpressionStatement* estmt = stmt->AsExpressionStatement();
- if (estmt != NULL &&
- estmt->expression()->AsVariableProxy() != NULL &&
- estmt->expression()->AsVariableProxy()->name()->Equals(
- isolate()->heap()->module_string()) &&
+ if (estmt != NULL && estmt->expression()->IsIdentifierNamed(
+ isolate()->heap()->module_string()) &&
!scanner().literal_contains_escapes()) {
return ParseModuleDeclaration(NULL, ok);
}
int pos = peek_position();
bool starts_with_idenfifier = peek_any_identifier();
Expression* expr = ParseExpression(true, CHECK_OK);
+ // Even if the expression starts with an identifier, it is not necessarily an
+ // identifier. For example, "foo + bar" starts with an identifier but is not
+ // an identifier.
if (peek() == Token::COLON && starts_with_idenfifier && expr != NULL &&
- expr->AsVariableProxy() != NULL &&
- !expr->AsVariableProxy()->is_this()) {
+ expr->IsIdentifier()) {
// Expression is a single identifier, and not, e.g., a parenthesized
// identifier.
VariableProxy* var = expr->AsVariableProxy();
peek() == Token::FUNCTION &&
!scanner().HasAnyLineTerminatorBeforeNext() &&
expr != NULL &&
- expr->AsVariableProxy() != NULL &&
- expr->AsVariableProxy()->name()->Equals(
- isolate()->heap()->native_string()) &&
+ expr->IsIdentifierNamed(isolate()->heap()->native_string()) &&
!scanner().literal_contains_escapes()) {
return ParseNativeDeclaration(ok);
}
if (!FLAG_harmony_modules ||
peek() != Token::IDENTIFIER ||
scanner().HasAnyLineTerminatorBeforeNext() ||
- expr->AsVariableProxy() == NULL ||
- !expr->AsVariableProxy()->name()->Equals(
- isolate()->heap()->module_string()) ||
+ !expr->IsIdentifierNamed(isolate()->heap()->module_string()) ||
scanner().literal_contains_escapes()) {
ExpectSemicolon(CHECK_OK);
}
Property* property = expression ? expression->AsProperty() : NULL;
if (op == Token::ASSIGN &&
property != NULL &&
- property->obj()->AsVariableProxy() != NULL &&
- property->obj()->AsVariableProxy()->is_this()) {
+ property->obj()->IsIdentifier()) {
current_function_state_->AddProperty();
}
// SourceElements ::
// (Statement)* <end_token>
- bool allow_directive_prologue = true;
+ bool directive_prologue = true;
while (peek() != end_token) {
+ if (directive_prologue && peek() != Token::STRING) {
+ directive_prologue = false;
+ }
Statement statement = ParseSourceElement(CHECK_OK);
- if (allow_directive_prologue) {
+ if (directive_prologue) {
if (statement.IsUseStrictLiteral()) {
set_language_mode(allow_harmony_scoping() ?
EXTENDED_MODE : STRICT_MODE);
} else if (!statement.IsStringLiteral()) {
- allow_directive_prologue = false;
+ directive_prologue = false;
}
}
}
// Expression ';'
// Identifier ':' Statement
+ bool starts_with_identifier = peek_any_identifier();
Expression expr = ParseExpression(true, CHECK_OK);
- if (expr.IsRawIdentifier()) {
+ // Even if the expression starts with an identifier, it is not necessarily an
+ // identifier. For example, "foo + bar" starts with an identifier but is not
+ // an identifier.
+ if (peek() == Token::COLON && starts_with_identifier && expr.IsIdentifier()) {
+ // Expression is a single identifier, and not, e.g., a parenthesized
+ // identifier.
ASSERT(!expr.AsIdentifier().IsFutureReserved());
ASSERT(is_classic_mode() ||
(!expr.AsIdentifier().IsFutureStrictReserved() &&
!expr.AsIdentifier().IsYield()));
- if (peek() == Token::COLON) {
- Consume(Token::COLON);
- return ParseStatement(ok);
- }
+ Consume(Token::COLON);
+ return ParseStatement(ok);
// Preparsing is disabled for extensions (because the extension details
// aren't passed to lazily compiled functions), so we don't
// accept "native function" in the preparser.
parenthesized_function_ = (peek() == Token::FUNCTION);
result = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- result = result.Parenthesize();
break;
case Token::MOD:
// if bit 1 is set, it's a string literal.
// If neither is set, it's no particular type, and both set isn't
// use yet.
- // Bit 2 is used to mark the expression as being parenthesized,
- // so "(foo)" isn't recognized as a pure identifier (and possible label).
class Expression {
public:
static Expression Default() {
static_cast<PreParser::Identifier::Type>(code_ >> kIdentifierShift));
}
- bool IsParenthesized() {
- // If bit 0 or 1 is set, we interpret bit 2 as meaning parenthesized.
- return (code_ & 7) > 4;
- }
-
- bool IsRawIdentifier() {
- return !IsParenthesized() && IsIdentifier();
- }
-
bool IsStringLiteral() { return (code_ & kStringLiteralFlag) != 0; }
- bool IsRawStringLiteral() {
- return !IsParenthesized() && IsStringLiteral();
- }
-
bool IsUseStrictLiteral() {
return (code_ & kStringLiteralMask) == kUseStrictString;
}
return code_ == kStrictFunctionExpression;
}
- Expression Parenthesize() {
- int type = code_ & 3;
- if (type != 0) {
- // Identifiers and string literals can be parenthesized.
- // They no longer work as labels or directive prologues,
- // but are still recognized in other contexts.
- return Expression(code_ | kParenthesizedExpressionFlag);
- }
- // For other types of expressions, it's not important to remember
- // the parentheses.
- return *this;
- }
-
private:
// First two/three bits are used as flags.
// Bit 0 and 1 represent identifiers or strings literals, and are
// mutually exclusive, but can both be absent.
- // If bit 0 or 1 are set, bit 2 marks that the expression has
- // been wrapped in parentheses (a string literal can no longer
- // be a directive prologue, and an identifier can no longer be
- // a label.
enum {
kUnknownExpression = 0,
// Identifiers
kUseStrictString = kStringLiteralFlag | 8,
kStringLiteralMask = kUseStrictString,
- // Only if identifier or string literal.
- kParenthesizedExpressionFlag = 4,
-
// Below here applies if neither identifier nor string literal.
kThisExpression = 4,
kThisPropertyExpression = 8,
// Preserves being an unparenthesized string literal, possibly
// "use strict".
static Statement ExpressionStatement(Expression expression) {
- if (!expression.IsParenthesized()) {
- if (expression.IsUseStrictLiteral()) {
- return Statement(kUseStrictExpressionStatement);
- }
- if (expression.IsStringLiteral()) {
- return Statement(kStringLiteralExpressionStatement);
- }
+ if (expression.IsUseStrictLiteral()) {
+ return Statement(kUseStrictExpressionStatement);
+ }
+ if (expression.IsStringLiteral()) {
+ return Statement(kStringLiteralExpressionStatement);
}
return Default();
}
RunParserSyncTest(context_data, statement_data, kSuccess);
}
+
+
+TEST(ErrorsParenthesizedLabels) {
+ // Parenthesized identifiers shouldn't be recognized as labels.
+ const char* context_data[][2] = {
+ { "", ""},
+ { "function test_func() {", "}" },
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "(mylabel): while(true) { break mylabel; }",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kError);
+}
+
+
+TEST(NoErrorsParenthesizedDirectivePrologue) {
+ // Parenthesized directive prologue shouldn't be recognized.
+ const char* context_data[][2] = {
+ { "", ""},
+ { NULL, NULL }
+ };
+
+ const char* statement_data[] = {
+ "(\"use strict\"); var eval;",
+ NULL
+ };
+
+ RunParserSyncTest(context_data, statement_data, kSuccess);
+}