| Index: runtime/vm/parser.cc
|
| ===================================================================
|
| --- runtime/vm/parser.cc (revision 3300)
|
| +++ runtime/vm/parser.cc (working copy)
|
| @@ -1,4 +1,4 @@
|
| -// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
| +// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
| // for details. All rights reserved. Use of this source code is governed by a
|
| // BSD-style license that can be found in the LICENSE file.
|
|
|
| @@ -246,9 +246,6 @@
|
| if (token_kind_ == Token::kERROR) {
|
| ErrorMsg(token_index_, CurrentLiteral()->ToCString());
|
| }
|
| - if (Token::IsPseudoKeyword(token_kind_) && !is_top_level_) {
|
| - token_kind_ = Token::kIDENT;
|
| - }
|
| }
|
| CompilerStats::num_token_checks++;
|
| return token_kind_;
|
| @@ -637,7 +634,7 @@
|
| AddFormalParamsToScope(¶ms, current_block_->scope);
|
|
|
| // Static const fields must have an initializer.
|
| - ExpectToken(Token::kIDENT);
|
| + ExpectIdentifier("field name expected");
|
| ExpectToken(Token::kASSIGN);
|
|
|
| // We don't want to use ParseConstExpr() here because we don't want
|
| @@ -677,7 +674,7 @@
|
| LoadLocalNode* load_receiver = new LoadLocalNode(token_index_, *receiver);
|
| // token_index_ is the function's token position which points to the name of
|
| // the field;
|
| - ASSERT(CurrentToken() == Token::kIDENT);
|
| + ASSERT(IsIdentifier());
|
| const String& field_name = *CurrentLiteral();
|
| const Class& field_class = Class::Handle(func.owner());
|
| const Field& field =
|
| @@ -813,7 +810,7 @@
|
| if (parameter.type == NULL) {
|
| // At this point, we must see an identifier for the type or the
|
| // function parameter.
|
| - if (CurrentToken() != Token::kIDENT) {
|
| + if (!IsIdentifier()) {
|
| ErrorMsg("parameter name or type expected");
|
| }
|
| // We have not seen a parameter type yet, so we check if the next
|
| @@ -823,7 +820,7 @@
|
| // We either parse a type or assume that no type is specified.
|
| if ((follower == Token::kLT) || // Parameterized type.
|
| (follower == Token::kPERIOD) || // Qualified class name of type.
|
| - (follower == Token::kIDENT) || // Parameter name following a type.
|
| + Token::IsIdentifier(follower) || // Parameter name following a type.
|
| (follower == Token::kTHIS)) { // Field parameter following a type.
|
| parameter.type = &AbstractType::ZoneHandle(
|
| ParseType(is_top_level_ ? kCanResolve : kMustResolve));
|
| @@ -837,13 +834,11 @@
|
| this_seen = true;
|
| parameter.is_field_initializer = true;
|
| }
|
| +
|
| // At this point, we must see an identifier for the parameter name.
|
| - if (CurrentToken() != Token::kIDENT) {
|
| - ErrorMsg("parameter name expected");
|
| - }
|
| - parameter.name = CurrentLiteral();
|
| parameter.name_pos = token_index_;
|
| - ConsumeToken();
|
| + parameter.name = ExpectIdentifier("parameter name expected");
|
| +
|
| if (parameter.is_field_initializer) {
|
| params->has_field_initializer = true;
|
| }
|
| @@ -1386,7 +1381,7 @@
|
| field ^= fields.At(i);
|
| intptr_t field_pos = field.token_index();
|
| SetPosition(field_pos);
|
| - ASSERT(CurrentToken() == Token::kIDENT);
|
| + ASSERT(IsIdentifier());
|
| ConsumeToken();
|
| ExpectToken(Token::kASSIGN);
|
| AstNode* init_expr = ParseConstExpr();
|
| @@ -1917,7 +1912,7 @@
|
|
|
|
|
| void Parser::ParseQualIdent(QualIdent* qual_ident) {
|
| - ASSERT(CurrentToken() == Token::kIDENT);
|
| + ASSERT(IsIdentifier());
|
| if (!is_top_level_) {
|
| bool is_local_ident = ResolveIdentInLocalScope(token_index_,
|
| *CurrentLiteral(),
|
| @@ -2272,11 +2267,13 @@
|
| void Parser::ParseClassMemberDefinition(ClassDesc* members) {
|
| MemberDesc member;
|
| current_member_ = &member;
|
| - if (CurrentToken() == Token::kABSTRACT) {
|
| + if ((CurrentToken() == Token::kABSTRACT) &&
|
| + (LookaheadToken(1) != Token::kLPAREN)) {
|
| ConsumeToken();
|
| member.has_abstract = true;
|
| }
|
| - if (CurrentToken() == Token::kSTATIC) {
|
| + if ((CurrentToken() == Token::kSTATIC) &&
|
| + (LookaheadToken(1) != Token::kLPAREN)) {
|
| ConsumeToken();
|
| member.has_static = true;
|
| }
|
| @@ -2324,7 +2321,7 @@
|
| (follower == Token::kGET) || // Getter following a type.
|
| (follower == Token::kSET) || // Setter following a type.
|
| (follower == Token::kOPERATOR) || // Operator following a type.
|
| - (follower == Token::kIDENT) || // Member name following a type.
|
| + (Token::IsIdentifier(follower)) || // Member name following a type.
|
| ((follower == Token::kPERIOD) && // Qualified class name of type,
|
| (LookaheadToken(3) != Token::kLPAREN))) { // but not a named constr.
|
| ASSERT(is_top_level_);
|
| @@ -2333,7 +2330,7 @@
|
| }
|
| }
|
| // Optionally parse a (possibly named) constructor name or factory.
|
| - if ((CurrentToken() == Token::kIDENT) &&
|
| + if (IsIdentifier() &&
|
| (CurrentLiteral()->Equals(members->class_name()) || member.has_factory)) {
|
| member.name = CurrentLiteral();
|
| member.name_pos = this->token_index_;
|
| @@ -2403,13 +2400,15 @@
|
| if (CurrentToken() != Token::kLPAREN) {
|
| ErrorMsg("left parenthesis expected");
|
| }
|
| - } else if (CurrentToken() == Token::kGET) {
|
| + } else if ((CurrentToken() == Token::kGET) &&
|
| + (LookaheadToken(1) != Token::kLPAREN) && !member.has_var) {
|
| ConsumeToken();
|
| member.kind = RawFunction::kGetterFunction;
|
| member.name_pos = this->token_index_;
|
| member.name = ExpectIdentifier("identifier expected");
|
| // If the result type was not specified, it will be set to DynamicType.
|
| - } else if (CurrentToken() == Token::kSET) {
|
| + } else if ((CurrentToken() == Token::kSET) &&
|
| + (LookaheadToken(1) != Token::kLPAREN) && !member.has_var) {
|
| ConsumeToken();
|
| member.kind = RawFunction::kSetterFunction;
|
| member.name_pos = this->token_index_;
|
| @@ -2419,7 +2418,8 @@
|
| if (member.type == NULL) {
|
| member.type = &Type::ZoneHandle(Type::DynamicType());
|
| }
|
| - } else if (CurrentToken() == Token::kOPERATOR) {
|
| + } else if ((CurrentToken() == Token::kOPERATOR) &&
|
| + (LookaheadToken(1) != Token::kLPAREN) && !member.has_var) {
|
| ConsumeToken();
|
| if (!Token::CanBeOverloaded(CurrentToken())) {
|
| ErrorMsg("invalid operator overloading");
|
| @@ -2432,7 +2432,7 @@
|
| member.name =
|
| &String::ZoneHandle(String::NewSymbol(Token::Str(CurrentToken())));
|
| ConsumeToken();
|
| - } else if (CurrentToken() == Token::kIDENT) {
|
| + } else if (IsIdentifier()) {
|
| member.name = CurrentLiteral();
|
| member.name_pos = token_index_;
|
| ConsumeToken();
|
| @@ -2482,7 +2482,7 @@
|
| const intptr_t class_pos = token_index_;
|
| ExpectToken(Token::kCLASS);
|
| const intptr_t classname_pos = token_index_;
|
| - String& class_name = *ExpectIdentifier("class name expected");
|
| + String& class_name = *ExpectTypeIdentifier("class name expected");
|
| if (FLAG_trace_parser) {
|
| OS::Print("TopLevel parsing class '%s'\n", class_name.ToCString());
|
| }
|
| @@ -2624,14 +2624,12 @@
|
| // and the alias name of a function type alias.
|
| // Token position remains unchanged.
|
| bool Parser::IsFunctionTypeAliasName() {
|
| - if ((CurrentToken() == Token::kIDENT) &&
|
| - (LookaheadToken(1) == Token::kLPAREN)) {
|
| + if (IsIdentifier() && (LookaheadToken(1) == Token::kLPAREN)) {
|
| return true;
|
| }
|
| const intptr_t saved_pos = token_index_;
|
| bool is_alias_name = false;
|
| - if ((CurrentToken() == Token::kIDENT) &&
|
| - (LookaheadToken(1) == Token::kLT)) {
|
| + if (IsIdentifier() && (LookaheadToken(1) == Token::kLT)) {
|
| ConsumeToken();
|
| if (IsTypeParameter() && (CurrentToken() == Token::kLPAREN)) {
|
| is_alias_name = true;
|
| @@ -2655,12 +2653,9 @@
|
| result_type = ParseType(kDoNotResolve); // No owner class yet.
|
| }
|
|
|
| - if (CurrentToken() != Token::kIDENT) {
|
| - ErrorMsg("function alias name expected");
|
| - }
|
| const intptr_t alias_name_pos = token_index_;
|
| - const String* alias_name = CurrentLiteral();
|
| - ConsumeToken();
|
| + const String* alias_name =
|
| + ExpectTypeIdentifier("function alias name expected");
|
|
|
| // Allocate an interface to hold the type parameters and their 'extends'
|
| // constraints. Make it the owner of the function type descriptor.
|
| @@ -2737,7 +2732,7 @@
|
| const intptr_t interface_pos = token_index_;
|
| ExpectToken(Token::kINTERFACE);
|
| const intptr_t interfacename_pos = token_index_;
|
| - String& interface_name = *ExpectIdentifier("interface name expected");
|
| + String& interface_name = *ExpectTypeIdentifier("interface name expected");
|
| if (FLAG_trace_parser) {
|
| OS::Print("TopLevel parsing interface '%s'\n", interface_name.ToCString());
|
| }
|
| @@ -3280,9 +3275,7 @@
|
| String& prefix = String::Handle();
|
| if (CurrentToken() == Token::kCOMMA) {
|
| ConsumeToken();
|
| - const String& kPrefix = String::Handle(String::NewSymbol("prefix"));
|
| - if ((CurrentToken() != Token::kIDENT) ||
|
| - !kPrefix.Equals(*CurrentLiteral())) {
|
| + if (!IsLiteral("prefix")) {
|
| ErrorMsg("prefix: expected");
|
| }
|
| ConsumeToken();
|
| @@ -3381,7 +3374,8 @@
|
| set_current_class(Class::Handle()); // No current class.
|
| if (CurrentToken() == Token::kCLASS) {
|
| ParseClassDefinition(&classes);
|
| - } else if (CurrentToken() == Token::kTYPEDEF) {
|
| + } else if ((CurrentToken() == Token::kTYPEDEF) &&
|
| + (LookaheadToken(1) != Token::kLPAREN)) {
|
| ParseFunctionTypeAlias(&classes);
|
| } else if (CurrentToken() == Token::kINTERFACE) {
|
| ParseInterfaceDefinition(&classes);
|
| @@ -3618,7 +3612,7 @@
|
| AstNode* Parser::ParseVariableDeclaration(
|
| const AbstractType& type, bool is_final) {
|
| TRACE_PARSER("ParseVariableDeclaration");
|
| - ASSERT(CurrentToken() == Token::kIDENT);
|
| + ASSERT(IsIdentifier());
|
| const intptr_t ident_pos = token_index_;
|
| LocalVariable* variable =
|
| new LocalVariable(ident_pos, *CurrentLiteral(), type);
|
| @@ -3671,7 +3665,7 @@
|
| if (type_specification == kIsOptional) {
|
| return Type::DynamicType();
|
| } else {
|
| - ErrorMsg("identifier expected");
|
| + ErrorMsg("type name expected");
|
| }
|
| }
|
| if (type_specification == kIsOptional) {
|
| @@ -3680,7 +3674,7 @@
|
| // We either parse a type or return now.
|
| if ((follower != Token::kLT) && // Parameterized type.
|
| (follower != Token::kPERIOD) && // Qualified class name of type.
|
| - (follower != Token::kIDENT) && // Variable name following a type.
|
| + !Token::IsIdentifier(follower) && // Variable name following a type.
|
| (follower != Token::kTHIS)) { // Field parameter following a type.
|
| return Type::DynamicType();
|
| }
|
| @@ -3697,7 +3691,7 @@
|
| bool is_final = (CurrentToken() == Token::kFINAL);
|
| const AbstractType& type = AbstractType::ZoneHandle(
|
| ParseFinalVarOrType(kIsMandatory, kMustResolve));
|
| - if (CurrentToken() != Token::kIDENT) {
|
| + if (!IsIdentifier()) {
|
| ErrorMsg("identifier expected");
|
| }
|
|
|
| @@ -3705,7 +3699,7 @@
|
| ASSERT(initializers != NULL);
|
| while (CurrentToken() == Token::kCOMMA) {
|
| ConsumeToken();
|
| - if (CurrentToken() != Token::kIDENT) {
|
| + if (!IsIdentifier()) {
|
| ErrorMsg("identifier expected after comma");
|
| }
|
| // We have a second initializer. Allocate a sequence node now.
|
| @@ -3735,7 +3729,7 @@
|
| result_type = ParseType(kMustResolve);
|
| }
|
| const intptr_t ident_pos = token_index_;
|
| - if (CurrentToken() == Token::kIDENT) {
|
| + if (IsIdentifier()) {
|
| variable_name = CurrentLiteral();
|
| function_name = variable_name;
|
| ConsumeToken();
|
| @@ -3926,6 +3920,12 @@
|
| }
|
|
|
|
|
| +// Returns true if the current token is kIDENT or a pseudo-keyword.
|
| +bool Parser::IsIdentifier() {
|
| + return Token::IsIdentifier(CurrentToken());
|
| +}
|
| +
|
| +
|
| // Returns true if the next tokens can be parsed as a type with optional
|
| // type parameters. Current token position is not restored.
|
| bool Parser::IsOptionalType() {
|
| @@ -3969,12 +3969,13 @@
|
| return true;
|
| }
|
| if (CurrentToken() != Token::kIDENT) {
|
| + // Not a legal type identifier.
|
| return false;
|
| }
|
| const intptr_t saved_pos = token_index_;
|
| bool is_var_decl = false;
|
| if (IsOptionalType()) {
|
| - if (CurrentToken() == Token::kIDENT) {
|
| + if (IsIdentifier()) {
|
| ConsumeToken();
|
| if ((CurrentToken() == Token::kSEMICOLON) ||
|
| (CurrentToken() == Token::kCOMMA) ||
|
| @@ -3998,9 +3999,8 @@
|
| bool Parser::IsTopLevelFunction() {
|
| // Top-level function declarations can omit the return type. Check for
|
| // that case separately.
|
| - return ((CurrentToken() == Token::kIDENT) &&
|
| - (LookaheadToken(1) == Token::kLPAREN)) ||
|
| - IsFunctionDeclaration();
|
| + return (IsIdentifier() &&
|
| + (LookaheadToken(1) == Token::kLPAREN)) || IsFunctionDeclaration();
|
| }
|
|
|
|
|
| @@ -4011,7 +4011,7 @@
|
| const intptr_t saved_pos = token_index_;
|
| if (IsReturnType()) {
|
| if ((CurrentToken() == Token::kGET) || (CurrentToken() == Token::kSET)) {
|
| - if (LookaheadToken(1) == Token::kIDENT) { // Accessor name.
|
| + if (Token::IsIdentifier(LookaheadToken(1))) { // Accessor name.
|
| SetPosition(saved_pos);
|
| return true;
|
| }
|
| @@ -4028,11 +4028,10 @@
|
| }
|
| const intptr_t saved_pos = token_index_;
|
| bool is_function_literal = false;
|
| - if ((CurrentToken() == Token::kIDENT) &&
|
| - (LookaheadToken(1) == Token::kLPAREN)) {
|
| + if (IsIdentifier() && (LookaheadToken(1) == Token::kLPAREN)) {
|
| ConsumeToken(); // Consume function identifier.
|
| } else if (IsReturnType()) {
|
| - if (CurrentToken() != Token::kIDENT) {
|
| + if (!IsIdentifier()) {
|
| SetPosition(saved_pos);
|
| return false;
|
| }
|
| @@ -4059,11 +4058,11 @@
|
| if (CurrentToken() == Token::kVAR || CurrentToken() == Token::kFINAL) {
|
| ConsumeToken();
|
| }
|
| - if (CurrentToken() == Token::kIDENT) {
|
| + if (IsIdentifier()) {
|
| if (LookaheadToken(1) == Token::kIN) {
|
| result = true;
|
| } else if (IsOptionalType()) {
|
| - if (CurrentToken() == Token::kIDENT) {
|
| + if (IsIdentifier()) {
|
| ConsumeToken();
|
| }
|
| result = (CurrentToken() == Token::kIN);
|
| @@ -4214,8 +4213,7 @@
|
| // clause. If we see 'case' or 'default', optionally preceeded by
|
| // a label, or closing brace, we stop parsing statements.
|
| Token::Kind next_token;
|
| - if (CurrentToken() == Token::kIDENT &&
|
| - LookaheadToken(1) == Token::kCOLON) {
|
| + if (IsIdentifier() && LookaheadToken(1) == Token::kCOLON) {
|
| next_token = LookaheadToken(2);
|
| } else {
|
| next_token = CurrentToken();
|
| @@ -4288,8 +4286,7 @@
|
| while (true) {
|
| // Check for statement label
|
| SourceLabel* case_label = NULL;
|
| - if (CurrentToken() == Token::kIDENT &&
|
| - LookaheadToken(1) == Token::kCOLON) {
|
| + if (IsIdentifier() && LookaheadToken(1) == Token::kCOLON) {
|
| // Case statements start with a label.
|
| String* label_name = CurrentLiteral();
|
| const intptr_t label_pos = token_index_;
|
| @@ -4648,12 +4645,8 @@
|
| catch_param->is_final = (CurrentToken() == Token::kFINAL);
|
| catch_param->type = &AbstractType::ZoneHandle(
|
| ParseFinalVarOrType(kIsMandatory, kMustResolve));
|
| - if (CurrentToken() != Token::kIDENT) {
|
| - ErrorMsg("identifier expected");
|
| - }
|
| catch_param->token_index = token_index_;
|
| - catch_param->var = CurrentLiteral();
|
| - ConsumeToken();
|
| + catch_param->var = ExpectIdentifier("identifier expected");
|
| }
|
|
|
|
|
| @@ -4988,7 +4981,7 @@
|
| const intptr_t jump_pos = token_index_;
|
| SourceLabel* target = NULL;
|
| ConsumeToken();
|
| - if (CurrentToken() == Token::kIDENT) {
|
| + if (IsIdentifier()) {
|
| // Explicit label after break/continue.
|
| const String& target_name = *CurrentLiteral();
|
| ConsumeToken();
|
| @@ -5044,12 +5037,22 @@
|
| }
|
|
|
|
|
| +bool Parser::IsDefinedInLexicalScope(const String& ident) {
|
| + if (ResolveIdentInLocalScope(token_index_, ident, NULL)) {
|
| + return true;
|
| + }
|
| + Object& obj = Object::Handle();
|
| + obj = library_.LookupObject(ident);
|
| + return !obj.IsNull();
|
| +}
|
| +
|
| +
|
| AstNode* Parser::ParseStatement() {
|
| TRACE_PARSER("ParseStatement");
|
| AstNode* statement = NULL;
|
| intptr_t label_pos = 0;
|
| String* label_name = NULL;
|
| - if (CurrentToken() == Token::kIDENT) {
|
| + if (IsIdentifier()) {
|
| if (LookaheadToken(1) == Token::kCOLON) {
|
| // Statement starts with a label.
|
| label_name = CurrentLiteral();
|
| @@ -5088,7 +5091,8 @@
|
| ExpectSemicolon();
|
| } else if (CurrentToken() == Token::kIF) {
|
| statement = ParseIfStatement(label_name);
|
| - } else if (CurrentToken() == Token::kASSERT) {
|
| + } else if ((CurrentToken() == Token::kASSERT) &&
|
| + !IsDefinedInLexicalScope(*CurrentLiteral())) {
|
| statement = ParseAssertStatement();
|
| ExpectSemicolon();
|
| } else if (IsVariableDeclaration()) {
|
| @@ -5314,7 +5318,7 @@
|
| }
|
|
|
|
|
| -String* Parser::ExpectIdentifier(const char* msg) {
|
| +String* Parser::ExpectTypeIdentifier(const char* msg) {
|
| if (CurrentToken() != Token::kIDENT) {
|
| ErrorMsg(msg);
|
| }
|
| @@ -5323,12 +5327,21 @@
|
| return ident;
|
| }
|
|
|
| +// Check whether current token is an identifier or a built-in identifier.
|
| +String* Parser::ExpectIdentifier(const char* msg) {
|
| + if (!IsIdentifier()) {
|
| + ErrorMsg(msg);
|
| + }
|
| + String* ident = CurrentLiteral();
|
| + ConsumeToken();
|
| + return ident;
|
| +}
|
|
|
| +
|
| bool Parser::IsLiteral(const char* literal) {
|
| const uint8_t* characters = reinterpret_cast<const uint8_t*>(literal);
|
| intptr_t len = strlen(literal);
|
| - return (CurrentToken() == Token::kIDENT)
|
| - && CurrentLiteral()->Equals(characters, len);
|
| + return IsIdentifier() && CurrentLiteral()->Equals(characters, len);
|
| }
|
|
|
|
|
| @@ -5704,8 +5717,7 @@
|
| ASSERT((CurrentToken() == Token::kLPAREN) ||
|
| (CurrentToken() == Token::kCOMMA));
|
| ConsumeToken();
|
| - if ((CurrentToken() == Token::kIDENT) &&
|
| - (LookaheadToken(1) == Token::kCOLON)) {
|
| + if (IsIdentifier() && (LookaheadToken(1) == Token::kCOLON)) {
|
| named_argument_seen = true;
|
| // The canonicalization of the argument descriptor array built in the
|
| // code generator requires that the names are symbols, i.e.
|
| @@ -7089,7 +7101,7 @@
|
| ASSERT((CurrentToken() == Token::kNEW) || (CurrentToken() == Token::kCONST));
|
| bool is_const = (CurrentToken() == Token::kCONST);
|
| ConsumeToken();
|
| - if (CurrentToken() != Token::kIDENT) {
|
| + if (!IsIdentifier()) {
|
| ErrorMsg("type name expected");
|
| }
|
|
|
| @@ -7350,7 +7362,7 @@
|
| OpenBlock();
|
| primary = ParseFunctionStatement(true);
|
| CloseBlock();
|
| - } else if (CurrentToken() == Token::kIDENT) {
|
| + } else if (IsIdentifier()) {
|
| QualIdent qual_ident;
|
| ParseQualIdent(&qual_ident);
|
| if (qual_ident.is_local_scope_ident) {
|
| @@ -7486,7 +7498,7 @@
|
|
|
|
|
| void Parser::SkipFunctionLiteral() {
|
| - if (CurrentToken() == Token::kIDENT) {
|
| + if (IsIdentifier()) {
|
| if (LookaheadToken(1) != Token::kLPAREN) {
|
| SkipType(true);
|
| }
|
| @@ -7564,7 +7576,7 @@
|
|
|
| void Parser::SkipNewOperator() {
|
| ConsumeToken(); // Skip new or const keyword.
|
| - if (CurrentToken() == Token::kIDENT) {
|
| + if (IsIdentifier()) {
|
| SkipType(false);
|
| if (CurrentToken() == Token::kLPAREN) {
|
| SkipActualParameters();
|
| @@ -7644,8 +7656,12 @@
|
| SkipCompoundLiteral();
|
| break;
|
| default:
|
| - UnexpectedToken();
|
| - UNREACHABLE();
|
| + if (IsIdentifier()) {
|
| + ConsumeToken(); // Handle pseudo-keyword identifiers.
|
| + } else {
|
| + UnexpectedToken();
|
| + UNREACHABLE();
|
| + }
|
| break;
|
| }
|
| }
|
|
|