Chromium Code Reviews| Index: runtime/vm/parser.cc |
| =================================================================== |
| --- runtime/vm/parser.cc (revision 3272) |
| +++ 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)) { |
| 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)) { |
| 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)) { |
| 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()); |
| } |
| @@ -3288,9 +3283,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(); |
| @@ -3389,7 +3382,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); |
| @@ -3626,7 +3620,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); |
| @@ -3679,7 +3673,7 @@ |
| if (type_specification == kIsOptional) { |
| return Type::DynamicType(); |
| } else { |
| - ErrorMsg("identifier expected"); |
| + ErrorMsg("type name expected"); |
| } |
| } |
| if (type_specification == kIsOptional) { |
| @@ -3688,7 +3682,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(); |
| } |
| @@ -3705,7 +3699,7 @@ |
| bool is_final = (CurrentToken() == Token::kFINAL); |
| const AbstractType& type = AbstractType::ZoneHandle( |
| ParseFinalVarOrType(kIsMandatory, kMustResolve)); |
| - if (CurrentToken() != Token::kIDENT) { |
| + if (!IsIdentifier()) { |
| ErrorMsg("identifier expected"); |
| } |
| @@ -3713,7 +3707,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. |
| @@ -3743,7 +3737,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(); |
| @@ -3936,6 +3930,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() { |
| @@ -3979,12 +3979,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) || |
| @@ -4008,9 +4009,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(); |
| } |
| @@ -4021,7 +4021,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; |
| } |
| @@ -4038,11 +4038,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; |
| } |
| @@ -4069,11 +4068,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); |
| @@ -4224,8 +4223,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(); |
| @@ -4298,8 +4296,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_; |
| @@ -4658,12 +4655,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"); |
| } |
| @@ -4998,7 +4991,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(); |
| @@ -5054,12 +5047,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(); |
| @@ -5098,7 +5101,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()) { |
| @@ -5324,7 +5328,7 @@ |
| } |
| -String* Parser::ExpectIdentifier(const char* msg) { |
| +String* Parser::ExpectTypeIdentifier(const char* msg) { |
| if (CurrentToken() != Token::kIDENT) { |
| ErrorMsg(msg); |
| } |
| @@ -5333,12 +5337,22 @@ |
| return ident; |
| } |
| +// Check whether current token is an identifier or a built-in identifier. |
| +String* Parser::ExpectIdentifier(const char* msg) { |
| + if (CurrentToken() != Token::kIDENT && |
| + !Token::IsPseudoKeyword(CurrentToken())) { |
|
siva
2012/01/13 18:48:20
Why not
if (!IsIdentifier()) {
ErrorMsg(msg);
}
hausner
2012/01/13 19:22:47
Excellent idea. I introduced IsIdentifier after I
|
| + 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); |
| } |
| @@ -5716,8 +5730,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. |
| @@ -7101,7 +7114,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"); |
| } |
| @@ -7362,7 +7375,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) { |
| @@ -7498,7 +7511,7 @@ |
| void Parser::SkipFunctionLiteral() { |
| - if (CurrentToken() == Token::kIDENT) { |
| + if (IsIdentifier()) { |
| if (LookaheadToken(1) != Token::kLPAREN) { |
| SkipType(true); |
| } |
| @@ -7576,7 +7589,7 @@ |
| void Parser::SkipNewOperator() { |
| ConsumeToken(); // Skip new or const keyword. |
| - if (CurrentToken() == Token::kIDENT) { |
| + if (IsIdentifier()) { |
| SkipType(false); |
| if (CurrentToken() == Token::kLPAREN) { |
| SkipActualParameters(); |
| @@ -7656,8 +7669,12 @@ |
| SkipCompoundLiteral(); |
| break; |
| default: |
| - UnexpectedToken(); |
| - UNREACHABLE(); |
| + if (IsIdentifier()) { |
| + ConsumeToken(); // Handle pseudo-keyword identifiers. |
| + } else { |
| + UnexpectedToken(); |
| + UNREACHABLE(); |
| + } |
| break; |
| } |
| } |