Chromium Code Reviews| Index: runtime/vm/parser.cc |
| =================================================================== |
| --- runtime/vm/parser.cc (revision 10915) |
| +++ runtime/vm/parser.cc (working copy) |
| @@ -2929,7 +2929,7 @@ |
| OS::Print("TopLevel parsing class '%s'\n", class_name.ToCString()); |
| } |
| Class& cls = Class::Handle(); |
| - Object& obj = Object::Handle(library_.LookupObject(class_name)); |
| + Object& obj = Object::Handle(library_.LookupLocalObject(class_name)); |
| if (obj.IsNull()) { |
| if (is_patch) { |
| ErrorMsg(classname_pos, "missing class '%s' cannot be patched", |
| @@ -3028,7 +3028,7 @@ |
| pending_classes.Add(cls, Heap::kOld); |
| } else { |
| // Lookup the patched class and apply the changes. |
| - obj = library_.LookupObject(class_name); |
| + obj = library_.LookupLocalObject(class_name); |
| const char* err_msg = Class::Cast(obj).ApplyPatch(cls); |
| if (err_msg != NULL) { |
| ErrorMsg(classname_pos, "applying patch failed with '%s'", err_msg); |
| @@ -3203,7 +3203,7 @@ |
| // Lookup alias name and report an error if it is already defined in |
| // the library scope. |
| - const Object& obj = Object::Handle(library_.LookupObject(*alias_name)); |
| + const Object& obj = Object::Handle(library_.LookupLocalObject(*alias_name)); |
| if (!obj.IsNull()) { |
| ErrorMsg(alias_name_pos, |
| "'%s' is already defined", alias_name->ToCString()); |
| @@ -3236,7 +3236,7 @@ |
| OS::Print("TopLevel parsing interface '%s'\n", interface_name.ToCString()); |
| } |
| Class& interface = Class::Handle(); |
| - Object& obj = Object::Handle(library_.LookupObject(interface_name)); |
| + Object& obj = Object::Handle(library_.LookupLocalObject(interface_name)); |
| if (obj.IsNull()) { |
| interface = Class::NewInterface(interface_name, script_, interfacename_pos); |
| library_.AddClass(interface); |
| @@ -3580,16 +3580,16 @@ |
| const intptr_t name_pos = TokenPos(); |
| String& var_name = *ExpectIdentifier("variable name expected"); |
| - if (library_.LookupObject(var_name) != Object::null()) { |
| + if (library_.LookupLocalObject(var_name) != Object::null()) { |
| ErrorMsg(name_pos, "'%s' is already defined", var_name.ToCString()); |
| } |
| String& accessor_name = String::Handle(Field::GetterName(var_name)); |
| - if (library_.LookupObject(accessor_name) != Object::null()) { |
| + if (library_.LookupLocalObject(accessor_name) != Object::null()) { |
| ErrorMsg(name_pos, "getter for '%s' is already defined", |
| var_name.ToCString()); |
| } |
| accessor_name = Field::SetterName(var_name); |
| - if (library_.LookupObject(accessor_name) != Object::null()) { |
| + if (library_.LookupLocalObject(accessor_name) != Object::null()) { |
| ErrorMsg(name_pos, "setter for '%s' is already defined", |
| var_name.ToCString()); |
| } |
| @@ -3669,19 +3669,19 @@ |
| const intptr_t name_pos = TokenPos(); |
| const String& func_name = *ExpectIdentifier("function name expected"); |
| - bool found = library_.LookupObject(func_name) != Object::null(); |
| + bool found = library_.LookupLocalObject(func_name) != Object::null(); |
| if (found && !is_patch) { |
| ErrorMsg(name_pos, "'%s' is already defined", func_name.ToCString()); |
| } else if (!found && is_patch) { |
| ErrorMsg(name_pos, "missing '%s' cannot be patched", func_name.ToCString()); |
| } |
| String& accessor_name = String::Handle(Field::GetterName(func_name)); |
| - if (library_.LookupObject(accessor_name) != Object::null()) { |
| + if (library_.LookupLocalObject(accessor_name) != Object::null()) { |
| ErrorMsg(name_pos, "'%s' is already defined as getter", |
| func_name.ToCString()); |
| } |
| accessor_name = Field::SetterName(func_name); |
| - if (library_.LookupObject(accessor_name) != Object::null()) { |
| + if (library_.LookupLocalObject(accessor_name) != Object::null()) { |
| ErrorMsg(name_pos, "'%s' is already defined as setter", |
| func_name.ToCString()); |
| } |
| @@ -3790,11 +3790,11 @@ |
| is_getter ? "getter" : "setter"); |
| } |
| - if (library_.LookupObject(*field_name) != Object::null()) { |
| + if (library_.LookupLocalObject(*field_name) != Object::null()) { |
| ErrorMsg(name_pos, "'%s' is already defined in this library", |
| field_name->ToCString()); |
| } |
| - bool found = library_.LookupObject(accessor_name) != Object::null(); |
| + bool found = library_.LookupLocalObject(accessor_name) != Object::null(); |
| if (found && !is_patch) { |
| ErrorMsg(name_pos, "%s for '%s' is already defined", |
| is_getter ? "getter" : "setter", |
| @@ -4031,9 +4031,7 @@ |
| (LookaheadToken(1) == Token::kCLASS)) { |
| ConsumeToken(); // Consume and ignore 'abstract'. |
| ParseClassDefinition(pending_classes); |
| - } else if (is_patch_source() && |
| - (CurrentToken() == Token::kIDENT) && |
| - CurrentLiteral()->Equals("patch") && |
| + } else if (is_patch_source() && IsLiteral("patch") && |
| (LookaheadToken(1) == Token::kCLASS)) { |
| ParseClassDefinition(pending_classes); |
| } else { |
| @@ -6241,10 +6239,14 @@ |
| ErrorMsg(msg); |
| } |
| String* ident = CurrentLiteral(); |
| + if (ident->Equals("Dynamic")) { |
| + ErrorMsg("illegal type name '%s'", ident->ToCString()); |
|
regis
2012/08/17 20:23:07
"illegal class name"
hausner
2012/08/17 21:05:52
Re-used the error message defined by the caller, s
|
| + } |
| ConsumeToken(); |
| return ident; |
| } |
| + |
| // Check whether current token is an identifier or a built-in identifier. |
| String* Parser::ExpectIdentifier(const char* msg) { |
| if (!IsIdentifier()) { |
| @@ -7258,13 +7260,18 @@ |
| return; |
| } |
| } |
| - // Global lookup in current library. |
| - resolved_type_class = library_.LookupClass(unresolved_class_name); |
| + // Resolve classname in the scope of the current library. |
| + resolved_type_class = |
| + ResolveClassInCurrentLibraryScope(unresolved_class.token_pos(), |
| + unresolved_class_name); |
| } else { |
| LibraryPrefix& lib_prefix = |
| LibraryPrefix::Handle(unresolved_class.library_prefix()); |
| - // Local lookup in library prefix scope. |
| - resolved_type_class = lib_prefix.LookupLocalClass(unresolved_class_name); |
| + // Resolve class name in the scope of the library prefix. |
| + resolved_type_class = |
| + ResolveClassInPrefixScope(unresolved_class.token_pos(), |
| + lib_prefix, |
| + unresolved_class_name); |
| } |
| // At this point, we can only have a parameterized_type. |
| Type& parameterized_type = Type::Handle(); |
| @@ -7620,99 +7627,198 @@ |
| } |
| -// Do a lookup for the identifier in the library scope of the specified |
| -// library. If resolve_locally is true the lookup does not consider |
| -// the libraries imported by it for the lookup. |
| -AstNode* Parser::ResolveIdentInLibraryScope(const Library& lib, |
| - const QualIdent& qual_ident, |
| - bool resolve_locally) { |
| - TRACE_PARSER("ResolveIdentInLibraryScope"); |
| +static RawObject* LookupNameInLibrary(const Library& lib, const String& name) { |
| Object& obj = Object::Handle(); |
| - if (resolve_locally) { |
| - obj = lib.LookupLocalObject(*qual_ident.ident); |
| - } else { |
| - obj = lib.LookupObject(*qual_ident.ident); |
| + obj = lib.LookupLocalObject(name); |
| + if (!obj.IsNull()) { |
| + return obj.raw(); |
| } |
| + String& accessor_name = String::Handle(Field::GetterName(name)); |
| + obj = lib.LookupLocalObject(accessor_name); |
| + if (!obj.IsNull()) { |
| + return obj.raw(); |
| + } |
| + accessor_name = Field::SetterName(name); |
| + obj = lib.LookupLocalObject(accessor_name); |
| + return obj.raw(); |
| +} |
| + |
| + |
| +// Resolve an name by checking the global scope of the current |
|
regis
2012/08/17 20:23:07
s/an/a/
hausner
2012/08/17 21:05:52
Done.
|
| +// library. If not found in the current library, then look in the scopes |
| +// of all libraries that are imported without a library prefix. |
| +// Issue an error if the name is not found in the global scope |
| +// of the current library, but is defined in more than one imported |
| +// library, i.e. if the name cannot be resolved unambiguously. |
| +RawObject* Parser::ResolveNameInCurrentLibraryScope(intptr_t ident_pos, |
| + const String& name) { |
| + Object& obj = Object::Handle(LookupNameInLibrary(library_, name)); |
| + if (obj.IsNull()) { |
| + // Name is not found in current library. Check scope of all |
| + // imported libraries. |
| + String& first_lib_url = String::Handle(); |
| + Library& lib = Library::Handle(); |
| + intptr_t num_imports = library_.num_imports(); |
| + Object& resolved_obj = Object::Handle(); |
| + for (int i = 0; i < num_imports; i++) { |
| + lib ^= library_.ImportAt(i); |
| + resolved_obj = LookupNameInLibrary(lib, name); |
| + if (!resolved_obj.IsNull()) { |
| + if (!first_lib_url.IsNull()) { |
| + // Found duplicate definition. |
| + ErrorMsg(ident_pos, |
| + "ambiguous reference: " |
| + "'%s' is defined in library '%s' and also in '%s'.", |
|
regis
2012/08/17 20:23:07
We usually do not terminate error messages with a
hausner
2012/08/17 21:05:52
Done.
|
| + name.ToCString(), |
| + first_lib_url.ToCString(), |
| + String::Handle(lib.url()).ToCString()); |
| + } else { |
| + first_lib_url = lib.url(); |
| + obj = resolved_obj.raw(); |
| + } |
| + } |
| + } |
| + } |
| + return obj.raw(); |
| +} |
| + |
| + |
| +RawClass* Parser::ResolveClassInCurrentLibraryScope(intptr_t ident_pos, |
| + const String& name) { |
| + const Object& obj = |
| + Object::Handle(ResolveNameInCurrentLibraryScope(ident_pos, name)); |
| if (obj.IsClass()) { |
| + return Class::Cast(obj).raw(); |
| + } |
| + return Class::null(); |
| +} |
| + |
| + |
| +// Resolve an identifier by checking the global scope of the current |
| +// library. If not found in the current library, then look in the scopes |
| +// of all libraries that are imported without a library prefix. |
| +// Issue an error if the identifier is not found in the global scope |
| +// of the current library, but is defined in more than one imported |
| +// library, i.e. if the identifier cannot be resolved unambiguously. |
| +AstNode* Parser::ResolveIdentInCurrentLibraryScope(intptr_t ident_pos, |
| + const String& ident) { |
| + const Object& obj = |
| + Object::Handle(ResolveNameInCurrentLibraryScope(ident_pos, ident)); |
| + if (obj.IsClass()) { |
| const Class& cls = Class::Cast(obj); |
| - return new PrimaryNode(qual_ident.ident_pos, Class::ZoneHandle(cls.raw())); |
| - } |
| - if (obj.IsField()) { |
| + return new PrimaryNode(ident_pos, Class::ZoneHandle(cls.raw())); |
| + } else if (obj.IsField()) { |
| const Field& field = Field::Cast(obj); |
| ASSERT(field.is_static()); |
| - return GenerateStaticFieldLookup(field, qual_ident.ident_pos); |
| - } |
| - if (obj.IsFunction()) { |
| + return GenerateStaticFieldLookup(field, ident_pos); |
| + } else if (obj.IsFunction()) { |
| const Function& func = Function::Cast(obj); |
| ASSERT(func.is_static()); |
| - return new PrimaryNode(qual_ident.ident_pos, |
| - Function::ZoneHandle(func.raw())); |
| - } else { |
| - ASSERT(obj.IsNull() || obj.IsLibraryPrefix()); |
| - } |
| + if (func.IsGetterFunction() || func.IsSetterFunction()) { |
| + return new StaticGetterNode(ident_pos, |
| + /* receiver */ NULL, |
| + /* is_super_getter */ false, |
| + Class::ZoneHandle(func.Owner()), |
| + ident); |
| - // Check if there is a global getter or setter for qual_ident. |
| - // We create a getter node even if a getter doesn't exist since |
| - // qual_ident could be followed by an assignment which will convert it |
| - // to a setter node. If there is no assignment we will get an error |
| - // when we try to invoke the getter. |
| - String& accessor_name = String::Handle(Field::GetterName(*qual_ident.ident)); |
| - if (resolve_locally) { |
| - obj = lib.LookupLocalObject(accessor_name); |
| - } else { |
| - obj = lib.LookupObject(accessor_name); |
| - } |
| - if (obj.IsNull()) { |
| - accessor_name = Field::SetterName(*qual_ident.ident); |
| - if (resolve_locally) { |
| - obj = lib.LookupLocalObject(accessor_name); |
| } else { |
| - obj = lib.LookupObject(accessor_name); |
| + return new PrimaryNode(ident_pos, Function::ZoneHandle(func.raw())); |
| } |
| + } else { |
| + ASSERT(obj.IsNull() || obj.IsLibraryPrefix()); |
| } |
| - if (!obj.IsNull()) { |
| - ASSERT(obj.IsFunction()); |
| - const Function& func = Function::Cast(obj); |
| - ASSERT(func.is_static()); |
| - ASSERT(AbstractType::Handle(func.result_type()).IsResolved()); |
| - return new StaticGetterNode(qual_ident.ident_pos, |
| - NULL, |
| - false, |
| - Class::ZoneHandle(func.Owner()), |
| - *qual_ident.ident); |
| - } |
| - if (qual_ident.lib_prefix != NULL) { |
| - return NULL; |
| - } |
| // Lexically unresolved primary identifiers are referenced by their name. |
| - return new PrimaryNode(qual_ident.ident_pos, *qual_ident.ident); |
| + return new PrimaryNode(ident_pos, ident); |
| } |
| -// Do a lookup for the identifier in the library prefix scope of the specified |
| -// library prefix. This would mean trying to resolve it locally in any of the |
| -// libraries present in the library prefix. |
| -AstNode* Parser::ResolveIdentInLibraryPrefixScope(const LibraryPrefix& prefix, |
| - const QualIdent& qual_ident) { |
| - TRACE_PARSER("ResolveIdentInLibraryPrefixScope"); |
| +RawObject* Parser::ResolveNameInPrefixScope(intptr_t ident_pos, |
| + const LibraryPrefix& prefix, |
| + const String& name) { |
| Library& lib = Library::Handle(); |
| - AstNode* result = NULL; |
| - for (intptr_t i = 0; ((i < prefix.num_libs()) && (result == NULL)); i++) { |
| + String& first_lib_url = String::Handle(); |
| + Object& obj = Object::Handle(); |
| + Object& resolved_obj = Object::Handle(); |
| + for (intptr_t i = 0; i < prefix.num_libs(); i++) { |
| lib = prefix.GetLibrary(i); |
| ASSERT(!lib.IsNull()); |
| - result = ResolveIdentInLibraryScope(lib, qual_ident, kResolveLocally); |
| + resolved_obj = LookupNameInLibrary(lib, name); |
| + if (!resolved_obj.IsNull()) { |
| + obj = resolved_obj.raw(); |
| + if (first_lib_url.IsNull()) { |
| + first_lib_url = lib.url(); |
| + } else { |
| + ErrorMsg(ident_pos, |
| + "ambiguous reference: '%s.%s' is defined in '%s' and '%s'", |
| + String::Handle(prefix.name()).ToCString(), |
| + name.ToCString(), |
| + first_lib_url.ToCString(), |
| + String::Handle(lib.url()).ToCString()); |
| + } |
| + } |
| } |
| - if (result == NULL) { |
| - // This is an unresolved prefixed primary identifier, need to report |
| - // an error. |
| - ErrorMsg(qual_ident.ident_pos, "identifier '%s.%s' cannot be resolved", |
| - String::Handle(qual_ident.lib_prefix->name()).ToCString(), |
| - qual_ident.ident->ToCString()); |
| + return obj.raw(); |
| +} |
| + |
| + |
| +RawClass* Parser::ResolveClassInPrefixScope(intptr_t ident_pos, |
| + const LibraryPrefix& prefix, |
| + const String& name) { |
| + const Object& obj = |
| + Object::Handle(ResolveNameInPrefixScope(ident_pos, prefix, name)); |
| + if (obj.IsClass()) { |
| + return Class::Cast(obj).raw(); |
| } |
| - return result; |
| + return Class::null(); |
| } |
| +// Do a lookup for the identifier in the scope of the specified |
| +// library prefix. This means trying to resolve it locally in all of the |
| +// libraries present in the library prefix. If there are multiple libraries |
| +// with the name, issue an ambiguous reference error. |
| +AstNode* Parser::ResolveIdentInPrefixScope(intptr_t ident_pos, |
| + const LibraryPrefix& prefix, |
| + const String& ident) { |
| + TRACE_PARSER("ResolveIdentInPrefixScope"); |
|
regis
2012/08/17 20:23:07
No TRACE_PARSER in other calls. On purpose?
hausner
2012/08/17 21:05:52
No on purpose. We have lots of functions that don'
|
| + Object& obj = |
| + Object::Handle(ResolveNameInPrefixScope(ident_pos, prefix, ident)); |
| + if (obj.IsNull()) { |
| + // Unresolved prefixed primary identifier. |
| + ErrorMsg(ident_pos, "identifier '%s.%s' cannot be resolved", |
| + String::Handle(prefix.name()).ToCString(), |
| + ident.ToCString()); |
| + } |
| + if (obj.IsClass()) { |
| + const Class& cls = Class::Cast(obj); |
| + return new PrimaryNode(ident_pos, Class::ZoneHandle(cls.raw())); |
| + } else if (obj.IsField()) { |
| + const Field& field = Field::Cast(obj); |
| + ASSERT(field.is_static()); |
| + return GenerateStaticFieldLookup(field, ident_pos); |
| + } else if (obj.IsFunction()) { |
| + const Function& func = Function::Cast(obj); |
| + ASSERT(func.is_static()); |
| + if (func.IsGetterFunction() || func.IsSetterFunction()) { |
| + return new StaticGetterNode(ident_pos, |
| + /* receiver */ NULL, |
| + /* is_super_getter */ false, |
| + Class::ZoneHandle(func.Owner()), |
| + ident); |
| + |
| + } else { |
| + return new PrimaryNode(ident_pos, Function::ZoneHandle(func.raw())); |
| + } |
| + } else { |
| + // TODO(hausner): Should this be an error? It is not meaningful to |
| + // reference a library prefix defined in an imported library. |
| + ASSERT(obj.IsLibraryPrefix()); |
| + } |
| + // Lexically unresolved primary identifiers are referenced by their name. |
| + return new PrimaryNode(ident_pos, ident); |
| +} |
| + |
| + |
| // Resolve identifier, issue an error message if the name refers to |
| // a class/interface or a type parameter. Issue an error message if |
| // the ident refers to a method and allow_closure_names is false. |
| @@ -7742,14 +7848,8 @@ |
| } |
| // Not found in the local scope, and the name is not a type parameter. |
| // Try finding the variable in the library scope (current library |
| - // and all libraries imported by it). |
| - QualIdent qual_ident; |
| - qual_ident.lib_prefix = NULL; |
| - qual_ident.ident_pos = ident_pos; |
| - qual_ident.ident = &(String::ZoneHandle(ident.raw())); |
| - resolved = ResolveIdentInLibraryScope(library_, |
| - qual_ident, |
| - kResolveIncludingImports); |
| + // and all libraries imported by it without a library prefix). |
| + resolved = ResolveIdentInCurrentLibraryScope(ident_pos, ident); |
| } |
| if (resolved->IsPrimaryNode()) { |
| PrimaryNode* primary = resolved->AsPrimaryNode(); |
| @@ -8707,16 +8807,16 @@ |
| // This is a non-local unqualified identifier so resolve the |
| // identifier locally in the main app library and all libraries |
| // imported by it. |
| - primary = ResolveIdentInLibraryScope(library_, |
| - qual_ident, |
| - kResolveIncludingImports); |
| + primary = ResolveIdentInCurrentLibraryScope(qual_ident.ident_pos, |
| + *qual_ident.ident); |
| } |
| } else { |
| // This is a qualified identifier with a library prefix so resolve |
| // the identifier locally in that library (we do not include the |
| // libraries imported by that library). |
| - primary = ResolveIdentInLibraryPrefixScope(*(qual_ident.lib_prefix), |
| - qual_ident); |
| + primary = ResolveIdentInPrefixScope(qual_ident.ident_pos, |
| + *qual_ident.lib_prefix, |
| + *qual_ident.ident); |
|
regis
2012/08/17 20:23:07
indentation
hausner
2012/08/17 21:05:52
Done.
|
| } |
| ASSERT(primary != NULL); |
| } else if (CurrentToken() == Token::kTHIS) { |