Index: pkg/analyzer/lib/src/summary/fasta/model.dart |
diff --git a/pkg/analyzer/lib/src/summary/fasta/model.dart b/pkg/analyzer/lib/src/summary/fasta/model.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..373ad9825c401ae2540cf5d06bcab37d0e4006a5 |
--- /dev/null |
+++ b/pkg/analyzer/lib/src/summary/fasta/model.dart |
@@ -0,0 +1,189 @@ |
+// Copyright (c) 2017, 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. |
+ |
+/// Additional data model classes used by the summary builder. |
+/// |
+/// The summary builder uses 4 pieces of data: |
+/// |
+/// * Unlinked**Builders: builder classes for each piece of output in the |
+/// summary (see format.dart). |
+/// |
+/// * A simplified expression syntax: model relevant pieces of initializers |
+/// and constants before serializing them (see expressions.dart). |
+/// |
+/// * Lazy references: a way to model references on the fly so we can build |
+/// summaries in a single pass. |
+/// |
+/// * Scopes: used to track the current context of the parser, used in great |
+/// part to easily resolve lazy references at the end of the build process. |
+library summary.src.scope; |
+ |
+import 'package:analyzer/src/summary/format.dart'; |
+import 'package:analyzer/src/summary/idl.dart'; |
+ |
+export 'package:analyzer/src/summary/format.dart'; |
+export 'package:analyzer/src/summary/idl.dart'; |
+export 'package:analyzer/src/summary/api_signature.dart'; |
+export 'expressions.dart'; |
+export 'visitor.dart'; |
+ |
+/// A scope corresponding to a scope in the program like units, classes, or |
+/// enums. |
+/// |
+/// It is used to hold results that correspond to a given scope in the program |
+/// and to lazily resolve name references. |
+abstract class Scope { |
+ Scope get parent; |
+ |
+ TopScope get top { |
+ var s = this; |
+ while (s.parent != null) s = s.parent; |
+ return s; |
+ } |
+ |
+ void computeReference(LazyEntityRef ref); |
+} |
+ |
+/// Top scope, where the top-level unit is built. |
+class TopScope extends Scope { |
+ get parent => null; |
+ toString() => "<top-scope>"; |
+ |
+ /// Results of parsing the unit. |
+ final UnlinkedUnitBuilder unit = new UnlinkedUnitBuilder( |
+ classes: [], |
+ enums: [], |
+ executables: [], |
+ exports: [], |
+ imports: [], |
+ parts: [], |
+ references: [new UnlinkedReferenceBuilder()], |
+ typedefs: [], |
+ variables: []); |
+ |
+ /// Stores publicly visible names exported from the unit. |
+ final UnlinkedPublicNamespaceBuilder publicNamespace = |
+ new UnlinkedPublicNamespaceBuilder(names: [], exports: [], parts: []); |
+ |
+ /// Lazy references that need to be expanded after all scope information is |
+ /// known. |
+ List<LazyEntityRef> _toExpand = []; |
+ |
+ void expandLazyReferences() { |
+ _toExpand.forEach((r) => r.expand()); |
+ } |
+ |
+ TopScope() { |
+ unit.publicNamespace = publicNamespace; |
+ } |
+ |
+ final Map<int, Map<String, int>> nameToReference = <int, Map<String, int>>{}; |
+ int serializeReference(int prefixIndex, String name) => nameToReference |
+ .putIfAbsent(prefixIndex, () => <String, int>{}) |
+ .putIfAbsent(name, () { |
+ int index = unit.references.length; |
+ unit.references.add(new UnlinkedReferenceBuilder( |
+ prefixReference: prefixIndex, name: name)); |
+ return index; |
+ }); |
+ |
+ void computeReference(LazyEntityRef ref) { |
+ ref.reference = serializeReference(null, ref.name); |
+ } |
+} |
+ |
+class TypeParameterScope extends Scope { |
+ final Scope parent; |
+ TypeParameterScope(this.parent); |
+ |
+ List<String> typeParameters = []; |
+ |
+ void computeReference(LazyEntityRef ref) { |
+ var i = typeParameters.indexOf(ref.name); |
+ if (i < 0) return parent.computeReference(ref); |
+ // Note: there is no indexOffset here because we don't go into functions at |
+ // all (so there is no nesting of type-parameter scopes). |
+ ref.paramReference = typeParameters.length - i; |
+ } |
+} |
+ |
+class ClassScope extends TypeParameterScope { |
+ String className; |
+ UnlinkedClassBuilder currentClass = new UnlinkedClassBuilder(); |
+ UnlinkedPublicNameBuilder publicName = new UnlinkedPublicNameBuilder(); |
+ Set<String> members = new Set<String>(); |
+ toString() => "<class-scope: $className>"; |
+ |
+ ClassScope(Scope parent) : super(parent); |
+ |
+ void computeReference(LazyEntityRef ref) { |
+ if (!members.contains(ref.name)) { |
+ return super.computeReference(ref); |
+ } |
+ ref.reference = top.serializeReference( |
+ top.serializeReference(null, className), ref.name); |
+ } |
+} |
+ |
+class EnumScope extends Scope { |
+ final Scope parent; |
+ UnlinkedEnumBuilder currentEnum = new UnlinkedEnumBuilder(); |
+ |
+ EnumScope(this.parent); |
+ |
+ void computeReference(LazyEntityRef ref) => throw "unexpected"; |
+} |
+ |
+ |
+/// A lazily encoded reference. |
+/// |
+/// References in summaries are encoded based on the scope where they appear. |
+/// Most top-level references can be encoded eagerly, but references in the |
+/// scope of a class need to check whether a name is a member of such class. |
+/// Because we don't have such list of members available upfront, we create |
+/// these lazy references and finalize them after we finish going through the |
+/// program. |
+class LazyEntityRef extends EntityRefBuilder { |
+ Scope scope; |
+ String name; |
+ LazyEntityRef(this.name, this.scope) : super() { |
+ scope.top._toExpand.add(this); |
+ } |
+ |
+ |
+ bool wasExpanded = false; |
+ expand() { |
+ if (!wasExpanded) { |
+ scope.computeReference(this); |
+ wasExpanded = true; |
+ } |
+ } |
+ |
+ @override |
+ int get reference { |
+ expand(); |
+ return super.reference; |
+ } |
+ |
+ @override |
+ int get paramReference { |
+ expand(); |
+ return super.paramReference; |
+ } |
+} |
+ |
+/// A nested lazy reference, modeling something like `a.b.c`. |
+class NestedLazyEntityRef extends LazyEntityRef { |
+ EntityRef prefix; |
+ NestedLazyEntityRef(this.prefix, String name, Scope scope) |
+ : super(name, scope.top); |
+ |
+ @override |
+ expand() { |
+ if (!wasExpanded) { |
+ super.reference = scope.top.serializeReference(prefix.reference, name); |
+ wasExpanded = true; |
+ } |
+ } |
+} |