| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2016, 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 library fasta.source_loader; |
| 6 |
| 7 import 'dart:async' show |
| 8 Future; |
| 9 |
| 10 import 'dart:io' show |
| 11 FileSystemException; |
| 12 |
| 13 import 'package:dart_scanner/io.dart' show |
| 14 readBytesFromFile; |
| 15 |
| 16 import 'package:dart_scanner/src/token.dart' show |
| 17 Token; |
| 18 |
| 19 import 'package:dart_scanner/dart_scanner.dart' show |
| 20 scan; |
| 21 |
| 22 import 'package:dart_parser/src/class_member_parser.dart' show |
| 23 ClassMemberParser; |
| 24 |
| 25 import 'package:kernel/ast.dart' show |
| 26 Program; |
| 27 |
| 28 import 'package:kernel/class_hierarchy.dart' show |
| 29 ClassHierarchy; |
| 30 |
| 31 import 'package:kernel/core_types.dart' show |
| 32 CoreTypes; |
| 33 |
| 34 import '../errors.dart' show |
| 35 inputError; |
| 36 |
| 37 import '../export.dart' show |
| 38 Export; |
| 39 |
| 40 import '../analyzer/element_store.dart' show |
| 41 ElementStore; |
| 42 |
| 43 import '../builder/builder.dart' show |
| 44 Builder, |
| 45 ClassBuilder, |
| 46 LibraryBuilder; |
| 47 |
| 48 import 'outline_builder.dart' show |
| 49 OutlineBuilder; |
| 50 |
| 51 import '../loader.dart' show |
| 52 Loader; |
| 53 |
| 54 import '../target_implementation.dart' show |
| 55 TargetImplementation; |
| 56 |
| 57 import 'diet_listener.dart' show |
| 58 DietListener; |
| 59 |
| 60 import 'diet_parser.dart' show |
| 61 DietParser; |
| 62 |
| 63 import 'source_library_builder.dart' show |
| 64 SourceLibraryBuilder; |
| 65 |
| 66 import '../ast_kind.dart' show |
| 67 AstKind; |
| 68 |
| 69 class SourceLoader<L> extends Loader<L> { |
| 70 // Used when building directly to kernel. |
| 71 ClassHierarchy hierarchy; |
| 72 CoreTypes coreTypes; |
| 73 |
| 74 // Used when building analyzer ASTs. |
| 75 ElementStore elementStore; |
| 76 |
| 77 SourceLoader(TargetImplementation target) |
| 78 : super(target); |
| 79 |
| 80 Future<Token> tokenize(SourceLibraryBuilder library) async { |
| 81 Uri uri = library.uri; |
| 82 if (uri.scheme != "file") { |
| 83 uri = target.translateUri(uri); |
| 84 if (uri == null) { |
| 85 print("Skipping ${library.uri}"); |
| 86 return null; |
| 87 } |
| 88 library.fileUri = uri; |
| 89 } |
| 90 try { |
| 91 List<int> bytes = await readBytesFromFile(uri); |
| 92 byteCount += bytes.length - 1; |
| 93 return scan(bytes).tokens; |
| 94 } on FileSystemException catch (e) { |
| 95 String message = e.message; |
| 96 String osMessage = e.osError?.message; |
| 97 if (osMessage != null && osMessage.isNotEmpty) { |
| 98 message = osMessage; |
| 99 } |
| 100 return inputError(uri, -1, message); |
| 101 } |
| 102 } |
| 103 |
| 104 Future<Null> buildOutline(SourceLibraryBuilder library) async { |
| 105 Token tokens = await tokenize(library); |
| 106 if (tokens == null) return; |
| 107 OutlineBuilder listener = new OutlineBuilder(library); |
| 108 new ClassMemberParser(listener).parseUnit(tokens); |
| 109 } |
| 110 |
| 111 Future<Null> buildBody(LibraryBuilder library, AstKind astKind) async { |
| 112 if (library is SourceLibraryBuilder) { |
| 113 Token tokens = await tokenize(library); |
| 114 if (tokens == null) return; |
| 115 DietListener listener = new DietListener( |
| 116 library, elementStore, hierarchy, coreTypes, astKind); |
| 117 DietParser parser = new DietParser(listener); |
| 118 parser.parseUnit(tokens); |
| 119 for (SourceLibraryBuilder part in library.parts) { |
| 120 Token tokens = await tokenize(part); |
| 121 if (tokens != null) { |
| 122 parser.parseUnit(tokens); |
| 123 } |
| 124 } |
| 125 } |
| 126 } |
| 127 |
| 128 void resolveParts() { |
| 129 List<Uri> parts = <Uri>[]; |
| 130 builders.forEach((Uri uri, LibraryBuilder library) { |
| 131 if (library is SourceLibraryBuilder) { |
| 132 if (library.isPart) { |
| 133 library.validatePart(); |
| 134 parts.add(uri); |
| 135 } else { |
| 136 library.includeParts(); |
| 137 } |
| 138 } |
| 139 }); |
| 140 parts.forEach(builders.remove); |
| 141 ticker.logMs("Resolved parts"); |
| 142 } |
| 143 |
| 144 void computeLibraryScopes() { |
| 145 Set<LibraryBuilder> exporters = new Set<LibraryBuilder>(); |
| 146 Set<LibraryBuilder> exportees = new Set<LibraryBuilder>(); |
| 147 builders.forEach((Uri uri, LibraryBuilder library) { |
| 148 if (library is SourceLibraryBuilder) { |
| 149 library.buildInitialScopes(); |
| 150 } |
| 151 if (library.exporters.isNotEmpty) { |
| 152 exportees.add(library); |
| 153 for (Export exporter in library.exporters) { |
| 154 exporters.add(exporter.exporter); |
| 155 } |
| 156 } |
| 157 }); |
| 158 Set<SourceLibraryBuilder> both = new Set<SourceLibraryBuilder>(); |
| 159 for (LibraryBuilder exported in exportees) { |
| 160 if (exporters.contains(exported)) { |
| 161 both.add(exported); |
| 162 } |
| 163 for (Export export in exported.exporters) { |
| 164 exported.exports.forEach(export.addToExportScope); |
| 165 } |
| 166 } |
| 167 bool wasChanged = false; |
| 168 do { |
| 169 wasChanged = false; |
| 170 for (SourceLibraryBuilder exported in both) { |
| 171 for (Export export in exported.exporters) { |
| 172 SourceLibraryBuilder exporter = export.exporter; |
| 173 exported.exports.forEach((String name, Builder member) { |
| 174 if (exporter.addToExportScope(name, member)) { |
| 175 wasChanged = true; |
| 176 } |
| 177 }); |
| 178 } |
| 179 } |
| 180 } while (wasChanged); |
| 181 builders.forEach((Uri uri, LibraryBuilder library) { |
| 182 if (library is SourceLibraryBuilder) { |
| 183 library.addImportsToScope(); |
| 184 } |
| 185 }); |
| 186 ticker.logMs("Computed library scopes"); |
| 187 // debugPrintExports(); |
| 188 } |
| 189 |
| 190 void debugPrintExports() { |
| 191 builders.forEach((Uri uri, SourceLibraryBuilder library) { |
| 192 Set<Builder> members = new Set<Builder>(); |
| 193 library.members.forEach((String name, Builder member) { |
| 194 while (member != null) { |
| 195 members.add(member); |
| 196 member = member.next; |
| 197 } |
| 198 }); |
| 199 List<String> exports = <String>[]; |
| 200 library.exports.forEach((String name, Builder member) { |
| 201 while (member != null) { |
| 202 if (!members.contains(member)) { |
| 203 exports.add(name); |
| 204 } |
| 205 member = member.next; |
| 206 } |
| 207 }); |
| 208 if (exports.isNotEmpty) { |
| 209 print("$uri exports $exports"); |
| 210 } |
| 211 }); |
| 212 } |
| 213 |
| 214 void resolveTypes() { |
| 215 int typeCount = 0; |
| 216 builders.forEach((Uri uri, LibraryBuilder library) { |
| 217 typeCount += library.resolveTypes(null); |
| 218 }); |
| 219 ticker.logMs("Resolved $typeCount types"); |
| 220 } |
| 221 |
| 222 void convertConstructors() { |
| 223 int count = 0; |
| 224 builders.forEach((Uri uri, LibraryBuilder library) { |
| 225 count += library.convertConstructors(null); |
| 226 }); |
| 227 ticker.logMs("Converted $count constructors"); |
| 228 } |
| 229 |
| 230 void finishStaticInvocations() { |
| 231 int count = 0; |
| 232 builders.forEach((Uri uri, LibraryBuilder library) { |
| 233 count += library.finishStaticInvocations(); |
| 234 }); |
| 235 ticker.logMs("Finished static invocations $count"); |
| 236 } |
| 237 |
| 238 void resolveConstructors() { |
| 239 int count = 0; |
| 240 builders.forEach((Uri uri, LibraryBuilder library) { |
| 241 count += library.resolveConstructors(null); |
| 242 }); |
| 243 ticker.logMs("Resolved $count constructors"); |
| 244 } |
| 245 |
| 246 /// Returns all the supertypes (including interfaces) of [cls] |
| 247 /// transitively. Includes [cls]. |
| 248 Set<ClassBuilder> allSupertypes(ClassBuilder cls) { |
| 249 int length = 0; |
| 250 Set<ClassBuilder> result = new Set<ClassBuilder>()..add(cls); |
| 251 while (length != result.length) { |
| 252 length = result.length; |
| 253 result.addAll(directSupertypes(result)); |
| 254 } |
| 255 return result; |
| 256 } |
| 257 |
| 258 /// Returns the direct supertypes (including interface) of [classes]. A class |
| 259 /// from [classes] is only included if it is a supertype of one of the other |
| 260 /// classes in [classes]. |
| 261 Set<ClassBuilder> directSupertypes(Iterable<ClassBuilder> classes) { |
| 262 Set<ClassBuilder> result = new Set<ClassBuilder>(); |
| 263 for (ClassBuilder cls in classes) { |
| 264 target.addDirectSupertype(cls, result); |
| 265 } |
| 266 return result; |
| 267 } |
| 268 |
| 269 /// Computes a set of classes that may have cycles. The set is empty if there |
| 270 /// are no cycles. If the set isn't empty, it will include supertypes of |
| 271 /// classes with cycles, as well as the classes with cycles. |
| 272 /// |
| 273 /// It is assumed that [classes] is a transitive closure with respect to |
| 274 /// supertypes. |
| 275 Iterable<ClassBuilder> cyclicCandidates(Iterable<ClassBuilder> classes) { |
| 276 // The candidates are found by a fixed-point computation. |
| 277 // |
| 278 // On each iteration, the classes that have no supertypes in the input set |
| 279 // will be removed. |
| 280 // |
| 281 // If there are no cycles, eventually, the set will converge on Object, and |
| 282 // the next iteration will make the set empty (as Object has no |
| 283 // supertypes). |
| 284 // |
| 285 // On the other hand, if there is a cycle, the cycle will remain in the |
| 286 // set, and so will its supertypes, and eventually the input and output set |
| 287 // will have the same length. |
| 288 Iterable<ClassBuilder> input = const []; |
| 289 Iterable<ClassBuilder> output = classes; |
| 290 while (input.length != output.length) { |
| 291 input = output; |
| 292 output = directSupertypes(input); |
| 293 } |
| 294 return output; |
| 295 } |
| 296 |
| 297 void checkSemantics() { |
| 298 List<ClassBuilder> allClasses = target.collectAllClasses(); |
| 299 Iterable<ClassBuilder> candidates = cyclicCandidates(allClasses); |
| 300 Map<ClassBuilder, Set<ClassBuilder>> realCycles = |
| 301 <ClassBuilder, Set<ClassBuilder>>{}; |
| 302 for (ClassBuilder cls in candidates) { |
| 303 Set<ClassBuilder> cycles = cyclicCandidates(allSupertypes(cls)); |
| 304 if (cycles.isNotEmpty) { |
| 305 realCycles[cls] = cycles; |
| 306 } |
| 307 } |
| 308 Set<ClassBuilder> reported = new Set<ClassBuilder>(); |
| 309 realCycles.forEach((ClassBuilder cls, Set<ClassBuilder> cycles) { |
| 310 target.breakCycle(cls); |
| 311 if (reported.add(cls)) { |
| 312 List<ClassBuilder> involved = <ClassBuilder>[]; |
| 313 for (ClassBuilder cls in cycles) { |
| 314 if (realCycles.containsKey(cls)) { |
| 315 involved.add(cls); |
| 316 reported.add(cls); |
| 317 } |
| 318 } |
| 319 print("${cls.name} is a supertype of itself via " |
| 320 "${involved.map((c) => c.name).join(' ')}"); |
| 321 } |
| 322 }); |
| 323 ticker.logMs("Found cycles"); |
| 324 } |
| 325 |
| 326 void buildProgram() { |
| 327 builders.forEach((Uri uri, LibraryBuilder library) { |
| 328 if (library is SourceLibraryBuilder) { |
| 329 libraries.add(library.build()); |
| 330 } |
| 331 }); |
| 332 ticker.logMs("Built program"); |
| 333 } |
| 334 |
| 335 void buildElementStore() { |
| 336 elementStore = new ElementStore(coreLibrary, builders); |
| 337 ticker.logMs("Built analyzer element model."); |
| 338 } |
| 339 |
| 340 void computeHierarchy(Program program) { |
| 341 hierarchy = new ClassHierarchy(program); |
| 342 ticker.logMs("Computed class hierarchy"); |
| 343 coreTypes = new CoreTypes(program); |
| 344 ticker.logMs("Computed core types"); |
| 345 } |
| 346 } |
| OLD | NEW |