| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 /** | 5 /** |
| 6 * A function element that represents a closure call. The signature is copied | 6 * A function element that represents a closure call. The signature is copied |
| 7 * from the given element. | 7 * from the given element. |
| 8 */ | 8 */ |
| 9 class ClosureInvocationElement extends FunctionElement { | 9 class ClosureInvocationElement extends FunctionElement { |
| 10 ClosureInvocationElement(SourceString name, | 10 ClosureInvocationElement(SourceString name, |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 => '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}'; | 62 => '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}'; |
| 63 String get supportsProtoName | 63 String get supportsProtoName |
| 64 => 'supportsProto'; | 64 => 'supportsProto'; |
| 65 | 65 |
| 66 final String GETTER_SUFFIX = "?"; | 66 final String GETTER_SUFFIX = "?"; |
| 67 final String SETTER_SUFFIX = "!"; | 67 final String SETTER_SUFFIX = "!"; |
| 68 final String GETTER_SETTER_SUFFIX = "="; | 68 final String GETTER_SETTER_SUFFIX = "="; |
| 69 | 69 |
| 70 String get generateGetterSetterFunction { | 70 String get generateGetterSetterFunction { |
| 71 return """ | 71 return """ |
| 72 function(field, prototype) { | 72 function(field, prototype) { |
| 73 var len = field.length; | 73 var len = field.length; |
| 74 var lastChar = field[len - 1]; | 74 var lastChar = field[len - 1]; |
| 75 var needsGetter = lastChar == '$GETTER_SUFFIX' || lastChar == '$GETTER_SETTER_
SUFFIX'; | 75 var needsGetter = lastChar == '$GETTER_SUFFIX' || lastChar == '$GETTER_SETTE
R_SUFFIX'; |
| 76 var needsSetter = lastChar == '$SETTER_SUFFIX' || lastChar == '$GETTER_SETTER_
SUFFIX'; | 76 var needsSetter = lastChar == '$SETTER_SUFFIX' || lastChar == '$GETTER_SETTE
R_SUFFIX'; |
| 77 if (needsGetter || needsSetter) field = field.substring(0, len - 1); | 77 if (needsGetter || needsSetter) field = field.substring(0, len - 1); |
| 78 if (needsGetter) { | 78 if (needsGetter) { |
| 79 var getterString = "return this." + field + ";"; | 79 var getterString = "return this." + field + ";"; |
| 80 """ /* The supportsProtoCheck below depends on the getter/setter convention. | 80 """ |
| 81 When changing here, update the protoCheck too. */ """ | 81 /* The supportsProtoCheck below depends on the getter/setter convention. |
| 82 prototype["get\$" + field] = new Function(getterString); | 82 When changing here, update the protoCheck too. */ |
| 83 } | 83 """ |
| 84 if (needsSetter) { | 84 prototype["get\$" + field] = new Function(getterString); |
| 85 var setterString = "this." + field + " = v;"; | 85 } |
| 86 prototype["set\$" + field] = new Function("v", setterString); | 86 if (needsSetter) { |
| 87 } | 87 var setterString = "this." + field + " = v;"; |
| 88 return field; | 88 prototype["set\$" + field] = new Function("v", setterString); |
| 89 }"""; | 89 } |
| 90 return field; |
| 91 }"""; |
| 90 } | 92 } |
| 91 | 93 |
| 92 String get defineClassFunction { | 94 String get defineClassFunction { |
| 93 // First the class name, then the super class name, followed by the fields | 95 // First the class name, then the super class name, followed by the fields |
| 94 // (in an array) and the members (inside an Object literal). | 96 // (in an array) and the members (inside an Object literal). |
| 95 // The caller can also pass in the constructor as a function if needed. | 97 // The caller can also pass in the constructor as a function if needed. |
| 96 // | 98 // |
| 97 // Example: | 99 // Example: |
| 98 // defineClass("A", "B", ["x", "y"], { | 100 // defineClass("A", "B", ["x", "y"], { |
| 99 // foo$1: function(y) { | 101 // foo$1: function(y) { |
| (...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 if (!parameters.optionalParameters.isEmpty()) { | 427 if (!parameters.optionalParameters.isEmpty()) { |
| 426 addParameterStubs(member, defineInstanceMember); | 428 addParameterStubs(member, defineInstanceMember); |
| 427 } | 429 } |
| 428 } else if (member.kind !== ElementKind.FIELD) { | 430 } else if (member.kind !== ElementKind.FIELD) { |
| 429 compiler.internalError('unexpected kind: "${member.kind}"', | 431 compiler.internalError('unexpected kind: "${member.kind}"', |
| 430 element: member); | 432 element: member); |
| 431 } | 433 } |
| 432 emitExtraAccessors(member, defineInstanceMember); | 434 emitExtraAccessors(member, defineInstanceMember); |
| 433 } | 435 } |
| 434 | 436 |
| 435 Set<Element> emitClassFields(ClassElement classElement, CodeBuffer buffer) { | 437 String generateCheckedSetter(Element member, String fieldName) { |
| 438 Type type = member.computeType(compiler); |
| 439 if (type.element.isTypeVariable() |
| 440 || type.element == compiler.dynamicClass |
| 441 || type.element == compiler.objectClass) { |
| 442 // TODO(ngeoffray): Support type checks on type parameters. |
| 443 return null; |
| 444 } else { |
| 445 SourceString helper = compiler.backend.getCheckedModeHelper(type); |
| 446 Element helperElement = compiler.findHelper(helper); |
| 447 String helperName = compiler.namer.isolateAccess(helperElement); |
| 448 String additionalArgument = compiler.namer.operatorIs(type.element); |
| 449 return " set\$$fieldName: function(v) { " |
| 450 "this.$fieldName = $helperName(v, '$additionalArgument'); }"; |
| 451 } |
| 452 } |
| 453 |
| 454 List<String> emitClassFields(ClassElement classElement, CodeBuffer buffer) { |
| 436 // If the class is never instantiated we still need to set it up for | 455 // If the class is never instantiated we still need to set it up for |
| 437 // inheritance purposes, but we can simplify its JavaScript constructor. | 456 // inheritance purposes, but we can simplify its JavaScript constructor. |
| 438 bool isInstantiated = | 457 bool isInstantiated = |
| 439 compiler.codegenWorld.instantiatedClasses.contains(classElement); | 458 compiler.codegenWorld.instantiatedClasses.contains(classElement); |
| 459 List<String> checkedSetters = <String>[]; |
| 440 | 460 |
| 441 bool isFirstField = true; | 461 bool isFirstField = true; |
| 442 void addField(ClassElement enclosingClass, Element member) { | 462 void addField(ClassElement enclosingClass, Element member) { |
| 443 assert(!member.isNative()); | 463 assert(!member.isNative()); |
| 444 | 464 |
| 445 LibraryElement library = member.getLibrary(); | 465 LibraryElement library = member.getLibrary(); |
| 446 SourceString name = member.name; | 466 SourceString name = member.name; |
| 447 bool isPrivate = name.isPrivate(); | 467 bool isPrivate = name.isPrivate(); |
| 448 // See if we can dynamically create getters and setters. | 468 // See if we can dynamically create getters and setters. |
| 449 // We can only generate getters and setters for [classElement] since | 469 // We can only generate getters and setters for [classElement] since |
| (...skipping 15 matching lines...) Expand all Loading... |
| 465 || needsDynamicGetter | 485 || needsDynamicGetter |
| 466 || needsDynamicSetter) { | 486 || needsDynamicSetter) { |
| 467 if (isFirstField) { | 487 if (isFirstField) { |
| 468 isFirstField = false; | 488 isFirstField = false; |
| 469 } else { | 489 } else { |
| 470 buffer.add(", "); | 490 buffer.add(", "); |
| 471 } | 491 } |
| 472 String fieldName = isShadowed | 492 String fieldName = isShadowed |
| 473 ? namer.shadowedFieldName(member) | 493 ? namer.shadowedFieldName(member) |
| 474 : namer.getName(member); | 494 : namer.getName(member); |
| 495 if (needsDynamicSetter && compiler.enableTypeAssertions) { |
| 496 String setter = generateCheckedSetter(member, fieldName); |
| 497 if (setter != null) { |
| 498 needsDynamicSetter = false; |
| 499 checkedSetters.add(setter); |
| 500 } |
| 501 } |
| 475 // Getters and setters with suffixes will be generated dynamically. | 502 // Getters and setters with suffixes will be generated dynamically. |
| 476 buffer.add('"$fieldName'); | 503 buffer.add('"$fieldName'); |
| 477 if (needsDynamicGetter || needsDynamicSetter) { | 504 if (needsDynamicGetter || needsDynamicSetter) { |
| 478 if (needsDynamicGetter && needsDynamicSetter) { | 505 if (needsDynamicGetter && needsDynamicSetter) { |
| 479 buffer.add(GETTER_SETTER_SUFFIX); | 506 buffer.add(GETTER_SETTER_SUFFIX); |
| 480 } else if (needsDynamicGetter) { | 507 } else if (needsDynamicGetter) { |
| 481 buffer.add(GETTER_SUFFIX); | 508 buffer.add(GETTER_SUFFIX); |
| 482 } else { | 509 } else { |
| 483 buffer.add(SETTER_SUFFIX); | 510 buffer.add(SETTER_SUFFIX); |
| 484 } | 511 } |
| 485 } | 512 } |
| 486 buffer.add('"'); | 513 buffer.add('"'); |
| 487 } | 514 } |
| 488 } | 515 } |
| 489 | 516 |
| 490 // If a class is not instantiated then we add the field just so we can | 517 // If a class is not instantiated then we add the field just so we can |
| 491 // generate the field getter/setter dynamically. Since this is only | 518 // generate the field getter/setter dynamically. Since this is only |
| 492 // allowed on fields that are in [classElement] we don't need to visit | 519 // allowed on fields that are in [classElement] we don't need to visit |
| 493 // superclasses for non-instantiated classes. | 520 // superclasses for non-instantiated classes. |
| 494 classElement.forEachInstanceField( | 521 classElement.forEachInstanceField( |
| 495 addField, | 522 addField, |
| 496 includeBackendMembers: true, | 523 includeBackendMembers: true, |
| 497 includeSuperMembers: isInstantiated && !classElement.isNative()); | 524 includeSuperMembers: isInstantiated && !classElement.isNative()); |
| 525 return checkedSetters; |
| 498 } | 526 } |
| 499 | 527 |
| 500 void emitInstanceMembers(ClassElement classElement, | 528 void emitInstanceMembers(ClassElement classElement, |
| 501 CodeBuffer buffer, | 529 CodeBuffer buffer, |
| 502 bool needsLeadingComma) { | 530 bool needsLeadingComma) { |
| 503 bool needsComma = needsLeadingComma; | 531 bool needsComma = needsLeadingComma; |
| 504 void defineInstanceMember(String name, CodeBuffer memberBuffer) { | 532 void defineInstanceMember(String name, CodeBuffer memberBuffer) { |
| 505 if (needsComma) buffer.add(','); | 533 if (needsComma) buffer.add(','); |
| 506 needsComma = true; | 534 needsComma = true; |
| 507 buffer.add('\n'); | 535 buffer.add('\n'); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 555 String className = namer.getName(classElement); | 583 String className = namer.getName(classElement); |
| 556 ClassElement superclass = classElement.superclass; | 584 ClassElement superclass = classElement.superclass; |
| 557 String superName = ""; | 585 String superName = ""; |
| 558 if (superclass !== null) { | 586 if (superclass !== null) { |
| 559 superName = namer.getName(superclass); | 587 superName = namer.getName(superclass); |
| 560 } | 588 } |
| 561 String constructorName = namer.safeName(classElement.name.slowToString()); | 589 String constructorName = namer.safeName(classElement.name.slowToString()); |
| 562 | 590 |
| 563 buffer.add('$classesCollector.$className = {"":\n'); | 591 buffer.add('$classesCollector.$className = {"":\n'); |
| 564 buffer.add(' ['); | 592 buffer.add(' ['); |
| 565 emitClassFields(classElement, buffer); | 593 List<String> checkedSetters = emitClassFields(classElement, buffer); |
| 566 buffer.add('],\n'); | 594 buffer.add('],\n'); |
| 567 // TODO(floitsch): the emitInstanceMember should simply always emit a ',\n'. | 595 // TODO(floitsch): the emitInstanceMember should simply always emit a ',\n'. |
| 568 // That does currently not work because the native classes have a different | 596 // That does currently not work because the native classes have a different |
| 569 // syntax. | 597 // syntax. |
| 570 buffer.add(' "super": "$superName"'); | 598 buffer.add(' "super": "$superName"'); |
| 599 if (!checkedSetters.isEmpty()) { |
| 600 buffer.add(',\n'); |
| 601 buffer.add('${Strings.join(checkedSetters, ",\n")}'); |
| 602 } |
| 571 emitInstanceMembers(classElement, buffer, true); | 603 emitInstanceMembers(classElement, buffer, true); |
| 572 buffer.add('\n};\n\n'); | 604 buffer.add('\n};\n\n'); |
| 573 } | 605 } |
| 574 | 606 |
| 575 void generateTypeTests(ClassElement cls, | 607 void generateTypeTests(ClassElement cls, |
| 576 void generateTypeTest(ClassElement element)) { | 608 void generateTypeTest(ClassElement element)) { |
| 577 if (compiler.codegenWorld.isChecks.contains(cls)) { | 609 if (compiler.codegenWorld.isChecks.contains(cls)) { |
| 578 generateTypeTest(cls); | 610 generateTypeTest(cls); |
| 579 } | 611 } |
| 580 generateInterfacesIsTests(cls, generateTypeTest, new Set<Element>()); | 612 generateInterfacesIsTests(cls, generateTypeTest, new Set<Element>()); |
| (...skipping 586 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1167 sourceName = token.slowToString(); | 1199 sourceName = token.slowToString(); |
| 1168 } | 1200 } |
| 1169 int totalOffset = bufferOffset + offset; | 1201 int totalOffset = bufferOffset + offset; |
| 1170 sourceMapBuilder.addMapping( | 1202 sourceMapBuilder.addMapping( |
| 1171 sourceFile, token.charOffset, sourceName, totalOffset); | 1203 sourceFile, token.charOffset, sourceName, totalOffset); |
| 1172 }); | 1204 }); |
| 1173 } | 1205 } |
| 1174 } | 1206 } |
| 1175 | 1207 |
| 1176 typedef void DefineMemberFunction(String invocationName, CodeBuffer definition); | 1208 typedef void DefineMemberFunction(String invocationName, CodeBuffer definition); |
| OLD | NEW |