| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 dart2js.js_emitter; | 5 part of dart2js.js_emitter; |
| 6 | 6 |
| 7 class ClassEmitter extends CodeEmitterHelper { | 7 class ClassEmitter extends CodeEmitterHelper { |
| 8 /** | 8 /** |
| 9 * Documentation wanted -- johnniwinther | 9 * Documentation wanted -- johnniwinther |
| 10 * | 10 * |
| 11 * Invariant: [classElement] must be a declaration element. | 11 * Invariant: [classElement] must be a declaration element. |
| 12 */ | 12 */ |
| 13 void generateClass(ClassElement classElement, | 13 void generateClass(ClassElement classElement, |
| 14 ClassBuilder properties, | 14 ClassBuilder properties, |
| 15 Map<String, jsAst.Expression> additionalProperties) { | 15 Map<String, jsAst.Expression> additionalProperties) { |
| 16 final onlyForRti = | 16 final onlyForRti = |
| 17 task.typeTestEmitter.rtiNeededClasses.contains(classElement); | 17 task.typeTestEmitter.rtiNeededClasses.contains(classElement); |
| 18 | 18 |
| 19 assert(invariant(classElement, classElement.isDeclaration)); | 19 assert(invariant(classElement, classElement.isDeclaration)); |
| 20 assert(invariant(classElement, !classElement.isNative() || onlyForRti)); | 20 assert(invariant(classElement, !classElement.isNative() || onlyForRti)); |
| 21 | 21 |
| 22 task.needsDefineClass = true; | 22 task.needsDefineClass = true; |
| 23 String className = namer.getNameOfClass(classElement); | 23 String className = namer.getNameOfClass(classElement); |
| 24 | 24 |
| 25 ClassElement superclass = classElement.superclass; | 25 ClassElement superclass = classElement.superclass; |
| 26 String superName = ""; | 26 String superName = ""; |
| 27 if (superclass != null) { | 27 if (superclass != null) { |
| 28 superName = namer.getNameOfClass(superclass); | 28 superName = namer.getNameOfClass(superclass); |
| 29 } | 29 } |
| 30 String runtimeName = | |
| 31 namer.getPrimitiveInterceptorRuntimeName(classElement); | |
| 32 | 30 |
| 33 if (classElement.isMixinApplication) { | 31 if (classElement.isMixinApplication) { |
| 34 String mixinName = namer.getNameOfClass(computeMixinClass(classElement)); | 32 String mixinName = namer.getNameOfClass(computeMixinClass(classElement)); |
| 35 superName = '$superName+$mixinName'; | 33 superName = '$superName+$mixinName'; |
| 36 task.needsMixinSupport = true; | 34 task.needsMixinSupport = true; |
| 37 } | 35 } |
| 38 | 36 |
| 39 ClassBuilder builder = new ClassBuilder(namer); | 37 ClassBuilder builder = new ClassBuilder(namer); |
| 40 emitClassConstructor(classElement, builder, runtimeName, | 38 emitClassConstructor(classElement, builder, onlyForRti: onlyForRti); |
| 41 onlyForRti: onlyForRti); | |
| 42 emitFields(classElement, builder, superName, onlyForRti: onlyForRti); | 39 emitFields(classElement, builder, superName, onlyForRti: onlyForRti); |
| 43 emitClassGettersSetters(classElement, builder, onlyForRti: onlyForRti); | 40 emitClassGettersSetters(classElement, builder, onlyForRti: onlyForRti); |
| 44 emitInstanceMembers(classElement, builder, onlyForRti: onlyForRti); | 41 emitInstanceMembers(classElement, builder, onlyForRti: onlyForRti); |
| 45 task.typeTestEmitter.emitIsTests(classElement, builder); | 42 task.typeTestEmitter.emitIsTests(classElement, builder); |
| 46 if (additionalProperties != null) { | 43 if (additionalProperties != null) { |
| 47 additionalProperties.forEach(builder.addProperty); | 44 additionalProperties.forEach(builder.addProperty); |
| 48 } | 45 } |
| 49 | 46 |
| 50 emitTypeVariableReaders(classElement, builder); | 47 emitTypeVariableReaders(classElement, builder); |
| 51 | 48 |
| 52 emitClassBuilderWithReflectionData( | 49 emitClassBuilderWithReflectionData( |
| 53 className, classElement, builder, properties); | 50 className, classElement, builder, properties); |
| 54 } | 51 } |
| 55 | 52 |
| 56 void emitClassConstructor(ClassElement classElement, | 53 void emitClassConstructor(ClassElement classElement, |
| 57 ClassBuilder builder, | 54 ClassBuilder builder, |
| 58 String runtimeName, | |
| 59 {bool onlyForRti: false}) { | 55 {bool onlyForRti: false}) { |
| 60 List<String> fields = <String>[]; | 56 List<String> fields = <String>[]; |
| 61 if (!onlyForRti && !classElement.isNative()) { | 57 if (!onlyForRti && !classElement.isNative()) { |
| 62 visitFields(classElement, false, | 58 visitFields(classElement, false, |
| 63 (Element member, | 59 (Element member, |
| 64 String name, | 60 String name, |
| 65 String accessorName, | 61 String accessorName, |
| 66 bool needsGetter, | 62 bool needsGetter, |
| 67 bool needsSetter, | 63 bool needsSetter, |
| 68 bool needsCheckedSetter) { | 64 bool needsCheckedSetter) { |
| 69 fields.add(name); | 65 fields.add(name); |
| 70 }); | 66 }); |
| 71 } | 67 } |
| 72 String constructorName = namer.getNameOfClass(classElement); | 68 String constructorName = namer.getNameOfClass(classElement); |
| 73 | 69 |
| 74 // TODO(sra): Implement placeholders in VariableDeclaration position: | 70 // TODO(sra): Implement placeholders in VariableDeclaration position: |
| 75 // task.precompiledFunction.add(js.statement('function #(#) { #; }', | 71 // task.precompiledFunction.add(js.statement('function #(#) { #; }', |
| 76 // [ constructorName, fields, | 72 // [ constructorName, fields, |
| 77 // fields.map( | 73 // fields.map( |
| 78 // (name) => js('this.# = #', [name, name]))])); | 74 // (name) => js('this.# = #', [name, name]))])); |
| 79 task.precompiledFunction.add( | 75 task.precompiledFunction.add( |
| 80 new jsAst.FunctionDeclaration( | 76 new jsAst.FunctionDeclaration( |
| 81 new jsAst.VariableDeclaration(constructorName), | 77 new jsAst.VariableDeclaration(constructorName), |
| 82 js('function(#) { #; }', | 78 js('function(#) { #; }', |
| 83 [fields, | 79 [fields, |
| 84 fields.map((name) => js('this.# = #', [name, name]))]))); | 80 fields.map((name) => js('this.# = #', [name, name]))]))); |
| 85 if (runtimeName == null) { | 81 // TODO(floitsch): do we actually need the name field? |
| 86 runtimeName = constructorName; | 82 // TODO(floitsch): these should all go through the namer. |
| 87 } | |
| 88 | 83 |
| 89 task.precompiledFunction.add( | 84 task.precompiledFunction.add( |
| 90 js.statement(r'''{ | 85 js.statement(r'''{ |
| 91 #.builtin$cls = #; | 86 #.builtin$cls = #; |
| 92 if (!"name" in #) | 87 if (!"name" in #) |
| 93 #.name = #; | 88 #.name = #; |
| 94 $desc=$collectedClasses.#; | 89 $desc=$collectedClasses.#; |
| 95 if ($desc instanceof Array) $desc = $desc[1]; | 90 if ($desc instanceof Array) $desc = $desc[1]; |
| 96 #.prototype = $desc; | 91 #.prototype = $desc; |
| 97 }''', | 92 }''', |
| 98 [ constructorName, js.string(runtimeName), | 93 [ constructorName, js.string(constructorName), |
| 99 constructorName, | 94 constructorName, |
| 100 constructorName, js.string(constructorName), | 95 constructorName, js.string(constructorName), |
| 101 constructorName, | 96 constructorName, |
| 102 constructorName | 97 constructorName |
| 103 ])); | 98 ])); |
| 104 | 99 |
| 105 task.precompiledConstructorNames.add(js('#', constructorName)); | 100 task.precompiledConstructorNames.add(js('#', constructorName)); |
| 106 } | 101 } |
| 107 | 102 |
| 108 /// Returns `true` if fields added. | 103 /// Returns `true` if fields added. |
| 109 bool emitFields(Element element, | 104 bool emitFields(Element element, |
| 110 ClassBuilder builder, | 105 ClassBuilder builder, |
| 111 String superName, | 106 String superName, |
| 112 { bool classIsNative: false, | 107 { bool classIsNative: false, |
| 113 bool emitStatics: false, | 108 bool emitStatics: false, |
| 114 bool onlyForRti: false }) { | 109 bool onlyForRti: false }) { |
| 115 assert(!emitStatics || !onlyForRti); | 110 assert(!emitStatics || !onlyForRti); |
| 116 if (element.isLibrary()) { | 111 if (element.isLibrary()) { |
| 117 assert(invariant(element, emitStatics)); | 112 assert(invariant(element, emitStatics)); |
| 118 } else if (!element.isClass()) { | 113 } else if (!element.isClass()) { |
| 119 throw new SpannableAssertionFailure( | 114 throw new SpannableAssertionFailure( |
| 120 element, 'Must be a ClassElement or a LibraryElement'); | 115 element, 'Must be a ClassElement or a LibraryElement'); |
| 121 } | 116 } |
| 122 if (emitStatics) { | 117 if (emitStatics) { |
| 123 assert(invariant(element, superName == null, message: superName)); | 118 assert(invariant(element, superName == null, message: superName)); |
| 124 } else { | 119 } else { |
| 125 assert(invariant(element, superName != null)); | 120 assert(invariant(element, superName != null)); |
| 126 String nativeName = | |
| 127 namer.getPrimitiveInterceptorRuntimeName(element); | |
| 128 if (nativeName != null) { | |
| 129 builder.nativeName = nativeName; | |
| 130 } | |
| 131 builder.superName = superName; | 121 builder.superName = superName; |
| 132 } | 122 } |
| 133 var fieldMetadata = []; | 123 var fieldMetadata = []; |
| 134 bool hasMetadata = false; | 124 bool hasMetadata = false; |
| 135 bool fieldsAdded = false; | 125 bool fieldsAdded = false; |
| 136 | 126 |
| 137 if (!onlyForRti) { | 127 if (!onlyForRti) { |
| 138 visitFields(element, emitStatics, | 128 visitFields(element, emitStatics, |
| 139 (VariableElement field, | 129 (VariableElement field, |
| 140 String name, | 130 String name, |
| (...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 612 computeTypeVariable = | 602 computeTypeVariable = |
| 613 js(r'this.$builtinTypeInfo && this.$builtinTypeInfo[#]', index); | 603 js(r'this.$builtinTypeInfo && this.$builtinTypeInfo[#]', index); |
| 614 } | 604 } |
| 615 jsAst.Expression convertRtiToRuntimeType = | 605 jsAst.Expression convertRtiToRuntimeType = |
| 616 namer.elementAccess(compiler.findHelper('convertRtiToRuntimeType')); | 606 namer.elementAccess(compiler.findHelper('convertRtiToRuntimeType')); |
| 617 builder.addProperty(name, | 607 builder.addProperty(name, |
| 618 js('function () { return #(#) }', | 608 js('function () { return #(#) }', |
| 619 [convertRtiToRuntimeType, computeTypeVariable])); | 609 [convertRtiToRuntimeType, computeTypeVariable])); |
| 620 } | 610 } |
| 621 } | 611 } |
| OLD | NEW |