OLD | NEW |
---|---|
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 part of js_backend; | 5 part of js_backend; |
6 | 6 |
7 /** | 7 /** |
8 * Assigns JavaScript identifiers to Dart variables, class-names and members. | 8 * Assigns JavaScript identifiers to Dart variables, class-names and members. |
9 * | 9 * |
10 * Names are generated through three stages: | 10 * Names are generated through three stages: |
(...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
363 static final RegExp NON_IDENTIFIER_CHAR = new RegExp(r'[^A-Za-z_0-9$]'); | 363 static final RegExp NON_IDENTIFIER_CHAR = new RegExp(r'[^A-Za-z_0-9$]'); |
364 | 364 |
365 final Compiler compiler; | 365 final Compiler compiler; |
366 | 366 |
367 /// Used disambiguated names in the global namespace, issued by | 367 /// Used disambiguated names in the global namespace, issued by |
368 /// [_disambiguateGlobal], and [_disambiguateInternalGlobal]. | 368 /// [_disambiguateGlobal], and [_disambiguateInternalGlobal]. |
369 /// | 369 /// |
370 /// Although global names are distributed across a number of global objects, | 370 /// Although global names are distributed across a number of global objects, |
371 /// (see [globalObjectFor]), we currently use a single namespace for all these | 371 /// (see [globalObjectFor]), we currently use a single namespace for all these |
372 /// names. | 372 /// names. |
373 final Set<String> usedGlobalNames = new Set<String>(); | 373 final NamingScope globalScope = new NamingScope(); |
374 final Map<Element, jsAst.Name> userGlobals = | 374 final Map<Element, jsAst.Name> userGlobals = |
375 new HashMap<Element, jsAst.Name>(); | 375 new HashMap<Element, jsAst.Name>(); |
376 final Map<String, jsAst.Name> internalGlobals = | 376 final Map<String, jsAst.Name> internalGlobals = |
377 new HashMap<String, jsAst.Name>(); | 377 new HashMap<String, jsAst.Name>(); |
378 | 378 |
379 /// Used disambiguated names in the instance namespace, issued by | 379 /// Used disambiguated names in the instance namespace, issued by |
380 /// [_disambiguateMember], [_disambiguateInternalMember], | 380 /// [_disambiguateMember], [_disambiguateInternalMember], |
381 /// [_disambiguateOperator], and [reservePublicMemberName]. | 381 /// [_disambiguateOperator], and [reservePublicMemberName]. |
382 final Set<String> usedInstanceNames = new Set<String>(); | 382 final NamingScope instanceScope = new NamingScope(); |
383 final Map<String, jsAst.Name> userInstanceMembers = | 383 final Map<String, jsAst.Name> userInstanceMembers = |
384 new HashMap<String, jsAst.Name>(); | 384 new HashMap<String, jsAst.Name>(); |
385 final Map<Element, jsAst.Name> internalInstanceMembers = | 385 final Map<Element, jsAst.Name> internalInstanceMembers = |
386 new HashMap<Element, jsAst.Name>(); | 386 new HashMap<Element, jsAst.Name>(); |
387 final Map<String, jsAst.Name> userInstanceOperators = | 387 final Map<String, jsAst.Name> userInstanceOperators = |
388 new HashMap<String, jsAst.Name>(); | 388 new HashMap<String, jsAst.Name>(); |
389 | 389 |
390 /// Used to disambiguate names for constants in [constantName]. | 390 /// Used to disambiguate names for constants in [constantName]. |
391 final Set<String> usedConstantNames = new Set<String>(); | 391 final NamingScope constantScope = new NamingScope(); |
392 | |
393 Set<String> getUsedNames(NamingScope scope) { | |
394 if (scope == NamingScope.global) { | |
395 return usedGlobalNames; | |
396 } else if (scope == NamingScope.instance){ | |
397 return usedInstanceNames; | |
398 } else { | |
399 assert(scope == NamingScope.constant); | |
400 return usedConstantNames; | |
401 } | |
402 } | |
403 | 392 |
404 final Map<String, int> popularNameCounters = <String, int>{}; | 393 final Map<String, int> popularNameCounters = <String, int>{}; |
405 | 394 |
406 final Map<LibraryElement, String> libraryLongNames = | 395 final Map<LibraryElement, String> libraryLongNames = |
407 new HashMap<LibraryElement, String>(); | 396 new HashMap<LibraryElement, String>(); |
408 | 397 |
409 final Map<ConstantValue, jsAst.Name> constantNames = | 398 final Map<ConstantValue, jsAst.Name> constantNames = |
410 new HashMap<ConstantValue, jsAst.Name>(); | 399 new HashMap<ConstantValue, jsAst.Name>(); |
411 final Map<ConstantValue, String> constantLongNames = | 400 final Map<ConstantValue, String> constantLongNames = |
412 <ConstantValue, String>{}; | 401 <ConstantValue, String>{}; |
413 ConstantCanonicalHasher constantHasher; | 402 ConstantCanonicalHasher constantHasher; |
414 | 403 |
415 /// Maps private names to a library that may use that name without prefixing | 404 /// Maps private names to a library that may use that name without prefixing |
416 /// itself. Used for building proposed names. | 405 /// itself. Used for building proposed names. |
417 final Map<String, LibraryElement> shortPrivateNameOwners = | 406 final Map<String, LibraryElement> shortPrivateNameOwners = |
418 <String, LibraryElement>{}; | 407 <String, LibraryElement>{}; |
419 | 408 |
420 /// Maps proposed names to *suggested* disambiguated names. | 409 |
421 /// | |
422 /// Suggested names are hints to the [MinifyNamer], suggesting that a specific | |
423 /// names be given to the first item with the given proposed name. | |
424 /// | |
425 /// This is currently used in [MinifyNamer] to assign very short minified | |
426 /// names to things that tend to be used very often. | |
427 final Map<String, String> suggestedGlobalNames = <String, String>{}; | 410 final Map<String, String> suggestedGlobalNames = <String, String>{}; |
428 final Map<String, String> suggestedInstanceNames = <String, String>{}; | 411 final Map<String, String> suggestedInstanceNames = <String, String>{}; |
429 | 412 |
430 Map<String, String> getSuggestedNames(NamingScope scope) { | |
431 if (scope == NamingScope.global) { | |
432 return suggestedGlobalNames; | |
433 } else if (scope == NamingScope.instance) { | |
434 return suggestedInstanceNames; | |
435 } else { | |
436 assert(scope == NamingScope.constant); | |
437 return const {}; | |
438 } | |
439 } | |
440 | |
441 | 413 |
442 /// Used to store unique keys for library names. Keys are not used as names, | 414 /// Used to store unique keys for library names. Keys are not used as names, |
443 /// nor are they visible in the output. The only serve as an internal | 415 /// nor are they visible in the output. The only serve as an internal |
444 /// key into maps. | 416 /// key into maps. |
445 final Map<LibraryElement, String> _libraryKeys = | 417 final Map<LibraryElement, String> _libraryKeys = |
446 new HashMap<LibraryElement, String>(); | 418 new HashMap<LibraryElement, String>(); |
447 | 419 |
448 Namer(Compiler compiler) | 420 Namer(Compiler compiler) |
449 : compiler = compiler, | 421 : compiler = compiler, |
450 constantHasher = new ConstantCanonicalHasher(compiler), | 422 constantHasher = new ConstantCanonicalHasher(compiler), |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
538 /// | 510 /// |
539 /// Unique within the global-member namespace. | 511 /// Unique within the global-member namespace. |
540 jsAst.Name constantName(ConstantValue constant) { | 512 jsAst.Name constantName(ConstantValue constant) { |
541 // In the current implementation it doesn't make sense to give names to | 513 // In the current implementation it doesn't make sense to give names to |
542 // function constants since the function-implementation itself serves as | 514 // function constants since the function-implementation itself serves as |
543 // constant and can be accessed directly. | 515 // constant and can be accessed directly. |
544 assert(!constant.isFunction); | 516 assert(!constant.isFunction); |
545 jsAst.Name result = constantNames[constant]; | 517 jsAst.Name result = constantNames[constant]; |
546 if (result == null) { | 518 if (result == null) { |
547 String longName = constantLongName(constant); | 519 String longName = constantLongName(constant); |
548 result = getFreshName(NamingScope.constant, longName); | 520 result = getFreshName(constantScope, longName); |
549 constantNames[constant] = result; | 521 constantNames[constant] = result; |
550 } | 522 } |
551 return _newReference(result); | 523 return _newReference(result); |
552 } | 524 } |
553 | 525 |
554 /// Proposed name for [constant]. | 526 /// Proposed name for [constant]. |
555 String constantLongName(ConstantValue constant) { | 527 String constantLongName(ConstantValue constant) { |
556 String longName = constantLongNames[constant]; | 528 String longName = constantLongNames[constant]; |
557 if (longName == null) { | 529 if (longName == null) { |
558 longName = new ConstantNamingVisitor(compiler, constantHasher) | 530 longName = new ConstantNamingVisitor(compiler, constantHasher) |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
792 /** | 764 /** |
793 * Returns the JavaScript property name used to store an instance field. | 765 * Returns the JavaScript property name used to store an instance field. |
794 */ | 766 */ |
795 jsAst.Name instanceFieldPropertyName(FieldElement element) { | 767 jsAst.Name instanceFieldPropertyName(FieldElement element) { |
796 ClassElement enclosingClass = element.enclosingClass; | 768 ClassElement enclosingClass = element.enclosingClass; |
797 | 769 |
798 if (backend.hasFixedBackendName(element)) { | 770 if (backend.hasFixedBackendName(element)) { |
799 return new StringBackedName(backend.getFixedBackendName(element)); | 771 return new StringBackedName(backend.getFixedBackendName(element)); |
800 } | 772 } |
801 | 773 |
802 // Instances of BoxFieldElement are special. They are already created with | 774 // Some elements, like e.g. instances of BoxFieldElement are special. |
803 // a unique and safe name. However, as boxes are not really instances of | 775 // They are created with a unique and safe name for the element model. |
804 // classes, the usual naming scheme that tries to avoid name clashes with | 776 // While their name is unique, it is not very readable. So we try to |
805 // super classes does not apply. We still do not mark the name as a | 777 // preserve the original, proposed name. |
806 // fixedBackendName, as we want to allow other namers to do something more | 778 // However, as boxes are not really instances of classes, the usual naming |
807 // clever with them. | 779 // scheme that tries to avoid name clashes with super classes does not |
808 if (element is BoxFieldElement) { | 780 // apply. So we can directly grab a name. |
809 return new StringBackedName(element.name); | 781 if (element is NameProposingEntity) { |
sra1
2015/11/04 02:27:49
Are the names generated here going to be stable?
T
herhut
2015/11/04 15:25:48
This is typically the order in which the model is
| |
782 var proposing = entity; | |
Siggi Cherem (dart-lang)
2015/11/03 17:21:34
remove this extra var? with the spec's type propag
sra1
2015/11/04 02:27:48
What Siggi says.
'entity' is not in scope.
Had to
herhut
2015/11/04 15:25:48
Sorry, last minute editing change.
herhut
2015/11/04 15:25:48
Did not work for me but with the new hierarchy it
| |
783 return _disambiguateInternalMember(element, proposing.proposeName); | |
Siggi Cherem (dart-lang)
2015/11/03 17:21:34
(related to my other comment, I'd assume the only
herhut
2015/11/04 15:25:48
It would have been, now I need to create a little
| |
810 } | 784 } |
811 | 785 |
812 // If the name of the field might clash with another field, | 786 // If the name of the field might clash with another field, |
813 // use a mangled field name to avoid potential clashes. | 787 // use a mangled field name to avoid potential clashes. |
814 // Note that if the class extends a native class, that native class might | 788 // Note that if the class extends a native class, that native class might |
815 // have fields with fixed backend names, so we assume the worst and always | 789 // have fields with fixed backend names, so we assume the worst and always |
816 // mangle the field names of classes extending native classes. | 790 // mangle the field names of classes extending native classes. |
817 // Methods on such classes are stored on the interceptor, not the instance, | 791 // Methods on such classes are stored on the interceptor, not the instance, |
818 // so only fields have the potential to clash with a native property name. | 792 // so only fields have the potential to clash with a native property name. |
819 ClassWorld classWorld = compiler.world; | 793 ClassWorld classWorld = compiler.world; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
875 jsAst.Name disambiguatedName = _disambiguateMember(originalName); | 849 jsAst.Name disambiguatedName = _disambiguateMember(originalName); |
876 return deriveGetterName(disambiguatedName); | 850 return deriveGetterName(disambiguatedName); |
877 } | 851 } |
878 | 852 |
879 /// Disambiguated name for a compiler-owned global variable. | 853 /// Disambiguated name for a compiler-owned global variable. |
880 /// | 854 /// |
881 /// The resulting name is unique within the global-member namespace. | 855 /// The resulting name is unique within the global-member namespace. |
882 jsAst.Name _disambiguateInternalGlobal(String name) { | 856 jsAst.Name _disambiguateInternalGlobal(String name) { |
883 jsAst.Name newName = internalGlobals[name]; | 857 jsAst.Name newName = internalGlobals[name]; |
884 if (newName == null) { | 858 if (newName == null) { |
885 newName = getFreshName(NamingScope.global, name); | 859 newName = getFreshName(globalScope, name); |
886 internalGlobals[name] = newName; | 860 internalGlobals[name] = newName; |
887 } | 861 } |
888 return _newReference(newName); | 862 return _newReference(newName); |
889 } | 863 } |
890 | 864 |
891 /// Returns the property name to use for a compiler-owner global variable, | 865 /// Returns the property name to use for a compiler-owner global variable, |
892 /// i.e. one that does not correspond to any element but is used as a utility | 866 /// i.e. one that does not correspond to any element but is used as a utility |
893 /// global by code generation. | 867 /// global by code generation. |
894 /// | 868 /// |
895 /// [name] functions as both the proposed name for the global, and as a key | 869 /// [name] functions as both the proposed name for the global, and as a key |
(...skipping 26 matching lines...) Expand all Loading... | |
922 /// Returns the disambiguated name for a top-level or static element. | 896 /// Returns the disambiguated name for a top-level or static element. |
923 /// | 897 /// |
924 /// The resulting name is unique within the global-member namespace. | 898 /// The resulting name is unique within the global-member namespace. |
925 jsAst.Name _disambiguateGlobal(Element element) { | 899 jsAst.Name _disambiguateGlobal(Element element) { |
926 // TODO(asgerf): We can reuse more short names if we disambiguate with | 900 // TODO(asgerf): We can reuse more short names if we disambiguate with |
927 // a separate namespace for each of the global holder objects. | 901 // a separate namespace for each of the global holder objects. |
928 element = element.declaration; | 902 element = element.declaration; |
929 jsAst.Name newName = userGlobals[element]; | 903 jsAst.Name newName = userGlobals[element]; |
930 if (newName == null) { | 904 if (newName == null) { |
931 String proposedName = _proposeNameForGlobal(element); | 905 String proposedName = _proposeNameForGlobal(element); |
932 newName = getFreshName(NamingScope.global, proposedName); | 906 newName = getFreshName(globalScope, proposedName); |
933 userGlobals[element] = newName; | 907 userGlobals[element] = newName; |
934 } | 908 } |
935 return _newReference(newName); | 909 return _newReference(newName); |
936 } | 910 } |
937 | 911 |
938 /// Returns the disambiguated name for an instance method or field | 912 /// Returns the disambiguated name for an instance method or field |
939 /// with [originalName] in [library]. | 913 /// with [originalName] in [library]. |
940 /// | 914 /// |
941 /// [library] may be `null` if [originalName] is known to be public. | 915 /// [library] may be `null` if [originalName] is known to be public. |
942 /// | 916 /// |
(...skipping 19 matching lines...) Expand all Loading... | |
962 // This avoids clashes since the original names cannot contain that symbol. | 936 // This avoids clashes since the original names cannot contain that symbol. |
963 String key = '$libraryKey@${originalName.text}@${suffixes.join('@')}'; | 937 String key = '$libraryKey@${originalName.text}@${suffixes.join('@')}'; |
964 jsAst.Name newName = userInstanceMembers[key]; | 938 jsAst.Name newName = userInstanceMembers[key]; |
965 if (newName == null) { | 939 if (newName == null) { |
966 String proposedName = privateName(originalName); | 940 String proposedName = privateName(originalName); |
967 if (!suffixes.isEmpty) { | 941 if (!suffixes.isEmpty) { |
968 // In the proposed name, separate the name parts by '$', because the | 942 // In the proposed name, separate the name parts by '$', because the |
969 // proposed name must be a valid identifier, but not necessarily unique. | 943 // proposed name must be a valid identifier, but not necessarily unique. |
970 proposedName += r'$' + suffixes.join(r'$'); | 944 proposedName += r'$' + suffixes.join(r'$'); |
971 } | 945 } |
972 newName = getFreshName(NamingScope.instance, proposedName, | 946 newName = getFreshName(instanceScope, proposedName, |
973 sanitizeForAnnotations: true); | 947 sanitizeForAnnotations: true); |
974 userInstanceMembers[key] = newName; | 948 userInstanceMembers[key] = newName; |
975 } | 949 } |
976 return _newReference(newName); | 950 return _newReference(newName); |
977 } | 951 } |
978 | 952 |
979 /// Returns the disambiguated name for the instance member identified by | 953 /// Returns the disambiguated name for the instance member identified by |
980 /// [key]. | 954 /// [key]. |
981 /// | 955 /// |
982 /// When a name for an element is requested by key, it may not be requested | 956 /// When a name for an element is requested by key, it may not be requested |
983 /// by element at the same time, as two different names would be returned. | 957 /// by element at the same time, as two different names would be returned. |
984 /// | 958 /// |
985 /// If key has not yet been registered, [proposeName] is used to generate | 959 /// If key has not yet been registered, [proposeName] is used to generate |
986 /// a name proposal for the given key. | 960 /// a name proposal for the given key. |
987 /// | 961 /// |
988 /// [key] must not clash with valid instance names. This is typically | 962 /// [key] must not clash with valid instance names. This is typically |
989 /// achieved by using at least one character in [key] that is not valid in | 963 /// achieved by using at least one character in [key] that is not valid in |
990 /// identifiers, for example the @ symbol. | 964 /// identifiers, for example the @ symbol. |
991 jsAst.Name _disambiguateMemberByKey(String key, String proposeName()) { | 965 jsAst.Name _disambiguateMemberByKey(String key, String proposeName()) { |
992 jsAst.Name newName = userInstanceMembers[key]; | 966 jsAst.Name newName = userInstanceMembers[key]; |
993 if (newName == null) { | 967 if (newName == null) { |
994 String name = proposeName(); | 968 String name = proposeName(); |
995 newName = getFreshName(NamingScope.instance, name, | 969 newName = getFreshName(instanceScope, name, |
996 sanitizeForAnnotations: true); | 970 sanitizeForAnnotations: true); |
997 userInstanceMembers[key] = newName; | 971 userInstanceMembers[key] = newName; |
998 } | 972 } |
999 return _newReference(newName); | 973 return _newReference(newName); |
1000 } | 974 } |
1001 | 975 |
1002 /// Forces the public instance member with [originalName] to have the given | 976 /// Forces the public instance member with [originalName] to have the given |
1003 /// [disambiguatedName]. | 977 /// [disambiguatedName]. |
1004 /// | 978 /// |
1005 /// The [originalName] must not have been disambiguated before, and the | 979 /// The [originalName] must not have been disambiguated before, and the |
1006 /// [disambiguatedName] must not have been used. | 980 /// [disambiguatedName] must not have been used. |
1007 /// | 981 /// |
1008 /// Using [_disambiguateMember] with the given [originalName] and no suffixes | 982 /// Using [_disambiguateMember] with the given [originalName] and no suffixes |
1009 /// will subsequently return [disambiguatedName]. | 983 /// will subsequently return [disambiguatedName]. |
1010 void reservePublicMemberName(String originalName, | 984 void reservePublicMemberName(String originalName, |
1011 String disambiguatedName) { | 985 String disambiguatedName) { |
1012 // Build a key that corresponds to the one built in disambiguateMember. | 986 // Build a key that corresponds to the one built in disambiguateMember. |
1013 String libraryPrefix = ''; // Public names have an empty library prefix. | 987 String libraryPrefix = ''; // Public names have an empty library prefix. |
1014 String suffix = ''; // We don't need any suffixes. | 988 String suffix = ''; // We don't need any suffixes. |
1015 String key = '$libraryPrefix@$originalName@$suffix'; | 989 String key = '$libraryPrefix@$originalName@$suffix'; |
1016 assert(!userInstanceMembers.containsKey(key)); | 990 assert(!userInstanceMembers.containsKey(key)); |
1017 assert(!usedInstanceNames.contains(disambiguatedName)); | 991 assert(!instanceScope.isUsed(disambiguatedName)); |
1018 userInstanceMembers[key] = new StringBackedName(disambiguatedName); | 992 userInstanceMembers[key] = new StringBackedName(disambiguatedName); |
1019 usedInstanceNames.add(disambiguatedName); | 993 instanceScope.registerUse(disambiguatedName); |
1020 } | 994 } |
1021 | 995 |
1022 /// Disambiguated name unique to [element]. | 996 /// Disambiguated name unique to [element]. |
1023 /// | 997 /// |
1024 /// This is used as the property name for fields, type variables, | 998 /// This is used as the property name for fields, type variables, |
1025 /// constructor bodies, and super-accessors. | 999 /// constructor bodies, and super-accessors. |
1026 /// | 1000 /// |
1027 /// The resulting name is unique within the instance-member namespace. | 1001 /// The resulting name is unique within the instance-member namespace. |
1028 jsAst.Name _disambiguateInternalMember(Element element, | 1002 jsAst.Name _disambiguateInternalMember(Element element, |
1029 String proposeName()) { | 1003 String proposeName()) { |
1030 jsAst.Name newName = internalInstanceMembers[element]; | 1004 jsAst.Name newName = internalInstanceMembers[element]; |
1031 if (newName == null) { | 1005 if (newName == null) { |
1032 String name = proposeName(); | 1006 String name = proposeName(); |
1033 bool mayClashNative = _isUserClassExtendingNative(element.enclosingClass); | 1007 |
1034 newName = getFreshName(NamingScope.instance, name, | 1008 if (element is ScopeBearingEntity) { |
1035 sanitizeForAnnotations: true, | 1009 var scopeProvider = element; |
sra1
2015/11/04 02:27:49
Don't use var to avoid static type checks.
herhut
2015/11/04 15:25:48
Done.
| |
1036 sanitizeForNatives: mayClashNative); | 1010 newName = getFreshName(scopeProvider.namingScope, name, |
1037 internalInstanceMembers[element] = newName; | 1011 sanitizeForAnnotations: true, |
1012 sanitizeForNatives: false); | |
1013 internalInstanceMembers[element] = newName; | |
1014 } else { | |
1015 bool mayClashNative = | |
1016 _isUserClassExtendingNative(element.enclosingClass); | |
1017 newName = getFreshName(instanceScope, name, | |
1018 sanitizeForAnnotations: true, | |
1019 sanitizeForNatives: mayClashNative); | |
1020 internalInstanceMembers[element] = newName; | |
1021 } | |
1038 } | 1022 } |
1039 return _newReference(newName); | 1023 return _newReference(newName); |
1040 } | 1024 } |
1041 | 1025 |
1042 /// Disambiguated name for the given operator. | 1026 /// Disambiguated name for the given operator. |
1043 /// | 1027 /// |
1044 /// [operatorIdentifier] must be the operator's identifier, e.g. | 1028 /// [operatorIdentifier] must be the operator's identifier, e.g. |
1045 /// `$add` and not `+`. | 1029 /// `$add` and not `+`. |
1046 /// | 1030 /// |
1047 /// The resulting name is unique within the instance-member namespace. | 1031 /// The resulting name is unique within the instance-member namespace. |
1048 jsAst.Name _disambiguateOperator(String operatorIdentifier) { | 1032 jsAst.Name _disambiguateOperator(String operatorIdentifier) { |
1049 jsAst.Name newName = userInstanceOperators[operatorIdentifier]; | 1033 jsAst.Name newName = userInstanceOperators[operatorIdentifier]; |
1050 if (newName == null) { | 1034 if (newName == null) { |
1051 newName = getFreshName(NamingScope.instance, operatorIdentifier); | 1035 newName = getFreshName(instanceScope, operatorIdentifier); |
1052 userInstanceOperators[operatorIdentifier] = newName; | 1036 userInstanceOperators[operatorIdentifier] = newName; |
1053 } | 1037 } |
1054 return _newReference(newName); | 1038 return _newReference(newName); |
1055 } | 1039 } |
1056 | 1040 |
1057 String _generateFreshStringForName(String proposedName, | 1041 String _generateFreshStringForName(String proposedName, |
1058 Set<String> usedNames, | 1042 NamingScope scope, |
1059 Map<String, String> suggestedNames, | |
1060 {bool sanitizeForAnnotations: false, | 1043 {bool sanitizeForAnnotations: false, |
1061 bool sanitizeForNatives: false}) { | 1044 bool sanitizeForNatives: false}) { |
1062 if (sanitizeForAnnotations) { | 1045 if (sanitizeForAnnotations) { |
1063 proposedName = _sanitizeForAnnotations(proposedName); | 1046 proposedName = _sanitizeForAnnotations(proposedName); |
1064 } | 1047 } |
1065 if (sanitizeForNatives) { | 1048 if (sanitizeForNatives) { |
1066 proposedName = _sanitizeForNatives(proposedName); | 1049 proposedName = _sanitizeForNatives(proposedName); |
1067 } | 1050 } |
1068 proposedName = _sanitizeForKeywords(proposedName); | 1051 proposedName = _sanitizeForKeywords(proposedName); |
1069 String candidate; | 1052 String candidate; |
1070 if (!usedNames.contains(proposedName)) { | 1053 if (scope.isUnused(proposedName)) { |
1071 candidate = proposedName; | 1054 candidate = proposedName; |
1072 } else { | 1055 } else { |
1073 int counter = popularNameCounters[proposedName]; | 1056 int counter = popularNameCounters[proposedName]; |
1074 int i = (counter == null) ? 0 : counter; | 1057 int i = (counter == null) ? 0 : counter; |
1075 while (usedNames.contains("$proposedName$i")) { | 1058 while (scope.isUsed("$proposedName$i")) { |
1076 i++; | 1059 i++; |
1077 } | 1060 } |
1078 popularNameCounters[proposedName] = i + 1; | 1061 popularNameCounters[proposedName] = i + 1; |
1079 candidate = "$proposedName$i"; | 1062 candidate = "$proposedName$i"; |
1080 } | 1063 } |
1081 usedNames.add(candidate); | 1064 scope.registerUse(candidate); |
1082 return candidate; | 1065 return candidate; |
1083 } | 1066 } |
1084 | 1067 |
1085 /// Returns an unused name. | 1068 /// Returns an unused name. |
1086 /// | 1069 /// |
1087 /// [proposedName] must be a valid JavaScript identifier. | 1070 /// [proposedName] must be a valid JavaScript identifier. |
1088 /// | 1071 /// |
1089 /// If [sanitizeForAnnotations] is `true`, then the result is guaranteed not | 1072 /// If [sanitizeForAnnotations] is `true`, then the result is guaranteed not |
1090 /// to have the form of an annotated name. | 1073 /// to have the form of an annotated name. |
1091 /// | 1074 /// |
1092 /// If [sanitizeForNatives] it `true`, then the result is guaranteed not to | 1075 /// If [sanitizeForNatives] it `true`, then the result is guaranteed not to |
1093 /// clash with a property name on a native object. | 1076 /// clash with a property name on a native object. |
1094 /// | 1077 /// |
1095 /// Note that [MinifyNamer] overrides this method with one that produces | 1078 /// Note that [MinifyNamer] overrides this method with one that produces |
1096 /// minified names. | 1079 /// minified names. |
1097 jsAst.Name getFreshName(NamingScope scope, | 1080 jsAst.Name getFreshName(NamingScope scope, |
1098 String proposedName, | 1081 String proposedName, |
1099 {bool sanitizeForAnnotations: false, | 1082 {bool sanitizeForAnnotations: false, |
1100 bool sanitizeForNatives: false}) { | 1083 bool sanitizeForNatives: false}) { |
1101 String candidate = | 1084 String candidate = |
1102 _generateFreshStringForName(proposedName, | 1085 _generateFreshStringForName(proposedName, |
1103 getUsedNames(scope), | 1086 scope, |
1104 getSuggestedNames(scope), | |
1105 sanitizeForAnnotations: | 1087 sanitizeForAnnotations: |
1106 sanitizeForAnnotations, | 1088 sanitizeForAnnotations, |
1107 sanitizeForNatives: sanitizeForNatives); | 1089 sanitizeForNatives: sanitizeForNatives); |
1108 return new StringBackedName(candidate); | 1090 return new StringBackedName(candidate); |
1109 } | 1091 } |
1110 | 1092 |
1111 /// Returns a variant of [name] that cannot clash with the annotated | 1093 /// Returns a variant of [name] that cannot clash with the annotated |
1112 /// version of another name, that is, the resulting name can never be returned | 1094 /// version of another name, that is, the resulting name can never be returned |
1113 /// by [deriveGetterName], [deriveSetterName], [deriveCallMethodName], | 1095 /// by [deriveGetterName], [deriveSetterName], [deriveCallMethodName], |
1114 /// [operatorIs], or [substitutionName]. | 1096 /// [operatorIs], or [substitutionName]. |
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1429 | 1411 |
1430 String get functionTypeNamedParametersTag => r'named'; | 1412 String get functionTypeNamedParametersTag => r'named'; |
1431 | 1413 |
1432 Map<FunctionType, jsAst.Name> functionTypeNameMap = | 1414 Map<FunctionType, jsAst.Name> functionTypeNameMap = |
1433 new HashMap<FunctionType, jsAst.Name>(); | 1415 new HashMap<FunctionType, jsAst.Name>(); |
1434 final FunctionTypeNamer functionTypeNamer; | 1416 final FunctionTypeNamer functionTypeNamer; |
1435 | 1417 |
1436 jsAst.Name getFunctionTypeName(FunctionType functionType) { | 1418 jsAst.Name getFunctionTypeName(FunctionType functionType) { |
1437 return functionTypeNameMap.putIfAbsent(functionType, () { | 1419 return functionTypeNameMap.putIfAbsent(functionType, () { |
1438 String proposedName = functionTypeNamer.computeName(functionType); | 1420 String proposedName = functionTypeNamer.computeName(functionType); |
1439 return getFreshName(NamingScope.instance, proposedName); | 1421 return getFreshName(instanceScope, proposedName); |
1440 }); | 1422 }); |
1441 } | 1423 } |
1442 | 1424 |
1443 jsAst.Name operatorIsType(DartType type) { | 1425 jsAst.Name operatorIsType(DartType type) { |
1444 if (type.isFunctionType) { | 1426 if (type.isFunctionType) { |
1445 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. | 1427 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. |
1446 return new CompoundName([new StringBackedName(operatorIsPrefix), | 1428 return new CompoundName([new StringBackedName(operatorIsPrefix), |
1447 _literalUnderscore, | 1429 _literalUnderscore, |
1448 getFunctionTypeName(type)]); | 1430 getFunctionTypeName(type)]); |
1449 } | 1431 } |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1565 | 1547 |
1566 String get incrementalHelperName => r'$dart_unsafe_incremental_support'; | 1548 String get incrementalHelperName => r'$dart_unsafe_incremental_support'; |
1567 | 1549 |
1568 jsAst.Expression get accessIncrementalHelper { | 1550 jsAst.Expression get accessIncrementalHelper { |
1569 return js('self.${incrementalHelperName}'); | 1551 return js('self.${incrementalHelperName}'); |
1570 } | 1552 } |
1571 | 1553 |
1572 void forgetElement(Element element) { | 1554 void forgetElement(Element element) { |
1573 jsAst.Name globalName = userGlobals[element]; | 1555 jsAst.Name globalName = userGlobals[element]; |
1574 invariant(element, globalName != null, message: 'No global name.'); | 1556 invariant(element, globalName != null, message: 'No global name.'); |
1575 usedGlobalNames.remove(globalName); | |
1576 userGlobals.remove(element); | 1557 userGlobals.remove(element); |
1577 } | 1558 } |
1578 } | 1559 } |
1579 | 1560 |
1580 /** | 1561 /** |
1581 * Generator of names for [ConstantValue] values. | 1562 * Generator of names for [ConstantValue] values. |
1582 * | 1563 * |
1583 * The names are stable under perturbations of the source. The name is either a | 1564 * The names are stable under perturbations of the source. The name is either a |
1584 * short sequence of words, if this can be found from the constant, or a type | 1565 * short sequence of words, if this can be found from the constant, or a type |
1585 * followed by a hash tag. | 1566 * followed by a hash tag. |
(...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2021 sb.write('_'); | 2002 sb.write('_'); |
2022 } | 2003 } |
2023 sb.write('_'); | 2004 sb.write('_'); |
2024 visit(parameter); | 2005 visit(parameter); |
2025 first = true; | 2006 first = true; |
2026 } | 2007 } |
2027 } | 2008 } |
2028 } | 2009 } |
2029 } | 2010 } |
2030 | 2011 |
2031 enum NamingScope { | 2012 abstract class NameProposingEntity implements Entity { |
2032 global, | 2013 String proposeName(); |
2033 instance, | |
2034 constant | |
2035 } | 2014 } |
2015 | |
2016 abstract class ScopeBearingEntity implements Entity { | |
2017 NamingScope get namingScope; | |
2018 } | |
2019 | |
2020 class NamingScope { | |
2021 /// Maps proposed names to *suggested* disambiguated names. | |
2022 /// | |
2023 /// Suggested names are hints to the [MinifyNamer], suggesting that a specific | |
2024 /// names be given to the first item with the given proposed name. | |
2025 /// | |
2026 /// This is currently used in [MinifyNamer] to assign very short minified | |
2027 /// names to things that tend to be used very often. | |
2028 final Map<String, String> _suggestedNames = new Map<String, String>(); | |
2029 final Set<String> _usedNames = new Set<String>(); | |
2030 | |
2031 bool isUsed(String name) => _usedNames.contains(name); | |
2032 bool isUnused(String name) => !_usedNames.contains(name); | |
2033 bool registerUse(String name) => _usedNames.add(name); | |
2034 | |
2035 String suggestName(String original) => _suggestedNames[original]; | |
2036 void addSuggestion(String original, String suggestion) { | |
2037 assert(!_suggestedNames.containsKey(original)); | |
2038 _suggestedNames[original] = suggestion; | |
2039 } | |
2040 bool hasSuggestion(String original) => _suggestedNames.containsKey(original); | |
2041 bool isSuggestion(String candidate) { | |
2042 return _suggestedNames.containsValue(candidate); | |
2043 } | |
2044 } | |
OLD | NEW |