Index: pkg/fasta/lib/src/builder/scope.dart |
diff --git a/pkg/fasta/lib/src/builder/scope.dart b/pkg/fasta/lib/src/builder/scope.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c0d17e6990831bff6d017fb21047fb776a879e0e |
--- /dev/null |
+++ b/pkg/fasta/lib/src/builder/scope.dart |
@@ -0,0 +1,130 @@ |
+// Copyright (c) 2016, 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. |
+ |
+library fasta.scope; |
+ |
+import 'builder.dart' show |
+ Builder, |
+ MixedAccessor; |
+ |
+import '../errors.dart' show |
+ internalError; |
+ |
+class Scope { |
+ final Map<String, Builder> local; |
+ |
+ final Scope parent; |
+ |
+ final bool isModifiable; |
+ |
+ Scope(this.local, this.parent, {this.isModifiable: true}); |
+ |
+ Scope createNestedScope({bool isModifiable: true}) { |
+ return new Scope(<String, Builder>{}, this, isModifiable: isModifiable); |
+ } |
+ |
+ Builder lookup(String name) { |
+ Builder builder = local[name]; |
+ if (builder != null) { |
+ if (builder.next != null) return lookupAmbiguous(name, builder, false); |
+ return builder.isSetter ? new AccessErrorBuilder(builder) : builder; |
+ } else { |
+ return parent?.lookup(name); |
+ } |
+ } |
+ |
+ Builder lookupSetter(String name) { |
+ Builder builder = local[name]; |
+ if (builder != null) { |
+ if (builder.next != null) return lookupAmbiguous(name, builder, true); |
+ if (builder.isField) { |
+ if (builder.isFinal) { |
+ return new AccessErrorBuilder(builder); |
+ } else { |
+ return builder; |
+ } |
+ } else if (builder.isSetter) { |
+ return builder; |
+ } else { |
+ return new AccessErrorBuilder(builder); |
+ } |
+ } else { |
+ return parent?.lookupSetter(name); |
+ } |
+ } |
+ |
+ Builder lookupAmbiguous(String name, Builder builder, bool setter) { |
+ assert(builder.next != null); |
+ if (builder is MixedAccessor) { |
+ return setter ? builder.setter : builder.getter; |
+ } |
+ Builder setterBuilder; |
+ Builder getterBuilder; |
+ Builder current = builder; |
+ while (current != null) { |
+ if (current.isGetter && getterBuilder == null) { |
+ getterBuilder = current; |
+ } else if (current.isSetter && setterBuilder == null) { |
+ setterBuilder = current; |
+ } else { |
+ return new AmbiguousBuilder(builder); |
+ } |
+ current = current.next; |
+ } |
+ assert(getterBuilder != null); |
+ assert(setterBuilder != null); |
+ return setter ? setterBuilder : getterBuilder; |
+ } |
+ |
+ // TODO(ahe): Rename to extend or something. |
+ void operator[]= (String name, Builder member) { |
+ if (isModifiable) { |
+ local[name] = member; |
+ } else { |
+ internalError("Can't extend an unmodifiable scope."); |
+ } |
+ } |
+} |
+ |
+class AccessErrorBuilder extends Builder { |
+ final Builder builder; |
+ |
+ AccessErrorBuilder(this.builder); |
+ |
+ Builder get parent => builder; |
+ |
+ get target => null; |
+ |
+ bool get isFinal => builder.isFinal; |
+ |
+ bool get isField => builder.isField; |
+ |
+ bool get isRegularMethod => builder.isRegularMethod; |
+ |
+ bool get isGetter => !builder.isGetter; |
+ |
+ bool get isSetter => !builder.isSetter; |
+ |
+ bool get isInstanceMember => builder.isInstanceMember; |
+ |
+ bool get isStatic => builder.isStatic; |
+ |
+ bool get isTopLevel => builder.isTopLevel; |
+ |
+ bool get isTypeDeclaration => builder.isTypeDeclaration; |
+ |
+ bool get isLocal => builder.isLocal; |
+ |
+ bool get hasProblem => true; |
+} |
+ |
+class AmbiguousBuilder extends Builder { |
+ final Builder builder; |
+ |
+ AmbiguousBuilder(this.builder); |
+ |
+ get target => null; |
+ |
+ bool get hasProblem => true; |
+} |