(Pre)Parser: Move ParsePrimaryExpression to ParserBase.
Notes: - To be able to move the recursive descent functions to ParserBase one at a time, we temporarily need routing functions from traits to Parser/PreParser, since the recursive descent functions form a cyclic structure. - PreParser used to always allow intrinsic syntax. After this CL, it depends on allow_natives_syntax() which was already in ParserBase. - This CL also decouples (Pre)ParserTraits better from (Pre)Parser, passing more information as parameters, so that the Traits don't need to get it from (Pre)Parser. R=ulan@chromium.org BUG=v8:3126 LOG=N Review URL: https://codereview.chromium.org/163333003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19374 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
4c2626a0c7
commit
cd50687b41
209
src/parser.cc
209
src/parser.cc
@ -535,7 +535,7 @@ void ParserTraits::ReportMessageAt(Scanner::Location source_location,
|
||||
}
|
||||
|
||||
|
||||
Handle<String> ParserTraits::GetSymbol() {
|
||||
Handle<String> ParserTraits::GetSymbol(Scanner* scanner) {
|
||||
int symbol_id = -1;
|
||||
if (parser_->pre_parse_data() != NULL) {
|
||||
symbol_id = parser_->pre_parse_data()->GetSymbolIdentifier();
|
||||
@ -544,21 +544,99 @@ Handle<String> ParserTraits::GetSymbol() {
|
||||
}
|
||||
|
||||
|
||||
Handle<String> ParserTraits::NextLiteralString(PretenureFlag tenured) {
|
||||
Scanner& scanner = parser_->scanner();
|
||||
if (scanner.is_next_literal_ascii()) {
|
||||
Handle<String> ParserTraits::NextLiteralString(Scanner* scanner,
|
||||
PretenureFlag tenured) {
|
||||
if (scanner->is_next_literal_ascii()) {
|
||||
return parser_->isolate_->factory()->NewStringFromAscii(
|
||||
scanner.next_literal_ascii_string(), tenured);
|
||||
scanner->next_literal_ascii_string(), tenured);
|
||||
} else {
|
||||
return parser_->isolate_->factory()->NewStringFromTwoByte(
|
||||
scanner.next_literal_utf16_string(), tenured);
|
||||
scanner->next_literal_utf16_string(), tenured);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Expression* ParserTraits::ThisExpression(
|
||||
Scope* scope,
|
||||
AstNodeFactory<AstConstructionVisitor>* factory) {
|
||||
return factory->NewVariableProxy(scope->receiver());
|
||||
}
|
||||
|
||||
|
||||
Expression* ParserTraits::ExpressionFromLiteral(
|
||||
Token::Value token, int pos,
|
||||
Scanner* scanner,
|
||||
AstNodeFactory<AstConstructionVisitor>* factory) {
|
||||
Factory* isolate_factory = parser_->isolate()->factory();
|
||||
switch (token) {
|
||||
case Token::NULL_LITERAL:
|
||||
return factory->NewLiteral(isolate_factory->null_value(), pos);
|
||||
case Token::TRUE_LITERAL:
|
||||
return factory->NewLiteral(isolate_factory->true_value(), pos);
|
||||
case Token::FALSE_LITERAL:
|
||||
return factory->NewLiteral(isolate_factory->false_value(), pos);
|
||||
case Token::NUMBER: {
|
||||
ASSERT(scanner->is_literal_ascii());
|
||||
double value = StringToDouble(parser_->isolate()->unicode_cache(),
|
||||
scanner->literal_ascii_string(),
|
||||
ALLOW_HEX | ALLOW_OCTAL |
|
||||
ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY);
|
||||
return factory->NewNumberLiteral(value, pos);
|
||||
}
|
||||
default:
|
||||
ASSERT(false);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
Expression* ParserTraits::ExpressionFromIdentifier(
|
||||
Handle<String> name, int pos, Scope* scope,
|
||||
AstNodeFactory<AstConstructionVisitor>* factory) {
|
||||
if (parser_->fni_ != NULL) parser_->fni_->PushVariableName(name);
|
||||
// The name may refer to a module instance object, so its type is unknown.
|
||||
#ifdef DEBUG
|
||||
if (FLAG_print_interface_details)
|
||||
PrintF("# Variable %s ", name->ToAsciiArray());
|
||||
#endif
|
||||
Interface* interface = Interface::NewUnknown(parser_->zone());
|
||||
return scope->NewUnresolved(factory, name, interface, pos);
|
||||
}
|
||||
|
||||
|
||||
Expression* ParserTraits::ExpressionFromString(
|
||||
int pos, Scanner* scanner,
|
||||
AstNodeFactory<AstConstructionVisitor>* factory) {
|
||||
Handle<String> symbol = GetSymbol(scanner);
|
||||
if (parser_->fni_ != NULL) parser_->fni_->PushLiteralName(symbol);
|
||||
return factory->NewLiteral(symbol, pos);
|
||||
}
|
||||
|
||||
|
||||
Expression* ParserTraits::ParseArrayLiteral(bool* ok) {
|
||||
return parser_->ParseArrayLiteral(ok);
|
||||
}
|
||||
|
||||
|
||||
Expression* ParserTraits::ParseObjectLiteral(bool* ok) {
|
||||
return parser_->ParseObjectLiteral(ok);
|
||||
}
|
||||
|
||||
|
||||
Expression* ParserTraits::ParseExpression(bool accept_IN, bool* ok) {
|
||||
return parser_->ParseExpression(accept_IN, ok);
|
||||
}
|
||||
|
||||
|
||||
Expression* ParserTraits::ParseV8Intrinsic(bool* ok) {
|
||||
return parser_->ParseV8Intrinsic(ok);
|
||||
}
|
||||
|
||||
|
||||
Parser::Parser(CompilationInfo* info)
|
||||
: ParserBase<ParserTraits>(&scanner_,
|
||||
info->isolate()->stack_guard()->real_climit(),
|
||||
info->extension(),
|
||||
this),
|
||||
isolate_(info->isolate()),
|
||||
symbol_cache_(0, info->zone()),
|
||||
@ -567,7 +645,6 @@ Parser::Parser(CompilationInfo* info)
|
||||
reusable_preparser_(NULL),
|
||||
original_scope_(NULL),
|
||||
target_stack_(NULL),
|
||||
extension_(info->extension()),
|
||||
pre_parse_data_(NULL),
|
||||
fni_(NULL),
|
||||
zone_(info->zone()),
|
||||
@ -3430,124 +3507,6 @@ void Parser::ReportInvalidPreparseData(Handle<String> name, bool* ok) {
|
||||
}
|
||||
|
||||
|
||||
Expression* Parser::ParsePrimaryExpression(bool* ok) {
|
||||
// PrimaryExpression ::
|
||||
// 'this'
|
||||
// 'null'
|
||||
// 'true'
|
||||
// 'false'
|
||||
// Identifier
|
||||
// Number
|
||||
// String
|
||||
// ArrayLiteral
|
||||
// ObjectLiteral
|
||||
// RegExpLiteral
|
||||
// '(' Expression ')'
|
||||
|
||||
int pos = peek_position();
|
||||
Expression* result = NULL;
|
||||
switch (peek()) {
|
||||
case Token::THIS: {
|
||||
Consume(Token::THIS);
|
||||
result = factory()->NewVariableProxy(scope_->receiver());
|
||||
break;
|
||||
}
|
||||
|
||||
case Token::NULL_LITERAL:
|
||||
Consume(Token::NULL_LITERAL);
|
||||
result = factory()->NewLiteral(isolate()->factory()->null_value(), pos);
|
||||
break;
|
||||
|
||||
case Token::TRUE_LITERAL:
|
||||
Consume(Token::TRUE_LITERAL);
|
||||
result = factory()->NewLiteral(isolate()->factory()->true_value(), pos);
|
||||
break;
|
||||
|
||||
case Token::FALSE_LITERAL:
|
||||
Consume(Token::FALSE_LITERAL);
|
||||
result = factory()->NewLiteral(isolate()->factory()->false_value(), pos);
|
||||
break;
|
||||
|
||||
case Token::IDENTIFIER:
|
||||
case Token::YIELD:
|
||||
case Token::FUTURE_STRICT_RESERVED_WORD: {
|
||||
// Using eval or arguments in this context is OK even in strict mode.
|
||||
Handle<String> name = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
|
||||
if (fni_ != NULL) fni_->PushVariableName(name);
|
||||
// The name may refer to a module instance object, so its type is unknown.
|
||||
#ifdef DEBUG
|
||||
if (FLAG_print_interface_details)
|
||||
PrintF("# Variable %s ", name->ToAsciiArray());
|
||||
#endif
|
||||
Interface* interface = Interface::NewUnknown(zone());
|
||||
result = scope_->NewUnresolved(factory(), name, interface, pos);
|
||||
break;
|
||||
}
|
||||
|
||||
case Token::NUMBER: {
|
||||
Consume(Token::NUMBER);
|
||||
ASSERT(scanner().is_literal_ascii());
|
||||
double value = StringToDouble(isolate()->unicode_cache(),
|
||||
scanner().literal_ascii_string(),
|
||||
ALLOW_HEX | ALLOW_OCTAL |
|
||||
ALLOW_IMPLICIT_OCTAL | ALLOW_BINARY);
|
||||
result = factory()->NewNumberLiteral(value, pos);
|
||||
break;
|
||||
}
|
||||
|
||||
case Token::STRING: {
|
||||
Consume(Token::STRING);
|
||||
Handle<String> symbol = GetSymbol();
|
||||
result = factory()->NewLiteral(symbol, pos);
|
||||
if (fni_ != NULL) fni_->PushLiteralName(symbol);
|
||||
break;
|
||||
}
|
||||
|
||||
case Token::ASSIGN_DIV:
|
||||
result = ParseRegExpLiteral(true, CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::DIV:
|
||||
result = ParseRegExpLiteral(false, CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::LBRACK:
|
||||
result = ParseArrayLiteral(CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::LBRACE:
|
||||
result = ParseObjectLiteral(CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::LPAREN:
|
||||
Consume(Token::LPAREN);
|
||||
// Heuristically try to detect immediately called functions before
|
||||
// seeing the call parentheses.
|
||||
parenthesized_function_ = (peek() == Token::FUNCTION);
|
||||
result = ParseExpression(true, CHECK_OK);
|
||||
Expect(Token::RPAREN, CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::MOD:
|
||||
if (allow_natives_syntax() || extension_ != NULL) {
|
||||
result = ParseV8Intrinsic(CHECK_OK);
|
||||
break;
|
||||
}
|
||||
// If we're not allowing special syntax we fall-through to the
|
||||
// default case.
|
||||
|
||||
default: {
|
||||
Token::Value tok = Next();
|
||||
ReportUnexpectedToken(tok);
|
||||
*ok = false;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Expression* Parser::ParseArrayLiteral(bool* ok) {
|
||||
// ArrayLiteral ::
|
||||
// '[' Expression? (',' Expression?)* ']'
|
||||
|
24
src/parser.h
24
src/parser.h
@ -463,8 +463,26 @@ class ParserTraits {
|
||||
}
|
||||
|
||||
// Producing data during the recursive descent.
|
||||
Handle<String> GetSymbol();
|
||||
Handle<String> NextLiteralString(PretenureFlag tenured);
|
||||
Handle<String> GetSymbol(Scanner* scanner = NULL);
|
||||
Handle<String> NextLiteralString(Scanner* scanner,
|
||||
PretenureFlag tenured);
|
||||
Expression* ThisExpression(Scope* scope,
|
||||
AstNodeFactory<AstConstructionVisitor>* factory);
|
||||
Expression* ExpressionFromLiteral(
|
||||
Token::Value token, int pos, Scanner* scanner,
|
||||
AstNodeFactory<AstConstructionVisitor>* factory);
|
||||
Expression* ExpressionFromIdentifier(
|
||||
Handle<String> name, int pos, Scope* scope,
|
||||
AstNodeFactory<AstConstructionVisitor>* factory);
|
||||
Expression* ExpressionFromString(
|
||||
int pos, Scanner* scanner,
|
||||
AstNodeFactory<AstConstructionVisitor>* factory);
|
||||
|
||||
// Temporary glue; these functions will move to ParserBase.
|
||||
Expression* ParseArrayLiteral(bool* ok);
|
||||
Expression* ParseObjectLiteral(bool* ok);
|
||||
Expression* ParseExpression(bool accept_IN, bool* ok);
|
||||
Expression* ParseV8Intrinsic(bool* ok);
|
||||
|
||||
private:
|
||||
Parser* parser_;
|
||||
@ -626,7 +644,6 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
Expression* ParseNewPrefix(PositionStack* stack, bool* ok);
|
||||
Expression* ParseMemberWithNewPrefixesExpression(PositionStack* stack,
|
||||
bool* ok);
|
||||
Expression* ParsePrimaryExpression(bool* ok);
|
||||
Expression* ParseArrayLiteral(bool* ok);
|
||||
Expression* ParseObjectLiteral(bool* ok);
|
||||
|
||||
@ -735,7 +752,6 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
PreParser* reusable_preparser_;
|
||||
Scope* original_scope_; // for ES5 function declarations in sloppy eval
|
||||
Target* target_stack_; // for break, continue statements
|
||||
v8::Extension* extension_;
|
||||
ScriptDataImpl* pre_parse_data_;
|
||||
FuncNameInferrer* fni_;
|
||||
|
||||
|
140
src/preparser.cc
140
src/preparser.cc
@ -81,8 +81,7 @@ void PreParserTraits::ReportMessageAt(int start_pos,
|
||||
}
|
||||
|
||||
|
||||
PreParserIdentifier PreParserTraits::GetSymbol() {
|
||||
Scanner* scanner = pre_parser_->scanner();
|
||||
PreParserIdentifier PreParserTraits::GetSymbol(Scanner* scanner) {
|
||||
pre_parser_->LogSymbol();
|
||||
if (scanner->current_token() == Token::FUTURE_RESERVED_WORD) {
|
||||
return PreParserIdentifier::FutureReserved();
|
||||
@ -107,6 +106,42 @@ PreParserIdentifier PreParserTraits::GetSymbol() {
|
||||
}
|
||||
|
||||
|
||||
PreParserExpression PreParserTraits::ExpressionFromString(
|
||||
int pos, Scanner* scanner, PreParserFactory* factory) {
|
||||
const int kUseStrictLength = 10;
|
||||
const char* kUseStrictChars = "use strict";
|
||||
pre_parser_->LogSymbol();
|
||||
if (scanner->is_literal_ascii() &&
|
||||
scanner->literal_length() == kUseStrictLength &&
|
||||
!scanner->literal_contains_escapes() &&
|
||||
!strncmp(scanner->literal_ascii_string().start(), kUseStrictChars,
|
||||
kUseStrictLength)) {
|
||||
return PreParserExpression::UseStrictStringLiteral();
|
||||
}
|
||||
return PreParserExpression::StringLiteral();
|
||||
}
|
||||
|
||||
|
||||
PreParserExpression PreParserTraits::ParseArrayLiteral(bool* ok) {
|
||||
return pre_parser_->ParseArrayLiteral(ok);
|
||||
}
|
||||
|
||||
|
||||
PreParserExpression PreParserTraits::ParseObjectLiteral(bool* ok) {
|
||||
return pre_parser_->ParseObjectLiteral(ok);
|
||||
}
|
||||
|
||||
|
||||
PreParserExpression PreParserTraits::ParseExpression(bool accept_IN, bool* ok) {
|
||||
return pre_parser_->ParseExpression(accept_IN, ok);
|
||||
}
|
||||
|
||||
|
||||
PreParserExpression PreParserTraits::ParseV8Intrinsic(bool* ok) {
|
||||
return pre_parser_->ParseV8Intrinsic(ok);
|
||||
}
|
||||
|
||||
|
||||
PreParser::PreParseResult PreParser::PreParseLazyFunction(
|
||||
LanguageMode mode, bool is_generator, ParserRecorder* log) {
|
||||
log_ = log;
|
||||
@ -1111,90 +1146,6 @@ PreParser::Expression PreParser::ParseMemberWithNewPrefixesExpression(
|
||||
}
|
||||
|
||||
|
||||
PreParser::Expression PreParser::ParsePrimaryExpression(bool* ok) {
|
||||
// PrimaryExpression ::
|
||||
// 'this'
|
||||
// 'null'
|
||||
// 'true'
|
||||
// 'false'
|
||||
// Identifier
|
||||
// Number
|
||||
// String
|
||||
// ArrayLiteral
|
||||
// ObjectLiteral
|
||||
// RegExpLiteral
|
||||
// '(' Expression ')'
|
||||
|
||||
Expression result = Expression::Default();
|
||||
switch (peek()) {
|
||||
case Token::THIS: {
|
||||
Next();
|
||||
result = Expression::This();
|
||||
break;
|
||||
}
|
||||
|
||||
case Token::FUTURE_RESERVED_WORD:
|
||||
case Token::FUTURE_STRICT_RESERVED_WORD:
|
||||
case Token::YIELD:
|
||||
case Token::IDENTIFIER: {
|
||||
// Using eval or arguments in this context is OK even in strict mode.
|
||||
Identifier id = ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
|
||||
result = Expression::FromIdentifier(id);
|
||||
break;
|
||||
}
|
||||
|
||||
case Token::NULL_LITERAL:
|
||||
case Token::TRUE_LITERAL:
|
||||
case Token::FALSE_LITERAL:
|
||||
case Token::NUMBER: {
|
||||
Next();
|
||||
break;
|
||||
}
|
||||
case Token::STRING: {
|
||||
Next();
|
||||
result = GetStringSymbol();
|
||||
break;
|
||||
}
|
||||
|
||||
case Token::ASSIGN_DIV:
|
||||
result = ParseRegExpLiteral(true, CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::DIV:
|
||||
result = ParseRegExpLiteral(false, CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::LBRACK:
|
||||
result = ParseArrayLiteral(CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::LBRACE:
|
||||
result = ParseObjectLiteral(CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::LPAREN:
|
||||
Consume(Token::LPAREN);
|
||||
parenthesized_function_ = (peek() == Token::FUNCTION);
|
||||
result = ParseExpression(true, CHECK_OK);
|
||||
Expect(Token::RPAREN, CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::MOD:
|
||||
result = ParseV8Intrinsic(CHECK_OK);
|
||||
break;
|
||||
|
||||
default: {
|
||||
Token::Value next = Next();
|
||||
ReportUnexpectedToken(next);
|
||||
*ok = false;
|
||||
return Expression::Default();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
PreParser::Expression PreParser::ParseArrayLiteral(bool* ok) {
|
||||
// ArrayLiteral ::
|
||||
// '[' Expression? (',' Expression?)* ']'
|
||||
@ -1266,7 +1217,7 @@ PreParser::Expression PreParser::ParseObjectLiteral(bool* ok) {
|
||||
case Token::STRING:
|
||||
Consume(next);
|
||||
checker.CheckProperty(next, kValueProperty, CHECK_OK);
|
||||
GetStringSymbol();
|
||||
LogSymbol();
|
||||
break;
|
||||
case Token::NUMBER:
|
||||
Consume(next);
|
||||
@ -1475,19 +1426,4 @@ void PreParser::LogSymbol() {
|
||||
}
|
||||
|
||||
|
||||
PreParser::Expression PreParser::GetStringSymbol() {
|
||||
const int kUseStrictLength = 10;
|
||||
const char* kUseStrictChars = "use strict";
|
||||
LogSymbol();
|
||||
if (scanner()->is_literal_ascii() &&
|
||||
scanner()->literal_length() == kUseStrictLength &&
|
||||
!scanner()->literal_contains_escapes() &&
|
||||
!strncmp(scanner()->literal_ascii_string().start(), kUseStrictChars,
|
||||
kUseStrictLength)) {
|
||||
return Expression::UseStrictStringLiteral();
|
||||
}
|
||||
return Expression::StringLiteral();
|
||||
}
|
||||
|
||||
|
||||
} } // v8::internal
|
||||
|
158
src/preparser.h
158
src/preparser.h
@ -32,6 +32,7 @@
|
||||
#include "scopes.h"
|
||||
#include "token.h"
|
||||
#include "scanner.h"
|
||||
#include "v8.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -41,11 +42,13 @@ template <typename Traits>
|
||||
class ParserBase : public Traits {
|
||||
public:
|
||||
ParserBase(Scanner* scanner, uintptr_t stack_limit,
|
||||
v8::Extension* extension,
|
||||
typename Traits::Type::Parser this_object)
|
||||
: Traits(this_object),
|
||||
parenthesized_function_(false),
|
||||
scope_(NULL),
|
||||
function_state_(NULL),
|
||||
extension_(extension),
|
||||
scanner_(scanner),
|
||||
stack_limit_(stack_limit),
|
||||
stack_overflow_(false),
|
||||
@ -329,7 +332,9 @@ class ParserBase : public Traits {
|
||||
bool* ok);
|
||||
|
||||
typename Traits::Type::Expression ParseRegExpLiteral(bool seen_equal,
|
||||
bool* ok);
|
||||
bool* ok);
|
||||
|
||||
typename Traits::Type::Expression ParsePrimaryExpression(bool* ok);
|
||||
|
||||
// Used to detect duplicates in object literals. Each of the values
|
||||
// kGetterProperty, kSetterProperty and kValueProperty represents
|
||||
@ -393,6 +398,7 @@ class ParserBase : public Traits {
|
||||
|
||||
typename Traits::Type::Scope* scope_; // Scope stack.
|
||||
FunctionState* function_state_; // Function state stack.
|
||||
v8::Extension* extension_;
|
||||
|
||||
private:
|
||||
Scanner* scanner_;
|
||||
@ -641,11 +647,39 @@ class PreParserTraits {
|
||||
}
|
||||
|
||||
// Producing data during the recursive descent.
|
||||
PreParserIdentifier GetSymbol();
|
||||
static PreParserIdentifier NextLiteralString(PretenureFlag tenured) {
|
||||
PreParserIdentifier GetSymbol(Scanner* scanner);
|
||||
static PreParserIdentifier NextLiteralString(Scanner* scanner,
|
||||
PretenureFlag tenured) {
|
||||
return PreParserIdentifier::Default();
|
||||
}
|
||||
|
||||
static PreParserExpression ThisExpression(PreParserScope* scope,
|
||||
PreParserFactory* factory) {
|
||||
return PreParserExpression::This();
|
||||
}
|
||||
|
||||
static PreParserExpression ExpressionFromLiteral(
|
||||
Token::Value token, int pos, Scanner* scanner,
|
||||
PreParserFactory* factory) {
|
||||
return PreParserExpression::Default();
|
||||
}
|
||||
|
||||
static PreParserExpression ExpressionFromIdentifier(
|
||||
PreParserIdentifier name, int pos, PreParserScope* scope,
|
||||
PreParserFactory* factory) {
|
||||
return PreParserExpression::FromIdentifier(name);
|
||||
}
|
||||
|
||||
PreParserExpression ExpressionFromString(int pos,
|
||||
Scanner* scanner,
|
||||
PreParserFactory* factory = NULL);
|
||||
|
||||
// Temporary glue; these functions will move to ParserBase.
|
||||
PreParserExpression ParseArrayLiteral(bool* ok);
|
||||
PreParserExpression ParseObjectLiteral(bool* ok);
|
||||
PreParserExpression ParseExpression(bool accept_IN, bool* ok);
|
||||
PreParserExpression ParseV8Intrinsic(bool* ok);
|
||||
|
||||
private:
|
||||
PreParser* pre_parser_;
|
||||
};
|
||||
@ -676,7 +710,7 @@ class PreParser : public ParserBase<PreParserTraits> {
|
||||
PreParser(Scanner* scanner,
|
||||
ParserRecorder* log,
|
||||
uintptr_t stack_limit)
|
||||
: ParserBase<PreParserTraits>(scanner, stack_limit, this),
|
||||
: ParserBase<PreParserTraits>(scanner, stack_limit, NULL, this),
|
||||
log_(log) {}
|
||||
|
||||
// Pre-parse the program from the character stream; returns true on
|
||||
@ -823,7 +857,6 @@ class PreParser : public ParserBase<PreParserTraits> {
|
||||
Expression ParseNewExpression(bool* ok);
|
||||
Expression ParseMemberExpression(bool* ok);
|
||||
Expression ParseMemberWithNewPrefixesExpression(unsigned new_count, bool* ok);
|
||||
Expression ParsePrimaryExpression(bool* ok);
|
||||
Expression ParseArrayLiteral(bool* ok);
|
||||
Expression ParseObjectLiteral(bool* ok);
|
||||
Expression ParseV8Intrinsic(bool* ok);
|
||||
@ -922,7 +955,7 @@ typename Traits::Type::Identifier ParserBase<Traits>::ParseIdentifier(
|
||||
bool* ok) {
|
||||
Token::Value next = Next();
|
||||
if (next == Token::IDENTIFIER) {
|
||||
typename Traits::Type::Identifier name = this->GetSymbol();
|
||||
typename Traits::Type::Identifier name = this->GetSymbol(scanner());
|
||||
if (allow_eval_or_arguments == kDontAllowEvalOrArguments &&
|
||||
!is_classic_mode() && this->IsEvalOrArguments(name)) {
|
||||
ReportMessageAt(scanner()->location(), "strict_eval_arguments");
|
||||
@ -931,7 +964,7 @@ typename Traits::Type::Identifier ParserBase<Traits>::ParseIdentifier(
|
||||
return name;
|
||||
} else if (is_classic_mode() && (next == Token::FUTURE_STRICT_RESERVED_WORD ||
|
||||
(next == Token::YIELD && !is_generator()))) {
|
||||
return this->GetSymbol();
|
||||
return this->GetSymbol(scanner());
|
||||
} else {
|
||||
this->ReportUnexpectedToken(next);
|
||||
*ok = false;
|
||||
@ -955,7 +988,7 @@ typename Traits::Type::Identifier ParserBase<
|
||||
*ok = false;
|
||||
return Traits::EmptyIdentifier();
|
||||
}
|
||||
return this->GetSymbol();
|
||||
return this->GetSymbol(scanner());
|
||||
}
|
||||
|
||||
|
||||
@ -969,7 +1002,7 @@ typename Traits::Type::Identifier ParserBase<Traits>::ParseIdentifierName(
|
||||
*ok = false;
|
||||
return Traits::EmptyIdentifier();
|
||||
}
|
||||
return this->GetSymbol();
|
||||
return this->GetSymbol(scanner());
|
||||
}
|
||||
|
||||
|
||||
@ -1004,7 +1037,7 @@ ParserBase<Traits>::ParseRegExpLiteral(bool seen_equal, bool* ok) {
|
||||
int literal_index = function_state_->NextMaterializedLiteralIndex();
|
||||
|
||||
typename Traits::Type::Identifier js_pattern =
|
||||
this->NextLiteralString(TENURED);
|
||||
this->NextLiteralString(scanner(), TENURED);
|
||||
if (!scanner()->ScanRegExpFlags()) {
|
||||
Next();
|
||||
ReportMessageAt(scanner()->location(), "invalid_regexp_flags");
|
||||
@ -1012,12 +1045,115 @@ ParserBase<Traits>::ParseRegExpLiteral(bool seen_equal, bool* ok) {
|
||||
return Traits::EmptyExpression();
|
||||
}
|
||||
typename Traits::Type::Identifier js_flags =
|
||||
this->NextLiteralString(TENURED);
|
||||
this->NextLiteralString(scanner(), TENURED);
|
||||
Next();
|
||||
return factory()->NewRegExpLiteral(js_pattern, js_flags, literal_index, pos);
|
||||
}
|
||||
|
||||
|
||||
#define CHECK_OK ok); \
|
||||
if (!*ok) return this->EmptyExpression(); \
|
||||
((void)0
|
||||
#define DUMMY ) // to make indentation work
|
||||
#undef DUMMY
|
||||
|
||||
template <class Traits>
|
||||
typename Traits::Type::Expression ParserBase<Traits>::ParsePrimaryExpression(
|
||||
bool* ok) {
|
||||
// PrimaryExpression ::
|
||||
// 'this'
|
||||
// 'null'
|
||||
// 'true'
|
||||
// 'false'
|
||||
// Identifier
|
||||
// Number
|
||||
// String
|
||||
// ArrayLiteral
|
||||
// ObjectLiteral
|
||||
// RegExpLiteral
|
||||
// '(' Expression ')'
|
||||
|
||||
int pos = peek_position();
|
||||
typename Traits::Type::Expression result = this->EmptyExpression();
|
||||
Token::Value token = peek();
|
||||
switch (token) {
|
||||
case Token::THIS: {
|
||||
Consume(Token::THIS);
|
||||
result = this->ThisExpression(scope_, factory());
|
||||
break;
|
||||
}
|
||||
|
||||
case Token::NULL_LITERAL:
|
||||
case Token::TRUE_LITERAL:
|
||||
case Token::FALSE_LITERAL:
|
||||
case Token::NUMBER:
|
||||
Next();
|
||||
result = this->ExpressionFromLiteral(token, pos, scanner(), factory());
|
||||
break;
|
||||
|
||||
case Token::IDENTIFIER:
|
||||
case Token::YIELD:
|
||||
case Token::FUTURE_STRICT_RESERVED_WORD: {
|
||||
// Using eval or arguments in this context is OK even in strict mode.
|
||||
typename Traits::Type::Identifier name =
|
||||
ParseIdentifier(kAllowEvalOrArguments, CHECK_OK);
|
||||
result =
|
||||
this->ExpressionFromIdentifier(name, pos, scope_, factory());
|
||||
break;
|
||||
}
|
||||
|
||||
case Token::STRING: {
|
||||
Consume(Token::STRING);
|
||||
result = this->ExpressionFromString(pos, scanner(), factory());
|
||||
break;
|
||||
}
|
||||
|
||||
case Token::ASSIGN_DIV:
|
||||
result = this->ParseRegExpLiteral(true, CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::DIV:
|
||||
result = this->ParseRegExpLiteral(false, CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::LBRACK:
|
||||
result = this->ParseArrayLiteral(CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::LBRACE:
|
||||
result = this->ParseObjectLiteral(CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::LPAREN:
|
||||
Consume(Token::LPAREN);
|
||||
// Heuristically try to detect immediately called functions before
|
||||
// seeing the call parentheses.
|
||||
parenthesized_function_ = (peek() == Token::FUNCTION);
|
||||
result = this->ParseExpression(true, CHECK_OK);
|
||||
Expect(Token::RPAREN, CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::MOD:
|
||||
if (allow_natives_syntax() || extension_ != NULL) {
|
||||
result = this->ParseV8Intrinsic(CHECK_OK);
|
||||
break;
|
||||
}
|
||||
// If we're not allowing special syntax we fall-through to the
|
||||
// default case.
|
||||
|
||||
default: {
|
||||
Next();
|
||||
ReportUnexpectedToken(token);
|
||||
*ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#undef CHECK_OK
|
||||
|
||||
|
||||
template <typename Traits>
|
||||
void ParserBase<Traits>::ObjectLiteralChecker::CheckProperty(
|
||||
Token::Value property,
|
||||
|
@ -1391,7 +1391,7 @@ void RunParserSyncTest(const char* context_data[][2],
|
||||
|
||||
static const ParserFlag flags[] = {
|
||||
kAllowLazy, kAllowHarmonyScoping, kAllowModules, kAllowGenerators,
|
||||
kAllowForOf
|
||||
kAllowForOf, kAllowNativesSyntax
|
||||
};
|
||||
for (int i = 0; context_data[i][0] != NULL; ++i) {
|
||||
for (int j = 0; statement_data[j] != NULL; ++j) {
|
||||
@ -2046,3 +2046,20 @@ TEST(NoErrorsRegexpLiteral) {
|
||||
|
||||
RunParserSyncTest(context_data, statement_data, kSuccess);
|
||||
}
|
||||
|
||||
|
||||
TEST(Intrinsics) {
|
||||
const char* context_data[][2] = {
|
||||
{"", ""},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
const char* statement_data[] = {
|
||||
"%someintrinsic(arg)",
|
||||
NULL
|
||||
};
|
||||
|
||||
// Parsing will fail or succeed depending on whether we allow natives syntax
|
||||
// or not.
|
||||
RunParserSyncTest(context_data, statement_data, kSuccessOrError);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user