OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 /// Additional data model classes used by the summary builder. |
| 6 /// |
| 7 /// The summary builder uses 4 pieces of data: |
| 8 /// |
| 9 /// * Unlinked**Builders: builder classes for each piece of output in the |
| 10 /// summary (see format.dart). |
| 11 /// |
| 12 /// * A simplified expression syntax: model relevant pieces of initializers |
| 13 /// and constants before serializing them (see expressions.dart). |
| 14 /// |
| 15 /// * Lazy references: a way to model references on the fly so we can build |
| 16 /// summaries in a single pass. |
| 17 /// |
| 18 /// * Scopes: used to track the current context of the parser, used in great |
| 19 /// part to easily resolve lazy references at the end of the build process. |
| 20 library summary.src.scope; |
| 21 |
| 22 import 'package:analyzer/src/summary/format.dart'; |
| 23 import 'package:analyzer/src/summary/idl.dart'; |
| 24 |
| 25 export 'package:analyzer/src/summary/format.dart'; |
| 26 export 'package:analyzer/src/summary/idl.dart'; |
| 27 export 'package:analyzer/src/summary/api_signature.dart'; |
| 28 export 'expressions.dart'; |
| 29 export 'visitor.dart'; |
| 30 |
| 31 /// A scope corresponding to a scope in the program like units, classes, or |
| 32 /// enums. |
| 33 /// |
| 34 /// It is used to hold results that correspond to a given scope in the program |
| 35 /// and to lazily resolve name references. |
| 36 abstract class Scope { |
| 37 Scope get parent; |
| 38 |
| 39 TopScope get top { |
| 40 var s = this; |
| 41 while (s.parent != null) s = s.parent; |
| 42 return s; |
| 43 } |
| 44 |
| 45 void computeReference(LazyEntityRef ref); |
| 46 } |
| 47 |
| 48 /// Top scope, where the top-level unit is built. |
| 49 class TopScope extends Scope { |
| 50 get parent => null; |
| 51 toString() => "<top-scope>"; |
| 52 |
| 53 /// Results of parsing the unit. |
| 54 final UnlinkedUnitBuilder unit = new UnlinkedUnitBuilder( |
| 55 classes: [], |
| 56 enums: [], |
| 57 executables: [], |
| 58 exports: [], |
| 59 imports: [], |
| 60 parts: [], |
| 61 references: [new UnlinkedReferenceBuilder()], |
| 62 typedefs: [], |
| 63 variables: []); |
| 64 |
| 65 /// Stores publicly visible names exported from the unit. |
| 66 final UnlinkedPublicNamespaceBuilder publicNamespace = |
| 67 new UnlinkedPublicNamespaceBuilder(names: [], exports: [], parts: []); |
| 68 |
| 69 /// Lazy references that need to be expanded after all scope information is |
| 70 /// known. |
| 71 List<LazyEntityRef> _toExpand = []; |
| 72 |
| 73 void expandLazyReferences() { |
| 74 _toExpand.forEach((r) => r.expand()); |
| 75 } |
| 76 |
| 77 TopScope() { |
| 78 unit.publicNamespace = publicNamespace; |
| 79 } |
| 80 |
| 81 final Map<int, Map<String, int>> nameToReference = <int, Map<String, int>>{}; |
| 82 int serializeReference(int prefixIndex, String name) => nameToReference |
| 83 .putIfAbsent(prefixIndex, () => <String, int>{}) |
| 84 .putIfAbsent(name, () { |
| 85 int index = unit.references.length; |
| 86 unit.references.add(new UnlinkedReferenceBuilder( |
| 87 prefixReference: prefixIndex, name: name)); |
| 88 return index; |
| 89 }); |
| 90 |
| 91 void computeReference(LazyEntityRef ref) { |
| 92 ref.reference = serializeReference(null, ref.name); |
| 93 } |
| 94 } |
| 95 |
| 96 class TypeParameterScope extends Scope { |
| 97 final Scope parent; |
| 98 TypeParameterScope(this.parent); |
| 99 |
| 100 List<String> typeParameters = []; |
| 101 |
| 102 void computeReference(LazyEntityRef ref) { |
| 103 var i = typeParameters.indexOf(ref.name); |
| 104 if (i < 0) return parent.computeReference(ref); |
| 105 // Note: there is no indexOffset here because we don't go into functions at |
| 106 // all (so there is no nesting of type-parameter scopes). |
| 107 ref.paramReference = typeParameters.length - i; |
| 108 } |
| 109 } |
| 110 |
| 111 class ClassScope extends TypeParameterScope { |
| 112 String className; |
| 113 UnlinkedClassBuilder currentClass = new UnlinkedClassBuilder(); |
| 114 UnlinkedPublicNameBuilder publicName = new UnlinkedPublicNameBuilder(); |
| 115 Set<String> members = new Set<String>(); |
| 116 toString() => "<class-scope: $className>"; |
| 117 |
| 118 ClassScope(Scope parent) : super(parent); |
| 119 |
| 120 void computeReference(LazyEntityRef ref) { |
| 121 if (!members.contains(ref.name)) { |
| 122 return super.computeReference(ref); |
| 123 } |
| 124 ref.reference = top.serializeReference( |
| 125 top.serializeReference(null, className), ref.name); |
| 126 } |
| 127 } |
| 128 |
| 129 class EnumScope extends Scope { |
| 130 final Scope parent; |
| 131 UnlinkedEnumBuilder currentEnum = new UnlinkedEnumBuilder(); |
| 132 |
| 133 EnumScope(this.parent); |
| 134 |
| 135 void computeReference(LazyEntityRef ref) => throw "unexpected"; |
| 136 } |
| 137 |
| 138 |
| 139 /// A lazily encoded reference. |
| 140 /// |
| 141 /// References in summaries are encoded based on the scope where they appear. |
| 142 /// Most top-level references can be encoded eagerly, but references in the |
| 143 /// scope of a class need to check whether a name is a member of such class. |
| 144 /// Because we don't have such list of members available upfront, we create |
| 145 /// these lazy references and finalize them after we finish going through the |
| 146 /// program. |
| 147 class LazyEntityRef extends EntityRefBuilder { |
| 148 Scope scope; |
| 149 String name; |
| 150 LazyEntityRef(this.name, this.scope) : super() { |
| 151 scope.top._toExpand.add(this); |
| 152 } |
| 153 |
| 154 |
| 155 bool wasExpanded = false; |
| 156 expand() { |
| 157 if (!wasExpanded) { |
| 158 scope.computeReference(this); |
| 159 wasExpanded = true; |
| 160 } |
| 161 } |
| 162 |
| 163 @override |
| 164 int get reference { |
| 165 expand(); |
| 166 return super.reference; |
| 167 } |
| 168 |
| 169 @override |
| 170 int get paramReference { |
| 171 expand(); |
| 172 return super.paramReference; |
| 173 } |
| 174 } |
| 175 |
| 176 /// A nested lazy reference, modeling something like `a.b.c`. |
| 177 class NestedLazyEntityRef extends LazyEntityRef { |
| 178 EntityRef prefix; |
| 179 NestedLazyEntityRef(this.prefix, String name, Scope scope) |
| 180 : super(name, scope.top); |
| 181 |
| 182 @override |
| 183 expand() { |
| 184 if (!wasExpanded) { |
| 185 super.reference = scope.top.serializeReference(prefix.reference, name); |
| 186 wasExpanded = true; |
| 187 } |
| 188 } |
| 189 } |
OLD | NEW |