Unify several checking methods between parser and pre-parser.
R=ulan@chromium.org Review URL: https://codereview.chromium.org/27206002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17207 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
75a02eb247
commit
bdc8c36ca0
@ -3025,7 +3025,7 @@ Expression* Parser::ParseConditionalExpression(bool accept_IN, bool* ok) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int Precedence(Token::Value tok, bool accept_IN) {
|
int ParserBase::Precedence(Token::Value tok, bool accept_IN) {
|
||||||
if (tok == Token::IN && !accept_IN)
|
if (tok == Token::IN && !accept_IN)
|
||||||
return 0; // 0 precedence will terminate binary expression parsing
|
return 0; // 0 precedence will terminate binary expression parsing
|
||||||
|
|
||||||
@ -3845,11 +3845,6 @@ void Parser::BuildObjectLiteralConstantProperties(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Force instantiation of template instances class.
|
|
||||||
template void ObjectLiteralChecker<Parser>::CheckProperty(
|
|
||||||
Token::Value property, PropertyKind type, bool* ok);
|
|
||||||
|
|
||||||
|
|
||||||
Expression* Parser::ParseObjectLiteral(bool* ok) {
|
Expression* Parser::ParseObjectLiteral(bool* ok) {
|
||||||
// ObjectLiteral ::
|
// ObjectLiteral ::
|
||||||
// '{' (
|
// '{' (
|
||||||
@ -3863,8 +3858,7 @@ Expression* Parser::ParseObjectLiteral(bool* ok) {
|
|||||||
int number_of_boilerplate_properties = 0;
|
int number_of_boilerplate_properties = 0;
|
||||||
bool has_function = false;
|
bool has_function = false;
|
||||||
|
|
||||||
ObjectLiteralChecker<Parser> checker(this, &scanner_,
|
ObjectLiteralChecker checker(this, top_scope_->language_mode());
|
||||||
top_scope_->language_mode());
|
|
||||||
|
|
||||||
Expect(Token::LBRACE, CHECK_OK);
|
Expect(Token::LBRACE, CHECK_OK);
|
||||||
|
|
||||||
@ -4618,9 +4612,9 @@ bool ParserBase::peek_any_identifier() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Parser::CheckContextualKeyword(Vector<const char> keyword) {
|
bool ParserBase::CheckContextualKeyword(Vector<const char> keyword) {
|
||||||
if (peek() == Token::IDENTIFIER &&
|
if (peek() == Token::IDENTIFIER &&
|
||||||
scanner().is_next_contextual_keyword(keyword)) {
|
scanner()->is_next_contextual_keyword(keyword)) {
|
||||||
Consume(Token::IDENTIFIER);
|
Consume(Token::IDENTIFIER);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -4645,12 +4639,12 @@ void ParserBase::ExpectSemicolon(bool* ok) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Parser::ExpectContextualKeyword(Vector<const char> keyword, bool* ok) {
|
void ParserBase::ExpectContextualKeyword(Vector<const char> keyword, bool* ok) {
|
||||||
Expect(Token::IDENTIFIER, ok);
|
Expect(Token::IDENTIFIER, ok);
|
||||||
if (!*ok) return;
|
if (!*ok) return;
|
||||||
if (!scanner().is_literal_contextual_keyword(keyword)) {
|
if (!scanner()->is_literal_contextual_keyword(keyword)) {
|
||||||
|
ReportUnexpectedToken(scanner()->current_token());
|
||||||
*ok = false;
|
*ok = false;
|
||||||
ReportUnexpectedToken(scanner().current_token());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4745,14 +4739,11 @@ void Parser::CheckStrictModeLValue(Expression* expression,
|
|||||||
|
|
||||||
// Checks whether an octal literal was last seen between beg_pos and end_pos.
|
// Checks whether an octal literal was last seen between beg_pos and end_pos.
|
||||||
// If so, reports an error. Only called for strict mode.
|
// If so, reports an error. Only called for strict mode.
|
||||||
void Parser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
|
void ParserBase::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
|
||||||
Scanner::Location octal = scanner().octal_position();
|
Scanner::Location octal = scanner()->octal_position();
|
||||||
if (octal.IsValid() &&
|
if (octal.IsValid() && beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) {
|
||||||
beg_pos <= octal.beg_pos &&
|
ReportMessageAt(octal, "strict_octal_literal");
|
||||||
octal.end_pos <= end_pos) {
|
scanner()->clear_octal_position();
|
||||||
ReportMessageAt(octal, "strict_octal_literal",
|
|
||||||
Vector<const char*>::empty());
|
|
||||||
scanner().clear_octal_position();
|
|
||||||
*ok = false;
|
*ok = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
25
src/parser.h
25
src/parser.h
@ -439,13 +439,6 @@ class Parser : public ParserBase {
|
|||||||
static bool Parse(CompilationInfo* info) { return Parser(info).Parse(); }
|
static bool Parse(CompilationInfo* info) { return Parser(info).Parse(); }
|
||||||
bool Parse();
|
bool Parse();
|
||||||
|
|
||||||
void ReportMessageAt(Scanner::Location loc,
|
|
||||||
const char* message,
|
|
||||||
Vector<const char*> args = Vector<const char*>::empty());
|
|
||||||
void ReportMessageAt(Scanner::Location loc,
|
|
||||||
const char* message,
|
|
||||||
Vector<Handle<String> > args);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int kMaxNumFunctionLocals = 131071; // 2^17-1
|
static const int kMaxNumFunctionLocals = 131071; // 2^17-1
|
||||||
|
|
||||||
@ -562,6 +555,15 @@ class Parser : public ParserBase {
|
|||||||
void ReportInvalidPreparseData(Handle<String> name, bool* ok);
|
void ReportInvalidPreparseData(Handle<String> name, bool* ok);
|
||||||
void ReportMessage(const char* message, Vector<const char*> args);
|
void ReportMessage(const char* message, Vector<const char*> args);
|
||||||
void ReportMessage(const char* message, Vector<Handle<String> > args);
|
void ReportMessage(const char* message, Vector<Handle<String> > args);
|
||||||
|
void ReportMessageAt(Scanner::Location location, const char* type) {
|
||||||
|
ReportMessageAt(location, type, Vector<const char*>::empty());
|
||||||
|
}
|
||||||
|
void ReportMessageAt(Scanner::Location loc,
|
||||||
|
const char* message,
|
||||||
|
Vector<const char*> args);
|
||||||
|
void ReportMessageAt(Scanner::Location loc,
|
||||||
|
const char* message,
|
||||||
|
Vector<Handle<String> > args);
|
||||||
|
|
||||||
void set_pre_parse_data(ScriptDataImpl *data) {
|
void set_pre_parse_data(ScriptDataImpl *data) {
|
||||||
pre_parse_data_ = data;
|
pre_parse_data_ = data;
|
||||||
@ -570,8 +572,6 @@ class Parser : public ParserBase {
|
|||||||
|
|
||||||
bool inside_with() const { return top_scope_->inside_with(); }
|
bool inside_with() const { return top_scope_->inside_with(); }
|
||||||
Scanner& scanner() { return scanner_; }
|
Scanner& scanner() { return scanner_; }
|
||||||
int position() { return scanner_.location().beg_pos; }
|
|
||||||
int peek_position() { return scanner_.peek_location().beg_pos; }
|
|
||||||
Mode mode() const { return mode_; }
|
Mode mode() const { return mode_; }
|
||||||
ScriptDataImpl* pre_parse_data() const { return pre_parse_data_; }
|
ScriptDataImpl* pre_parse_data() const { return pre_parse_data_; }
|
||||||
bool is_extended_mode() {
|
bool is_extended_mode() {
|
||||||
@ -694,9 +694,6 @@ class Parser : public ParserBase {
|
|||||||
|
|
||||||
bool CheckInOrOf(bool accept_OF, ForEachStatement::VisitMode* visit_mode);
|
bool CheckInOrOf(bool accept_OF, ForEachStatement::VisitMode* visit_mode);
|
||||||
|
|
||||||
bool CheckContextualKeyword(Vector<const char> keyword);
|
|
||||||
void ExpectContextualKeyword(Vector<const char> keyword, bool* ok);
|
|
||||||
|
|
||||||
Handle<String> LiteralString(PretenureFlag tenured) {
|
Handle<String> LiteralString(PretenureFlag tenured) {
|
||||||
if (scanner().is_literal_ascii()) {
|
if (scanner().is_literal_ascii()) {
|
||||||
return isolate_->factory()->NewStringFromAscii(
|
return isolate_->factory()->NewStringFromAscii(
|
||||||
@ -741,9 +738,6 @@ class Parser : public ParserBase {
|
|||||||
const char* error,
|
const char* error,
|
||||||
bool* ok);
|
bool* ok);
|
||||||
|
|
||||||
// Strict mode octal literal validation.
|
|
||||||
void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok);
|
|
||||||
|
|
||||||
// For harmony block scoping mode: Check if the scope has conflicting var/let
|
// For harmony block scoping mode: Check if the scope has conflicting var/let
|
||||||
// declarations from different scopes. It covers for example
|
// declarations from different scopes. It covers for example
|
||||||
//
|
//
|
||||||
@ -826,7 +820,6 @@ class Parser : public ParserBase {
|
|||||||
CompilationInfo* info_;
|
CompilationInfo* info_;
|
||||||
friend class BlockState;
|
friend class BlockState;
|
||||||
friend class FunctionState;
|
friend class FunctionState;
|
||||||
friend class ObjectLiteralChecker<Parser>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction(
|
|||||||
function_scope.set_is_generator(is_generator);
|
function_scope.set_is_generator(is_generator);
|
||||||
ASSERT_EQ(i::Token::LBRACE, scanner()->current_token());
|
ASSERT_EQ(i::Token::LBRACE, scanner()->current_token());
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
int start_position = scanner()->peek_location().beg_pos;
|
int start_position = peek_position();
|
||||||
ParseLazyFunctionLiteralBody(&ok);
|
ParseLazyFunctionLiteralBody(&ok);
|
||||||
if (stack_overflow()) return kPreParseStackOverflow;
|
if (stack_overflow()) return kPreParseStackOverflow;
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
@ -129,18 +129,6 @@ void PreParser::ReportUnexpectedToken(i::Token::Value token) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Checks whether octal literal last seen is between beg_pos and end_pos.
|
|
||||||
// If so, reports an error.
|
|
||||||
void PreParser::CheckOctalLiteral(int beg_pos, int end_pos, bool* ok) {
|
|
||||||
i::Scanner::Location octal = scanner()->octal_position();
|
|
||||||
if (beg_pos <= octal.beg_pos && octal.end_pos <= end_pos) {
|
|
||||||
ReportMessageAt(octal, "strict_octal_literal", NULL);
|
|
||||||
scanner()->clear_octal_position();
|
|
||||||
*ok = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define CHECK_OK ok); \
|
#define CHECK_OK ok); \
|
||||||
if (!*ok) return kUnknownSourceElements; \
|
if (!*ok) return kUnknownSourceElements; \
|
||||||
((void)0
|
((void)0
|
||||||
@ -659,10 +647,9 @@ PreParser::Statement PreParser::ParseWhileStatement(bool* ok) {
|
|||||||
|
|
||||||
|
|
||||||
bool PreParser::CheckInOrOf(bool accept_OF) {
|
bool PreParser::CheckInOrOf(bool accept_OF) {
|
||||||
if (peek() == i::Token::IN ||
|
if (Check(Token::IN) ||
|
||||||
(allow_for_of() && accept_OF && peek() == i::Token::IDENTIFIER &&
|
(allow_for_of() && accept_OF &&
|
||||||
scanner()->is_next_contextual_keyword(v8::internal::CStrVector("of")))) {
|
CheckContextualKeyword(CStrVector("of")))) {
|
||||||
Next();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -901,14 +888,6 @@ PreParser::Expression PreParser::ParseConditionalExpression(bool accept_IN,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int PreParser::Precedence(i::Token::Value tok, bool accept_IN) {
|
|
||||||
if (tok == i::Token::IN && !accept_IN)
|
|
||||||
return 0; // 0 precedence will terminate binary expression parsing
|
|
||||||
|
|
||||||
return i::Token::Precedence(tok);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Precedence >= 4
|
// Precedence >= 4
|
||||||
PreParser::Expression PreParser::ParseBinaryExpression(int prec,
|
PreParser::Expression PreParser::ParseBinaryExpression(int prec,
|
||||||
bool accept_IN,
|
bool accept_IN,
|
||||||
@ -1238,7 +1217,7 @@ PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
|
|||||||
// | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
|
// | (('get' | 'set') (IdentifierName | String | Number) FunctionLiteral)
|
||||||
// )*[','] '}'
|
// )*[','] '}'
|
||||||
|
|
||||||
i::ObjectLiteralChecker<PreParser> checker(this, scanner(), language_mode());
|
ObjectLiteralChecker checker(this, language_mode());
|
||||||
|
|
||||||
Expect(i::Token::LBRACE, CHECK_OK);
|
Expect(i::Token::LBRACE, CHECK_OK);
|
||||||
while (peek() != i::Token::RBRACE) {
|
while (peek() != i::Token::RBRACE) {
|
||||||
@ -1265,8 +1244,7 @@ PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
|
|||||||
if (!is_keyword) {
|
if (!is_keyword) {
|
||||||
LogSymbol();
|
LogSymbol();
|
||||||
}
|
}
|
||||||
i::PropertyKind type = is_getter ? i::kGetterProperty
|
PropertyKind type = is_getter ? kGetterProperty : kSetterProperty;
|
||||||
: i::kSetterProperty;
|
|
||||||
checker.CheckProperty(name, type, CHECK_OK);
|
checker.CheckProperty(name, type, CHECK_OK);
|
||||||
ParseFunctionLiteral(false, CHECK_OK);
|
ParseFunctionLiteral(false, CHECK_OK);
|
||||||
if (peek() != i::Token::RBRACE) {
|
if (peek() != i::Token::RBRACE) {
|
||||||
@ -1274,22 +1252,22 @@ PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
|
|||||||
}
|
}
|
||||||
continue; // restart the while
|
continue; // restart the while
|
||||||
}
|
}
|
||||||
checker.CheckProperty(next, i::kValueProperty, CHECK_OK);
|
checker.CheckProperty(next, kValueProperty, CHECK_OK);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case i::Token::STRING:
|
case i::Token::STRING:
|
||||||
Consume(next);
|
Consume(next);
|
||||||
checker.CheckProperty(next, i::kValueProperty, CHECK_OK);
|
checker.CheckProperty(next, kValueProperty, CHECK_OK);
|
||||||
GetStringSymbol();
|
GetStringSymbol();
|
||||||
break;
|
break;
|
||||||
case i::Token::NUMBER:
|
case i::Token::NUMBER:
|
||||||
Consume(next);
|
Consume(next);
|
||||||
checker.CheckProperty(next, i::kValueProperty, CHECK_OK);
|
checker.CheckProperty(next, kValueProperty, CHECK_OK);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (i::Token::IsKeyword(next)) {
|
if (i::Token::IsKeyword(next)) {
|
||||||
Consume(next);
|
Consume(next);
|
||||||
checker.CheckProperty(next, i::kValueProperty, CHECK_OK);
|
checker.CheckProperty(next, kValueProperty, CHECK_OK);
|
||||||
} else {
|
} else {
|
||||||
// Unexpected token.
|
// Unexpected token.
|
||||||
*ok = false;
|
*ok = false;
|
||||||
@ -1368,7 +1346,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool is_generator,
|
|||||||
// FormalParameterList ::
|
// FormalParameterList ::
|
||||||
// '(' (Identifier)*[','] ')'
|
// '(' (Identifier)*[','] ')'
|
||||||
Expect(i::Token::LPAREN, CHECK_OK);
|
Expect(i::Token::LPAREN, CHECK_OK);
|
||||||
int start_position = scanner()->location().beg_pos;
|
int start_position = position();
|
||||||
bool done = (peek() == i::Token::RPAREN);
|
bool done = (peek() == i::Token::RPAREN);
|
||||||
i::DuplicateFinder duplicate_finder(scanner()->unicode_cache());
|
i::DuplicateFinder duplicate_finder(scanner()->unicode_cache());
|
||||||
while (!done) {
|
while (!done) {
|
||||||
@ -1428,7 +1406,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(bool is_generator,
|
|||||||
|
|
||||||
|
|
||||||
void PreParser::ParseLazyFunctionLiteralBody(bool* ok) {
|
void PreParser::ParseLazyFunctionLiteralBody(bool* ok) {
|
||||||
int body_start = scanner()->location().beg_pos;
|
int body_start = position();
|
||||||
log_->PauseRecording();
|
log_->PauseRecording();
|
||||||
ParseSourceElements(i::Token::RBRACE, ok);
|
ParseSourceElements(i::Token::RBRACE, ok);
|
||||||
log_->ResumeRecording();
|
log_->ResumeRecording();
|
||||||
@ -1462,7 +1440,7 @@ PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) {
|
|||||||
|
|
||||||
|
|
||||||
void PreParser::LogSymbol() {
|
void PreParser::LogSymbol() {
|
||||||
int identifier_pos = scanner()->location().beg_pos;
|
int identifier_pos = position();
|
||||||
if (scanner()->is_literal_ascii()) {
|
if (scanner()->is_literal_ascii()) {
|
||||||
log_->LogAsciiSymbol(identifier_pos, scanner()->literal_ascii_string());
|
log_->LogAsciiSymbol(identifier_pos, scanner()->literal_ascii_string());
|
||||||
} else {
|
} else {
|
||||||
@ -1602,7 +1580,7 @@ void PreParser::StrictModeIdentifierViolation(i::Scanner::Location location,
|
|||||||
PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) {
|
PreParser::Identifier PreParser::ParseIdentifierName(bool* ok) {
|
||||||
i::Token::Value next = Next();
|
i::Token::Value next = Next();
|
||||||
if (i::Token::IsKeyword(next)) {
|
if (i::Token::IsKeyword(next)) {
|
||||||
int pos = scanner()->location().beg_pos;
|
int pos = position();
|
||||||
const char* keyword = i::Token::String(next);
|
const char* keyword = i::Token::String(next);
|
||||||
log_->LogAsciiSymbol(pos, i::Vector<const char>(keyword,
|
log_->LogAsciiSymbol(pos, i::Vector<const char>(keyword,
|
||||||
i::StrLength(keyword)));
|
i::StrLength(keyword)));
|
||||||
@ -1637,4 +1615,36 @@ PreParser::Identifier PreParser::ParseIdentifierNameOrGetOrSet(bool* is_get,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PreParser::ObjectLiteralChecker::CheckProperty(Token::Value property,
|
||||||
|
PropertyKind type,
|
||||||
|
bool* ok) {
|
||||||
|
int old;
|
||||||
|
if (property == Token::NUMBER) {
|
||||||
|
old = finder_.AddNumber(scanner()->literal_ascii_string(), type);
|
||||||
|
} else if (scanner()->is_literal_ascii()) {
|
||||||
|
old = finder_.AddAsciiSymbol(scanner()->literal_ascii_string(), type);
|
||||||
|
} else {
|
||||||
|
old = finder_.AddUtf16Symbol(scanner()->literal_utf16_string(), type);
|
||||||
|
}
|
||||||
|
PropertyKind old_type = static_cast<PropertyKind>(old);
|
||||||
|
if (HasConflict(old_type, type)) {
|
||||||
|
if (IsDataDataConflict(old_type, type)) {
|
||||||
|
// Both are data properties.
|
||||||
|
if (language_mode_ == CLASSIC_MODE) return;
|
||||||
|
parser()->ReportMessageAt(scanner()->location(),
|
||||||
|
"strict_duplicate_property");
|
||||||
|
} else if (IsDataAccessorConflict(old_type, type)) {
|
||||||
|
// Both a data and an accessor property with the same name.
|
||||||
|
parser()->ReportMessageAt(scanner()->location(),
|
||||||
|
"accessor_data_property");
|
||||||
|
} else {
|
||||||
|
ASSERT(IsAccessorAccessorConflict(old_type, type));
|
||||||
|
// Both accessors of the same type.
|
||||||
|
parser()->ReportMessageAt(scanner()->location(),
|
||||||
|
"accessor_get_set");
|
||||||
|
}
|
||||||
|
*ok = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} } // v8::internal
|
} } // v8::internal
|
||||||
|
209
src/preparser.h
209
src/preparser.h
@ -35,96 +35,6 @@
|
|||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
// Used to detect duplicates in object literals. Each of the values
|
|
||||||
// kGetterProperty, kSetterProperty and kValueProperty represents
|
|
||||||
// a type of object literal property. When parsing a property, its
|
|
||||||
// type value is stored in the DuplicateFinder for the property name.
|
|
||||||
// Values are chosen so that having intersection bits means the there is
|
|
||||||
// an incompatibility.
|
|
||||||
// I.e., you can add a getter to a property that already has a setter, since
|
|
||||||
// kGetterProperty and kSetterProperty doesn't intersect, but not if it
|
|
||||||
// already has a getter or a value. Adding the getter to an existing
|
|
||||||
// setter will store the value (kGetterProperty | kSetterProperty), which
|
|
||||||
// is incompatible with adding any further properties.
|
|
||||||
enum PropertyKind {
|
|
||||||
kNone = 0,
|
|
||||||
// Bit patterns representing different object literal property types.
|
|
||||||
kGetterProperty = 1,
|
|
||||||
kSetterProperty = 2,
|
|
||||||
kValueProperty = 7,
|
|
||||||
// Helper constants.
|
|
||||||
kValueFlag = 4
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Validation per 11.1.5 Object Initialiser
|
|
||||||
template<typename P>
|
|
||||||
class ObjectLiteralChecker {
|
|
||||||
public:
|
|
||||||
ObjectLiteralChecker(P* parser, Scanner* scanner, LanguageMode mode)
|
|
||||||
: parser_(parser),
|
|
||||||
scanner_(scanner),
|
|
||||||
finder_(scanner->unicode_cache()),
|
|
||||||
language_mode_(mode) { }
|
|
||||||
|
|
||||||
void CheckProperty(Token::Value property, PropertyKind type, bool* ok);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Checks the type of conflict based on values coming from PropertyType.
|
|
||||||
bool HasConflict(PropertyKind type1, PropertyKind type2) {
|
|
||||||
return (type1 & type2) != 0;
|
|
||||||
}
|
|
||||||
bool IsDataDataConflict(PropertyKind type1, PropertyKind type2) {
|
|
||||||
return ((type1 & type2) & kValueFlag) != 0;
|
|
||||||
}
|
|
||||||
bool IsDataAccessorConflict(PropertyKind type1, PropertyKind type2) {
|
|
||||||
return ((type1 ^ type2) & kValueFlag) != 0;
|
|
||||||
}
|
|
||||||
bool IsAccessorAccessorConflict(PropertyKind type1, PropertyKind type2) {
|
|
||||||
return ((type1 | type2) & kValueFlag) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
P* parser_;
|
|
||||||
Scanner* scanner_;
|
|
||||||
DuplicateFinder finder_;
|
|
||||||
LanguageMode language_mode_;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template<typename P>
|
|
||||||
void ObjectLiteralChecker<P>::CheckProperty(Token::Value property,
|
|
||||||
PropertyKind type,
|
|
||||||
bool* ok) {
|
|
||||||
int old;
|
|
||||||
if (property == Token::NUMBER) {
|
|
||||||
old = finder_.AddNumber(scanner_->literal_ascii_string(), type);
|
|
||||||
} else if (scanner_->is_literal_ascii()) {
|
|
||||||
old = finder_.AddAsciiSymbol(scanner_->literal_ascii_string(), type);
|
|
||||||
} else {
|
|
||||||
old = finder_.AddUtf16Symbol(scanner_->literal_utf16_string(), type);
|
|
||||||
}
|
|
||||||
PropertyKind old_type = static_cast<PropertyKind>(old);
|
|
||||||
if (HasConflict(old_type, type)) {
|
|
||||||
if (IsDataDataConflict(old_type, type)) {
|
|
||||||
// Both are data properties.
|
|
||||||
if (language_mode_ == CLASSIC_MODE) return;
|
|
||||||
parser_->ReportMessageAt(scanner_->location(),
|
|
||||||
"strict_duplicate_property");
|
|
||||||
} else if (IsDataAccessorConflict(old_type, type)) {
|
|
||||||
// Both a data and an accessor property with the same name.
|
|
||||||
parser_->ReportMessageAt(scanner_->location(),
|
|
||||||
"accessor_data_property");
|
|
||||||
} else {
|
|
||||||
ASSERT(IsAccessorAccessorConflict(old_type, type));
|
|
||||||
// Both accessors of the same type.
|
|
||||||
parser_->ReportMessageAt(scanner_->location(),
|
|
||||||
"accessor_get_set");
|
|
||||||
}
|
|
||||||
*ok = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Common base class shared between parser and pre-parser.
|
// Common base class shared between parser and pre-parser.
|
||||||
class ParserBase {
|
class ParserBase {
|
||||||
public:
|
public:
|
||||||
@ -167,6 +77,8 @@ class ParserBase {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
Scanner* scanner() const { return scanner_; }
|
Scanner* scanner() const { return scanner_; }
|
||||||
|
int position() { return scanner_->location().beg_pos; }
|
||||||
|
int peek_position() { return scanner_->peek_location().beg_pos; }
|
||||||
bool stack_overflow() const { return stack_overflow_; }
|
bool stack_overflow() const { return stack_overflow_; }
|
||||||
void set_stack_overflow() { stack_overflow_ = true; }
|
void set_stack_overflow() { stack_overflow_ = true; }
|
||||||
|
|
||||||
@ -215,9 +127,72 @@ class ParserBase {
|
|||||||
|
|
||||||
bool peek_any_identifier();
|
bool peek_any_identifier();
|
||||||
void ExpectSemicolon(bool* ok);
|
void ExpectSemicolon(bool* ok);
|
||||||
|
bool CheckContextualKeyword(Vector<const char> keyword);
|
||||||
|
void ExpectContextualKeyword(Vector<const char> keyword, bool* ok);
|
||||||
|
|
||||||
|
// Strict mode octal literal validation.
|
||||||
|
void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok);
|
||||||
|
|
||||||
|
// Determine precedence of given token.
|
||||||
|
static int Precedence(Token::Value token, bool accept_IN);
|
||||||
|
|
||||||
// Report syntax errors.
|
// Report syntax errors.
|
||||||
virtual void ReportUnexpectedToken(Token::Value token) = 0;
|
virtual void ReportUnexpectedToken(Token::Value token) = 0;
|
||||||
|
virtual void ReportMessageAt(Scanner::Location loc, const char* type) = 0;
|
||||||
|
|
||||||
|
// Used to detect duplicates in object literals. Each of the values
|
||||||
|
// kGetterProperty, kSetterProperty and kValueProperty represents
|
||||||
|
// a type of object literal property. When parsing a property, its
|
||||||
|
// type value is stored in the DuplicateFinder for the property name.
|
||||||
|
// Values are chosen so that having intersection bits means the there is
|
||||||
|
// an incompatibility.
|
||||||
|
// I.e., you can add a getter to a property that already has a setter, since
|
||||||
|
// kGetterProperty and kSetterProperty doesn't intersect, but not if it
|
||||||
|
// already has a getter or a value. Adding the getter to an existing
|
||||||
|
// setter will store the value (kGetterProperty | kSetterProperty), which
|
||||||
|
// is incompatible with adding any further properties.
|
||||||
|
enum PropertyKind {
|
||||||
|
kNone = 0,
|
||||||
|
// Bit patterns representing different object literal property types.
|
||||||
|
kGetterProperty = 1,
|
||||||
|
kSetterProperty = 2,
|
||||||
|
kValueProperty = 7,
|
||||||
|
// Helper constants.
|
||||||
|
kValueFlag = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
// Validation per ECMA 262 - 11.1.5 "Object Initialiser".
|
||||||
|
class ObjectLiteralChecker {
|
||||||
|
public:
|
||||||
|
ObjectLiteralChecker(ParserBase* parser, LanguageMode mode)
|
||||||
|
: parser_(parser),
|
||||||
|
finder_(scanner()->unicode_cache()),
|
||||||
|
language_mode_(mode) { }
|
||||||
|
|
||||||
|
void CheckProperty(Token::Value property, PropertyKind type, bool* ok);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ParserBase* parser() const { return parser_; }
|
||||||
|
Scanner* scanner() const { return parser_->scanner(); }
|
||||||
|
|
||||||
|
// Checks the type of conflict based on values coming from PropertyType.
|
||||||
|
bool HasConflict(PropertyKind type1, PropertyKind type2) {
|
||||||
|
return (type1 & type2) != 0;
|
||||||
|
}
|
||||||
|
bool IsDataDataConflict(PropertyKind type1, PropertyKind type2) {
|
||||||
|
return ((type1 & type2) & kValueFlag) != 0;
|
||||||
|
}
|
||||||
|
bool IsDataAccessorConflict(PropertyKind type1, PropertyKind type2) {
|
||||||
|
return ((type1 ^ type2) & kValueFlag) != 0;
|
||||||
|
}
|
||||||
|
bool IsAccessorAccessorConflict(PropertyKind type1, PropertyKind type2) {
|
||||||
|
return ((type1 | type2) & kValueFlag) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ParserBase* parser_;
|
||||||
|
DuplicateFinder finder_;
|
||||||
|
LanguageMode language_mode_;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Scanner* scanner_;
|
Scanner* scanner_;
|
||||||
@ -254,14 +229,13 @@ class PreParser : public ParserBase {
|
|||||||
kPreParseSuccess
|
kPreParseSuccess
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PreParser(Scanner* scanner,
|
||||||
PreParser(i::Scanner* scanner,
|
ParserRecorder* log,
|
||||||
i::ParserRecorder* log,
|
|
||||||
uintptr_t stack_limit)
|
uintptr_t stack_limit)
|
||||||
: ParserBase(scanner, stack_limit),
|
: ParserBase(scanner, stack_limit),
|
||||||
log_(log),
|
log_(log),
|
||||||
scope_(NULL),
|
scope_(NULL),
|
||||||
strict_mode_violation_location_(i::Scanner::Location::invalid()),
|
strict_mode_violation_location_(Scanner::Location::invalid()),
|
||||||
strict_mode_violation_type_(NULL),
|
strict_mode_violation_type_(NULL),
|
||||||
parenthesized_function_(false) { }
|
parenthesized_function_(false) { }
|
||||||
|
|
||||||
@ -275,7 +249,7 @@ class PreParser : public ParserBase {
|
|||||||
Scope top_scope(&scope_, kTopLevelScope);
|
Scope top_scope(&scope_, kTopLevelScope);
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
int start_position = scanner()->peek_location().beg_pos;
|
int start_position = scanner()->peek_location().beg_pos;
|
||||||
ParseSourceElements(i::Token::EOS, &ok);
|
ParseSourceElements(Token::EOS, &ok);
|
||||||
if (stack_overflow()) return kPreParseStackOverflow;
|
if (stack_overflow()) return kPreParseStackOverflow;
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
ReportUnexpectedToken(scanner()->current_token());
|
ReportUnexpectedToken(scanner()->current_token());
|
||||||
@ -293,9 +267,9 @@ class PreParser : public ParserBase {
|
|||||||
// keyword and parameters, and have consumed the initial '{'.
|
// keyword and parameters, and have consumed the initial '{'.
|
||||||
// At return, unless an error occurred, the scanner is positioned before the
|
// At return, unless an error occurred, the scanner is positioned before the
|
||||||
// the final '}'.
|
// the final '}'.
|
||||||
PreParseResult PreParseLazyFunction(i::LanguageMode mode,
|
PreParseResult PreParseLazyFunction(LanguageMode mode,
|
||||||
bool is_generator,
|
bool is_generator,
|
||||||
i::ParserRecorder* log);
|
ParserRecorder* log);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// These types form an algebra over syntactic categories that is just
|
// These types form an algebra over syntactic categories that is just
|
||||||
@ -556,7 +530,7 @@ class PreParser : public ParserBase {
|
|||||||
expected_properties_(0),
|
expected_properties_(0),
|
||||||
with_nesting_count_(0),
|
with_nesting_count_(0),
|
||||||
language_mode_(
|
language_mode_(
|
||||||
(prev_ != NULL) ? prev_->language_mode() : i::CLASSIC_MODE),
|
(prev_ != NULL) ? prev_->language_mode() : CLASSIC_MODE),
|
||||||
is_generator_(false) {
|
is_generator_(false) {
|
||||||
*variable = this;
|
*variable = this;
|
||||||
}
|
}
|
||||||
@ -570,12 +544,12 @@ class PreParser : public ParserBase {
|
|||||||
bool is_generator() { return is_generator_; }
|
bool is_generator() { return is_generator_; }
|
||||||
void set_is_generator(bool is_generator) { is_generator_ = is_generator; }
|
void set_is_generator(bool is_generator) { is_generator_ = is_generator; }
|
||||||
bool is_classic_mode() {
|
bool is_classic_mode() {
|
||||||
return language_mode_ == i::CLASSIC_MODE;
|
return language_mode_ == CLASSIC_MODE;
|
||||||
}
|
}
|
||||||
i::LanguageMode language_mode() {
|
LanguageMode language_mode() {
|
||||||
return language_mode_;
|
return language_mode_;
|
||||||
}
|
}
|
||||||
void set_language_mode(i::LanguageMode language_mode) {
|
void set_language_mode(LanguageMode language_mode) {
|
||||||
language_mode_ = language_mode;
|
language_mode_ = language_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -599,15 +573,18 @@ class PreParser : public ParserBase {
|
|||||||
int materialized_literal_count_;
|
int materialized_literal_count_;
|
||||||
int expected_properties_;
|
int expected_properties_;
|
||||||
int with_nesting_count_;
|
int with_nesting_count_;
|
||||||
i::LanguageMode language_mode_;
|
LanguageMode language_mode_;
|
||||||
bool is_generator_;
|
bool is_generator_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Report syntax error
|
// Report syntax error
|
||||||
void ReportUnexpectedToken(i::Token::Value token);
|
void ReportUnexpectedToken(Token::Value token);
|
||||||
void ReportMessageAt(i::Scanner::Location location,
|
void ReportMessageAt(Scanner::Location location, const char* type) {
|
||||||
|
ReportMessageAt(location, type, NULL);
|
||||||
|
}
|
||||||
|
void ReportMessageAt(Scanner::Location location,
|
||||||
const char* type,
|
const char* type,
|
||||||
const char* name_opt = NULL) {
|
const char* name_opt) {
|
||||||
log_->LogMessage(location.beg_pos, location.end_pos, type, name_opt);
|
log_->LogMessage(location.beg_pos, location.end_pos, type, name_opt);
|
||||||
}
|
}
|
||||||
void ReportMessageAt(int start_pos,
|
void ReportMessageAt(int start_pos,
|
||||||
@ -617,8 +594,6 @@ class PreParser : public ParserBase {
|
|||||||
log_->LogMessage(start_pos, end_pos, type, name_opt);
|
log_->LogMessage(start_pos, end_pos, type, name_opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckOctalLiteral(int beg_pos, int end_pos, bool* ok);
|
|
||||||
|
|
||||||
// All ParseXXX functions take as the last argument an *ok parameter
|
// All ParseXXX functions take as the last argument an *ok parameter
|
||||||
// which is set to false if parsing failed; it is unchanged otherwise.
|
// which is set to false if parsing failed; it is unchanged otherwise.
|
||||||
// By making the 'exception handling' explicit, we are forced to check
|
// By making the 'exception handling' explicit, we are forced to check
|
||||||
@ -682,42 +657,38 @@ class PreParser : public ParserBase {
|
|||||||
// Log the currently parsed string literal.
|
// Log the currently parsed string literal.
|
||||||
Expression GetStringSymbol();
|
Expression GetStringSymbol();
|
||||||
|
|
||||||
void set_language_mode(i::LanguageMode language_mode) {
|
void set_language_mode(LanguageMode language_mode) {
|
||||||
scope_->set_language_mode(language_mode);
|
scope_->set_language_mode(language_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_classic_mode() {
|
bool is_classic_mode() {
|
||||||
return scope_->language_mode() == i::CLASSIC_MODE;
|
return scope_->language_mode() == CLASSIC_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_extended_mode() {
|
bool is_extended_mode() {
|
||||||
return scope_->language_mode() == i::EXTENDED_MODE;
|
return scope_->language_mode() == EXTENDED_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
i::LanguageMode language_mode() { return scope_->language_mode(); }
|
LanguageMode language_mode() { return scope_->language_mode(); }
|
||||||
|
|
||||||
bool CheckInOrOf(bool accept_OF);
|
bool CheckInOrOf(bool accept_OF);
|
||||||
|
|
||||||
static int Precedence(i::Token::Value tok, bool accept_IN);
|
void SetStrictModeViolation(Scanner::Location,
|
||||||
|
|
||||||
void SetStrictModeViolation(i::Scanner::Location,
|
|
||||||
const char* type,
|
const char* type,
|
||||||
bool* ok);
|
bool* ok);
|
||||||
|
|
||||||
void CheckDelayedStrictModeViolation(int beg_pos, int end_pos, bool* ok);
|
void CheckDelayedStrictModeViolation(int beg_pos, int end_pos, bool* ok);
|
||||||
|
|
||||||
void StrictModeIdentifierViolation(i::Scanner::Location,
|
void StrictModeIdentifierViolation(Scanner::Location,
|
||||||
const char* eval_args_type,
|
const char* eval_args_type,
|
||||||
Identifier identifier,
|
Identifier identifier,
|
||||||
bool* ok);
|
bool* ok);
|
||||||
|
|
||||||
i::ParserRecorder* log_;
|
ParserRecorder* log_;
|
||||||
Scope* scope_;
|
Scope* scope_;
|
||||||
i::Scanner::Location strict_mode_violation_location_;
|
Scanner::Location strict_mode_violation_location_;
|
||||||
const char* strict_mode_violation_type_;
|
const char* strict_mode_violation_type_;
|
||||||
bool parenthesized_function_;
|
bool parenthesized_function_;
|
||||||
|
|
||||||
friend class i::ObjectLiteralChecker<PreParser>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} } // v8::internal
|
} } // v8::internal
|
||||||
|
Loading…
Reference in New Issue
Block a user