}
-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();
}
-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()),
reusable_preparser_(NULL),
original_scope_(NULL),
target_stack_(NULL),
- extension_(info->extension()),
pre_parse_data_(NULL),
fni_(NULL),
zone_(info->zone()),
}
-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?)* ']'
}
// 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_;
Expression* ParseNewPrefix(PositionStack* stack, bool* ok);
Expression* ParseMemberWithNewPrefixesExpression(PositionStack* stack,
bool* ok);
- Expression* ParsePrimaryExpression(bool* ok);
Expression* ParseArrayLiteral(bool* ok);
Expression* ParseObjectLiteral(bool* ok);
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_;
}
-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();
}
+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;
}
-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?)* ']'
case Token::STRING:
Consume(next);
checker.CheckProperty(next, kValueProperty, CHECK_OK);
- GetStringSymbol();
+ LogSymbol();
break;
case Token::NUMBER:
Consume(next);
}
-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
#include "scopes.h"
#include "token.h"
#include "scanner.h"
+#include "v8.h"
namespace v8 {
namespace internal {
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),
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
typename Traits::Type::Scope* scope_; // Scope stack.
FunctionState* function_state_; // Function state stack.
+ v8::Extension* extension_;
private:
Scanner* scanner_;
}
// 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_;
};
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
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);
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");
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;
*ok = false;
return Traits::EmptyIdentifier();
}
- return this->GetSymbol();
+ return this->GetSymbol(scanner());
}
*ok = false;
return Traits::EmptyIdentifier();
}
- return this->GetSymbol();
+ return this->GetSymbol(scanner());
}
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");
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,
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) {
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);
+}