OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library fasta.source_library_builder; | 5 library fasta.source_library_builder; |
6 | 6 |
7 import 'package:kernel/ast.dart' show AsyncMarker, ProcedureKind; | 7 import 'package:kernel/ast.dart' show AsyncMarker, ProcedureKind; |
8 | 8 |
9 import '../combinator.dart' show Combinator; | 9 import '../combinator.dart' show Combinator; |
10 | 10 |
(...skipping 20 matching lines...) Expand all Loading... |
31 Scope, | 31 Scope, |
32 TypeBuilder, | 32 TypeBuilder, |
33 TypeDeclarationBuilder, | 33 TypeDeclarationBuilder, |
34 TypeVariableBuilder, | 34 TypeVariableBuilder, |
35 Unhandled; | 35 Unhandled; |
36 | 36 |
37 abstract class SourceLibraryBuilder<T extends TypeBuilder, R> | 37 abstract class SourceLibraryBuilder<T extends TypeBuilder, R> |
38 extends LibraryBuilder<T, R> { | 38 extends LibraryBuilder<T, R> { |
39 final SourceLoader loader; | 39 final SourceLoader loader; |
40 | 40 |
41 final DeclarationBuilder<T> libraryDeclaration = | 41 final DeclarationBuilder<T> libraryDeclaration; |
42 new DeclarationBuilder<T>(<String, Builder>{}, null); | |
43 | 42 |
44 final List<ConstructorReferenceBuilder> constructorReferences = | 43 final List<ConstructorReferenceBuilder> constructorReferences = |
45 <ConstructorReferenceBuilder>[]; | 44 <ConstructorReferenceBuilder>[]; |
46 | 45 |
47 final List<SourceLibraryBuilder<T, R>> parts = <SourceLibraryBuilder<T, R>>[]; | 46 final List<SourceLibraryBuilder<T, R>> parts = <SourceLibraryBuilder<T, R>>[]; |
48 | 47 |
49 final List<Import> imports = <Import>[]; | 48 final List<Import> imports = <Import>[]; |
50 | 49 |
51 final Map<String, Builder> exports = <String, Builder>{}; | 50 final Scope importScope; |
52 | |
53 final Scope scope = new Scope.top(); | |
54 | 51 |
55 final Uri fileUri; | 52 final Uri fileUri; |
56 | 53 |
57 final List<List> implementationBuilders = <List<List>>[]; | 54 final List<List> implementationBuilders = <List<List>>[]; |
58 | 55 |
59 String name; | 56 String name; |
60 | 57 |
61 String partOfName; | 58 String partOfName; |
62 | 59 |
63 Uri partOfUri; | 60 Uri partOfUri; |
64 | 61 |
65 List<MetadataBuilder> metadata; | 62 List<MetadataBuilder> metadata; |
66 | 63 |
67 /// The current declaration that is being built. When we start parsing a | 64 /// The current declaration that is being built. When we start parsing a |
68 /// declaration (class, method, and so on), we don't have enough information | 65 /// declaration (class, method, and so on), we don't have enough information |
69 /// to create a builder and this object records its members and types until, | 66 /// to create a builder and this object records its members and types until, |
70 /// for example, [addClass] is called. | 67 /// for example, [addClass] is called. |
71 DeclarationBuilder<T> currentDeclaration; | 68 DeclarationBuilder<T> currentDeclaration; |
72 | 69 |
73 bool canAddImplementationBuilders = false; | 70 bool canAddImplementationBuilders = false; |
74 | 71 |
75 SourceLibraryBuilder(this.loader, Uri fileUri) | 72 SourceLibraryBuilder(SourceLoader loader, Uri fileUri) |
76 : fileUri = fileUri, | 73 : this.fromScopes(loader, fileUri, new DeclarationBuilder<T>.library(), |
77 super(fileUri) { | 74 new Scope.top()); |
78 currentDeclaration = libraryDeclaration; | 75 |
79 } | 76 SourceLibraryBuilder.fromScopes( |
| 77 this.loader, this.fileUri, this.libraryDeclaration, this.importScope) |
| 78 : currentDeclaration = libraryDeclaration, |
| 79 super( |
| 80 fileUri, libraryDeclaration.toScope(importScope), new Scope.top()); |
80 | 81 |
81 Uri get uri; | 82 Uri get uri; |
82 | 83 |
83 bool get isPart => partOfName != null || partOfUri != null; | 84 bool get isPart => partOfName != null || partOfUri != null; |
84 | 85 |
85 Map<String, Builder> get members => libraryDeclaration.members; | |
86 | |
87 List<T> get types => libraryDeclaration.types; | 86 List<T> get types => libraryDeclaration.types; |
88 | 87 |
89 T addNamedType(String name, List<T> arguments, int charOffset); | 88 T addNamedType(String name, List<T> arguments, int charOffset); |
90 | 89 |
91 T addMixinApplication(T supertype, List<T> mixins, int charOffset); | 90 T addMixinApplication(T supertype, List<T> mixins, int charOffset); |
92 | 91 |
93 T addType(T type) { | 92 T addType(T type) { |
94 currentDeclaration.addType(type); | 93 currentDeclaration.addType(type); |
95 return type; | 94 return type; |
96 } | 95 } |
97 | 96 |
98 T addVoidType(int charOffset); | 97 T addVoidType(int charOffset); |
99 | 98 |
100 ConstructorReferenceBuilder addConstructorReference( | 99 ConstructorReferenceBuilder addConstructorReference( |
101 String name, List<T> typeArguments, String suffix, int charOffset) { | 100 String name, List<T> typeArguments, String suffix, int charOffset) { |
102 ConstructorReferenceBuilder ref = new ConstructorReferenceBuilder( | 101 ConstructorReferenceBuilder ref = new ConstructorReferenceBuilder( |
103 name, typeArguments, suffix, this, charOffset); | 102 name, typeArguments, suffix, this, charOffset); |
104 constructorReferences.add(ref); | 103 constructorReferences.add(ref); |
105 return ref; | 104 return ref; |
106 } | 105 } |
107 | 106 |
108 void beginNestedDeclaration(String name, {bool hasMembers}) { | 107 void beginNestedDeclaration(String name, {bool hasMembers: true}) { |
109 currentDeclaration = new DeclarationBuilder( | 108 currentDeclaration = currentDeclaration.createNested(name, hasMembers); |
110 <String, MemberBuilder>{}, name, currentDeclaration); | |
111 } | 109 } |
112 | 110 |
113 DeclarationBuilder<T> endNestedDeclaration() { | 111 DeclarationBuilder<T> endNestedDeclaration() { |
114 DeclarationBuilder<T> previous = currentDeclaration; | 112 DeclarationBuilder<T> previous = currentDeclaration; |
115 currentDeclaration = currentDeclaration.parent; | 113 currentDeclaration = currentDeclaration.parent; |
116 return previous; | 114 return previous; |
117 } | 115 } |
118 | 116 |
119 Uri resolve(String path) => uri.resolve(path); | 117 Uri resolve(String path) => uri.resolve(path); |
120 | 118 |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 int charOpenParenOffset, | 225 int charOpenParenOffset, |
228 int charEndOffset, | 226 int charEndOffset, |
229 String nativeMethodName); | 227 String nativeMethodName); |
230 | 228 |
231 FormalParameterBuilder addFormalParameter(List<MetadataBuilder> metadata, | 229 FormalParameterBuilder addFormalParameter(List<MetadataBuilder> metadata, |
232 int modifiers, T type, String name, bool hasThis, int charOffset); | 230 int modifiers, T type, String name, bool hasThis, int charOffset); |
233 | 231 |
234 TypeVariableBuilder addTypeVariable(String name, T bound, int charOffset); | 232 TypeVariableBuilder addTypeVariable(String name, T bound, int charOffset); |
235 | 233 |
236 Builder addBuilder(String name, Builder builder, int charOffset) { | 234 Builder addBuilder(String name, Builder builder, int charOffset) { |
237 if (name.indexOf(".") != -1 && name.indexOf("&") == -1) { | |
238 addCompileTimeError( | |
239 charOffset, | |
240 "Only constructors and factories can have" | |
241 " names containing a period ('.'): $name"); | |
242 } | |
243 // TODO(ahe): Set the parent correctly here. Could then change the | 235 // TODO(ahe): Set the parent correctly here. Could then change the |
244 // implementation of MemberBuilder.isTopLevel to test explicitly for a | 236 // implementation of MemberBuilder.isTopLevel to test explicitly for a |
245 // LibraryBuilder. | 237 // LibraryBuilder. |
246 if (currentDeclaration == libraryDeclaration) { | 238 if (currentDeclaration == libraryDeclaration) { |
247 if (builder is MemberBuilder) { | 239 if (builder is MemberBuilder) { |
248 builder.parent = this; | 240 builder.parent = this; |
249 } else if (builder is TypeDeclarationBuilder) { | 241 } else if (builder is TypeDeclarationBuilder) { |
250 builder.parent = this; | 242 builder.parent = this; |
251 } else if (builder is PrefixBuilder) { | 243 } else if (builder is PrefixBuilder) { |
252 assert(builder.parent == this); | 244 assert(builder.parent == this); |
253 } else { | 245 } else { |
254 return internalError("Unhandled: ${builder.runtimeType}"); | 246 return internalError("Unhandled: ${builder.runtimeType}"); |
255 } | 247 } |
256 } else { | 248 } else { |
257 assert(currentDeclaration.parent == libraryDeclaration); | 249 assert(currentDeclaration.parent == libraryDeclaration); |
258 } | 250 } |
259 Map<String, Builder> members = currentDeclaration.members; | 251 bool isConstructor = builder is ProcedureBuilder && |
| 252 (builder.isConstructor || builder.isFactory); |
| 253 Map<String, Builder> members = isConstructor |
| 254 ? currentDeclaration.constructors |
| 255 : (builder.isSetter |
| 256 ? currentDeclaration.setters |
| 257 : currentDeclaration.members); |
260 Builder existing = members[name]; | 258 Builder existing = members[name]; |
261 builder.next = existing; | 259 builder.next = existing; |
262 if (builder is PrefixBuilder && existing is PrefixBuilder) { | 260 if (builder is PrefixBuilder && existing is PrefixBuilder) { |
263 assert(existing.next == null); | 261 assert(existing.next == null); |
264 builder.exports.forEach((String name, Builder builder) { | 262 return existing |
265 Builder other = existing.exports.putIfAbsent(name, () => builder); | 263 ..exports.merge(builder.exports, |
266 if (other != builder) { | 264 (String name, Builder existing, Builder member) { |
267 existing.exports[name] = | 265 return buildAmbiguousBuilder(name, existing, member, charOffset); |
268 buildAmbiguousBuilder(name, other, builder, charOffset); | 266 }); |
269 } | |
270 }); | |
271 return existing; | |
272 } else if (isDuplicatedDefinition(existing, builder)) { | 267 } else if (isDuplicatedDefinition(existing, builder)) { |
273 addCompileTimeError(charOffset, "Duplicated definition of '$name'."); | 268 addCompileTimeError(charOffset, "Duplicated definition of '$name'."); |
274 } | 269 } |
275 return members[name] = builder; | 270 return members[name] = builder; |
276 } | 271 } |
277 | 272 |
278 bool isDuplicatedDefinition(Builder existing, Builder other) { | 273 bool isDuplicatedDefinition(Builder existing, Builder other) { |
279 if (existing == null) return false; | 274 if (existing == null) return false; |
280 Builder next = existing.next; | 275 Builder next = existing.next; |
281 if (next == null) { | 276 if (next == null) { |
(...skipping 24 matching lines...) Expand all Loading... |
306 } while (builder != null); | 301 } while (builder != null); |
307 }); | 302 }); |
308 for (List list in implementationBuilders) { | 303 for (List list in implementationBuilders) { |
309 String name = list[0]; | 304 String name = list[0]; |
310 Builder builder = list[1]; | 305 Builder builder = list[1]; |
311 int charOffset = list[2]; | 306 int charOffset = list[2]; |
312 addBuilder(name, builder, charOffset); | 307 addBuilder(name, builder, charOffset); |
313 buildBuilder(builder); | 308 buildBuilder(builder); |
314 } | 309 } |
315 canAddImplementationBuilders = false; | 310 canAddImplementationBuilders = false; |
| 311 |
| 312 scope.setters.forEach((String name, Builder setter) { |
| 313 Builder member = scopeBuilder[name]; |
| 314 if (member == null || !member.isField || member.isFinal) return; |
| 315 // TODO(ahe): charOffset is missing. |
| 316 addCompileTimeError( |
| 317 setter.charOffset, "Conflicts with member '${name}'."); |
| 318 addCompileTimeError( |
| 319 member.charOffset, "Conflicts with setter '${name}'."); |
| 320 }); |
| 321 |
316 return null; | 322 return null; |
317 } | 323 } |
318 | 324 |
319 /// Used to add implementation builder during the call to [build] above. | 325 /// Used to add implementation builder during the call to [build] above. |
320 /// Currently, only anonymous mixins are using implementation builders (see | 326 /// Currently, only anonymous mixins are using implementation builders (see |
321 /// [KernelMixinApplicationBuilder] | 327 /// [KernelMixinApplicationBuilder] |
322 /// (../kernel/kernel_mixin_application_builder.dart)). | 328 /// (../kernel/kernel_mixin_application_builder.dart)). |
323 void addImplementationBuilder(String name, Builder builder, int charOffset) { | 329 void addImplementationBuilder(String name, Builder builder, int charOffset) { |
324 assert(canAddImplementationBuilders, "$uri"); | 330 assert(canAddImplementationBuilders, "$uri"); |
325 implementationBuilders.add([name, builder, charOffset]); | 331 implementationBuilders.add([name, builder, charOffset]); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
374 part.forEach((String name, Builder builder) { | 380 part.forEach((String name, Builder builder) { |
375 if (builder.next != null) { | 381 if (builder.next != null) { |
376 assert(builder.next.next == null); | 382 assert(builder.next.next == null); |
377 addBuilder(name, builder.next, builder.next.charOffset); | 383 addBuilder(name, builder.next, builder.next.charOffset); |
378 } | 384 } |
379 addBuilder(name, builder, builder.charOffset); | 385 addBuilder(name, builder, builder.charOffset); |
380 }); | 386 }); |
381 types.addAll(part.types); | 387 types.addAll(part.types); |
382 constructorReferences.addAll(part.constructorReferences); | 388 constructorReferences.addAll(part.constructorReferences); |
383 part.partOfLibrary = this; | 389 part.partOfLibrary = this; |
| 390 part.scope.becomePartOf(scope); |
384 // TODO(ahe): Include metadata from part? | 391 // TODO(ahe): Include metadata from part? |
385 } | 392 } |
386 | 393 |
387 void buildInitialScopes() { | 394 void buildInitialScopes() { |
388 forEach(addToExportScope); | 395 forEach(addToExportScope); |
389 forEach((String name, Builder member) { | |
390 addToScope(name, member, member.charOffset, false); | |
391 }); | |
392 } | 396 } |
393 | 397 |
394 void addImportsToScope() { | 398 void addImportsToScope() { |
395 bool explicitCoreImport = this == loader.coreLibrary; | 399 bool explicitCoreImport = this == loader.coreLibrary; |
396 for (Import import in imports) { | 400 for (Import import in imports) { |
397 if (import.imported == loader.coreLibrary) { | 401 if (import.imported == loader.coreLibrary) { |
398 explicitCoreImport = true; | 402 explicitCoreImport = true; |
399 } | 403 } |
400 import.finalizeImports(this); | 404 import.finalizeImports(this); |
401 } | 405 } |
402 if (!explicitCoreImport) { | 406 if (!explicitCoreImport) { |
403 loader.coreLibrary.exports.forEach((String name, Builder member) { | 407 loader.coreLibrary.exports.forEach((String name, Builder member) { |
404 addToScope(name, member, -1, true); | 408 addToScope(name, member, -1, true); |
405 }); | 409 }); |
406 } | 410 } |
407 } | 411 } |
408 | 412 |
409 @override | 413 @override |
410 void addToScope(String name, Builder member, int charOffset, bool isImport) { | 414 void addToScope(String name, Builder member, int charOffset, bool isImport) { |
411 Builder existing = scope.lookup(name, member.charOffset, fileUri); | 415 Map<String, Builder> map = |
| 416 member.isSetter ? importScope.setters : importScope.local; |
| 417 Builder existing = map[name]; |
412 if (existing != null) { | 418 if (existing != null) { |
413 if (existing != member) { | 419 if (existing != member) { |
414 scope.local[name] = buildAmbiguousBuilder( | 420 map[name] = buildAmbiguousBuilder(name, existing, member, charOffset, |
415 name, existing, member, charOffset, | |
416 isImport: isImport); | 421 isImport: isImport); |
417 } | 422 } |
418 } else { | 423 } else { |
419 scope.local[name] = member; | 424 map[name] = member; |
420 } | 425 } |
421 } | 426 } |
422 | 427 |
423 /// Returns true if the export scope was modified. | 428 /// Returns true if the export scope was modified. |
424 bool addToExportScope(String name, Builder member) { | 429 bool addToExportScope(String name, Builder member) { |
425 if (name.startsWith("_")) return false; | 430 if (name.startsWith("_")) return false; |
426 if (member is PrefixBuilder) return false; | 431 if (member is PrefixBuilder) return false; |
427 Builder existing = exports[name]; | 432 Map<String, Builder> map = |
| 433 member.isSetter ? exports.setters : exports.local; |
| 434 Builder existing = map[name]; |
428 if (existing == member) return false; | 435 if (existing == member) return false; |
429 if (existing != null) { | 436 if (existing != null) { |
430 Builder result = | 437 Builder result = |
431 buildAmbiguousBuilder(name, existing, member, -1, isExport: true); | 438 buildAmbiguousBuilder(name, existing, member, -1, isExport: true); |
432 exports[name] = result; | 439 map[name] = result; |
433 return result != existing; | 440 return result != existing; |
434 } else { | 441 } else { |
435 exports[name] = member; | 442 map[name] = member; |
436 } | 443 } |
437 return true; | 444 return true; |
438 } | 445 } |
439 | 446 |
440 int resolveTypes(_) { | 447 int resolveTypes(_) { |
441 int typeCount = types.length; | 448 int typeCount = types.length; |
442 for (T t in types) { | 449 for (T t in types) { |
443 t.resolveIn(scope); | 450 t.resolveIn(scope); |
444 } | 451 } |
445 forEach((String name, Builder member) { | 452 forEach((String name, Builder member) { |
(...skipping 18 matching lines...) Expand all Loading... |
464 String get fullNameForErrors => name ?? "<library '$relativeFileUri'>"; | 471 String get fullNameForErrors => name ?? "<library '$relativeFileUri'>"; |
465 } | 472 } |
466 | 473 |
467 /// Unlike [Scope], this scope is used during construction of builders to | 474 /// Unlike [Scope], this scope is used during construction of builders to |
468 /// ensure types and members are added to and resolved in the correct location. | 475 /// ensure types and members are added to and resolved in the correct location. |
469 class DeclarationBuilder<T extends TypeBuilder> { | 476 class DeclarationBuilder<T extends TypeBuilder> { |
470 final DeclarationBuilder<T> parent; | 477 final DeclarationBuilder<T> parent; |
471 | 478 |
472 final Map<String, Builder> members; | 479 final Map<String, Builder> members; |
473 | 480 |
| 481 final Map<String, Builder> constructors; |
| 482 |
| 483 final Map<String, Builder> setters; |
| 484 |
474 final List<T> types = <T>[]; | 485 final List<T> types = <T>[]; |
475 | 486 |
476 final String name; | 487 final String name; |
477 | 488 |
478 final Map<ProcedureBuilder, DeclarationBuilder<T>> factoryDeclarations = | 489 final Map<ProcedureBuilder, DeclarationBuilder<T>> factoryDeclarations; |
479 <ProcedureBuilder, DeclarationBuilder<T>>{}; | |
480 | 490 |
481 DeclarationBuilder(this.members, this.name, [this.parent]); | 491 DeclarationBuilder(this.members, this.setters, this.constructors, |
| 492 this.factoryDeclarations, this.name, this.parent); |
482 | 493 |
483 void addMember(String name, MemberBuilder builder) { | 494 DeclarationBuilder.library() |
484 if (members == null) { | 495 : this(<String, Builder>{}, <String, Builder>{}, null, null, null, null); |
485 parent.addMember(name, builder); | |
486 } else { | |
487 members[name] = builder; | |
488 } | |
489 } | |
490 | 496 |
491 MemberBuilder lookupMember(String name) { | 497 DeclarationBuilder createNested(String name, bool hasMembers) { |
492 return members == null ? parent.lookupMember(name) : members[name]; | 498 return new DeclarationBuilder<T>( |
| 499 hasMembers ? <String, MemberBuilder>{} : null, |
| 500 hasMembers ? <String, MemberBuilder>{} : null, |
| 501 hasMembers ? <String, MemberBuilder>{} : null, |
| 502 <ProcedureBuilder, DeclarationBuilder<T>>{}, |
| 503 name, |
| 504 this); |
493 } | 505 } |
494 | 506 |
495 void addType(T type) { | 507 void addType(T type) { |
496 types.add(type); | 508 types.add(type); |
497 } | 509 } |
498 | 510 |
499 /// Resolves type variables in [types] and propagate other types to [parent]. | 511 /// Resolves type variables in [types] and propagate other types to [parent]. |
500 void resolveTypes( | 512 void resolveTypes( |
501 List<TypeVariableBuilder> typeVariables, SourceLibraryBuilder library) { | 513 List<TypeVariableBuilder> typeVariables, SourceLibraryBuilder library) { |
502 // TODO(ahe): The input to this method, [typeVariables], shouldn't be just | 514 // TODO(ahe): The input to this method, [typeVariables], shouldn't be just |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
539 types.clear(); | 551 types.clear(); |
540 } | 552 } |
541 | 553 |
542 /// Called to register [procedure] as a factory whose types are collected in | 554 /// Called to register [procedure] as a factory whose types are collected in |
543 /// [factoryDeclaration]. Later, once the class has been built, we can | 555 /// [factoryDeclaration]. Later, once the class has been built, we can |
544 /// synthesize type variables on the factory matching the class'. | 556 /// synthesize type variables on the factory matching the class'. |
545 void addFactoryDeclaration( | 557 void addFactoryDeclaration( |
546 ProcedureBuilder procedure, DeclarationBuilder<T> factoryDeclaration) { | 558 ProcedureBuilder procedure, DeclarationBuilder<T> factoryDeclaration) { |
547 factoryDeclarations[procedure] = factoryDeclaration; | 559 factoryDeclarations[procedure] = factoryDeclaration; |
548 } | 560 } |
| 561 |
| 562 Scope toScope(Scope parent) { |
| 563 return new Scope(members, setters, parent, isModifiable: false); |
| 564 } |
549 } | 565 } |
OLD | NEW |