Chromium Code Reviews| Index: lib/compiler/implementation/elements/elements.dart |
| diff --git a/lib/compiler/implementation/elements/elements.dart b/lib/compiler/implementation/elements/elements.dart |
| index 03895b2087442c5c6508b957b756e0c79043ea58..7e84bdbe9c93e6dd2ff1989cbe429d778ea21e52 100644 |
| --- a/lib/compiler/implementation/elements/elements.dart |
| +++ b/lib/compiler/implementation/elements/elements.dart |
| @@ -4,6 +4,8 @@ |
| #library('elements'); |
| +#import('dart:uri'); |
| + |
| #import('../tree/tree.dart'); |
| #import('../scanner/scannerlib.dart'); |
| #import('../leg.dart'); // TODO(karlklose): we only need type. |
| @@ -202,11 +204,8 @@ class Element implements Hashable { |
| } |
| CompilationUnitElement getCompilationUnit() { |
|
ahe
2012/08/14 12:45:26
I'm confused about getCompilationUnit and asCompil
|
| - Element element = this; |
| - while (element !== null && !element.isCompilationUnit()) { |
| - element = element.enclosingElement; |
| - } |
| - return element.asCompilationUnit(); |
| + if (isCompilationUnit()) return this; |
| + return enclosingElement.getCompilationUnit(); |
| } |
| LibraryElement getLibrary() { |
| @@ -278,10 +277,44 @@ class Element implements Hashable { |
| } |
| class ContainerElement extends Element { |
| - ContainerElement(name, kind, enclosingElement) : |
| - super(name, kind, enclosingElement); |
| + Link<Element> localMembers = const EmptyLink<Element>(); |
| + |
| + ContainerElement(name, kind, enclosingElement) |
| + : super(name, kind, enclosingElement); |
| + |
| + void addMember(Element element, DiagnosticListener listener) { |
| + localMembers = localMembers.prepend(element); |
| + } |
| +} |
| + |
| +class ScopeContainerElement extends ContainerElement { |
|
ahe
2012/08/14 12:45:26
Nit: Rename to ScopedContainerElement?
|
| + final Map<SourceString, Element> localScope; |
| + |
| + ScopeContainerElement(name, kind, enclosingElement) |
| + : super(name, kind, enclosingElement), |
| + localScope = new Map<SourceString, Element>(); |
| + |
| + void addMember(Element element, DiagnosticListener listener) { |
| + super.addMember(element, listener); |
| + addToScope(element, listener); |
| + } |
| + |
| + void addToScope(Element element, DiagnosticListener listener) { |
| + if (element.isAccessor()) { |
| + addGetterOrSetter(element, localScope[element.name], listener); |
| + } else { |
| + Element existing = localScope.putIfAbsent(element.name, () => element); |
| + if (existing !== element) { |
| + // TODO(ahe): Do something similar to Resolver.reportErrorWithContext. |
| + listener.cancel('duplicate definition', token: element.position()); |
| + listener.cancel('existing definition', token: existing.position()); |
| + } |
| + } |
| + } |
| - abstract void addMember(Element element, DiagnosticListener listener); |
| + Element localLookup(SourceString elementName) { |
| + return localScope[elementName]; |
| + } |
| void addGetterOrSetter(Element element, |
| Element existing, |
| @@ -324,7 +357,6 @@ class ContainerElement extends Element { |
| class CompilationUnitElement extends ContainerElement { |
| final Script script; |
| - Link<Element> topLevelElements = const EmptyLink<Element>(); |
| CompilationUnitElement(Script script, Element enclosing) |
| : this.script = script, |
| @@ -332,25 +364,11 @@ class CompilationUnitElement extends ContainerElement { |
| ElementKind.COMPILATION_UNIT, |
| enclosing); |
| - CompilationUnitElement.library(Script script) |
| - : this.script = script, |
| - super(new SourceString(script.name), ElementKind.LIBRARY, null); |
| - |
| - CompilationUnitElement asCompilationUnit() => this; |
| - |
| void addMember(Element element, DiagnosticListener listener) { |
| - LibraryElement library = enclosingElement; |
| - library.addMember(element, listener); |
| - topLevelElements = topLevelElements.prepend(element); |
| - } |
| - |
| - void define(Element element, DiagnosticListener listener) { |
| - LibraryElement library = enclosingElement; |
| - library.define(element, listener); |
| - } |
| - |
| - void addTag(ScriptTag tag, DiagnosticListener listener) { |
| - listener.cancel("script tags not allowed here", node: tag); |
| + // Keep a list of top level members. |
| + super.addMember(element, listener); |
| + // Provide the member to the library to build scope. |
| + getLibrary().addMember(element, listener); |
| } |
| } |
| @@ -367,21 +385,22 @@ class CompilationUnitOverrideElement extends Element { |
| CompilationUnitElement asCompilationUnit() => compilationUnit; |
| } |
| -class LibraryElement extends CompilationUnitElement { |
| - // TODO(ahe): Library element should not be a subclass of |
| - // CompilationUnitElement. |
| - |
| +class LibraryElement extends ScopeContainerElement { |
| + CompilationUnitElement entryCompilationUnit; |
| Link<CompilationUnitElement> compilationUnits = |
| - const EmptyLink<CompilationUnitElement>(); |
| + const EmptyLink<CompilationUnitElement>(); |
| + |
| Link<ScriptTag> tags = const EmptyLink<ScriptTag>(); |
| ScriptTag libraryTag; |
| - Map<SourceString, Element> elements; |
| bool canUseNative = false; |
| LibraryElement patch = null; |
| LibraryElement(Script script) |
| - : elements = new Map<SourceString, Element>(), |
| - super.library(script); |
| + : super(new SourceString(script.name), ElementKind.LIBRARY, null) { |
| + entryCompilationUnit = new CompilationUnitElement(script, this); |
| + } |
| + |
| + Uri get uri() => entryCompilationUnit.script.uri; |
|
ahe
2012/08/14 12:45:26
Looking at some of the other changes in this CL, t
|
| bool get isPatched() => patch !== null; |
| @@ -393,46 +412,28 @@ class LibraryElement extends CompilationUnitElement { |
| tags = tags.prepend(tag); |
| } |
| - void addMember(Element element, DiagnosticListener listener) { |
| - topLevelElements = topLevelElements.prepend(element); |
| - define(element, listener); |
| - } |
| - |
| - void define(Element element, DiagnosticListener listener) { |
| - if (element.kind == ElementKind.GETTER |
| - || element.kind == ElementKind.SETTER) { |
| - addGetterOrSetter(element, elements[element.name], listener); |
| - } else { |
| - Element existing = elements.putIfAbsent(element.name, () => element); |
| - if (existing !== element) { |
| - // TODO(ahe): Do something similar to Resolver.reportErrorWithContext. |
| - listener.cancel('duplicate definition', token: element.position()); |
| - listener.cancel('existing definition', token: existing.position()); |
| - } |
| - } |
| - } |
| - |
| /** Look up a top-level element in this library. The element could |
| * potentially have been imported from another library. Returns |
| * null if no such element exist. */ |
| Element find(SourceString elementName) { |
| - return elements[elementName]; |
| + return localScope[elementName]; |
| } |
| /** Look up a top-level element in this library, but only look for |
| * non-imported elements. Returns null if no such element exist. */ |
| Element findLocal(SourceString elementName) { |
| - Element result = elements[elementName]; |
| + Element result = localScope[elementName]; |
| if (result === null || result.getLibrary() != this) return null; |
| return result; |
| } |
| void forEachExport(f(Element element)) { |
| - elements.forEach((SourceString _, Element e) { |
| + localScope.forEach((_, Element e) { |
| if (this === e.getLibrary() |
| && e.kind !== ElementKind.PREFIX |
| - && e.kind !== ElementKind.FOREIGN) { |
| - if (!e.name.isPrivate()) f(e); |
| + && e.kind !== ElementKind.FOREIGN |
| + && !e.name.isPrivate()) { |
| + f(e); |
| } |
| }); |
| } |
| @@ -449,11 +450,13 @@ class LibraryElement extends CompilationUnitElement { |
| return libraryTag.argument.dartString.slowToString(); |
| } else { |
| // Use the file name as script name. |
| - var path = script.uri.path; |
| + String path = uri.path; |
| return path.substring(path.lastIndexOf('/') + 1); |
| } |
| } |
| + CompilationUnitElement getCompilationUnit() => entryCompilationUnit; |
| + |
| Scope buildEnclosingScope() => new TopScope(this); |
| } |
| @@ -693,7 +696,8 @@ class AbstractFieldElement extends Element { |
| // |
| // We need to make sure that the position returned is relative to |
| // the compilation unit of the abstract element. |
| - if (getter !== null && getter.enclosingElement === enclosingElement) { |
| + if (getter !== null |
| + && getter.getCompilationUnit() === getCompilationUnit()) { |
| return getter.position(); |
| } else { |
| return setter.position(); |
| @@ -980,7 +984,7 @@ abstract class TypeDeclarationElement implements Element { |
| } |
| } |
| -class ClassElement extends ContainerElement |
| +class ClassElement extends ScopeContainerElement |
| implements TypeDeclarationElement { |
| static final int STATE_NOT_STARTED = 0; |
| static final int STATE_STARTED = 1; |
| @@ -990,9 +994,6 @@ class ClassElement extends ContainerElement |
| InterfaceType type; |
| Type supertype; |
| Type defaultClass; |
| - Link<Element> members = const EmptyLink<Element>(); |
| - Map<SourceString, Element> localMembers; |
| - Map<SourceString, Element> constructors; |
| Link<Type> interfaces; |
| SourceString nativeName; |
| @@ -1019,27 +1020,7 @@ class ClassElement extends ContainerElement |
| Link<Type> allSupertypes; |
| ClassElement(SourceString name, Element enclosing, this.id) |
| - : localMembers = new Map<SourceString, Element>(), |
| - constructors = new Map<SourceString, Element>(), |
| - super(name, ElementKind.CLASS, enclosing); |
| - |
| - void addMember(Element element, DiagnosticListener listener) { |
| - members = members.prepend(element); |
| - if (element.kind == ElementKind.GENERATIVE_CONSTRUCTOR || |
| - element.modifiers.isFactory()) { |
| - constructors[element.name] = element; |
| - } else if (element.kind == ElementKind.GETTER |
| - || element.kind == ElementKind.SETTER) { |
| - addGetterOrSetter(element, localMembers[element.name], listener); |
| - } else { |
| - Element existing = localMembers.putIfAbsent(element.name, () => element); |
| - if (existing !== element) { |
| - // TODO(ahe): Do something similar to Resolver.reportErrorWithContext. |
| - listener.cancel('duplicate definition', token: element.position()); |
| - listener.cancel('existing definition', token: existing.position()); |
| - } |
| - } |
| - } |
| + : super(name, ElementKind.CLASS, enclosing); |
| InterfaceType computeType(compiler) { |
| if (type == null) { |
| @@ -1060,10 +1041,18 @@ class ClassElement extends ContainerElement |
| return this; |
| } |
| + /** |
| + * Lookup local members in the class. This will ignore constructors. |
| + */ |
| Element lookupLocalMember(SourceString memberName) { |
| - return localMembers[memberName]; |
| + var result = localLookup(memberName); |
| + if (result !== null && result.isConstructor()) return null; |
| + return result; |
| } |
| + /** |
| + * Lookup super members for the class. This will ignore constructors. |
|
ahe
2012/08/14 12:45:26
Indent.
|
| + */ |
| Element lookupSuperMember(SourceString memberName) { |
| bool isPrivate = memberName.isPrivate(); |
| for (ClassElement s = superclass; s != null; s = s.superclass) { |
| @@ -1085,7 +1074,7 @@ class ClassElement extends ContainerElement |
| * rules, where library scope comes before superclass scope. |
| */ |
| Element lookupMember(SourceString memberName) { |
| - Element localMember = localMembers[memberName]; |
| + Element localMember = lookupLocalMember(memberName); |
| return localMember === null ? lookupSuperMember(memberName) : localMember; |
| } |
| @@ -1130,9 +1119,26 @@ class ClassElement extends ContainerElement |
| } else { |
| normalizedName = className; |
| } |
| - Element result = constructors[normalizedName]; |
| - if (result === null && noMatch !== null) { |
| - result = noMatch(lookupLocalMember(constructorName)); |
| + Element result = localLookup(normalizedName); |
| + if (result === null || !result.isConstructor()) { |
| + result = noMatch !== null ? noMatch(result) : null; |
| + } |
| + return result; |
| + } |
| + |
| + bool get hasConstructor() { |
|
ahe
2012/08/14 12:45:26
This is an O(n) operation but looks like a simple
|
| + // Search in scope to be sure we search patched constructors. |
| + for (var element in localScope.getValues()) { |
|
ahe
2012/08/14 12:45:26
This should be iterating through a Link-list and u
|
| + if (element.isConstructor()) return true; |
| + } |
| + return false; |
| + } |
| + |
| + Link<Element> get constructors() { |
|
ahe
2012/08/14 12:45:26
Same issue as above: doesn't feel like a getter as
|
| + // TODO(ajohnsen): See if we can avoid this method at some point. |
| + Link<Element> result = const EmptyLink<Element>(); |
| + for (Element member in localMembers) { |
|
ahe
2012/08/14 12:45:26
C-style for-loop, please.
|
| + if (member.isConstructor()) result = result.prepend(member); |
| } |
| return result; |
| } |
| @@ -1161,7 +1167,7 @@ class ClassElement extends ContainerElement |
| do { |
| if (seen.contains(classElement)) return; |
| seen.add(classElement); |
| - for (Element element in classElement.members) { |
| + for (Element element in classElement.localMembers) { |
| f(classElement, element); |
| } |
| if (includeBackendMembers) { |