| Index: src/preparser.h
|
| diff --git a/src/preparser.h b/src/preparser.h
|
| index 44bd85c85e2d01070068afa4bb39fe4b972477dd..e99b4b0a181e200030100aa10446cfa2cb7bf923 100644
|
| --- a/src/preparser.h
|
| +++ b/src/preparser.h
|
| @@ -33,103 +33,178 @@
|
| #include "scanner.h"
|
|
|
| namespace v8 {
|
| -
|
| 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 {
|
| +// Common base class shared between parser and pre-parser.
|
| +class ParserBase {
|
| 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);
|
| + ParserBase(Scanner* scanner, uintptr_t stack_limit)
|
| + : scanner_(scanner),
|
| + stack_limit_(stack_limit),
|
| + stack_overflow_(false),
|
| + allow_lazy_(false),
|
| + allow_natives_syntax_(false),
|
| + allow_generators_(false),
|
| + allow_for_of_(false) { }
|
| + // TODO(mstarzinger): Only virtual until message reporting has been unified.
|
| + virtual ~ParserBase() { }
|
|
|
| - private:
|
| - // Checks the type of conflict based on values coming from PropertyType.
|
| - bool HasConflict(PropertyKind type1, PropertyKind type2) {
|
| - return (type1 & type2) != 0;
|
| + // Getters that indicate whether certain syntactical constructs are
|
| + // allowed to be parsed by this instance of the parser.
|
| + bool allow_lazy() const { return allow_lazy_; }
|
| + bool allow_natives_syntax() const { return allow_natives_syntax_; }
|
| + bool allow_generators() const { return allow_generators_; }
|
| + bool allow_for_of() const { return allow_for_of_; }
|
| + bool allow_modules() const { return scanner()->HarmonyModules(); }
|
| + bool allow_harmony_scoping() const { return scanner()->HarmonyScoping(); }
|
| + bool allow_harmony_numeric_literals() const {
|
| + return scanner()->HarmonyNumericLiterals();
|
| }
|
| - bool IsDataDataConflict(PropertyKind type1, PropertyKind type2) {
|
| - return ((type1 & type2) & kValueFlag) != 0;
|
| +
|
| + // Setters that determine whether certain syntactical constructs are
|
| + // allowed to be parsed by this instance of the parser.
|
| + void set_allow_lazy(bool allow) { allow_lazy_ = allow; }
|
| + void set_allow_natives_syntax(bool allow) { allow_natives_syntax_ = allow; }
|
| + void set_allow_generators(bool allow) { allow_generators_ = allow; }
|
| + void set_allow_for_of(bool allow) { allow_for_of_ = allow; }
|
| + void set_allow_modules(bool allow) { scanner()->SetHarmonyModules(allow); }
|
| + void set_allow_harmony_scoping(bool allow) {
|
| + scanner()->SetHarmonyScoping(allow);
|
| }
|
| - bool IsDataAccessorConflict(PropertyKind type1, PropertyKind type2) {
|
| - return ((type1 ^ type2) & kValueFlag) != 0;
|
| + void set_allow_harmony_numeric_literals(bool allow) {
|
| + scanner()->SetHarmonyNumericLiterals(allow);
|
| }
|
| - bool IsAccessorAccessorConflict(PropertyKind type1, PropertyKind type2) {
|
| - return ((type1 | type2) & kValueFlag) == 0;
|
| +
|
| + protected:
|
| + 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_; }
|
| + void set_stack_overflow() { stack_overflow_ = true; }
|
| +
|
| + INLINE(Token::Value peek()) {
|
| + if (stack_overflow_) return Token::ILLEGAL;
|
| + return scanner()->peek();
|
| }
|
|
|
| - P* parser_;
|
| - Scanner* scanner_;
|
| - DuplicateFinder finder_;
|
| - LanguageMode language_mode_;
|
| -};
|
| + INLINE(Token::Value Next()) {
|
| + if (stack_overflow_) return Token::ILLEGAL;
|
| + {
|
| + int marker;
|
| + if (reinterpret_cast<uintptr_t>(&marker) < stack_limit_) {
|
| + // Any further calls to Next or peek will return the illegal token.
|
| + // The current call must return the next token, which might already
|
| + // have been peek'ed.
|
| + stack_overflow_ = true;
|
| + }
|
| + }
|
| + return scanner()->Next();
|
| + }
|
|
|
| + void Consume(Token::Value token) {
|
| + Token::Value next = Next();
|
| + USE(next);
|
| + USE(token);
|
| + ASSERT(next == token);
|
| + }
|
|
|
| -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);
|
| + bool Check(Token::Value token) {
|
| + Token::Value next = peek();
|
| + if (next == token) {
|
| + Consume(next);
|
| + return true;
|
| + }
|
| + return false;
|
| }
|
| - 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;
|
| +
|
| + void Expect(Token::Value token, bool* ok) {
|
| + Token::Value next = Next();
|
| + if (next != token) {
|
| + ReportUnexpectedToken(next);
|
| + *ok = false;
|
| + }
|
| }
|
| -}
|
|
|
| -} // v8::internal
|
| + bool peek_any_identifier();
|
| + 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.
|
| + 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:
|
| + Scanner* scanner_;
|
| + uintptr_t stack_limit_;
|
| + bool stack_overflow_;
|
|
|
| -namespace preparser {
|
| + bool allow_lazy_;
|
| + bool allow_natives_syntax_;
|
| + bool allow_generators_;
|
| + bool allow_for_of_;
|
| +};
|
|
|
| -typedef uint8_t byte;
|
|
|
| // Preparsing checks a JavaScript program and emits preparse-data that helps
|
| // a later parsing to be faster.
|
| @@ -143,57 +218,25 @@ typedef uint8_t byte;
|
| // rather it is to speed up properly written and correct programs.
|
| // That means that contextual checks (like a label being declared where
|
| // it is used) are generally omitted.
|
| -
|
| -namespace i = v8::internal;
|
| -
|
| -class PreParser {
|
| +class PreParser : public ParserBase {
|
| public:
|
| enum PreParseResult {
|
| kPreParseStackOverflow,
|
| kPreParseSuccess
|
| };
|
|
|
| -
|
| - PreParser(i::Scanner* scanner,
|
| - i::ParserRecorder* log,
|
| + PreParser(Scanner* scanner,
|
| + ParserRecorder* log,
|
| uintptr_t stack_limit)
|
| - : scanner_(scanner),
|
| + : ParserBase(scanner, stack_limit),
|
| log_(log),
|
| scope_(NULL),
|
| - stack_limit_(stack_limit),
|
| - strict_mode_violation_location_(i::Scanner::Location::invalid()),
|
| + strict_mode_violation_location_(Scanner::Location::invalid()),
|
| strict_mode_violation_type_(NULL),
|
| - stack_overflow_(false),
|
| - allow_lazy_(false),
|
| - allow_natives_syntax_(false),
|
| - allow_generators_(false),
|
| - allow_for_of_(false),
|
| parenthesized_function_(false) { }
|
|
|
| ~PreParser() {}
|
|
|
| - bool allow_natives_syntax() const { return allow_natives_syntax_; }
|
| - bool allow_lazy() const { return allow_lazy_; }
|
| - bool allow_modules() const { return scanner_->HarmonyModules(); }
|
| - bool allow_harmony_scoping() const { return scanner_->HarmonyScoping(); }
|
| - bool allow_generators() const { return allow_generators_; }
|
| - bool allow_for_of() const { return allow_for_of_; }
|
| - bool allow_harmony_numeric_literals() const {
|
| - return scanner_->HarmonyNumericLiterals();
|
| - }
|
| -
|
| - void set_allow_natives_syntax(bool allow) { allow_natives_syntax_ = allow; }
|
| - void set_allow_lazy(bool allow) { allow_lazy_ = allow; }
|
| - void set_allow_modules(bool allow) { scanner_->SetHarmonyModules(allow); }
|
| - void set_allow_harmony_scoping(bool allow) {
|
| - scanner_->SetHarmonyScoping(allow);
|
| - }
|
| - void set_allow_generators(bool allow) { allow_generators_ = allow; }
|
| - void set_allow_for_of(bool allow) { allow_for_of_ = allow; }
|
| - void set_allow_harmony_numeric_literals(bool allow) {
|
| - scanner_->SetHarmonyNumericLiterals(allow);
|
| - }
|
| -
|
| // Pre-parse the program from the character stream; returns true on
|
| // success (even if parsing failed, the pre-parse data successfully
|
| // captured the syntax error), and false if a stack-overflow happened
|
| @@ -201,13 +244,13 @@ class PreParser {
|
| PreParseResult PreParseProgram() {
|
| Scope top_scope(&scope_, kTopLevelScope);
|
| bool ok = true;
|
| - int start_position = scanner_->peek_location().beg_pos;
|
| - ParseSourceElements(i::Token::EOS, &ok);
|
| - if (stack_overflow_) return kPreParseStackOverflow;
|
| + int start_position = scanner()->peek_location().beg_pos;
|
| + ParseSourceElements(Token::EOS, &ok);
|
| + if (stack_overflow()) return kPreParseStackOverflow;
|
| if (!ok) {
|
| - ReportUnexpectedToken(scanner_->current_token());
|
| + ReportUnexpectedToken(scanner()->current_token());
|
| } else if (!scope_->is_classic_mode()) {
|
| - CheckOctalLiteral(start_position, scanner_->location().end_pos, &ok);
|
| + CheckOctalLiteral(start_position, scanner()->location().end_pos, &ok);
|
| }
|
| return kPreParseSuccess;
|
| }
|
| @@ -220,9 +263,9 @@ class PreParser {
|
| // keyword and parameters, and have consumed the initial '{'.
|
| // At return, unless an error occurred, the scanner is positioned before the
|
| // the final '}'.
|
| - PreParseResult PreParseLazyFunction(i::LanguageMode mode,
|
| + PreParseResult PreParseLazyFunction(LanguageMode mode,
|
| bool is_generator,
|
| - i::ParserRecorder* log);
|
| + ParserRecorder* log);
|
|
|
| private:
|
| // These types form an algebra over syntactic categories that is just
|
| @@ -444,7 +487,7 @@ class PreParser {
|
| }
|
|
|
| bool IsStringLiteral() {
|
| - return code_ != kUnknownStatement;
|
| + return code_ == kStringLiteralExpressionStatement;
|
| }
|
|
|
| bool IsUseStrictLiteral() {
|
| @@ -483,7 +526,7 @@ class PreParser {
|
| expected_properties_(0),
|
| with_nesting_count_(0),
|
| language_mode_(
|
| - (prev_ != NULL) ? prev_->language_mode() : i::CLASSIC_MODE),
|
| + (prev_ != NULL) ? prev_->language_mode() : CLASSIC_MODE),
|
| is_generator_(false) {
|
| *variable = this;
|
| }
|
| @@ -497,12 +540,12 @@ class PreParser {
|
| bool is_generator() { return is_generator_; }
|
| void set_is_generator(bool is_generator) { is_generator_ = is_generator; }
|
| 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_;
|
| }
|
| - void set_language_mode(i::LanguageMode language_mode) {
|
| + void set_language_mode(LanguageMode language_mode) {
|
| language_mode_ = language_mode;
|
| }
|
|
|
| @@ -526,15 +569,18 @@ class PreParser {
|
| int materialized_literal_count_;
|
| int expected_properties_;
|
| int with_nesting_count_;
|
| - i::LanguageMode language_mode_;
|
| + LanguageMode language_mode_;
|
| bool is_generator_;
|
| };
|
|
|
| // Report syntax error
|
| - void ReportUnexpectedToken(i::Token::Value token);
|
| - void ReportMessageAt(i::Scanner::Location location,
|
| + void ReportUnexpectedToken(Token::Value token);
|
| + void ReportMessageAt(Scanner::Location location, const char* type) {
|
| + ReportMessageAt(location, type, NULL);
|
| + }
|
| + void ReportMessageAt(Scanner::Location location,
|
| const char* type,
|
| - const char* name_opt = NULL) {
|
| + const char* name_opt) {
|
| log_->LogMessage(location.beg_pos, location.end_pos, type, name_opt);
|
| }
|
| void ReportMessageAt(int start_pos,
|
| @@ -544,8 +590,6 @@ class PreParser {
|
| 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
|
| // which is set to false if parsing failed; it is unchanged otherwise.
|
| // By making the 'exception handling' explicit, we are forced to check
|
| @@ -609,90 +653,40 @@ class PreParser {
|
| // Log the currently parsed string literal.
|
| Expression GetStringSymbol();
|
|
|
| - i::Token::Value peek() {
|
| - if (stack_overflow_) return i::Token::ILLEGAL;
|
| - return scanner_->peek();
|
| - }
|
| -
|
| - i::Token::Value Next() {
|
| - if (stack_overflow_) return i::Token::ILLEGAL;
|
| - {
|
| - int marker;
|
| - if (reinterpret_cast<uintptr_t>(&marker) < stack_limit_) {
|
| - // Further calls to peek/Next will return illegal token.
|
| - // The current one will still be returned. It might already
|
| - // have been seen using peek.
|
| - stack_overflow_ = true;
|
| - }
|
| - }
|
| - return scanner_->Next();
|
| - }
|
| -
|
| - bool peek_any_identifier();
|
| -
|
| - void set_language_mode(i::LanguageMode language_mode) {
|
| + void set_language_mode(LanguageMode language_mode) {
|
| scope_->set_language_mode(language_mode);
|
| }
|
|
|
| bool is_classic_mode() {
|
| - return scope_->language_mode() == i::CLASSIC_MODE;
|
| + return scope_->language_mode() == CLASSIC_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(); }
|
| -
|
| - void Consume(i::Token::Value token) { Next(); }
|
| -
|
| - void Expect(i::Token::Value token, bool* ok) {
|
| - if (Next() != token) {
|
| - *ok = false;
|
| - }
|
| - }
|
| -
|
| - bool Check(i::Token::Value token) {
|
| - i::Token::Value next = peek();
|
| - if (next == token) {
|
| - Consume(next);
|
| - return true;
|
| - }
|
| - return false;
|
| - }
|
| - void ExpectSemicolon(bool* ok);
|
| + LanguageMode language_mode() { return scope_->language_mode(); }
|
|
|
| bool CheckInOrOf(bool accept_OF);
|
|
|
| - static int Precedence(i::Token::Value tok, bool accept_IN);
|
| -
|
| - void SetStrictModeViolation(i::Scanner::Location,
|
| + void SetStrictModeViolation(Scanner::Location,
|
| const char* type,
|
| 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,
|
| Identifier identifier,
|
| bool* ok);
|
|
|
| - i::Scanner* scanner_;
|
| - i::ParserRecorder* log_;
|
| + ParserRecorder* log_;
|
| Scope* scope_;
|
| - uintptr_t stack_limit_;
|
| - i::Scanner::Location strict_mode_violation_location_;
|
| + Scanner::Location strict_mode_violation_location_;
|
| const char* strict_mode_violation_type_;
|
| - bool stack_overflow_;
|
| - bool allow_lazy_;
|
| - bool allow_natives_syntax_;
|
| - bool allow_generators_;
|
| - bool allow_for_of_;
|
| bool parenthesized_function_;
|
| -
|
| - friend class i::ObjectLiteralChecker<PreParser>;
|
| };
|
|
|
| -} } // v8::preparser
|
| +} } // v8::internal
|
|
|
| #endif // V8_PREPARSER_H
|
|
|