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 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |