Chromium Code Reviews| Index: runtime/vm/parser.cc |
| =================================================================== |
| --- runtime/vm/parser.cc (revision 4300) |
| +++ runtime/vm/parser.cc (working copy) |
| @@ -356,6 +356,7 @@ |
| has_static = false; |
| has_var = false; |
| has_factory = false; |
| + is_operator = false; |
| type = NULL; |
| name_pos = 0; |
| name = NULL; |
| @@ -384,6 +385,7 @@ |
| bool has_static; |
| bool has_var; |
| bool has_factory; |
| + bool is_operator; |
| const AbstractType* type; |
| intptr_t name_pos; |
| String* name; |
| @@ -615,6 +617,7 @@ |
| SequenceNode* Parser::ParseStaticConstGetter(const Function& func) { |
| + TRACE_PARSER("ParseStaticConstGetter"); |
| ParamList params; |
| ASSERT(func.num_fixed_parameters() == 0); // static. |
| ASSERT(func.num_optional_parameters() == 0); |
| @@ -1146,6 +1149,7 @@ |
| AstNode* Parser::ParseSuperFieldAccess(const String& field_name) { |
| + TRACE_PARSER("ParseSuperFieldAccess"); |
| const intptr_t field_pos = token_index_; |
| const Class& super_class = Class::Handle(current_class().SuperClass()); |
| if (super_class.IsNull()) { |
| @@ -1359,6 +1363,7 @@ |
| void Parser::ParseInitializedInstanceFields(const Class& cls, |
| GrowableArray<FieldInitExpression>* initializers) { |
| + TRACE_PARSER("ParseInitializedInstanceFields"); |
| const Array& fields = Array::Handle(cls.fields()); |
| Field& f = Field::Handle(); |
| const intptr_t saved_pos = token_index_; |
| @@ -1426,6 +1431,7 @@ |
| void Parser::ParseConstructorRedirection(const Class& cls, |
| LocalVariable* receiver) { |
| + TRACE_PARSER("ParseConstructorRedirection"); |
| ASSERT(CurrentToken() == Token::kTHIS); |
| const intptr_t call_pos = token_index_; |
| ConsumeToken(); |
| @@ -1519,6 +1525,7 @@ |
| // of function. Parse the formal parameters, initializers and code. |
| SequenceNode* Parser::ParseConstructor(const Function& func, |
| Array& default_parameter_values) { |
| + TRACE_PARSER("ParseConstructor"); |
| ASSERT(func.IsConstructor()); |
| ASSERT(!func.IsFactory()); |
| ASSERT(!func.is_static()); |
| @@ -1770,6 +1777,7 @@ |
| // Parse the formal parameters and code. |
| SequenceNode* Parser::ParseFunc(const Function& func, |
| Array& default_parameter_values) { |
| + TRACE_PARSER("ParseFunc"); |
| if (func.IsConstructor()) { |
| return ParseConstructor(func, default_parameter_values); |
| } |
| @@ -1900,6 +1908,7 @@ |
| void Parser::ParseQualIdent(QualIdent* qual_ident) { |
| + TRACE_PARSER("ParseQualIdent"); |
| ASSERT(IsIdentifier()); |
| ASSERT(!current_class().IsNull()); |
| qual_ident->ident_pos = token_index_; |
| @@ -1935,6 +1944,7 @@ |
| void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) { |
| + TRACE_PARSER("ParseMethodOrConstructor"); |
| ASSERT(CurrentToken() == Token::kLPAREN); |
| intptr_t method_pos = this->token_index_; |
| ASSERT(method->type != NULL); |
| @@ -2145,6 +2155,7 @@ |
| void Parser::ParseFieldDefinition(ClassDesc* members, MemberDesc* field) { |
| + TRACE_PARSER("ParseFieldDefinition"); |
| // The parser has read the first field name and is now at the token |
| // after the field name. |
| ASSERT(CurrentToken() == Token::kSEMICOLON || |
| @@ -2250,7 +2261,34 @@ |
| } |
| +void Parser::CheckOperatorArity(const MemberDesc& member) { |
| + const String& assign_index_name = |
| + String::Handle(String::NewSymbol(Token::Str(Token::kASSIGN_INDEX))); |
| + const String& negate_name = |
| + String::Handle(String::NewSymbol(Token::Str(Token::kNEGATE))); |
| + const String& bit_not_name = |
| + String::Handle(String::NewSymbol(Token::Str(Token::kBIT_NOT))); |
| + intptr_t expected_num_parameters; // Includes receiver. |
| + if (member.name->Equals(assign_index_name)) { |
| + expected_num_parameters = 3; |
| + } else if (member.name->Equals(negate_name) || |
| + member.name->Equals(bit_not_name)) { |
| + expected_num_parameters = 1; |
| + } else { |
| + expected_num_parameters = 2; |
| + } |
| + if ((member.params.num_optional_parameters > 0) || |
| + (member.params.has_named_optional_parameters) || |
| + (member.params.num_fixed_parameters != expected_num_parameters)) { |
| + // Subtract receiver when reporting number of expected arguments. |
| + ErrorMsg(member.name_pos, "operator %s expects %d argument(s)", |
| + member.name->ToCString(), (expected_num_parameters - 1)); |
| + } |
| +} |
| + |
| + |
| void Parser::ParseClassMemberDefinition(ClassDesc* members) { |
| + TRACE_PARSER("ParseClassMemberDefinition"); |
| MemberDesc member; |
| current_member_ = &member; |
| if ((CurrentToken() == Token::kABSTRACT) && |
| @@ -2409,6 +2447,7 @@ |
| ErrorMsg("operator overloading functions cannot be static"); |
| } |
| member.kind = RawFunction::kFunction; |
| + member.is_operator = true; |
| member.name_pos = this->token_index_; |
| member.name = |
| &String::ZoneHandle(String::NewSymbol(Token::Str(CurrentToken()))); |
| @@ -2435,6 +2474,9 @@ |
| member.type = &Type::ZoneHandle(Type::DynamicType()); |
| } |
| ParseMethodOrConstructor(members, &member); |
| + if (member.is_operator) { |
| + CheckOperatorArity(member); |
|
hausner
2012/02/16 17:39:36
Suggestion. I think this is unnecessarily complica
|
| + } |
| } else if (CurrentToken() == Token::kSEMICOLON || |
| CurrentToken() == Token::kCOMMA || |
| CurrentToken() == Token::kASSIGN) { |
| @@ -2866,6 +2908,7 @@ |
| void Parser::ParseTypeParameters(const Class& cls) { |
| + TRACE_PARSER("ParseTypeParameters"); |
| if (CurrentToken() == Token::kLT) { |
| GrowableArray<AbstractType*> type_parameters_array; |
| GrowableArray<AbstractType*> bounds_array; |
| @@ -2915,6 +2958,7 @@ |
| RawAbstractTypeArguments* Parser::ParseTypeArguments( |
| TypeResolution type_resolution) { |
| + TRACE_PARSER("ParseTypeArguments"); |
| if (CurrentToken() == Token::kLT) { |
| GrowableArray<AbstractType*> types; |
| do { |
| @@ -2938,6 +2982,7 @@ |
| // Parse and return an array of interface types. |
| RawArray* Parser::ParseInterfaceList() { |
| + TRACE_PARSER("ParseInterfaceList"); |
| ASSERT((CurrentToken() == Token::kIMPLEMENTS) || |
| (CurrentToken() == Token::kEXTENDS)); |
| GrowableArray<AbstractType*> interfaces; |
| @@ -3005,6 +3050,7 @@ |
| void Parser::ParseTopLevelVariable(TopLevel* top_level) { |
| + TRACE_PARSER("ParseTopLevelVariable"); |
| const bool is_final = (CurrentToken() == Token::kFINAL); |
| const bool is_static = true; |
| const AbstractType& type = AbstractType::ZoneHandle(ParseFinalVarOrType( |
| @@ -3062,6 +3108,7 @@ |
| void Parser::ParseTopLevelFunction(TopLevel* top_level) { |
| + TRACE_PARSER("ParseTopLevelFunction"); |
| AbstractType& result_type = Type::Handle(Type::DynamicType()); |
| const bool is_static = true; |
| if (CurrentToken() == Token::kVOID) { |
| @@ -3125,6 +3172,7 @@ |
| void Parser::ParseTopLevelAccessor(TopLevel* top_level) { |
| + TRACE_PARSER("ParseTopLevelAccessor"); |
| const bool is_static = true; |
| AbstractType& result_type = AbstractType::Handle(); |
| bool is_getter = (CurrentToken() == Token::kGET); |
| @@ -3205,6 +3253,7 @@ |
| void Parser::ParseLibraryName() { |
| + TRACE_PARSER("ParseLibraryName"); |
| if ((script_.kind() == RawScript::kLibrary) && |
| (CurrentToken() != Token::kLIBRARY)) { |
| // Handle error case early to get consistent error message. |
| @@ -3245,6 +3294,7 @@ |
| void Parser::ParseLibraryImport() { |
| + TRACE_PARSER("ParseLibraryImport"); |
| while (CurrentToken() == Token::kIMPORT) { |
| const intptr_t import_pos = token_index_; |
| ConsumeToken(); |
| @@ -3310,6 +3360,7 @@ |
| void Parser::ParseLibraryInclude() { |
| + TRACE_PARSER("ParseLibraryInclude"); |
| const Array& import_map = Array::Handle(library_.import_map()); |
| while (CurrentToken() == Token::kSOURCE) { |
| const intptr_t source_pos = token_index_; |
| @@ -3332,6 +3383,7 @@ |
| void Parser::ParseLibraryDefinition() { |
| + TRACE_PARSER("ParseLibraryDefinition"); |
| // Handle the script tag. |
| if (CurrentToken() == Token::kSCRIPTTAG) { |
| // Nothing to do for script tags except to skip them. |
| @@ -3345,6 +3397,7 @@ |
| void Parser::ParseTopLevel() { |
| + TRACE_PARSER("ParseTopLevel"); |
| // Collect the classes found at the top level in this growable array. |
| // They need to be registered with class finalization after parsing |
| // has been completed. |
| @@ -3526,6 +3579,7 @@ |
| // Builds ReturnNode/NativeBodyNode for a native function. |
| void Parser::ParseNativeFunctionBlock(const ParamList* params, |
| const Function& func) { |
| + TRACE_PARSER("ParseNativeFunctionBlock"); |
| const Class& cls = Class::Handle(func.owner()); |
| const int num_parameters = params->parameters->length(); |
| @@ -3642,6 +3696,7 @@ |
| // The presence of 'final' must be detected and remembered before the call. |
| // If a type is parsed, it is resolved (or not) according to type_resolution. |
| RawAbstractType* Parser::ParseFinalVarOrType(TypeResolution type_resolution) { |
| + TRACE_PARSER("ParseFinalVarOrType"); |
| if (CurrentToken() == Token::kVAR) { |
| ConsumeToken(); |
| return Type::DynamicType(); |
| @@ -4352,6 +4407,7 @@ |
| AstNode* Parser::ParseForInStatement(intptr_t forin_pos, |
| SourceLabel* label) { |
| + TRACE_PARSER("ParseForInStatement"); |
| bool is_final = (CurrentToken() == Token::kFINAL); |
| const String* loop_var_name = NULL; |
| LocalVariable* loop_var = NULL; |
| @@ -4575,6 +4631,7 @@ |
| AstNode* Parser::ParseAssertStatement() { |
| + TRACE_PARSER("ParseAssertStatement"); |
| ConsumeToken(); // Consume assert keyword. |
| ExpectToken(Token::kLPAREN); |
| const intptr_t condition_pos = token_index_; |
| @@ -4657,6 +4714,7 @@ |
| SequenceNode* Parser::ParseFinallyBlock() { |
| + TRACE_PARSER("ParseFinallyBlock"); |
| OpenBlock(); |
| ExpectToken(Token::kLBRACE); |
| ParseStatementSequence(); |
| @@ -4952,6 +5010,7 @@ |
| AstNode* Parser::ParseJump(String* label_name) { |
| + TRACE_PARSER("ParseJump"); |
| ASSERT(CurrentToken() == Token::kBREAK || CurrentToken() == Token::kCONTINUE); |
| Token::Kind jump_kind = CurrentToken(); |
| const intptr_t jump_pos = token_index_; |
| @@ -5809,6 +5868,7 @@ |
| AstNode* Parser::ParseInstanceCall(AstNode* receiver, const String& func_name) { |
| + TRACE_PARSER("ParseInstanceCall"); |
| const intptr_t call_pos = token_index_; |
| if (CurrentToken() != Token::kLPAREN) { |
| ErrorMsg(call_pos, "left parenthesis expected"); |
| @@ -5819,6 +5879,7 @@ |
| AstNode* Parser::ParseClosureCall(AstNode* closure) { |
| + TRACE_PARSER("ParseClosureCall"); |
| const intptr_t call_pos = token_index_; |
| ASSERT(CurrentToken() == Token::kLPAREN); |
| ArgumentListNode* arguments = ParseActualParameters(NULL, kAllowConst); |
| @@ -6654,6 +6715,7 @@ |
| // Parses type = [ident "."] ident ["<" type { "," type } ">"] and resolve it |
| // according to the given type_resolution. |
| RawAbstractType* Parser::ParseType(TypeResolution type_resolution) { |
| + TRACE_PARSER("ParseType"); |
| if (CurrentToken() != Token::kIDENT) { |
| ErrorMsg("type name expected"); |
| } |
| @@ -7046,6 +7108,7 @@ |
| AstNode* Parser::ParseCompoundLiteral() { |
| + TRACE_PARSER("ParseCompoundLiteral"); |
| bool is_const = false; |
| if (CurrentToken() == Token::kCONST) { |
| is_const = true; |
| @@ -7287,6 +7350,7 @@ |
| // a string literal always begins and ends with a kSTRING token, and |
| // there are never two kSTRING tokens next to each other. |
| AstNode* Parser::ParseStringLiteral() { |
| + TRACE_PARSER("ParseStringLiteral"); |
| AstNode* primary = NULL; |
| const intptr_t literal_start = token_index_; |
| if ((CurrentToken() == Token::kSTRING) && |
| @@ -7342,6 +7406,7 @@ |
| // a string literal always begins and ends with a kSTRING token, and |
| // there are never two kSTRING tokens next to each other. |
| String* Parser::ParseImportStringLiteral() { |
| + TRACE_PARSER("ParseImportStringLiteral"); |
| if ((CurrentToken() == Token::kSTRING) && |
| (LookaheadToken(1) != Token::kINTERPOL_VAR) && |
| (LookaheadToken(1) != Token::kINTERPOL_START)) { |