blob: 81eadaebbfd52814cf78aa4811fd73e8ee023b46 [file] [log] [blame]
// 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.
part of resolution;
abstract class Scope {
/**
* Adds [element] to this scope. This operation is only allowed on mutable
* scopes such as [MethodScope] and [BlockScope].
*/
Element add(Element element);
/**
* Looks up the [Element] for [name] in this scope.
*/
Element lookup(SourceString name);
static Scope buildEnclosingScope(Element element) {
return element.enclosingElement != null
? element.enclosingElement.buildScope() : element.buildScope();
}
}
abstract class NestedScope extends Scope {
final Scope parent;
NestedScope(this.parent);
Element lookup(SourceString name) {
Element result = localLookup(name);
if (result != null) return result;
return parent.lookup(name);
}
Element localLookup(SourceString name);
static Scope buildEnclosingScope(Element element) {
return element.enclosingElement != null
? element.enclosingElement.buildScope() : element.buildScope();
}
}
class VariableDefinitionScope extends NestedScope {
final SourceString variableName;
bool variableReferencedInInitializer = false;
VariableDefinitionScope(Scope parent, this.variableName) : super(parent);
Element localLookup(SourceString name) {
if (name == variableName) {
variableReferencedInInitializer = true;
}
return null;
}
Element add(Element newElement) {
throw "Cannot add element to VariableDefinitionScope";
}
}
/**
* [TypeDeclarationScope] defines the outer scope of a type declaration in
* which the declared type variables and the entities in the enclosing scope are
* available but where declared and inherited members are not available. This
* scope is only used for class declarations during resolution of the
* class hierarchy. In all other cases [ClassScope] is used.
*/
class TypeDeclarationScope extends NestedScope {
final TypeDeclarationElement element;
TypeDeclarationScope(parent, this.element)
: super(parent) {
assert(parent != null);
}
Element add(Element newElement) {
throw "Cannot add element to TypeDeclarationScope";
}
Element lookupTypeVariable(SourceString name) {
Link<DartType> typeVariableLink = element.typeVariables;
while (!typeVariableLink.isEmpty) {
TypeVariableType typeVariable = typeVariableLink.head;
if (typeVariable.name == name) {
return typeVariable.element;
}
typeVariableLink = typeVariableLink.tail;
}
return null;
}
Element localLookup(SourceString name) => lookupTypeVariable(name);
String toString() =>
'TypeDeclarationScope($element)';
}
abstract class MutableScope extends NestedScope {
final Map<SourceString, Element> elements;
MutableScope(Scope parent)
: super(parent),
this.elements = new Map<SourceString, Element>() {
assert(parent != null);
}
Element add(Element newElement) {
if (elements.containsKey(newElement.name)) {
return elements[newElement.name];
}
elements[newElement.name] = newElement;
return newElement;
}
Element localLookup(SourceString name) => elements[name];
}
class MethodScope extends MutableScope {
final Element element;
MethodScope(Scope parent, this.element)
: super(parent);
String toString() => 'MethodScope($element${elements.keys.toList()})';
}
class BlockScope extends MutableScope {
BlockScope(Scope parent) : super(parent);
String toString() => 'BlockScope(${elements.keys.toList()})';
}
/**
* [ClassScope] defines the inner scope of a class/interface declaration in
* which declared members, declared type variables, entities in the enclosing
* scope and inherited members are available, in the given order.
*/
class ClassScope extends TypeDeclarationScope {
ClassElement get element => super.element;
ClassScope(Scope parentScope, ClassElement element)
: super(parentScope, element) {
assert(parent != null);
}
Element localLookup(SourceString name) {
Element result = element.lookupLocalMember(name);
if (result != null) return result;
return super.localLookup(name);
}
Element lookup(SourceString name) {
Element result = localLookup(name);
if (result != null) return result;
result = parent.lookup(name);
if (result != null) return result;
return element.lookupSuperMember(name);
}
Element add(Element newElement) {
throw "Cannot add an element in a class scope";
}
String toString() => 'ClassScope($element)';
}
class LibraryScope implements Scope {
final LibraryElement library;
LibraryScope(LibraryElement this.library);
Element localLookup(SourceString name) => library.find(name);
Element lookup(SourceString name) => localLookup(name);
Element add(Element newElement) {
throw "Cannot add an element to a library scope";
}
String toString() => 'LibraryScope($library)';
}