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 part of js_backend; | 5 part of js_backend; |
6 | 6 |
7 /** | 7 /** |
8 * A function element that represents a closure call. The signature is copied | 8 * A function element that represents a closure call. The signature is copied |
9 * from the given element. | 9 * from the given element. |
10 */ | 10 */ |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 } | 128 } |
129 if (needsSetter) { | 129 if (needsSetter) { |
130 var setterString = "this." + field + " = v;"; | 130 var setterString = "this." + field + " = v;"; |
131 prototype["set\$" + field] = new Function("v", setterString); | 131 prototype["set\$" + field] = new Function("v", setterString); |
132 } | 132 } |
133 return field; | 133 return field; |
134 }"""; | 134 }"""; |
135 } | 135 } |
136 | 136 |
137 String get defineClassFunction { | 137 String get defineClassFunction { |
138 // First the class name, then the super class name, followed by the fields | 138 // First the class name, then the field names in an array and the members |
139 // (in an array) and the members (inside an Object literal). | 139 // (inside an Object literal). |
140 // The caller can also pass in the constructor as a function if needed. | 140 // The caller can also pass in the constructor as a function if needed. |
141 // | 141 // |
142 // Example: | 142 // Example: |
143 // defineClass("A", "B", ["x", "y"], { | 143 // defineClass("A", ["x", "y"], { |
144 // foo$1: function(y) { | 144 // foo$1: function(y) { |
145 // print(this.x + y); | 145 // print(this.x + y); |
146 // }, | 146 // }, |
147 // bar$2: function(t, v) { | 147 // bar$2: function(t, v) { |
148 // this.x = t - v; | 148 // this.x = t - v; |
149 // }, | 149 // }, |
150 // }); | 150 // }); |
151 return """ | 151 return """ |
152 function(cls, fields, prototype) { | 152 function(cls, fields, prototype) { |
153 var generateGetterSetter = $generateGetterSetterFunction; | 153 var generateGetterSetter = $generateGetterSetterFunction; |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 // constructor. | 207 // constructor. |
208 // For engines where we have access to the '__proto__' we can manipulate | 208 // For engines where we have access to the '__proto__' we can manipulate |
209 // the object literal directly. For other engines we have to create a new | 209 // the object literal directly. For other engines we have to create a new |
210 // object and copy over the members. | 210 // object and copy over the members. |
211 return ''' | 211 return ''' |
212 function(collectedClasses) { | 212 function(collectedClasses) { |
213 var hasOwnProperty = Object.prototype.hasOwnProperty; | 213 var hasOwnProperty = Object.prototype.hasOwnProperty; |
214 for (var cls in collectedClasses) { | 214 for (var cls in collectedClasses) { |
215 if (hasOwnProperty.call(collectedClasses, cls)) { | 215 if (hasOwnProperty.call(collectedClasses, cls)) { |
216 var desc = collectedClasses[cls]; | 216 var desc = collectedClasses[cls]; |
217 '''/* If the class does not have any declared fields (in the '' | 217 '''/* Get the superclass and the fields in the format Super;field1,field2 from |
218 property of the description), then provide an empty list of fields. */''' | 218 the null-string property on the descriptor. */''' |
219 $isolatePropertiesName[cls] = $defineClassName(cls, desc[''] || [], desc); | 219 var s = desc[''].split(';'), supr = s[0]; |
220 if (desc['super'] !== "") $pendingClassesName[cls] = desc['super']; | 220 var fields = s[1] == '' ? [] : s[1].split(','); |
| 221 $isolatePropertiesName[cls] = $defineClassName(cls, fields, desc); |
| 222 if (supr) $pendingClassesName[cls] = supr; |
221 } | 223 } |
222 } | 224 } |
223 var pendingClasses = $pendingClassesName; | 225 var pendingClasses = $pendingClassesName; |
224 '''/* FinishClasses can be called multiple times. This means that we need to | 226 '''/* FinishClasses can be called multiple times. This means that we need to |
225 clear the pendingClasses property. */''' | 227 clear the pendingClasses property. */''' |
226 $pendingClassesName = {}; | 228 $pendingClassesName = {}; |
227 var finishedClasses = {}; | 229 var finishedClasses = {}; |
228 function finishClass(cls) { | 230 function finishClass(cls) { |
229 '''/* Opera does not support 'getOwnPropertyNames'. Therefore we use | 231 '''/* Opera does not support 'getOwnPropertyNames'. Therefore we use |
230 hasOwnProperty instead. */''' | 232 hasOwnProperty instead. */''' |
(...skipping 10 matching lines...) Expand all Loading... |
241 if ($supportsProtoName) { | 243 if ($supportsProtoName) { |
242 prototype.__proto__ = superConstructor.prototype; | 244 prototype.__proto__ = superConstructor.prototype; |
243 prototype.constructor = constructor; | 245 prototype.constructor = constructor; |
244 } else { | 246 } else { |
245 function tmp() {}; | 247 function tmp() {}; |
246 tmp.prototype = superConstructor.prototype; | 248 tmp.prototype = superConstructor.prototype; |
247 var newPrototype = new tmp(); | 249 var newPrototype = new tmp(); |
248 constructor.prototype = newPrototype; | 250 constructor.prototype = newPrototype; |
249 newPrototype.constructor = constructor; | 251 newPrototype.constructor = constructor; |
250 for (var member in prototype) { | 252 for (var member in prototype) { |
251 if (member == '' || member == 'super') continue; | 253 if (!member) continue; '''/* Short version of: if (member == '') */''' |
252 if (hasOwnProperty.call(prototype, member)) { | 254 if (hasOwnProperty.call(prototype, member)) { |
253 newPrototype[member] = prototype[member]; | 255 newPrototype[member] = prototype[member]; |
254 } | 256 } |
255 } | 257 } |
256 } | 258 } |
257 } | 259 } |
258 for (var cls in pendingClasses) finishClass(cls); | 260 for (var cls in pendingClasses) finishClass(cls); |
259 }'''; | 261 }'''; |
260 } | 262 } |
261 | 263 |
(...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
819 buffer.add("$setterName: function(v) { " | 821 buffer.add("$setterName: function(v) { " |
820 "this.$fieldName = $helperName(v$additionalArgument); }"); | 822 "this.$fieldName = $helperName(v$additionalArgument); }"); |
821 } | 823 } |
822 | 824 |
823 void emitClassConstructor(ClassElement classElement, CodeBuffer buffer) { | 825 void emitClassConstructor(ClassElement classElement, CodeBuffer buffer) { |
824 /* Do nothing. */ | 826 /* Do nothing. */ |
825 } | 827 } |
826 | 828 |
827 void emitClassFields(ClassElement classElement, | 829 void emitClassFields(ClassElement classElement, |
828 CodeBuffer buffer, | 830 CodeBuffer buffer, |
829 bool emitEndingComma) { | 831 bool emitEndingComma, |
| 832 { String superClass: "", |
| 833 bool isNative: false}) { |
| 834 assert(!isNative || superClass != ""); |
830 bool isFirstField = true; | 835 bool isFirstField = true; |
| 836 bool isAnythingOutput = false; |
| 837 if (!isNative) { |
| 838 buffer.add('"":"$superClass;'); |
| 839 isAnythingOutput = true; |
| 840 } |
831 visitClassFields(classElement, (Element member, | 841 visitClassFields(classElement, (Element member, |
832 String name, | 842 String name, |
833 bool needsGetter, | 843 bool needsGetter, |
834 bool needsSetter, | 844 bool needsSetter, |
835 bool needsCheckedSetter) { | 845 bool needsCheckedSetter) { |
836 | |
837 if (!getterAndSetterCanBeImplementedByFieldSpec( | 846 if (!getterAndSetterCanBeImplementedByFieldSpec( |
838 member, name, needsGetter, needsSetter)) { | 847 member, name, needsGetter, needsSetter)) { |
839 return; | 848 return; |
840 } | 849 } |
841 | 850 if (!isNative || needsCheckedSetter || needsGetter || needsSetter) { |
842 if (isFirstField) { | 851 if (isFirstField) { |
843 buffer.add('"": ['); | 852 isFirstField = false; |
844 isFirstField = false; | 853 if (!isAnythingOutput) { |
845 } else { | 854 buffer.add('"":"'); |
846 buffer.add(", "); | 855 isAnythingOutput = true; |
| 856 } |
| 857 } else { |
| 858 buffer.add(","); |
| 859 } |
| 860 buffer.add('$name'); |
| 861 if (needsGetter && needsSetter) { |
| 862 buffer.add(GETTER_SETTER_SUFFIX); |
| 863 } else if (needsGetter) { |
| 864 buffer.add(GETTER_SUFFIX); |
| 865 } else if (needsSetter) { |
| 866 buffer.add(SETTER_SUFFIX); |
| 867 } |
847 } | 868 } |
848 buffer.add('"$name'); | 869 }); |
849 if (needsGetter && needsSetter) { | 870 if (isAnythingOutput) { |
850 buffer.add(GETTER_SETTER_SUFFIX); | |
851 } else if (needsGetter) { | |
852 buffer.add(GETTER_SUFFIX); | |
853 } else if (needsSetter) { | |
854 buffer.add(SETTER_SUFFIX); | |
855 } | |
856 buffer.add('"'); | 871 buffer.add('"'); |
857 }); | |
858 if (!isFirstField) { | |
859 // There was at least one field. | |
860 buffer.add(']'); | |
861 if (emitEndingComma) { | 872 if (emitEndingComma) { |
862 buffer.add(','); | 873 buffer.add(','); |
863 } | 874 } |
864 } | 875 } |
865 } | 876 } |
866 | 877 |
867 /** Each getter/setter must be prefixed with a ",\n ". */ | 878 /** Each getter/setter must be prefixed with a ",\n ". */ |
868 void emitClassGettersSetters(ClassElement classElement, | 879 void emitClassGettersSetters(ClassElement classElement, |
869 CodeBuffer buffer, | 880 CodeBuffer buffer, |
870 bool emitLeadingComma) { | 881 bool emitLeadingComma) { |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
940 needsDefineClass = true; | 951 needsDefineClass = true; |
941 String className = namer.getName(classElement); | 952 String className = namer.getName(classElement); |
942 ClassElement superclass = classElement.superclass; | 953 ClassElement superclass = classElement.superclass; |
943 String superName = ""; | 954 String superName = ""; |
944 if (superclass != null) { | 955 if (superclass != null) { |
945 superName = namer.getName(superclass); | 956 superName = namer.getName(superclass); |
946 } | 957 } |
947 | 958 |
948 buffer.add('$classesCollector.$className = {'); | 959 buffer.add('$classesCollector.$className = {'); |
949 emitClassConstructor(classElement, buffer); | 960 emitClassConstructor(classElement, buffer); |
950 emitClassFields(classElement, buffer, true); | 961 emitClassFields(classElement, buffer, false, |
| 962 superClass: superName, isNative: false); |
951 // TODO(floitsch): the emitInstanceMember should simply always emit a ',\n'. | 963 // TODO(floitsch): the emitInstanceMember should simply always emit a ',\n'. |
952 // That does currently not work because the native classes have a different | 964 // That does currently not work because the native classes have a different |
953 // syntax. | 965 // syntax. |
954 buffer.add('\n "super": "$superName"'); | |
955 emitClassGettersSetters(classElement, buffer, true); | 966 emitClassGettersSetters(classElement, buffer, true); |
956 emitInstanceMembers(classElement, buffer, true); | 967 emitInstanceMembers(classElement, buffer, true); |
957 buffer.add('\n};\n\n'); | 968 buffer.add('\n};\n\n'); |
958 } | 969 } |
959 | 970 |
960 void emitInterceptorMethods( | 971 void emitInterceptorMethods( |
961 void defineInstanceMember(String name, StringBuffer memberBuffer)) { | 972 void defineInstanceMember(String name, StringBuffer memberBuffer)) { |
962 JavaScriptBackend backend = compiler.backend; | 973 JavaScriptBackend backend = compiler.backend; |
963 // Emit forwarders for the ObjectInterceptor class. We need to | 974 // Emit forwarders for the ObjectInterceptor class. We need to |
964 // emit all possible sends on intercepted methods. | 975 // emit all possible sends on intercepted methods. |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1153 // in case it is used in spawnFunction. | 1164 // in case it is used in spawnFunction. |
1154 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; | 1165 String fieldName = namer.STATIC_CLOSURE_NAME_NAME; |
1155 buffer.add('$fieldAccess.$fieldName = "$staticName";\n'); | 1166 buffer.add('$fieldAccess.$fieldName = "$staticName";\n'); |
1156 } | 1167 } |
1157 } | 1168 } |
1158 | 1169 |
1159 void emitBoundClosureClassHeader(String mangledName, | 1170 void emitBoundClosureClassHeader(String mangledName, |
1160 String superName, | 1171 String superName, |
1161 String extraArgument, | 1172 String extraArgument, |
1162 CodeBuffer buffer) { | 1173 CodeBuffer buffer) { |
1163 extraArgument = extraArgument.isEmpty ? '' : ", '$extraArgument'"; | 1174 extraArgument = extraArgument.isEmpty ? '' : ",$extraArgument"; |
1164 buffer.add(""" | 1175 buffer.add(""" |
1165 $classesCollector.$mangledName = {'': | 1176 $classesCollector.$mangledName = {'': |
1166 ['self'$extraArgument, 'target'], | 1177 \"$superName;self$extraArgument,target\", |
1167 'super': '$superName', | |
1168 """); | 1178 """); |
1169 } | 1179 } |
1170 | 1180 |
1171 /** | 1181 /** |
1172 * Documentation wanted -- johnniwinther | 1182 * Documentation wanted -- johnniwinther |
1173 * | 1183 * |
1174 * Invariant: [member] must be a declaration element. | 1184 * Invariant: [member] must be a declaration element. |
1175 */ | 1185 */ |
1176 void emitDynamicFunctionGetter(FunctionElement member, | 1186 void emitDynamicFunctionGetter(FunctionElement member, |
1177 DefineMemberFunction defineInstanceMember) { | 1187 DefineMemberFunction defineInstanceMember) { |
(...skipping 638 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1816 const String HOOKS_API_USAGE = """ | 1826 const String HOOKS_API_USAGE = """ |
1817 // Generated by dart2js, the Dart to JavaScript compiler. | 1827 // Generated by dart2js, the Dart to JavaScript compiler. |
1818 // The code supports the following hooks: | 1828 // The code supports the following hooks: |
1819 // dartPrint(message) - if this function is defined it is called | 1829 // dartPrint(message) - if this function is defined it is called |
1820 // instead of the Dart [print] method. | 1830 // instead of the Dart [print] method. |
1821 // dartMainRunner(main) - if this function is defined, the Dart [main] | 1831 // dartMainRunner(main) - if this function is defined, the Dart [main] |
1822 // method will not be invoked directly. | 1832 // method will not be invoked directly. |
1823 // Instead, a closure that will invoke [main] is | 1833 // Instead, a closure that will invoke [main] is |
1824 // passed to [dartMainRunner]. | 1834 // passed to [dartMainRunner]. |
1825 """; | 1835 """; |
OLD | NEW |