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); | |
karlklose
2017/04/03 08:05:37
It feels wrong that 'isConstructor' has two differ
ahe
2017/04/04 09:54:51
Perhaps, but on the other hand, kernel uses the na
| |
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 void addImplementationBuilder(String name, Builder builder, int charOffset) { | 325 void addImplementationBuilder(String name, Builder builder, int charOffset) { |
320 assert(canAddImplementationBuilders, "$uri"); | 326 assert(canAddImplementationBuilders, "$uri"); |
321 implementationBuilders.add([name, builder, charOffset]); | 327 implementationBuilders.add([name, builder, charOffset]); |
322 } | 328 } |
323 | 329 |
324 void validatePart() { | 330 void validatePart() { |
325 if (parts.isNotEmpty) { | 331 if (parts.isNotEmpty) { |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
370 part.forEach((String name, Builder builder) { | 376 part.forEach((String name, Builder builder) { |
371 if (builder.next != null) { | 377 if (builder.next != null) { |
372 assert(builder.next.next == null); | 378 assert(builder.next.next == null); |
373 addBuilder(name, builder.next, builder.next.charOffset); | 379 addBuilder(name, builder.next, builder.next.charOffset); |
374 } | 380 } |
375 addBuilder(name, builder, builder.charOffset); | 381 addBuilder(name, builder, builder.charOffset); |
376 }); | 382 }); |
377 types.addAll(part.types); | 383 types.addAll(part.types); |
378 constructorReferences.addAll(part.constructorReferences); | 384 constructorReferences.addAll(part.constructorReferences); |
379 part.partOfLibrary = this; | 385 part.partOfLibrary = this; |
386 part.scope.becomePartOf(scope); | |
380 // TODO(ahe): Include metadata from part? | 387 // TODO(ahe): Include metadata from part? |
381 } | 388 } |
382 | 389 |
383 void buildInitialScopes() { | 390 void buildInitialScopes() { |
384 forEach(addToExportScope); | 391 forEach(addToExportScope); |
385 forEach((String name, Builder member) { | |
386 addToScope(name, member, member.charOffset, false); | |
387 }); | |
388 } | 392 } |
389 | 393 |
390 void addImportsToScope() { | 394 void addImportsToScope() { |
391 bool explicitCoreImport = this == loader.coreLibrary; | 395 bool explicitCoreImport = this == loader.coreLibrary; |
392 for (Import import in imports) { | 396 for (Import import in imports) { |
393 if (import.imported == loader.coreLibrary) { | 397 if (import.imported == loader.coreLibrary) { |
394 explicitCoreImport = true; | 398 explicitCoreImport = true; |
395 } | 399 } |
396 import.finalizeImports(this); | 400 import.finalizeImports(this); |
397 } | 401 } |
398 if (!explicitCoreImport) { | 402 if (!explicitCoreImport) { |
399 loader.coreLibrary.exports.forEach((String name, Builder member) { | 403 loader.coreLibrary.exports.forEach((String name, Builder member) { |
400 addToScope(name, member, -1, true); | 404 addToScope(name, member, -1, true); |
401 }); | 405 }); |
402 } | 406 } |
403 } | 407 } |
404 | 408 |
405 @override | 409 @override |
406 void addToScope(String name, Builder member, int charOffset, bool isImport) { | 410 void addToScope(String name, Builder member, int charOffset, bool isImport) { |
407 Builder existing = scope.lookup(name, member.charOffset, fileUri); | 411 Map<String, Builder> map = |
412 member.isSetter ? importScope.setters : importScope.local; | |
413 Builder existing = map[name]; | |
408 if (existing != null) { | 414 if (existing != null) { |
409 if (existing != member) { | 415 if (existing != member) { |
410 scope.local[name] = buildAmbiguousBuilder( | 416 map[name] = buildAmbiguousBuilder(name, existing, member, charOffset, |
411 name, existing, member, charOffset, | |
412 isImport: isImport); | 417 isImport: isImport); |
413 } | 418 } |
414 } else { | 419 } else { |
415 scope.local[name] = member; | 420 map[name] = member; |
416 } | 421 } |
417 } | 422 } |
418 | 423 |
419 /// Returns true if the export scope was modified. | 424 /// Returns true if the export scope was modified. |
420 bool addToExportScope(String name, Builder member) { | 425 bool addToExportScope(String name, Builder member) { |
421 if (name.startsWith("_")) return false; | 426 if (name.startsWith("_")) return false; |
422 if (member is PrefixBuilder) return false; | 427 if (member is PrefixBuilder) return false; |
423 Builder existing = exports[name]; | 428 Map<String, Builder> map = |
429 member.isSetter ? exports.setters : exports.local; | |
430 Builder existing = map[name]; | |
424 if (existing == member) return false; | 431 if (existing == member) return false; |
425 if (existing != null) { | 432 if (existing != null) { |
426 Builder result = | 433 Builder result = |
427 buildAmbiguousBuilder(name, existing, member, -1, isExport: true); | 434 buildAmbiguousBuilder(name, existing, member, -1, isExport: true); |
428 exports[name] = result; | 435 map[name] = result; |
429 return result != existing; | 436 return result != existing; |
430 } else { | 437 } else { |
431 exports[name] = member; | 438 map[name] = member; |
432 } | 439 } |
433 return true; | 440 return true; |
434 } | 441 } |
435 | 442 |
436 int resolveTypes(_) { | 443 int resolveTypes(_) { |
437 int typeCount = types.length; | 444 int typeCount = types.length; |
438 for (T t in types) { | 445 for (T t in types) { |
439 t.resolveIn(scope); | 446 t.resolveIn(scope); |
440 } | 447 } |
441 forEach((String name, Builder member) { | 448 forEach((String name, Builder member) { |
(...skipping 17 matching lines...) Expand all Loading... | |
459 String get fullNameForErrors => name ?? "<library '$relativeFileUri'>"; | 466 String get fullNameForErrors => name ?? "<library '$relativeFileUri'>"; |
460 } | 467 } |
461 | 468 |
462 /// Unlike [Scope], this scope is used during construction of builders to | 469 /// Unlike [Scope], this scope is used during construction of builders to |
463 /// ensure types and members are added to and resolved in the correct location. | 470 /// ensure types and members are added to and resolved in the correct location. |
464 class DeclarationBuilder<T extends TypeBuilder> { | 471 class DeclarationBuilder<T extends TypeBuilder> { |
465 final DeclarationBuilder<T> parent; | 472 final DeclarationBuilder<T> parent; |
466 | 473 |
467 final Map<String, Builder> members; | 474 final Map<String, Builder> members; |
468 | 475 |
476 final Map<String, Builder> constructors; | |
477 | |
478 final Map<String, Builder> setters; | |
479 | |
469 final List<T> types = <T>[]; | 480 final List<T> types = <T>[]; |
470 | 481 |
471 final String name; | 482 final String name; |
472 | 483 |
473 final Map<ProcedureBuilder, DeclarationBuilder<T>> factoryDeclarations = | 484 final Map<ProcedureBuilder, DeclarationBuilder<T>> factoryDeclarations; |
474 <ProcedureBuilder, DeclarationBuilder<T>>{}; | |
475 | 485 |
476 DeclarationBuilder(this.members, this.name, [this.parent]); | 486 DeclarationBuilder(this.members, this.setters, this.constructors, |
487 this.factoryDeclarations, this.name, this.parent); | |
477 | 488 |
478 void addMember(String name, MemberBuilder builder) { | 489 DeclarationBuilder.library() |
479 if (members == null) { | 490 : this(<String, Builder>{}, <String, Builder>{}, null, null, null, null); |
480 parent.addMember(name, builder); | |
481 } else { | |
482 members[name] = builder; | |
483 } | |
484 } | |
485 | 491 |
486 MemberBuilder lookupMember(String name) { | 492 DeclarationBuilder createNested(String name, bool hasMembers) { |
487 return members == null ? parent.lookupMember(name) : members[name]; | 493 return new DeclarationBuilder<T>( |
494 hasMembers ? <String, MemberBuilder>{} : null, | |
495 hasMembers ? <String, MemberBuilder>{} : null, | |
496 hasMembers ? <String, MemberBuilder>{} : null, | |
497 <ProcedureBuilder, DeclarationBuilder<T>>{}, | |
498 name, | |
499 this); | |
488 } | 500 } |
489 | 501 |
490 void addType(T type) { | 502 void addType(T type) { |
491 types.add(type); | 503 types.add(type); |
492 } | 504 } |
493 | 505 |
494 /// Resolves type variables in [types] and propagate other types to [parent]. | 506 /// Resolves type variables in [types] and propagate other types to [parent]. |
495 void resolveTypes( | 507 void resolveTypes( |
496 List<TypeVariableBuilder> typeVariables, SourceLibraryBuilder library) { | 508 List<TypeVariableBuilder> typeVariables, SourceLibraryBuilder library) { |
497 // TODO(ahe): The input to this method, [typeVariables], shouldn't be just | 509 // 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... | |
534 types.clear(); | 546 types.clear(); |
535 } | 547 } |
536 | 548 |
537 /// Called to register [procedure] as a factory whose types are collected in | 549 /// Called to register [procedure] as a factory whose types are collected in |
538 /// [factoryDeclaration]. Later, once the class has been built, we can | 550 /// [factoryDeclaration]. Later, once the class has been built, we can |
539 /// synthesize type variables on the factory matching the class'. | 551 /// synthesize type variables on the factory matching the class'. |
540 void addFactoryDeclaration( | 552 void addFactoryDeclaration( |
541 ProcedureBuilder procedure, DeclarationBuilder<T> factoryDeclaration) { | 553 ProcedureBuilder procedure, DeclarationBuilder<T> factoryDeclaration) { |
542 factoryDeclarations[procedure] = factoryDeclaration; | 554 factoryDeclarations[procedure] = factoryDeclaration; |
543 } | 555 } |
556 | |
557 Scope toScope(Scope parent) { | |
558 return new Scope(members, setters, parent, isModifiable: false); | |
559 } | |
544 } | 560 } |
OLD | NEW |