Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(123)

Side by Side Diff: pkg/compiler/lib/src/js_backend/namer.dart

Issue 1198293002: dart2js: Use an abstract Name class for names in the generated JavaScript ast. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Fix new emitter. Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 325 matching lines...) Expand 10 before | Expand all | Expand 10 after
336 final String methodsWithOptionalArgumentsField = 336 final String methodsWithOptionalArgumentsField =
337 r'$methodsWithOptionalArguments'; 337 r'$methodsWithOptionalArguments';
338 final String deferredAction = r'$deferredAction'; 338 final String deferredAction = r'$deferredAction';
339 339
340 final String classDescriptorProperty = r'^'; 340 final String classDescriptorProperty = r'^';
341 final String requiredParameterField = r'$requiredArgCount'; 341 final String requiredParameterField = r'$requiredArgCount';
342 342
343 /// The non-minifying namer's [callPrefix] with a dollar after it. 343 /// The non-minifying namer's [callPrefix] with a dollar after it.
344 static const String _callPrefixDollar = r'call$'; 344 static const String _callPrefixDollar = r'call$';
345 345
346 static final jsAst.Name literalSuper = new StringBackedName("super");
347 static final jsAst.Name literalDollar = new StringBackedName(r'$');
348 static final jsAst.Name literalUnderscore = new StringBackedName('_');
349 static final jsAst.Name literalPlus = new StringBackedName('+');
350 static final jsAst.Name literalDynamic = new StringBackedName("dynamic");
351
346 // Name of property in a class description for the native dispatch metadata. 352 // Name of property in a class description for the native dispatch metadata.
347 final String nativeSpecProperty = '%'; 353 final String nativeSpecProperty = '%';
348 354
349 static final RegExp IDENTIFIER = new RegExp(r'^[A-Za-z_$][A-Za-z0-9_$]*$'); 355 static final RegExp IDENTIFIER = new RegExp(r'^[A-Za-z_$][A-Za-z0-9_$]*$');
350 static final RegExp NON_IDENTIFIER_CHAR = new RegExp(r'[^A-Za-z_0-9$]'); 356 static final RegExp NON_IDENTIFIER_CHAR = new RegExp(r'[^A-Za-z_0-9$]');
351 357
352 final Compiler compiler; 358 final Compiler compiler;
353 359
354 /// Used disambiguated names in the global namespace, issued by 360 /// Used disambiguated names in the global namespace, issued by
355 /// [_disambiguateGlobal], and [_disambiguateInternalGlobal]. 361 /// [_disambiguateGlobal], and [_disambiguateInternalGlobal].
356 /// 362 ///
357 /// Although global names are distributed across a number of global objects, 363 /// Although global names are distributed across a number of global objects,
358 /// (see [globalObjectFor]), we currently use a single namespace for all these 364 /// (see [globalObjectFor]), we currently use a single namespace for all these
359 /// names. 365 /// names.
360 final Set<String> usedGlobalNames = new Set<String>(); 366 final Set<String> usedGlobalNames = new Set<String>();
361 final Map<Element, String> userGlobals = <Element, String>{}; 367 final Map<Element, jsAst.Name> userGlobals =
362 final Map<String, String> internalGlobals = <String, String>{}; 368 new HashMap<Element, jsAst.Name>();
369 final Map<String, jsAst.Name> internalGlobals =
370 new HashMap<String, jsAst.Name>();
363 371
364 /// Used disambiguated names in the instance namespace, issued by 372 /// Used disambiguated names in the instance namespace, issued by
365 /// [_disambiguateMember], [_disambiguateInternalMember], 373 /// [_disambiguateMember], [_disambiguateInternalMember],
366 /// [_disambiguateOperator], and [reservePublicMemberName]. 374 /// [_disambiguateOperator], and [reservePublicMemberName].
367 final Set<String> usedInstanceNames = new Set<String>(); 375 final Set<String> usedInstanceNames = new Set<String>();
368 final Map<String, String> userInstanceMembers = <String, String>{}; 376 final Map<String, jsAst.Name> userInstanceMembers =
369 final Map<Element, String> internalInstanceMembers = <Element, String>{}; 377 new HashMap<String, jsAst.Name>();
370 final Map<String, String> userInstanceOperators = <String, String>{}; 378 final Map<Element, jsAst.Name> internalInstanceMembers =
379 new HashMap<Element, jsAst.Name>();
380 final Map<String, jsAst.Name> userInstanceOperators =
381 new HashMap<String, jsAst.Name>();
371 382
372 final Map<String, int> popularNameCounters = <String, int>{}; 383 final Map<String, int> popularNameCounters = <String, int>{};
373 384
374 final Map<ConstantValue, String> constantNames = <ConstantValue, String>{}; 385 final Map<LibraryElement, String> libraryLongNames =
386 new HashMap<LibraryElement, String>();
387
388 final Map<ConstantValue, jsAst.Name> constantNames =
389 new HashMap<ConstantValue, jsAst.Name>();
375 final Map<ConstantValue, String> constantLongNames = 390 final Map<ConstantValue, String> constantLongNames =
376 <ConstantValue, String>{}; 391 <ConstantValue, String>{};
377 ConstantCanonicalHasher constantHasher; 392 ConstantCanonicalHasher constantHasher;
378 393
379 /// Maps private names to a library that may use that name without prefixing 394 /// Maps private names to a library that may use that name without prefixing
380 /// itself. Used for building proposed names. 395 /// itself. Used for building proposed names.
381 final Map<String, LibraryElement> shortPrivateNameOwners = 396 final Map<String, LibraryElement> shortPrivateNameOwners =
382 <String, LibraryElement>{}; 397 <String, LibraryElement>{};
383 398
384 /// Maps proposed names to *suggested* disambiguated names. 399 /// Maps proposed names to *suggested* disambiguated names.
385 /// 400 ///
386 /// Suggested names are hints to the [MinifyNamer], suggesting that a specific 401 /// Suggested names are hints to the [MinifyNamer], suggesting that a specific
387 /// names be given to the first item with the given proposed name. 402 /// names be given to the first item with the given proposed name.
388 /// 403 ///
389 /// This is currently used in [MinifyNamer] to assign very short minified 404 /// This is currently used in [MinifyNamer] to assign very short minified
390 /// names to things that tend to be used very often. 405 /// names to things that tend to be used very often.
391 final Map<String, String> suggestedGlobalNames = <String, String>{}; 406 final Map<String, String> suggestedGlobalNames = <String, String>{};
392 final Map<String, String> suggestedInstanceNames = <String, String>{}; 407 final Map<String, String> suggestedInstanceNames = <String, String>{};
393 408
409 /// Used to store unique keys for library names. Keys are not used as names,
410 /// nor are they visible in the output. The only serve as an internal
411 /// key into maps.
412 final Map<LibraryElement, String> _libraryKeys =
413 new HashMap<LibraryElement, String>();
414
394 Namer(Compiler compiler) 415 Namer(Compiler compiler)
395 : compiler = compiler, 416 : compiler = compiler,
396 constantHasher = new ConstantCanonicalHasher(compiler), 417 constantHasher = new ConstantCanonicalHasher(compiler),
397 functionTypeNamer = new FunctionTypeNamer(compiler); 418 functionTypeNamer = new FunctionTypeNamer(compiler);
398 419
399 JavaScriptBackend get backend => compiler.backend; 420 JavaScriptBackend get backend => compiler.backend;
400 421
401 String get deferredTypesName => 'deferredTypes'; 422 String get deferredTypesName => 'deferredTypes';
402 String get isolateName => 'Isolate'; 423 String get isolateName => 'Isolate';
403 String get isolatePropertiesName => r'$isolateProperties'; 424 String get isolatePropertiesName => r'$isolateProperties';
404 String get noSuchMethodName => publicInstanceMethodNameByArity( 425 jsAst.Name get noSuchMethodName => publicInstanceMethodNameByArity(
405 Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT); 426 Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT);
406 /** 427 /**
407 * Some closures must contain their name. The name is stored in 428 * Some closures must contain their name. The name is stored in
408 * [STATIC_CLOSURE_NAME_NAME]. 429 * [STATIC_CLOSURE_NAME_NAME].
409 */ 430 */
410 String get STATIC_CLOSURE_NAME_NAME => r'$name'; 431 String get STATIC_CLOSURE_NAME_NAME => r'$name';
411 String get closureInvocationSelectorName => Compiler.CALL_OPERATOR_NAME; 432 String get closureInvocationSelectorName => Compiler.CALL_OPERATOR_NAME;
412 bool get shouldMinify => false; 433 bool get shouldMinify => false;
413 434
414 /// Returns the string that is to be used as the result of a call to 435 /// Returns the string that is to be used as the result of a call to
415 /// [JS_GET_NAME] at [node] with argument [name]. 436 /// [JS_GET_NAME] at [node] with argument [name].
416 String getNameForJsGetName(Node node, JsGetName name) { 437 jsAst.Name getNameForJsGetName(Node node, JsGetName name) {
417 switch (name) { 438 switch (name) {
418 case JsGetName.GETTER_PREFIX: return getterPrefix; 439 case JsGetName.GETTER_PREFIX: return asName(getterPrefix);
419 case JsGetName.SETTER_PREFIX: return setterPrefix; 440 case JsGetName.SETTER_PREFIX: return asName(setterPrefix);
420 case JsGetName.CALL_PREFIX: return callPrefix; 441 case JsGetName.CALL_PREFIX: return asName(callPrefix);
421 case JsGetName.CALL_PREFIX0: return '${callPrefix}\$0'; 442 case JsGetName.CALL_PREFIX0: return asName('${callPrefix}\$0');
422 case JsGetName.CALL_PREFIX1: return '${callPrefix}\$1'; 443 case JsGetName.CALL_PREFIX1: return asName('${callPrefix}\$1');
423 case JsGetName.CALL_PREFIX2: return '${callPrefix}\$2'; 444 case JsGetName.CALL_PREFIX2: return asName('${callPrefix}\$2');
424 case JsGetName.CALL_PREFIX3: return '${callPrefix}\$3'; 445 case JsGetName.CALL_PREFIX3: return asName('${callPrefix}\$3');
425 case JsGetName.CALL_CATCH_ALL: return callCatchAllName; 446 case JsGetName.CALL_CATCH_ALL: return asName(callCatchAllName);
426 case JsGetName.REFLECTABLE: return reflectableField; 447 case JsGetName.REFLECTABLE: return asName(reflectableField);
427 case JsGetName.CLASS_DESCRIPTOR_PROPERTY: 448 case JsGetName.CLASS_DESCRIPTOR_PROPERTY:
428 return classDescriptorProperty; 449 return asName(classDescriptorProperty);
429 case JsGetName.REQUIRED_PARAMETER_PROPERTY: 450 case JsGetName.REQUIRED_PARAMETER_PROPERTY:
430 return requiredParameterField; 451 return asName(requiredParameterField);
431 case JsGetName.DEFAULT_VALUES_PROPERTY: return defaultValuesField; 452 case JsGetName.DEFAULT_VALUES_PROPERTY: return asName(defaultValuesField);
432 case JsGetName.CALL_NAME_PROPERTY: return callNameField; 453 case JsGetName.CALL_NAME_PROPERTY: return asName(callNameField);
433 case JsGetName.DEFERRED_ACTION_PROPERTY: return deferredAction; 454 case JsGetName.DEFERRED_ACTION_PROPERTY: return asName(deferredAction);
434 case JsGetName.OPERATOR_AS_PREFIX: return operatorAsPrefix; 455 case JsGetName.OPERATOR_AS_PREFIX: return asName(operatorAsPrefix);
435 case JsGetName.SIGNATURE_NAME: return operatorSignature; 456 case JsGetName.SIGNATURE_NAME: return asName(operatorSignature);
436 case JsGetName.TYPEDEF_TAG: return typedefTag; 457 case JsGetName.TYPEDEF_TAG: return asName(typedefTag);
437 case JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG: 458 case JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG:
438 return functionTypeVoidReturnTag; 459 return asName(functionTypeVoidReturnTag);
439 case JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG: 460 case JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG:
440 return functionTypeReturnTypeTag; 461 return asName(functionTypeReturnTypeTag);
441 case JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG: 462 case JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG:
442 return functionTypeRequiredParametersTag; 463 return asName(functionTypeRequiredParametersTag);
443 case JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG: 464 case JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG:
444 return functionTypeOptionalParametersTag; 465 return asName(functionTypeOptionalParametersTag);
445 case JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG: 466 case JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG:
446 return functionTypeNamedParametersTag; 467 return asName(functionTypeNamedParametersTag);
447 case JsGetName.IS_INDEXABLE_FIELD_NAME: 468 case JsGetName.IS_INDEXABLE_FIELD_NAME:
448 Element cls = backend.findHelper('JavaScriptIndexingBehavior'); 469 Element cls = backend.findHelper('JavaScriptIndexingBehavior');
449 return operatorIs(cls); 470 return operatorIs(cls);
471 case JsGetName.NULL_CLASS_TYPE_NAME:
472 return runtimeTypeName(compiler.nullClass);
473 case JsGetName.OBJECT_CLASS_TYPE_NAME:
474 return runtimeTypeName(compiler.objectClass);
475 case JsGetName.FUNCTION_CLASS_TYPE_NAME:
476 return runtimeTypeName(compiler.functionClass);
450 default: 477 default:
451 compiler.reportError( 478 compiler.reportError(
452 node, MessageKind.GENERIC, 479 node, MessageKind.GENERIC,
453 {'text': 'Error: Namer has no name for "$name".'}); 480 {'text': 'Error: Namer has no name for "$name".'});
454 return 'BROKEN'; 481 return asName('BROKEN');
455 } 482 }
456 } 483 }
457 484
458 /// Disambiguated name for [constant]. 485 /// Disambiguated name for [constant].
459 /// 486 ///
460 /// Unique within the global-member namespace. 487 /// Unique within the global-member namespace.
461 String constantName(ConstantValue constant) { 488 jsAst.Name constantName(ConstantValue constant) {
462 // In the current implementation it doesn't make sense to give names to 489 // In the current implementation it doesn't make sense to give names to
463 // function constants since the function-implementation itself serves as 490 // function constants since the function-implementation itself serves as
464 // constant and can be accessed directly. 491 // constant and can be accessed directly.
465 assert(!constant.isFunction); 492 assert(!constant.isFunction);
466 String result = constantNames[constant]; 493 jsAst.Name result = constantNames[constant];
467 if (result == null) { 494 if (result == null) {
468 String longName = constantLongName(constant); 495 String longName = constantLongName(constant);
469 result = getFreshName(longName, usedGlobalNames, suggestedGlobalNames); 496 result = getFreshName(longName, usedGlobalNames, suggestedGlobalNames);
470 constantNames[constant] = result; 497 constantNames[constant] = result;
471 } 498 }
472 return result; 499 return result;
473 } 500 }
474 501
475 /// Proposed name for [constant]. 502 /// Proposed name for [constant].
476 String constantLongName(ConstantValue constant) { 503 String constantLongName(ConstantValue constant) {
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
523 // The first library asking for a short private name wins. 550 // The first library asking for a short private name wins.
524 LibraryElement owner = 551 LibraryElement owner =
525 shortPrivateNameOwners.putIfAbsent(text, () => library); 552 shortPrivateNameOwners.putIfAbsent(text, () => library);
526 553
527 if (owner == library) { 554 if (owner == library) {
528 return text; 555 return text;
529 } else { 556 } else {
530 // Make sure to return a private name that starts with _ so it 557 // Make sure to return a private name that starts with _ so it
531 // cannot clash with any public names. 558 // cannot clash with any public names.
532 // The name is still not guaranteed to be unique, since both the library 559 // The name is still not guaranteed to be unique, since both the library
533 // name and originalName could contain $ symbols. 560 // name and originalName could contain $ symbols and as the library
534 String libraryName = _disambiguateGlobal(library); 561 // name itself might clash.
535 return '_$libraryName\$${text}'; 562 String libraryName = _proposeNameForGlobal(library);
563 return "_$libraryName\$$text";
536 } 564 }
537 } 565 }
538 566
539 String _proposeNameForConstructorBody(ConstructorBodyElement method) { 567 _proposeNameForConstructorBody(ConstructorBodyElement method) {
floitsch 2015/06/22 17:43:44 returns a String.
herhut 2015/06/23 13:26:30 Done.
540 String name = Elements.reconstructConstructorNameSourceString(method); 568 String name = Elements.reconstructConstructorNameSourceString(method);
541 // We include the method suffix on constructor bodies. It has no purpose, 569 // We include the method suffix on constructor bodies. It has no purpose,
542 // but this way it produces the same names as previous versions of the 570 // but this way it produces the same names as previous versions of the
543 // Namer class did. 571 // Namer class did.
544 List<String> suffix = callSuffixForSignature(method.functionSignature); 572 List<String> suffix = callSuffixForSignature(method.functionSignature);
545 return '$name\$${suffix.join(r'$')}'; 573 return '$name\$${suffix.join(r'$')}';
546 } 574 }
547 575
548 /// Annotated name for [method] encoding arity and named parameters. 576 /// Annotated name for [method] encoding arity and named parameters.
549 String instanceMethodName(FunctionElement method) { 577 jsAst.Name instanceMethodName(FunctionElement method) {
550 if (method.isGenerativeConstructorBody) { 578 if (method.isGenerativeConstructorBody) {
551 return _disambiguateInternalMember(method, 579 return _disambiguateInternalMember(method,
552 () => _proposeNameForConstructorBody(method)); 580 () => _proposeNameForConstructorBody(method));
553 } 581 }
554 return invocationName(new Selector.fromElement(method)); 582 return invocationName(new Selector.fromElement(method));
555 } 583 }
556 584
557 /// Annotated name for a public method with the given [originalName] 585 /// Annotated name for a public method with the given [originalName]
558 /// and [arity] and no named parameters. 586 /// and [arity] and no named parameters.
559 String publicInstanceMethodNameByArity(String originalName, int arity) { 587 jsAst.Name publicInstanceMethodNameByArity(String originalName,
588 int arity) {
floitsch 2015/06/22 17:43:44 indentation.
herhut 2015/06/23 13:26:30 Done.
560 return invocationName(new Selector.call(originalName, null, arity)); 589 return invocationName(new Selector.call(originalName, null, arity));
561 } 590 }
562 591
563 /// Returns the annotated name for a variant of `call`. 592 /// Returns the annotated name for a variant of `call`.
564 /// The result has the form: 593 /// The result has the form:
565 /// 594 ///
566 /// call$<N>$namedParam1...$namedParam<M> 595 /// call$<N>$namedParam1...$namedParam<M>
567 /// 596 ///
568 /// This name cannot be minified because it is generated by string 597 /// This name cannot be minified because it is generated by string
569 /// concatenation at runtime, by applyFunction in js_helper.dart. 598 /// concatenation at runtime, by applyFunction in js_helper.dart.
570 String deriveCallMethodName(List<String> suffix) { 599 jsAst.Name deriveCallMethodName(List<String> suffix) {
571 // TODO(asgerf): Avoid clashes when named parameters contain $ symbols. 600 // TODO(asgerf): Avoid clashes when named parameters contain $ symbols.
572 return '$callPrefix\$${suffix.join(r'$')}'; 601 return new StringBackedName('$callPrefix\$${suffix.join(r'$')}');
573 } 602 }
574 603
575 /// The suffix list for the pattern: 604 /// The suffix list for the pattern:
576 /// 605 ///
577 /// $<N>$namedParam1...$namedParam<M> 606 /// $<N>$namedParam1...$namedParam<M>
578 /// 607 ///
579 /// This is used for the annotated names of `call`, and for the proposed name 608 /// This is used for the annotated names of `call`, and for the proposed name
580 /// for other instance methods. 609 /// for other instance methods.
581 List<String> callSuffixForStructure(CallStructure callStructure) { 610 List<String> callSuffixForStructure(CallStructure callStructure) {
582 List<String> suffixes = ['${callStructure.argumentCount}']; 611 List<String> suffixes = ['${callStructure.argumentCount}'];
(...skipping 11 matching lines...) Expand all
594 List<String> suffixes = ['${sig.parameterCount}']; 623 List<String> suffixes = ['${sig.parameterCount}'];
595 if (sig.optionalParametersAreNamed) { 624 if (sig.optionalParametersAreNamed) {
596 for (FormalElement param in sig.orderedOptionalParameters) { 625 for (FormalElement param in sig.orderedOptionalParameters) {
597 suffixes.add(param.name); 626 suffixes.add(param.name);
598 } 627 }
599 } 628 }
600 return suffixes; 629 return suffixes;
601 } 630 }
602 631
603 /// Annotated name for the member being invoked by [selector]. 632 /// Annotated name for the member being invoked by [selector].
604 String invocationName(Selector selector) { 633 jsAst.Name invocationName(Selector selector) {
605 switch (selector.kind) { 634 switch (selector.kind) {
606 case SelectorKind.GETTER: 635 case SelectorKind.GETTER:
607 String disambiguatedName = _disambiguateMember(selector.memberName); 636 jsAst.Name disambiguatedName =
637 _disambiguateMember(selector.memberName);
608 return deriveGetterName(disambiguatedName); 638 return deriveGetterName(disambiguatedName);
609 639
610 case SelectorKind.SETTER: 640 case SelectorKind.SETTER:
611 String disambiguatedName = _disambiguateMember(selector.memberName); 641 jsAst.Name disambiguatedName =
642 _disambiguateMember(selector.memberName);
612 return deriveSetterName(disambiguatedName); 643 return deriveSetterName(disambiguatedName);
613 644
614 case SelectorKind.OPERATOR: 645 case SelectorKind.OPERATOR:
615 case SelectorKind.INDEX: 646 case SelectorKind.INDEX:
616 String operatorIdentifier = operatorNameToIdentifier(selector.name); 647 String operatorIdentifier = operatorNameToIdentifier(selector.name);
617 String disambiguatedName = _disambiguateOperator(operatorIdentifier); 648 jsAst.Name disambiguatedName =
649 _disambiguateOperator(operatorIdentifier);
618 return disambiguatedName; // Operators are not annotated. 650 return disambiguatedName; // Operators are not annotated.
619 651
620 case SelectorKind.CALL: 652 case SelectorKind.CALL:
621 List<String> suffix = callSuffixForStructure(selector.callStructure); 653 List<String> suffix = callSuffixForStructure(selector.callStructure);
622 if (selector.name == Compiler.CALL_OPERATOR_NAME) { 654 if (selector.name == Compiler.CALL_OPERATOR_NAME) {
623 // Derive the annotated name for this variant of 'call'. 655 // Derive the annotated name for this variant of 'call'.
624 return deriveCallMethodName(suffix); 656 return deriveCallMethodName(suffix);
625 } 657 }
626 String disambiguatedName = 658 jsAst.Name disambiguatedName =
627 _disambiguateMember(selector.memberName, suffix); 659 _disambiguateMember(selector.memberName, suffix);
628 return disambiguatedName; // Methods other than call are not annotated. 660 return disambiguatedName; // Methods other than call are not annotated.
629 661
630 default: 662 default:
631 compiler.internalError(compiler.currentElement, 663 compiler.internalError(compiler.currentElement,
632 'Unexpected selector kind: ${selector.kind}'); 664 'Unexpected selector kind: ${selector.kind}');
633 return null; 665 return null;
634 } 666 }
635 } 667 }
636 668
637 /** 669 /**
638 * Returns the internal name used for an invocation mirror of this selector. 670 * Returns the internal name used for an invocation mirror of this selector.
639 */ 671 */
640 String invocationMirrorInternalName(Selector selector) 672 jsAst.Name invocationMirrorInternalName(Selector selector)
641 => invocationName(selector); 673 => invocationName(selector);
642 674
643 /** 675 /**
644 * Returns the disambiguated name for the given field, used for constructing 676 * Returns the disambiguated name for the given field, used for constructing
645 * the getter and setter names. 677 * the getter and setter names.
646 */ 678 */
647 String fieldAccessorName(FieldElement element) { 679 jsAst.Name fieldAccessorName(FieldElement element) {
648 return element.isInstanceMember 680 return element.isInstanceMember
649 ? _disambiguateMember(element.memberName) 681 ? _disambiguateMember(element.memberName)
650 : _disambiguateGlobal(element); 682 : _disambiguateGlobal(element);
651 } 683 }
652 684
653 /** 685 /**
654 * Returns name of the JavaScript property used to store a static or instance 686 * Returns name of the JavaScript property used to store a static or instance
655 * field. 687 * field.
656 */ 688 */
657 String fieldPropertyName(FieldElement element) { 689 jsAst.Name fieldPropertyName(FieldElement element) {
658 return element.isInstanceMember 690 return element.isInstanceMember
659 ? instanceFieldPropertyName(element) 691 ? instanceFieldPropertyName(element)
660 : _disambiguateGlobal(element); 692 : _disambiguateGlobal(element);
661 } 693 }
662 694
663 /** 695 /**
664 * Returns name of the JavaScript property used to store the 696 * Returns name of the JavaScript property used to store the
665 * `readTypeVariable` function for the given type variable. 697 * `readTypeVariable` function for the given type variable.
666 */ 698 */
667 String nameForReadTypeVariable(TypeVariableElement element) { 699 jsAst.Name nameForReadTypeVariable(TypeVariableElement element) {
668 return _disambiguateInternalMember(element, () => element.name); 700 return _disambiguateInternalMember(element, () => element.name);
669 } 701 }
670 702
671 /** 703 /**
672 * Returns a JavaScript property name used to store [element] on one 704 * Returns a JavaScript property name used to store [element] on one
673 * of the global objects. 705 * of the global objects.
674 * 706 *
675 * Should be used together with [globalObjectFor], which denotes the object 707 * Should be used together with [globalObjectFor], which denotes the object
676 * on which the returned property name should be used. 708 * on which the returned property name should be used.
677 */ 709 */
678 String globalPropertyName(Element element) { 710 jsAst.Name globalPropertyName(Element element) {
679 return _disambiguateGlobal(element); 711 return _disambiguateGlobal(element);
680 } 712 }
681 713
682 /** 714 /**
683 * Returns the JavaScript property name used to store an instance field. 715 * Returns the JavaScript property name used to store an instance field.
684 */ 716 */
685 String instanceFieldPropertyName(FieldElement element) { 717 jsAst.Name instanceFieldPropertyName(FieldElement element) {
686 ClassElement enclosingClass = element.enclosingClass; 718 ClassElement enclosingClass = element.enclosingClass;
687 719
688 if (element.hasFixedBackendName) { 720 if (element.hasFixedBackendName) {
689 // Certain native fields must be given a specific name. Native names must 721 // Certain native fields must be given a specific name. Native names must
690 // not contain '$'. We rely on this to avoid clashes. 722 // not contain '$'. We rely on this to avoid clashes.
691 assert(enclosingClass.isNative && 723 assert(enclosingClass.isNative &&
692 !element.fixedBackendName.contains(r'$')); 724 !element.fixedBackendName.contains(r'$'));
693 725
694 return element.fixedBackendName; 726 return new StringBackedName(element.fixedBackendName);
695 } 727 }
696 728
697 // Instances of BoxFieldElement are special. They are already created with 729 // Instances of BoxFieldElement are special. They are already created with
698 // a unique and safe name. However, as boxes are not really instances of 730 // a unique and safe name. However, as boxes are not really instances of
699 // classes, the usual naming scheme that tries to avoid name clashes with 731 // classes, the usual naming scheme that tries to avoid name clashes with
700 // super classes does not apply. We still do not mark the name as a 732 // super classes does not apply. We still do not mark the name as a
701 // fixedBackendName, as we want to allow other namers to do something more 733 // fixedBackendName, as we want to allow other namers to do something more
702 // clever with them. 734 // clever with them.
703 if (element is BoxFieldElement) { 735 if (element is BoxFieldElement) {
704 return element.name; 736 return new StringBackedName(element.name);
705 } 737 }
706 738
707 // If the name of the field might clash with another field, 739 // If the name of the field might clash with another field,
708 // use a mangled field name to avoid potential clashes. 740 // use a mangled field name to avoid potential clashes.
709 // Note that if the class extends a native class, that native class might 741 // Note that if the class extends a native class, that native class might
710 // have fields with fixed backend names, so we assume the worst and always 742 // have fields with fixed backend names, so we assume the worst and always
711 // mangle the field names of classes extending native classes. 743 // mangle the field names of classes extending native classes.
712 // Methods on such classes are stored on the interceptor, not the instance, 744 // Methods on such classes are stored on the interceptor, not the instance,
713 // so only fields have the potential to clash with a native property name. 745 // so only fields have the potential to clash with a native property name.
714 ClassWorld classWorld = compiler.world; 746 ClassWorld classWorld = compiler.world;
(...skipping 14 matching lines...) Expand all
729 return element.enclosingClass.hasFieldShadowedBy(element); 761 return element.enclosingClass.hasFieldShadowedBy(element);
730 } 762 }
731 763
732 /// True if [class_] is a non-native class that inherits from a native class. 764 /// True if [class_] is a non-native class that inherits from a native class.
733 bool _isUserClassExtendingNative(ClassElement class_) { 765 bool _isUserClassExtendingNative(ClassElement class_) {
734 return !class_.isNative && 766 return !class_.isNative &&
735 Elements.isNativeOrExtendsNative(class_.superclass); 767 Elements.isNativeOrExtendsNative(class_.superclass);
736 } 768 }
737 769
738 /// Annotated name for the setter of [element]. 770 /// Annotated name for the setter of [element].
739 String setterForElement(MemberElement element) { 771 jsAst.Name setterForElement(MemberElement element) {
740 // We dynamically create setters from the field-name. The setter name must 772 // We dynamically create setters from the field-name. The setter name must
741 // therefore be derived from the instance field-name. 773 // therefore be derived from the instance field-name.
742 String name = _disambiguateMember(element.memberName); 774 jsAst.Name name = _disambiguateMember(element.memberName);
743 return deriveSetterName(name); 775 return deriveSetterName(name);
744 } 776 }
745 777
746 /// Annotated name for the setter of any member with [disambiguatedName]. 778 /// Annotated name for the setter of any member with [disambiguatedName].
747 String deriveSetterName(String disambiguatedName) { 779 jsAst.Name deriveSetterName(jsAst.Name disambiguatedName) {
748 // We dynamically create setters from the field-name. The setter name must 780 // We dynamically create setters from the field-name. The setter name must
749 // therefore be derived from the instance field-name. 781 // therefore be derived from the instance field-name.
750 return '$setterPrefix$disambiguatedName'; 782 return new SetterName(new StringBackedName(setterPrefix),
sra1 2015/06/23 04:47:54 The prefix should probably be cached.
herhut 2015/06/23 13:26:30 Done.
783 disambiguatedName);
751 } 784 }
752 785
753 /// Annotated name for the setter of any member with [disambiguatedName]. 786 /// Annotated name for the setter of any member with [disambiguatedName].
754 String deriveGetterName(String disambiguatedName) { 787 jsAst.Name deriveGetterName(jsAst.Name disambiguatedName) {
755 // We dynamically create getters from the field-name. The getter name must 788 // We dynamically create getters from the field-name. The getter name must
756 // therefore be derived from the instance field-name. 789 // therefore be derived from the instance field-name.
757 return '$getterPrefix$disambiguatedName'; 790 return new GetterName(new StringBackedName(getterPrefix),
791 disambiguatedName);
758 } 792 }
759 793
760 /// Annotated name for the getter of [element]. 794 /// Annotated name for the getter of [element].
761 String getterForElement(MemberElement element) { 795 jsAst.Name getterForElement(MemberElement element) {
762 // We dynamically create getters from the field-name. The getter name must 796 // We dynamically create getters from the field-name. The getter name must
763 // therefore be derived from the instance field-name. 797 // therefore be derived from the instance field-name.
764 String name = _disambiguateMember(element.memberName); 798 jsAst.Name name = _disambiguateMember(element.memberName);
765 return deriveGetterName(name); 799 return deriveGetterName(name);
766 } 800 }
767 801
768 /// Property name for the getter of an instance member with [originalName]. 802 /// Property name for the getter of an instance member with [originalName].
769 String getterForMember(Name originalName) { 803 jsAst.Name getterForMember(Name originalName) {
770 String disambiguatedName = _disambiguateMember(originalName); 804 jsAst.Name disambiguatedName = _disambiguateMember(originalName);
771 return deriveGetterName(disambiguatedName); 805 return deriveGetterName(disambiguatedName);
772 } 806 }
773 807
774 /// Disambiguated name for a compiler-owned global variable. 808 /// Disambiguated name for a compiler-owned global variable.
775 /// 809 ///
776 /// The resulting name is unique within the global-member namespace. 810 /// The resulting name is unique within the global-member namespace.
777 String _disambiguateInternalGlobal(String name) { 811 jsAst.Name _disambiguateInternalGlobal(String name) {
778 String newName = internalGlobals[name]; 812 jsAst.Name newName = internalGlobals[name];
779 if (newName == null) { 813 if (newName == null) {
780 newName = getFreshName(name, usedGlobalNames, suggestedGlobalNames); 814 newName = getFreshName(name, usedGlobalNames, suggestedGlobalNames);
781 internalGlobals[name] = newName; 815 internalGlobals[name] = newName;
782 } 816 }
783 return newName; 817 return newName;
784 } 818 }
785 819
786 /// Returns the property name to use for a compiler-owner global variable, 820 /// Returns the property name to use for a compiler-owner global variable,
787 /// i.e. one that does not correspond to any element but is used as a utility 821 /// i.e. one that does not correspond to any element but is used as a utility
788 /// global by code generation. 822 /// global by code generation.
789 /// 823 ///
790 /// [name] functions as both the proposed name for the global, and as a key 824 /// [name] functions as both the proposed name for the global, and as a key
791 /// identifying the global. The [name] must not contain `$` symbols, since 825 /// identifying the global. The [name] must not contain `$` symbols, since
792 /// the [Namer] uses those names internally. 826 /// the [Namer] uses those names internally.
793 /// 827 ///
794 /// This provides an easy mechanism of avoiding a name-clash with user-space 828 /// This provides an easy mechanism of avoiding a name-clash with user-space
795 /// globals, although the callers of must still take care not to accidentally 829 /// globals, although the callers of must still take care not to accidentally
796 /// pass in the same [name] for two different internal globals. 830 /// pass in the same [name] for two different internal globals.
797 String internalGlobal(String name) { 831 jsAst.Name internalGlobal(String name) {
798 assert(!name.contains(r'$')); 832 assert(!name.contains(r'$'));
799 return _disambiguateInternalGlobal(name); 833 return _disambiguateInternalGlobal(name);
800 } 834 }
801 835
836 /// Generates a unique key for [library].
837 ///
838 /// Keys are meant to be used in maps and should not be visible in the output.
839 String _generateLibraryKey(LibraryElement library) {
840 return _libraryKeys.putIfAbsent(library, () {
841 String keyBase = library.name;
842 int counter = 0;
843 String key = keyBase;
844 while (_libraryKeys.values.contains(key)) {
845 key ="$keyBase${counter++}";
846 }
847 return key;
848 });
849 }
850
802 /// Returns the disambiguated name for a top-level or static element. 851 /// Returns the disambiguated name for a top-level or static element.
803 /// 852 ///
804 /// The resulting name is unique within the global-member namespace. 853 /// The resulting name is unique within the global-member namespace.
805 String _disambiguateGlobal(Element element) { 854 jsAst.Name _disambiguateGlobal(Element element) {
806 // TODO(asgerf): We can reuse more short names if we disambiguate with 855 // TODO(asgerf): We can reuse more short names if we disambiguate with
807 // a separate namespace for each of the global holder objects. 856 // a separate namespace for each of the global holder objects.
808 element = element.declaration; 857 element = element.declaration;
809 String newName = userGlobals[element]; 858 jsAst.Name newName = userGlobals[element];
810 if (newName == null) { 859 if (newName == null) {
811 String proposedName = _proposeNameForGlobal(element); 860 String proposedName = _proposeNameForGlobal(element);
812 newName = getFreshName(proposedName, usedGlobalNames, 861 newName = getFreshName(proposedName, usedGlobalNames,
813 suggestedGlobalNames); 862 suggestedGlobalNames);
814 userGlobals[element] = newName; 863 userGlobals[element] = newName;
815 } 864 }
816 return newName; 865 return newName;
817 } 866 }
818 867
819 /// Returns the disambiguated name for an instance method or field 868 /// Returns the disambiguated name for an instance method or field
820 /// with [originalName] in [library]. 869 /// with [originalName] in [library].
821 /// 870 ///
822 /// [library] may be `null` if [originalName] is known to be public. 871 /// [library] may be `null` if [originalName] is known to be public.
823 /// 872 ///
824 /// This is the name used for deriving property names of accessors (getters 873 /// This is the name used for deriving property names of accessors (getters
825 /// and setters) and as property name for storing methods and method stubs. 874 /// and setters) and as property name for storing methods and method stubs.
826 /// 875 ///
827 /// [suffixes] denote an extension of [originalName] to distiguish it from 876 /// [suffixes] denote an extension of [originalName] to distiguish it from
828 /// other members with that name. These are used to encode the arity and 877 /// other members with that name. These are used to encode the arity and
829 /// named parameters to a method. Disambiguating the same [originalName] with 878 /// named parameters to a method. Disambiguating the same [originalName] with
830 /// different [suffixes] will yield different disambiguated names. 879 /// different [suffixes] will yield different disambiguated names.
831 /// 880 ///
832 /// The resulting name, and its associated annotated names, are unique 881 /// The resulting name, and its associated annotated names, are unique
833 /// to the ([originalName], [suffixes]) pair within the instance-member 882 /// to the ([originalName], [suffixes]) pair within the instance-member
834 /// namespace. 883 /// namespace.
835 String _disambiguateMember(Name originalName, 884 jsAst.Name _disambiguateMember(Name originalName,
836 [List<String> suffixes = const []]) { 885 [List<String> suffixes = const []]) {
837 // Build a string encoding the library name, if the name is private. 886 // Build a string encoding the library name, if the name is private.
838 String libraryKey = originalName.isPrivate 887 String libraryKey = originalName.isPrivate
839 ? _disambiguateGlobal(originalName.library) 888 ? _generateLibraryKey(originalName.library)
840 : ''; 889 : '';
841 890
842 // In the unique key, separate the name parts by '@'. 891 // In the unique key, separate the name parts by '@'.
843 // This avoids clashes since the original names cannot contain that symbol. 892 // This avoids clashes since the original names cannot contain that symbol.
844 String key = '$libraryKey@${originalName.text}@${suffixes.join('@')}'; 893 String key = '$libraryKey@${originalName.text}@${suffixes.join('@')}';
845 String newName = userInstanceMembers[key]; 894 jsAst.Name newName = userInstanceMembers[key];
846 if (newName == null) { 895 if (newName == null) {
847 String proposedName = privateName(originalName); 896 String proposedName = privateName(originalName);
848 if (!suffixes.isEmpty) { 897 if (!suffixes.isEmpty) {
849 // In the proposed name, separate the name parts by '$', because the 898 // In the proposed name, separate the name parts by '$', because the
850 // proposed name must be a valid identifier, but not necessarily unique. 899 // proposed name must be a valid identifier, but not necessarily unique.
851 proposedName += r'$' + suffixes.join(r'$'); 900 proposedName += r'$' + suffixes.join(r'$');
852 } 901 }
853 newName = getFreshName(proposedName, 902 newName = getFreshName(proposedName,
854 usedInstanceNames, suggestedInstanceNames, 903 usedInstanceNames, suggestedInstanceNames,
855 sanitizeForAnnotations: true); 904 sanitizeForAnnotations: true);
(...skipping 11 matching lines...) Expand all
867 /// Using [_disambiguateMember] with the given [originalName] and no suffixes 916 /// Using [_disambiguateMember] with the given [originalName] and no suffixes
868 /// will subsequently return [disambiguatedName]. 917 /// will subsequently return [disambiguatedName].
869 void reservePublicMemberName(String originalName, 918 void reservePublicMemberName(String originalName,
870 String disambiguatedName) { 919 String disambiguatedName) {
871 // Build a key that corresponds to the one built in disambiguateMember. 920 // Build a key that corresponds to the one built in disambiguateMember.
872 String libraryPrefix = ''; // Public names have an empty library prefix. 921 String libraryPrefix = ''; // Public names have an empty library prefix.
873 String suffix = ''; // We don't need any suffixes. 922 String suffix = ''; // We don't need any suffixes.
874 String key = '$libraryPrefix@$originalName@$suffix'; 923 String key = '$libraryPrefix@$originalName@$suffix';
875 assert(!userInstanceMembers.containsKey(key)); 924 assert(!userInstanceMembers.containsKey(key));
876 assert(!usedInstanceNames.contains(disambiguatedName)); 925 assert(!usedInstanceNames.contains(disambiguatedName));
877 userInstanceMembers[key] = disambiguatedName; 926 userInstanceMembers[key] = new StringBackedName(disambiguatedName);
878 usedInstanceNames.add(disambiguatedName); 927 usedInstanceNames.add(disambiguatedName);
879 } 928 }
880 929
881 /// Disambiguated name unique to [element]. 930 /// Disambiguated name unique to [element].
882 /// 931 ///
883 /// This is used as the property name for fields, type variables, 932 /// This is used as the property name for fields, type variables,
884 /// constructor bodies, and super-accessors. 933 /// constructor bodies, and super-accessors.
885 /// 934 ///
886 /// The resulting name is unique within the instance-member namespace. 935 /// The resulting name is unique within the instance-member namespace.
887 String _disambiguateInternalMember(Element element, String proposeName()) { 936 jsAst.Name _disambiguateInternalMember(Element element,
888 String newName = internalInstanceMembers[element]; 937 String proposeName()) {
938 jsAst.Name newName = internalInstanceMembers[element];
889 if (newName == null) { 939 if (newName == null) {
890 String name = proposeName(); 940 String name = proposeName();
891 bool mayClashNative = _isUserClassExtendingNative(element.enclosingClass); 941 bool mayClashNative = _isUserClassExtendingNative(element.enclosingClass);
892 newName = getFreshName(name, 942 newName = getFreshName(name,
893 usedInstanceNames, suggestedInstanceNames, 943 usedInstanceNames, suggestedInstanceNames,
894 sanitizeForAnnotations: true, 944 sanitizeForAnnotations: true,
895 sanitizeForNatives: mayClashNative); 945 sanitizeForNatives: mayClashNative);
896 internalInstanceMembers[element] = newName; 946 internalInstanceMembers[element] = newName;
897 } 947 }
898 return newName; 948 return newName;
899 } 949 }
900 950
901 /// Disambiguated name for the given operator. 951 /// Disambiguated name for the given operator.
902 /// 952 ///
903 /// [operatorIdentifier] must be the operator's identifier, e.g. 953 /// [operatorIdentifier] must be the operator's identifier, e.g.
904 /// `$add` and not `+`. 954 /// `$add` and not `+`.
905 /// 955 ///
906 /// The resulting name is unique within the instance-member namespace. 956 /// The resulting name is unique within the instance-member namespace.
907 String _disambiguateOperator(String operatorIdentifier) { 957 jsAst.Name _disambiguateOperator(String operatorIdentifier) {
908 String newName = userInstanceOperators[operatorIdentifier]; 958 jsAst.Name newName = userInstanceOperators[operatorIdentifier];
909 if (newName == null) { 959 if (newName == null) {
910 newName = getFreshName(operatorIdentifier, usedInstanceNames, 960 newName = getFreshName(operatorIdentifier, usedInstanceNames,
911 suggestedInstanceNames); 961 suggestedInstanceNames);
912 userInstanceOperators[operatorIdentifier] = newName; 962 userInstanceOperators[operatorIdentifier] = newName;
913 } 963 }
914 return newName; 964 return newName;
915 } 965 }
916 966
917 /// Returns an unused name. 967 /// Returns an unused name.
918 /// 968 ///
919 /// [proposedName] must be a valid JavaScript identifier. 969 /// [proposedName] must be a valid JavaScript identifier.
920 /// 970 ///
921 /// If [sanitizeForAnnotations] is `true`, then the result is guaranteed not 971 /// If [sanitizeForAnnotations] is `true`, then the result is guaranteed not
922 /// to have the form of an annotated name. 972 /// to have the form of an annotated name.
923 /// 973 ///
924 /// If [sanitizeForNatives] it `true`, then the result is guaranteed not to 974 /// If [sanitizeForNatives] it `true`, then the result is guaranteed not to
925 /// clash with a property name on a native object. 975 /// clash with a property name on a native object.
926 /// 976 ///
927 /// Note that [MinifyNamer] overrides this method with one that produces 977 /// Note that [MinifyNamer] overrides this method with one that produces
928 /// minified names. 978 /// minified names.
929 String getFreshName(String proposedName, 979 jsAst.Name getFreshName(String proposedName,
930 Set<String> usedNames, 980 Set<String> usedNames,
931 Map<String, String> suggestedNames, 981 Map<String, String> suggestedNames,
932 {bool sanitizeForAnnotations: false, 982 {bool sanitizeForAnnotations: false,
933 bool sanitizeForNatives: false}) { 983 bool sanitizeForNatives: false}) {
934 if (sanitizeForAnnotations) { 984 if (sanitizeForAnnotations) {
935 proposedName = _sanitizeForAnnotations(proposedName); 985 proposedName = _sanitizeForAnnotations(proposedName);
936 } 986 }
937 if (sanitizeForNatives) { 987 if (sanitizeForNatives) {
938 proposedName = _sanitizeForNatives(proposedName); 988 proposedName = _sanitizeForNatives(proposedName);
939 } 989 }
940 proposedName = _sanitizeForKeywords(proposedName); 990 proposedName = _sanitizeForKeywords(proposedName);
941 String candidate; 991 String candidate;
942 if (!usedNames.contains(proposedName)) { 992 if (!usedNames.contains(proposedName)) {
943 candidate = proposedName; 993 candidate = proposedName;
944 } else { 994 } else {
945 int counter = popularNameCounters[proposedName]; 995 int counter = popularNameCounters[proposedName];
946 int i = (counter == null) ? 0 : counter; 996 int i = (counter == null) ? 0 : counter;
947 while (usedNames.contains("$proposedName$i")) { 997 while (usedNames.contains("$proposedName$i")) {
948 i++; 998 i++;
949 } 999 }
950 popularNameCounters[proposedName] = i + 1; 1000 popularNameCounters[proposedName] = i + 1;
951 candidate = "$proposedName$i"; 1001 candidate = "$proposedName$i";
952 } 1002 }
953 usedNames.add(candidate); 1003 usedNames.add(candidate);
954 return candidate; 1004 return new StringBackedName(candidate);
955 } 1005 }
956 1006
957 /// Returns a variant of [name] that cannot clash with the annotated 1007 /// Returns a variant of [name] that cannot clash with the annotated
958 /// version of another name, that is, the resulting name can never be returned 1008 /// version of another name, that is, the resulting name can never be returned
959 /// by [deriveGetterName], [deriveSetterName], [deriveCallMethodName], 1009 /// by [deriveGetterName], [deriveSetterName], [deriveCallMethodName],
960 /// [operatorIs], or [substitutionName]. 1010 /// [operatorIs], or [substitutionName].
961 /// 1011 ///
962 /// For example, a name `get$x` would be converted to `$get$x` to ensure it 1012 /// For example, a name `get$x` would be converted to `$get$x` to ensure it
963 /// cannot clash with the getter for `x`. 1013 /// cannot clash with the getter for `x`.
964 /// 1014 ///
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
1010 } else if (Elements.isStaticOrTopLevel(element)) { 1060 } else if (Elements.isStaticOrTopLevel(element)) {
1011 if (element.isClassMember) { 1061 if (element.isClassMember) {
1012 ClassElement enclosingClass = element.enclosingClass; 1062 ClassElement enclosingClass = element.enclosingClass;
1013 name = "${enclosingClass.name}_" 1063 name = "${enclosingClass.name}_"
1014 "${element.name}"; 1064 "${element.name}";
1015 } else { 1065 } else {
1016 name = element.name.replaceAll('+', '_'); 1066 name = element.name.replaceAll('+', '_');
1017 } 1067 }
1018 } else if (element.isLibrary) { 1068 } else if (element.isLibrary) {
1019 LibraryElement library = element; 1069 LibraryElement library = element;
1070 name = libraryLongNames[library];
1071 if (name != null) return name;
1020 name = library.getLibraryOrScriptName(); 1072 name = library.getLibraryOrScriptName();
1021 if (name.contains('.')) { 1073 if (name.contains('.')) {
1022 // For libraries that have a library tag, we use the last part 1074 // For libraries that have a library tag, we use the last part
1023 // of the fully qualified name as their base name. For all other 1075 // of the fully qualified name as their base name. For all other
1024 // libraries, we use the first part of their filename. 1076 // libraries, we use the first part of their filename.
1025 name = library.hasLibraryName() 1077 name = library.hasLibraryName()
1026 ? name.substring(name.lastIndexOf('.') + 1) 1078 ? name.substring(name.lastIndexOf('.') + 1)
1027 : name.substring(0, name.indexOf('.')); 1079 : name.substring(0, name.indexOf('.'));
1028 } 1080 }
1029 // The filename based name can contain all kinds of nasty characters. Make 1081 // The filename based name can contain all kinds of nasty characters. Make
1030 // sure it is an identifier. 1082 // sure it is an identifier.
1031 if (!IDENTIFIER.hasMatch(name)) { 1083 if (!IDENTIFIER.hasMatch(name)) {
1032 name = name.replaceAllMapped(NON_IDENTIFIER_CHAR, 1084 name = name.replaceAllMapped(NON_IDENTIFIER_CHAR,
1033 (match) => match[0].codeUnitAt(0).toRadixString(16)); 1085 (match) => match[0].codeUnitAt(0).toRadixString(16));
1034 if (!IDENTIFIER.hasMatch(name)) { // e.g. starts with digit. 1086 if (!IDENTIFIER.hasMatch(name)) { // e.g. starts with digit.
1035 name = 'lib_$name'; 1087 name = 'lib_$name';
1036 } 1088 }
1037 } 1089 }
1090 // Names constructed based on a libary name will be further disambiguated.
1091 // However, as names from the same libary should have the same libary
1092 // name part, we disambiguate the library name here.
1093 String disambiguated = name;
1094 for (int c = 0; libraryLongNames.containsValue(disambiguated); c++) {
1095 disambiguated = "$name$c";
1096 }
1097 libraryLongNames[library] = disambiguated;
1098 name = disambiguated;
1038 } else { 1099 } else {
1039 name = element.name; 1100 name = element.name;
1040 } 1101 }
1041 return name; 1102 return name;
1042 } 1103 }
1043 1104
1044 String suffixForGetInterceptor(Iterable<ClassElement> classes) { 1105 String suffixForGetInterceptor(Iterable<ClassElement> classes) {
1045 String abbreviate(ClassElement cls) { 1106 String abbreviate(ClassElement cls) {
1046 if (cls == compiler.objectClass) return "o"; 1107 if (cls == compiler.objectClass) return "o";
1047 if (cls == backend.jsStringClass) return "s"; 1108 if (cls == backend.jsStringClass) return "s";
(...skipping 14 matching lines...) Expand all
1062 if (classes.any((cls) => Elements.isNativeOrExtendsNative(cls))) { 1123 if (classes.any((cls) => Elements.isNativeOrExtendsNative(cls))) {
1063 names.add("x"); 1124 names.add("x");
1064 } 1125 }
1065 // Sort the names of the classes after abbreviating them to ensure 1126 // Sort the names of the classes after abbreviating them to ensure
1066 // the suffix is stable and predictable for the suggested names. 1127 // the suffix is stable and predictable for the suggested names.
1067 names.sort(); 1128 names.sort();
1068 return names.join(); 1129 return names.join();
1069 } 1130 }
1070 1131
1071 /// Property name used for `getInterceptor` or one of its specializations. 1132 /// Property name used for `getInterceptor` or one of its specializations.
1072 String nameForGetInterceptor(Iterable<ClassElement> classes) { 1133 jsAst.Name nameForGetInterceptor(Iterable<ClassElement> classes) {
1073 FunctionElement getInterceptor = backend.getInterceptorMethod; 1134 FunctionElement getInterceptor = backend.getInterceptorMethod;
1074 if (classes.contains(backend.jsInterceptorClass)) { 1135 if (classes.contains(backend.jsInterceptorClass)) {
1075 // If the base Interceptor class is in the set of intercepted classes, we 1136 // If the base Interceptor class is in the set of intercepted classes, we
1076 // need to go through the generic getInterceptorMethod, since any subclass 1137 // need to go through the generic getInterceptorMethod, since any subclass
1077 // of the base Interceptor could match. 1138 // of the base Interceptor could match.
1078 // The unspecialized getInterceptor method can also be accessed through 1139 // The unspecialized getInterceptor method can also be accessed through
1079 // its element, so we treat this as a user-space global instead of an 1140 // its element, so we treat this as a user-space global instead of an
1080 // internal global. 1141 // internal global.
1081 return _disambiguateGlobal(getInterceptor); 1142 return _disambiguateGlobal(getInterceptor);
1082 } 1143 }
1083 String suffix = suffixForGetInterceptor(classes); 1144 String suffix = suffixForGetInterceptor(classes);
1084 return _disambiguateInternalGlobal("${getInterceptor.name}\$$suffix"); 1145 return _disambiguateInternalGlobal("${getInterceptor.name}\$$suffix");
1085 } 1146 }
1086 1147
1087 /// Property name used for the one-shot interceptor method for the given 1148 /// Property name used for the one-shot interceptor method for the given
1088 /// [selector] and return-type specialization. 1149 /// [selector] and return-type specialization.
1089 String nameForGetOneShotInterceptor(Selector selector, 1150 jsAst.Name nameForGetOneShotInterceptor(Selector selector,
1090 Iterable<ClassElement> classes) { 1151 Iterable<ClassElement> classes) {
1091 // The one-shot name is a global name derived from the invocation name. To 1152 // The one-shot name is a global name derived from the invocation name. To
1092 // avoid instability we would like the names to be unique and not clash with 1153 // avoid instability we would like the names to be unique and not clash with
1093 // other global names. 1154 // other global names.
1094 1155
1095 String root = invocationName(selector); 1156 jsAst.Name root = invocationName(selector);
1096 1157
1097 if (classes.contains(backend.jsInterceptorClass)) { 1158 if (classes.contains(backend.jsInterceptorClass)) {
1098 // If the base Interceptor class is in the set of intercepted classes, 1159 // If the base Interceptor class is in the set of intercepted classes,
1099 // this is the most general specialization which uses the generic 1160 // this is the most general specialization which uses the generic
1100 // getInterceptor method. To keep the name short, we add '$' only to 1161 // getInterceptor method. To keep the name short, we add '$' only to
1101 // distinguish from internal globals requested from outside the Namer 1162 // distinguish from internal globals requested from outside the Namer
1102 // with internalGlobal(). 1163 // with internalGlobal().
1103 // TODO(sra): Find a way to get the simple name when Object is not in the 1164 // TODO(sra): Find a way to get the simple name when Object is not in the
1104 // set of classes for most general variant, e.g. "$lt$n" could be "$lt". 1165 // set of classes for most general variant, e.g. "$lt$n" could be "$lt".
1105 if (selector.isGetter || selector.isSetter) root = '$root\$'; 1166 if (selector.isGetter || selector.isSetter) {
1106 return _disambiguateInternalGlobal(root); 1167 return new CompoundName([root, literalDollar]);
1168 } else {
1169 return root;
1170 }
1107 } else { 1171 } else {
1108 String suffix = suffixForGetInterceptor(classes); 1172 String suffix = suffixForGetInterceptor(classes);
1109 return _disambiguateInternalGlobal("$root\$$suffix"); 1173 return new CompoundName([root, literalDollar,
1174 new StringBackedName(suffix)]);
1110 } 1175 }
1111 } 1176 }
1112 1177
1113 /// Returns the runtime name for [element]. 1178 /// Returns the runtime name for [element].
1114 /// 1179 ///
1115 /// This name is used as the basis for deriving `is` and `as` property names 1180 /// This name is used as the basis for deriving `is` and `as` property names
1116 /// for the given type. 1181 /// for the given type.
1117 /// 1182 ///
1118 /// The result is not always safe as a property name unless prefixing 1183 /// The result is not always safe as a property name unless prefixing
1119 /// [operatorIsPrefix] or [operatorAsPrefix]. If this is a function type, 1184 /// [operatorIsPrefix] or [operatorAsPrefix]. If this is a function type,
1120 /// then by convention, an underscore must also separate [operatorIsPrefix] 1185 /// then by convention, an underscore must also separate [operatorIsPrefix]
1121 /// from the type name. 1186 /// from the type name.
1122 String runtimeTypeName(TypeDeclarationElement element) { 1187 jsAst.Name runtimeTypeName(TypeDeclarationElement element) {
1123 if (element == null) return 'dynamic'; 1188 if (element == null) return literalDynamic;
1124 // The returned name affects both the global and instance member namespaces: 1189 // The returned name affects both the global and instance member namespaces:
1125 // 1190 //
1126 // - If given a class, this must coincide with the class name, which 1191 // - If given a class, this must coincide with the class name, which
1127 // is also the GLOBAL property name of its constructor. 1192 // is also the GLOBAL property name of its constructor.
1128 // 1193 //
1129 // - The result is used to derive `$isX` and `$asX` names, which are used 1194 // - The result is used to derive `$isX` and `$asX` names, which are used
1130 // as INSTANCE property names. 1195 // as INSTANCE property names.
1131 // 1196 //
1132 // To prevent clashes in both namespaces at once, we disambiguate the name 1197 // To prevent clashes in both namespaces at once, we disambiguate the name
1133 // as a global here, and in [_sanitizeForAnnotations] we ensure that 1198 // as a global here, and in [_sanitizeForAnnotations] we ensure that
1134 // ordinary instance members cannot start with `$is` or `$as`. 1199 // ordinary instance members cannot start with `$is` or `$as`.
1135 return _disambiguateGlobal(element); 1200 return _disambiguateGlobal(element);
1136 } 1201 }
1137 1202
1138 /// Returns the disambiguated name of [class_]. 1203 /// Returns the disambiguated name of [class_].
1139 /// 1204 ///
1140 /// This is both the *runtime type* of the class (see [runtimeTypeName]) 1205 /// This is both the *runtime type* of the class (see [runtimeTypeName])
1141 /// and a global property name in which to store its JS constructor. 1206 /// and a global property name in which to store its JS constructor.
1142 String className(ClassElement class_) => _disambiguateGlobal(class_); 1207 jsAst.Name className(ClassElement class_) => _disambiguateGlobal(class_);
1143 1208
1144 /// Property name on which [member] can be accessed directly, 1209 /// Property name on which [member] can be accessed directly,
1145 /// without clashing with another JS property name. 1210 /// without clashing with another JS property name.
1146 /// 1211 ///
1147 /// This is used for implementing super-calls, where ordinary dispatch 1212 /// This is used for implementing super-calls, where ordinary dispatch
1148 /// semantics must be circumvented. For example: 1213 /// semantics must be circumvented. For example:
1149 /// 1214 ///
1150 /// class A { foo() } 1215 /// class A { foo() }
1151 /// class B extends A { 1216 /// class B extends A {
1152 /// foo() { super.foo() } 1217 /// foo() { super.foo() }
1153 /// } 1218 /// }
1154 /// 1219 ///
1155 /// Example translation to JS: 1220 /// Example translation to JS:
1156 /// 1221 ///
1157 /// A.prototype.super$A$foo = function() {...} 1222 /// A.prototype.super$A$foo = function() {...}
1158 /// A.prototype.foo$0 = A.prototype.super$A$foo 1223 /// A.prototype.foo$0 = A.prototype.super$A$foo
1159 /// 1224 ///
1160 /// B.prototype.foo$0 = function() { 1225 /// B.prototype.foo$0 = function() {
1161 /// this.super$A$foo(); // super.foo() 1226 /// this.super$A$foo(); // super.foo()
1162 /// } 1227 /// }
1163 /// 1228 ///
1164 String aliasedSuperMemberPropertyName(Element member) { 1229 jsAst.Name aliasedSuperMemberPropertyName(Element member) {
1165 assert(!member.isField); // Fields do not need super aliases. 1230 assert(!member.isField); // Fields do not need super aliases.
1166 String methodName = instanceMethodName(member); 1231 return _disambiguateInternalMember(member, () {
1167 return _disambiguateInternalMember(member, 1232 String invocationName = operatorNameToIdentifier(member.name);
1168 () => 'super\$${member.enclosingClass.name}\$$methodName'); 1233 return "super\$${member.enclosingClass.name}\$$invocationName";
1234 });
1169 } 1235 }
1170 1236
1171 /// Property name in which to store the given static or instance [method]. 1237 /// Property name in which to store the given static or instance [method].
1172 /// For instance methods, this includes the suffix encoding arity and named 1238 /// For instance methods, this includes the suffix encoding arity and named
1173 /// parameters. 1239 /// parameters.
1174 /// 1240 ///
1175 /// The name is not necessarily unique to [method], since a static method 1241 /// The name is not necessarily unique to [method], since a static method
1176 /// may share its name with an instance method. 1242 /// may share its name with an instance method.
1177 String methodPropertyName(Element method) { 1243 jsAst.Name methodPropertyName(Element method) {
1178 return method.isInstanceMember 1244 return method.isInstanceMember
1179 ? instanceMethodName(method) 1245 ? instanceMethodName(method)
1180 : globalPropertyName(method); 1246 : globalPropertyName(method);
1181 } 1247 }
1182 1248
1183 /// Returns true if [element] is stored on current isolate ('$'). We intend 1249 /// Returns true if [element] is stored on current isolate ('$'). We intend
1184 /// to store only mutable static state in [currentIsolate], constants are 1250 /// to store only mutable static state in [currentIsolate], constants are
1185 /// stored in 'C', and functions, accessors, classes, etc. are stored in one 1251 /// stored in 'C', and functions, accessors, classes, etc. are stored in one
1186 /// of the other objects in [reservedGlobalObjectNames]. 1252 /// of the other objects in [reservedGlobalObjectNames].
1187 bool isPropertyOfCurrentIsolate(Element element) { 1253 bool isPropertyOfCurrentIsolate(Element element) {
(...skipping 18 matching lines...) Expand all
1206 if (library == backend.interceptorsLibrary) return 'J'; 1272 if (library == backend.interceptorsLibrary) return 'J';
1207 if (library.isInternalLibrary) return 'H'; 1273 if (library.isInternalLibrary) return 'H';
1208 if (library.isPlatformLibrary) { 1274 if (library.isPlatformLibrary) {
1209 if ('${library.canonicalUri}' == 'dart:html') return 'W'; 1275 if ('${library.canonicalUri}' == 'dart:html') return 'W';
1210 return 'P'; 1276 return 'P';
1211 } 1277 }
1212 return userGlobalObjects[ 1278 return userGlobalObjects[
1213 library.getLibraryOrScriptName().hashCode % userGlobalObjects.length]; 1279 library.getLibraryOrScriptName().hashCode % userGlobalObjects.length];
1214 } 1280 }
1215 1281
1216 String lazyInitializerName(Element element) { 1282 jsAst.Name lazyInitializerName(Element element) {
1217 assert(Elements.isStaticOrTopLevelField(element)); 1283 assert(Elements.isStaticOrTopLevelField(element));
1218 String name = _disambiguateGlobal(element); 1284 jsAst.Name name = _disambiguateGlobal(element);
1219 return _disambiguateInternalGlobal("$getterPrefix$name"); 1285 // Why do we need to disambiguate here?
floitsch 2015/06/22 17:43:44 Maybe I'm missing something, but I think you can h
herhut 2015/06/23 13:26:30 Good point. Fixed.
1286 // return _disambiguateInternalGlobal("$getterPrefix$name");
1287 return deriveGetterName(name);
1220 } 1288 }
1221 1289
1222 String staticClosureName(Element element) { 1290 jsAst.Name staticClosureName(Element element) {
1223 assert(Elements.isStaticOrTopLevelFunction(element)); 1291 assert(Elements.isStaticOrTopLevelFunction(element));
1224 String name = _disambiguateGlobal(element); 1292 String enclosing = element.enclosingClass == null
1225 return _disambiguateInternalGlobal("$name\$closure"); 1293 ? "" : element.enclosingClass.name;
1294 String library = _proposeNameForGlobal(element.library);
1295 return _disambiguateInternalGlobal(
1296 "${library}_${enclosing}_${element.name}\$closure");
1226 } 1297 }
1227 1298
1228 // This name is used as part of the name of a TypeConstant 1299 // This name is used as part of the name of a TypeConstant
1229 String uniqueNameForTypeConstantElement(Element element) { 1300 String uniqueNameForTypeConstantElement(Element element) {
1230 // TODO(sra): If we replace the period with an identifier character, 1301 // TODO(sra): If we replace the period with an identifier character,
1231 // TypeConstants will have better names in unminified code. 1302 // TypeConstants will have better names in unminified code.
1232 return "${globalObjectFor(element)}.${globalPropertyName(element)}"; 1303 String library = _proposeNameForGlobal(element.library);
1304 return "${library}.${element.name}";
1233 } 1305 }
1234 1306
1235 String globalObjectForConstant(ConstantValue constant) => 'C'; 1307 String globalObjectForConstant(ConstantValue constant) => 'C';
1236 1308
1237 String get operatorIsPrefix => r'$is'; 1309 String get operatorIsPrefix => r'$is';
1238 1310
1239 String get operatorAsPrefix => r'$as'; 1311 String get operatorAsPrefix => r'$as';
1240 1312
1241 String get operatorSignature => r'$signature'; 1313 String get operatorSignature => r'$signature';
1242 1314
1243 String get typedefTag => r'typedef'; 1315 String get typedefTag => r'typedef';
1244 1316
1245 String get functionTypeTag => r'func'; 1317 String get functionTypeTag => r'func';
1246 1318
1247 String get functionTypeVoidReturnTag => r'void'; 1319 String get functionTypeVoidReturnTag => r'void';
1248 1320
1249 String get functionTypeReturnTypeTag => r'ret'; 1321 String get functionTypeReturnTypeTag => r'ret';
1250 1322
1251 String get functionTypeRequiredParametersTag => r'args'; 1323 String get functionTypeRequiredParametersTag => r'args';
1252 1324
1253 String get functionTypeOptionalParametersTag => r'opt'; 1325 String get functionTypeOptionalParametersTag => r'opt';
1254 1326
1255 String get functionTypeNamedParametersTag => r'named'; 1327 String get functionTypeNamedParametersTag => r'named';
1256 1328
1257 Map<FunctionType,String> functionTypeNameMap = 1329 Map<FunctionType, jsAst.Name> functionTypeNameMap =
1258 new Map<FunctionType,String>(); 1330 new HashMap<FunctionType, jsAst.Name>();
1259 final FunctionTypeNamer functionTypeNamer; 1331 final FunctionTypeNamer functionTypeNamer;
1260 1332
1261 String getFunctionTypeName(FunctionType functionType) { 1333 jsAst.Name getFunctionTypeName(FunctionType functionType) {
1262 return functionTypeNameMap.putIfAbsent(functionType, () { 1334 return functionTypeNameMap.putIfAbsent(functionType, () {
1263 String proposedName = functionTypeNamer.computeName(functionType); 1335 String proposedName = functionTypeNamer.computeName(functionType);
1264 String freshName = getFreshName(proposedName, usedInstanceNames, 1336 return getFreshName(proposedName, usedInstanceNames,
1265 suggestedInstanceNames); 1337 suggestedInstanceNames);
1266 return freshName;
1267 }); 1338 });
1268 } 1339 }
1269 1340
1270 String operatorIsType(DartType type) { 1341 jsAst.Name operatorIsType(DartType type) {
1271 if (type.isFunctionType) { 1342 if (type.isFunctionType) {
1272 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. 1343 // TODO(erikcorry): Reduce from $isx to ix when we are minifying.
1273 return '${operatorIsPrefix}_${getFunctionTypeName(type)}'; 1344 return new CompoundName([new StringBackedName(operatorIsPrefix),
1345 literalUnderscore,
1346 getFunctionTypeName(type)]);
1274 } 1347 }
1275 return operatorIs(type.element); 1348 return operatorIs(type.element);
1276 } 1349 }
1277 1350
1278 String operatorIs(ClassElement element) { 1351 jsAst.Name operatorIs(ClassElement element) {
1279 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. 1352 // TODO(erikcorry): Reduce from $isx to ix when we are minifying.
1280 return '${operatorIsPrefix}${runtimeTypeName(element)}'; 1353 return new CompoundName([new StringBackedName(operatorIsPrefix),
1354 runtimeTypeName(element)]);
1281 } 1355 }
1282 1356
1283 /// Returns a name that does not clash with reserved JS keywords. 1357 /// Returns a name that does not clash with reserved JS keywords.
1284 String _sanitizeForKeywords(String name) { 1358 String _sanitizeForKeywords(String name) {
1285 if (jsReserved.contains(name)) { 1359 if (jsReserved.contains(name)) {
1286 name = '\$$name'; 1360 name = '\$$name';
1287 } 1361 }
1288 assert(!jsReserved.contains(name)); 1362 assert(!jsReserved.contains(name));
1289 return name; 1363 return name;
1290 } 1364 }
1291 1365
1292 String substitutionName(Element element) { 1366 jsAst.Name substitutionName(Element element) {
1293 return '${operatorAsPrefix}${runtimeTypeName(element)}'; 1367 return new CompoundName([new StringBackedName(operatorAsPrefix),
1368 runtimeTypeName(element)]);
1369 }
1370
1371 /// Translates a [String] into the corresponding [Name] data structure as
1372 /// used by the namer.
1373 ///
1374 /// If [name] is a setter or getter name, the corresponding [GetterName] or
floitsch 2015/06/22 17:43:44 That shouldn't be necessary for static names. (unl
herhut 2015/06/23 13:26:30 This is mostly used in testing (as otherwise one c
1375 /// [SetterName] data structure is used.
1376 jsAst.Name asName(String name) {
1377 if (name.startsWith(getterPrefix) && name.length > getterPrefix.length) {
1378 return new GetterName(new StringBackedName(getterPrefix),
1379 new StringBackedName(
1380 name.substring(getterPrefix.length)));
1381 }
1382 if (name.startsWith(setterPrefix) && name.length > setterPrefix.length) {
1383 return new GetterName(new StringBackedName(setterPrefix),
1384 new StringBackedName(
1385 name.substring(setterPrefix.length)));
1386 }
1387
1388 return new StringBackedName(name);
1294 } 1389 }
1295 1390
1296 /// Returns a variable name that cannot clash with a keyword, a global 1391 /// Returns a variable name that cannot clash with a keyword, a global
1297 /// variable, or any name starting with a single '$'. 1392 /// variable, or any name starting with a single '$'.
1298 /// 1393 ///
1299 /// Furthermore, this function is injective, that is, it never returns the 1394 /// Furthermore, this function is injective, that is, it never returns the
1300 /// same name for two different inputs. 1395 /// same name for two different inputs.
1301 String safeVariableName(String name) { 1396 String safeVariableName(String name) {
1302 if (jsVariableReserved.contains(name) || name.startsWith(r'$')) { 1397 if (jsVariableReserved.contains(name) || name.startsWith(r'$')) {
1303 return '\$$name'; 1398 return '\$$name';
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
1352 } 1447 }
1353 } 1448 }
1354 1449
1355 String get incrementalHelperName => r'$dart_unsafe_incremental_support'; 1450 String get incrementalHelperName => r'$dart_unsafe_incremental_support';
1356 1451
1357 jsAst.Expression get accessIncrementalHelper { 1452 jsAst.Expression get accessIncrementalHelper {
1358 return js('self.${incrementalHelperName}'); 1453 return js('self.${incrementalHelperName}');
1359 } 1454 }
1360 1455
1361 void forgetElement(Element element) { 1456 void forgetElement(Element element) {
1362 String globalName = userGlobals[element]; 1457 jsAst.Name globalName = userGlobals[element];
1363 invariant(element, globalName != null, message: 'No global name.'); 1458 invariant(element, globalName != null, message: 'No global name.');
1364 usedGlobalNames.remove(globalName); 1459 usedGlobalNames.remove(globalName);
1365 userGlobals.remove(element); 1460 userGlobals.remove(element);
1366 } 1461 }
1367 } 1462 }
1368 1463
1464 abstract class _NamerName extends jsAst.Name {
1465 int get _kind;
1466 }
1467
1468 class StringBackedName extends _NamerName {
1469 final String name;
1470 final int _kind = 1;
sra1 2015/06/23 04:47:54 int get _kind => 1; Otherwise you are still doing
herhut 2015/06/23 13:26:30 Done.
1471
1472 StringBackedName(this.name);
1473
1474 toString() => throw new UnsupportedError("Cannot convert a name to a string");
1475
1476 operator==(other) => (other is StringBackedName) && other.name == name;
sra1 2015/06/23 04:47:54 Is the purpose of ==, hashCode and compareTo? Are
herhut 2015/06/23 13:26:30 Yes. However, typically only instances of StingBac
1477
1478 int get hashCode => name.hashCode;
1479
1480 int compareTo(other) {
1481 if (other is! _NamerName) return -1;
sra1 2015/06/23 04:47:54 Since you can't make the other implementation of N
herhut 2015/06/23 13:26:30 Done.
1482 if (other._kind != _kind) return other._kind - _kind;
1483 return name.compareTo(other.name);
1484 }
1485 }
1486
1487 abstract class _PrefixedName extends _NamerName {
1488 final jsAst.Name prefix;
1489 final jsAst.Name base;
1490 int get _kind;
sra1 2015/06/23 04:47:54 Somewhat redundant with _NamerName._kind. Leave it
herhut 2015/06/23 13:26:31 Removed.
1491
1492 _PrefixedName(this.prefix, this.base);
1493
1494 String get name => prefix.name + base.name;
1495
1496 toString() => throw new UnsupportedError("Cannot convert a name to a string");
1497
1498 operator==(other) {
1499 if (other is! _PrefixedName) return false;
1500 return other.base == base && other.prefix == prefix;
1501 }
1502
1503 int get hashCode => base.hashCode * 13 + prefix.hashCode;
1504
1505 int compareTo(other) {
1506 if (other is! _NamerName) return -1;
1507 if (other._kind != _kind) return other._kind - _kind;
1508 int result = prefix.compareTo(other.prefix);
1509 if (result == 0) {
1510 result = name.compareTo(other.name);
1511 }
1512 return result;
1513 }
1514 }
1515
1516 class GetterName extends _PrefixedName {
1517 final int _kind = 2;
1518
1519 GetterName(jsAst.Name prefix, jsAst.Name base) : super(prefix, base);
1520 }
1521
1522 class SetterName extends _PrefixedName {
1523 final int _kind = 3;
1524
1525 SetterName(jsAst.Name prefix, jsAst.Name base) : super(prefix, base);
1526 }
1527
1528 class CompoundName extends _NamerName {
1529 final List<_NamerName> _parts;
1530 final int _kind = 4;
1531 String _cachedName;
1532 int _cachedHashCode = -1;
1533
1534 CompoundName(this._parts);
1535
1536 String get name {
1537 if (_cachedName == null) {
1538 _cachedName = _parts.map((jsAst.Name name) => name.name).join();
1539 }
1540 return _cachedName;
1541 }
1542
1543 toString() => throw new UnsupportedError("Cannot convert a name to a string");
1544
1545 operator==(other) {
floitsch 2015/06/22 17:43:44 bool
herhut 2015/06/23 13:26:31 Done.
1546 if (other is! CompoundName) return false;
1547 if (other._parts.length != _parts.length) return false;
1548 for (int i = 0; i < _parts.length; ++i) {
1549 if (other._parts[i] != _parts[i]) return false;
1550 }
1551 return true;
1552 }
1553
1554 int get hashCode {
1555 if (_cachedHashCode < 0) {
1556 _cachedHashCode = 0;
1557 for (jsAst.Name name in _parts) {
1558 _cachedHashCode = (_cachedHashCode * 17) & 0x7fffffff;
1559 }
1560 }
1561 return _cachedHashCode;
1562 }
1563
1564 int compareTo(other) {
1565 if (other is! _NamerName) return -1;
1566 if (other._kind != _kind) return other._kind - _kind;
1567 if (other._parts.length != _parts.length) {
1568 return other._parts.length - _parts.length;
1569 }
1570 int result = 0;
1571 for (int pos = 0; result == 0 && pos < _parts.length; pos++) {
1572 result = _parts[pos].compareTo(other._parts[pos]);
1573 }
1574 return result;
1575 }
1576 }
1577
1369 /** 1578 /**
1370 * Generator of names for [ConstantValue] values. 1579 * Generator of names for [ConstantValue] values.
1371 * 1580 *
1372 * The names are stable under perturbations of the source. The name is either a 1581 * The names are stable under perturbations of the source. The name is either a
1373 * short sequence of words, if this can be found from the constant, or a type 1582 * short sequence of words, if this can be found from the constant, or a type
1374 * followed by a hash tag. 1583 * followed by a hash tag.
1375 * 1584 *
1376 * List_imX // A List, with hash tag. 1585 * List_imX // A List, with hash tag.
1377 * C_Sentinel // const Sentinel(), "C_" added to avoid clash 1586 * C_Sentinel // const Sentinel(), "C_" added to avoid clash
1378 * // with class name. 1587 * // with class name.
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
1543 1752
1544 @override 1753 @override
1545 void visitSynthetic(SyntheticConstantValue constant, [_]) { 1754 void visitSynthetic(SyntheticConstantValue constant, [_]) {
1546 switch (constant.kind) { 1755 switch (constant.kind) {
1547 case SyntheticConstantKind.DUMMY_INTERCEPTOR: 1756 case SyntheticConstantKind.DUMMY_INTERCEPTOR:
1548 add('dummy_receiver'); 1757 add('dummy_receiver');
1549 break; 1758 break;
1550 case SyntheticConstantKind.TYPEVARIABLE_REFERENCE: 1759 case SyntheticConstantKind.TYPEVARIABLE_REFERENCE:
1551 add('type_variable_reference'); 1760 add('type_variable_reference');
1552 break; 1761 break;
1762 case SyntheticConstantKind.NAME:
1763 add('name');
1764 break;
1553 default: 1765 default:
1554 compiler.internalError(compiler.currentElement, 1766 compiler.internalError(compiler.currentElement,
1555 "Unexpected SyntheticConstantValue"); 1767 "Unexpected SyntheticConstantValue");
1556 } 1768 }
1557 } 1769 }
1558 1770
1559 @override 1771 @override
1560 void visitDeferred(DeferredConstantValue constant, [_]) { 1772 void visitDeferred(DeferredConstantValue constant, [_]) {
1561 addRoot('Deferred'); 1773 addRoot('Deferred');
1562 } 1774 }
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
1791 if (!first) { 2003 if (!first) {
1792 sb.write('_'); 2004 sb.write('_');
1793 } 2005 }
1794 sb.write('_'); 2006 sb.write('_');
1795 visit(parameter); 2007 visit(parameter);
1796 first = true; 2008 first = true;
1797 } 2009 }
1798 } 2010 }
1799 } 2011 }
1800 } 2012 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698