| 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 class ConstantEmitter { | 7 class ConstantEmitter { |
| 8 ConstantReferenceEmitter _referenceEmitter; | 8 ConstantReferenceEmitter _referenceEmitter; |
| 9 ConstantLiteralEmitter _literalEmitter; | 9 ConstantLiteralEmitter _literalEmitter; |
| 10 | 10 |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 48 jsAst.Expression initializationExpression(ConstantValue constant) { | 48 jsAst.Expression initializationExpression(ConstantValue constant) { |
| 49 return _literalEmitter.generate(constant); | 49 return _literalEmitter.generate(constant); |
| 50 } | 50 } |
| 51 } | 51 } |
| 52 | 52 |
| 53 /** | 53 /** |
| 54 * Visitor for generating JavaScript expressions to refer to [ConstantValue]s. | 54 * Visitor for generating JavaScript expressions to refer to [ConstantValue]s. |
| 55 * Do not use directly, use methods from [ConstantEmitter]. | 55 * Do not use directly, use methods from [ConstantEmitter]. |
| 56 */ | 56 */ |
| 57 class ConstantReferenceEmitter | 57 class ConstantReferenceEmitter |
| 58 implements ConstantValueVisitor<jsAst.Expression> { | 58 implements ConstantValueVisitor<jsAst.Expression, Null> { |
| 59 final Compiler compiler; | 59 final Compiler compiler; |
| 60 final Namer namer; | 60 final Namer namer; |
| 61 | 61 |
| 62 final ConstantEmitter constantEmitter; | 62 final ConstantEmitter constantEmitter; |
| 63 | 63 |
| 64 ConstantReferenceEmitter(this.compiler, this.namer, this.constantEmitter); | 64 ConstantReferenceEmitter(this.compiler, this.namer, this.constantEmitter); |
| 65 | 65 |
| 66 jsAst.Expression generate(ConstantValue constant) { | 66 jsAst.Expression generate(ConstantValue constant) { |
| 67 return _visit(constant); | 67 return _visit(constant); |
| 68 } | 68 } |
| 69 | 69 |
| 70 jsAst.Expression _visit(ConstantValue constant) { | 70 jsAst.Expression _visit(ConstantValue constant) { |
| 71 return constant.accept(this); | 71 return constant.accept(this, null); |
| 72 } | 72 } |
| 73 | 73 |
| 74 jsAst.Expression emitCanonicalVersion(ConstantValue constant) { | 74 jsAst.Expression emitCanonicalVersion(ConstantValue constant) { |
| 75 String name = namer.constantName(constant); | 75 String name = namer.constantName(constant); |
| 76 return new jsAst.PropertyAccess.field( | 76 return new jsAst.PropertyAccess.field( |
| 77 new jsAst.VariableUse(namer.globalObjectForConstant(constant)), name); | 77 new jsAst.VariableUse(namer.globalObjectForConstant(constant)), name); |
| 78 } | 78 } |
| 79 | 79 |
| 80 jsAst.Expression literal(ConstantValue constant) { | 80 jsAst.Expression literal(ConstantValue constant) { |
| 81 return constantEmitter.literal(constant); | 81 return constantEmitter.literal(constant); |
| 82 } | 82 } |
| 83 | 83 |
| 84 jsAst.Expression visitFunction(FunctionConstantValue constant) { | 84 @override |
| 85 jsAst.Expression visitFunction(FunctionConstantValue constant, [_]) { |
| 85 return namer.isolateStaticClosureAccess(constant.element); | 86 return namer.isolateStaticClosureAccess(constant.element); |
| 86 } | 87 } |
| 87 | 88 |
| 88 jsAst.Expression visitNull(NullConstantValue constant) { | 89 @override |
| 90 jsAst.Expression visitNull(NullConstantValue constant, [_]) { |
| 89 return literal(constant); | 91 return literal(constant); |
| 90 } | 92 } |
| 91 | 93 |
| 92 jsAst.Expression visitInt(IntConstantValue constant) { | 94 @override |
| 95 jsAst.Expression visitInt(IntConstantValue constant, [_]) { |
| 93 return literal(constant); | 96 return literal(constant); |
| 94 } | 97 } |
| 95 | 98 |
| 96 jsAst.Expression visitDouble(DoubleConstantValue constant) { | 99 @override |
| 100 jsAst.Expression visitDouble(DoubleConstantValue constant, [_]) { |
| 97 return literal(constant); | 101 return literal(constant); |
| 98 } | 102 } |
| 99 | 103 |
| 100 jsAst.Expression visitTrue(TrueConstantValue constant) { | 104 @override |
| 105 jsAst.Expression visitBool(BoolConstantValue constant, [_]) { |
| 101 return literal(constant); | 106 return literal(constant); |
| 102 } | 107 } |
| 103 | 108 |
| 104 jsAst.Expression visitFalse(FalseConstantValue constant) { | |
| 105 return literal(constant); | |
| 106 } | |
| 107 | |
| 108 /** | 109 /** |
| 109 * Write the contents of the quoted string to a [CodeBuffer] in | 110 * Write the contents of the quoted string to a [CodeBuffer] in |
| 110 * a form that is valid as JavaScript string literal content. | 111 * a form that is valid as JavaScript string literal content. |
| 111 * The string is assumed quoted by double quote characters. | 112 * The string is assumed quoted by double quote characters. |
| 112 */ | 113 */ |
| 113 jsAst.Expression visitString(StringConstantValue constant) { | 114 @override |
| 115 jsAst.Expression visitString(StringConstantValue constant, [_]) { |
| 114 // TODO(sra): If the string is long *and repeated* (and not on a hot path) | 116 // TODO(sra): If the string is long *and repeated* (and not on a hot path) |
| 115 // then it should be assigned to a name. We don't have reference counts (or | 117 // then it should be assigned to a name. We don't have reference counts (or |
| 116 // profile information) here, so this is the wrong place. | 118 // profile information) here, so this is the wrong place. |
| 117 return literal(constant); | 119 return literal(constant); |
| 118 } | 120 } |
| 119 | 121 |
| 120 jsAst.Expression visitList(ListConstantValue constant) { | 122 @override |
| 123 jsAst.Expression visitList(ListConstantValue constant, [_]) { |
| 121 return emitCanonicalVersion(constant); | 124 return emitCanonicalVersion(constant); |
| 122 } | 125 } |
| 123 | 126 |
| 124 jsAst.Expression visitMap(MapConstantValue constant) { | 127 @override |
| 128 jsAst.Expression visitMap(MapConstantValue constant, [_]) { |
| 125 return emitCanonicalVersion(constant); | 129 return emitCanonicalVersion(constant); |
| 126 } | 130 } |
| 127 | 131 |
| 128 jsAst.Expression visitType(TypeConstantValue constant) { | 132 @override |
| 133 jsAst.Expression visitType(TypeConstantValue constant, [_]) { |
| 129 return emitCanonicalVersion(constant); | 134 return emitCanonicalVersion(constant); |
| 130 } | 135 } |
| 131 | 136 |
| 132 jsAst.Expression visitConstructed(ConstructedConstantValue constant) { | 137 @override |
| 138 jsAst.Expression visitConstructed(ConstructedConstantValue constant, [_]) { |
| 133 return emitCanonicalVersion(constant); | 139 return emitCanonicalVersion(constant); |
| 134 } | 140 } |
| 135 | 141 |
| 136 jsAst.Expression visitInterceptor(InterceptorConstantValue constant) { | 142 @override |
| 143 jsAst.Expression visitInterceptor(InterceptorConstantValue constant, [_]) { |
| 137 return emitCanonicalVersion(constant); | 144 return emitCanonicalVersion(constant); |
| 138 } | 145 } |
| 139 | 146 |
| 140 jsAst.Expression visitDummy(DummyConstantValue constant) { | 147 @override |
| 148 jsAst.Expression visitDummy(DummyConstantValue constant, [_]) { |
| 141 return literal(constant); | 149 return literal(constant); |
| 142 } | 150 } |
| 143 | 151 |
| 144 jsAst.Expression visitDeferred(DeferredConstantValue constant) { | 152 @override |
| 153 jsAst.Expression visitDeferred(DeferredConstantValue constant, [_]) { |
| 145 return emitCanonicalVersion(constant); | 154 return emitCanonicalVersion(constant); |
| 146 } | 155 } |
| 147 } | 156 } |
| 148 | 157 |
| 149 /** | 158 /** |
| 150 * Visitor for generating JavaScript expressions that litterally represent | 159 * Visitor for generating JavaScript expressions that litterally represent |
| 151 * [ConstantValue]s. These can be used for inlining constants or in | 160 * [ConstantValue]s. These can be used for inlining constants or in |
| 152 * initializers. Do not use directly, use methods from [ConstantEmitter]. | 161 * initializers. Do not use directly, use methods from [ConstantEmitter]. |
| 153 */ | 162 */ |
| 154 class ConstantLiteralEmitter implements ConstantValueVisitor<jsAst.Expression> { | 163 class ConstantLiteralEmitter |
| 164 implements ConstantValueVisitor<jsAst.Expression, Null> { |
| 155 | 165 |
| 156 // Matches blank lines, comment lines and trailing comments that can't be part | 166 // Matches blank lines, comment lines and trailing comments that can't be part |
| 157 // of a string. | 167 // of a string. |
| 158 static final RegExp COMMENT_RE = | 168 static final RegExp COMMENT_RE = |
| 159 new RegExp(r'''^ *(//.*)?\n| *//[^''"\n]*$''' , multiLine: true); | 169 new RegExp(r'''^ *(//.*)?\n| *//[^''"\n]*$''' , multiLine: true); |
| 160 | 170 |
| 161 final Compiler compiler; | 171 final Compiler compiler; |
| 162 final Namer namer; | 172 final Namer namer; |
| 163 final jsAst.Template makeConstantListTemplate; | 173 final jsAst.Template makeConstantListTemplate; |
| 164 final ConstantEmitter constantEmitter; | 174 final ConstantEmitter constantEmitter; |
| 165 | 175 |
| 166 ConstantLiteralEmitter(this.compiler, | 176 ConstantLiteralEmitter(this.compiler, |
| 167 this.namer, | 177 this.namer, |
| 168 this.makeConstantListTemplate, | 178 this.makeConstantListTemplate, |
| 169 this.constantEmitter); | 179 this.constantEmitter); |
| 170 | 180 |
| 171 jsAst.Expression generate(ConstantValue constant) { | 181 jsAst.Expression generate(ConstantValue constant) { |
| 172 return _visit(constant); | 182 return _visit(constant); |
| 173 } | 183 } |
| 174 | 184 |
| 175 jsAst.Expression _visit(ConstantValue constant) { | 185 jsAst.Expression _visit(ConstantValue constant) { |
| 176 return constant.accept(this); | 186 return constant.accept(this, null); |
| 177 } | 187 } |
| 178 | 188 |
| 179 jsAst.Expression visitFunction(FunctionConstantValue constant) { | 189 @override |
| 190 jsAst.Expression visitFunction(FunctionConstantValue constant, [_]) { |
| 180 compiler.internalError(NO_LOCATION_SPANNABLE, | 191 compiler.internalError(NO_LOCATION_SPANNABLE, |
| 181 "The function constant does not need specific JS code."); | 192 "The function constant does not need specific JS code."); |
| 182 return null; | 193 return null; |
| 183 } | 194 } |
| 184 | 195 |
| 185 jsAst.Expression visitNull(NullConstantValue constant) { | 196 @override |
| 197 jsAst.Expression visitNull(NullConstantValue constant, [_]) { |
| 186 return new jsAst.LiteralNull(); | 198 return new jsAst.LiteralNull(); |
| 187 } | 199 } |
| 188 | 200 |
| 189 jsAst.Expression visitInt(IntConstantValue constant) { | 201 @override |
| 202 jsAst.Expression visitInt(IntConstantValue constant, [_]) { |
| 190 return new jsAst.LiteralNumber('${constant.primitiveValue}'); | 203 return new jsAst.LiteralNumber('${constant.primitiveValue}'); |
| 191 } | 204 } |
| 192 | 205 |
| 193 jsAst.Expression visitDouble(DoubleConstantValue constant) { | 206 @override |
| 207 jsAst.Expression visitDouble(DoubleConstantValue constant, [_]) { |
| 194 double value = constant.primitiveValue; | 208 double value = constant.primitiveValue; |
| 195 if (value.isNaN) { | 209 if (value.isNaN) { |
| 196 return js("0/0"); | 210 return js("0/0"); |
| 197 } else if (value == double.INFINITY) { | 211 } else if (value == double.INFINITY) { |
| 198 return js("1/0"); | 212 return js("1/0"); |
| 199 } else if (value == -double.INFINITY) { | 213 } else if (value == -double.INFINITY) { |
| 200 return js("-1/0"); | 214 return js("-1/0"); |
| 201 } else { | 215 } else { |
| 202 return new jsAst.LiteralNumber("$value"); | 216 return new jsAst.LiteralNumber("$value"); |
| 203 } | 217 } |
| 204 } | 218 } |
| 205 | 219 |
| 206 jsAst.Expression visitTrue(TrueConstantValue constant) { | 220 @override |
| 221 jsAst.Expression visitBool(BoolConstantValue constant, [_]) { |
| 207 if (compiler.enableMinification) { | 222 if (compiler.enableMinification) { |
| 208 // Use !0 for true. | 223 if (constant.isTrue) { |
| 209 return js("!0"); | 224 // Use !0 for true. |
| 225 return js("!0"); |
| 226 } else { |
| 227 // Use !1 for false. |
| 228 return js("!1"); |
| 229 } |
| 210 } else { | 230 } else { |
| 211 return js('true'); | 231 return constant.isTrue ? js('true') : js('false'); |
| 212 } | 232 } |
| 213 } | 233 } |
| 214 | 234 |
| 215 jsAst.Expression visitFalse(FalseConstantValue constant) { | |
| 216 if (compiler.enableMinification) { | |
| 217 // Use !1 for false. | |
| 218 return js("!1"); | |
| 219 } else { | |
| 220 return js('false'); | |
| 221 } | |
| 222 } | |
| 223 | |
| 224 /** | 235 /** |
| 225 * Write the contents of the quoted string to a [CodeBuffer] in | 236 * Write the contents of the quoted string to a [CodeBuffer] in |
| 226 * a form that is valid as JavaScript string literal content. | 237 * a form that is valid as JavaScript string literal content. |
| 227 * The string is assumed quoted by double quote characters. | 238 * The string is assumed quoted by double quote characters. |
| 228 */ | 239 */ |
| 229 jsAst.Expression visitString(StringConstantValue constant) { | 240 @override |
| 241 jsAst.Expression visitString(StringConstantValue constant, [_]) { |
| 230 StringBuffer sb = new StringBuffer(); | 242 StringBuffer sb = new StringBuffer(); |
| 231 writeJsonEscapedCharsOn(constant.primitiveValue.slowToString(), sb); | 243 writeJsonEscapedCharsOn(constant.primitiveValue.slowToString(), sb); |
| 232 return new jsAst.LiteralString('"$sb"'); | 244 return new jsAst.LiteralString('"$sb"'); |
| 233 } | 245 } |
| 234 | 246 |
| 235 jsAst.Expression visitList(ListConstantValue constant) { | 247 @override |
| 248 jsAst.Expression visitList(ListConstantValue constant, [_]) { |
| 236 List<jsAst.Expression> elements = _array(constant.entries); | 249 List<jsAst.Expression> elements = _array(constant.entries); |
| 237 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer(elements); | 250 jsAst.ArrayInitializer array = new jsAst.ArrayInitializer(elements); |
| 238 jsAst.Expression value = makeConstantListTemplate.instantiate([array]); | 251 jsAst.Expression value = makeConstantListTemplate.instantiate([array]); |
| 239 return maybeAddTypeArguments(constant.type, value); | 252 return maybeAddTypeArguments(constant.type, value); |
| 240 } | 253 } |
| 241 | 254 |
| 242 jsAst.Expression getJsConstructor(ClassElement element) { | 255 jsAst.Expression getJsConstructor(ClassElement element) { |
| 243 return namer.elementAccess(element); | 256 return namer.elementAccess(element); |
| 244 } | 257 } |
| 245 | 258 |
| 246 jsAst.Expression visitMap(JavaScriptMapConstant constant) { | 259 @override |
| 260 jsAst.Expression visitMap(JavaScriptMapConstant constant, [_]) { |
| 247 jsAst.Expression jsMap() { | 261 jsAst.Expression jsMap() { |
| 248 List<jsAst.Property> properties = <jsAst.Property>[]; | 262 List<jsAst.Property> properties = <jsAst.Property>[]; |
| 249 for (int i = 0; i < constant.length; i++) { | 263 for (int i = 0; i < constant.length; i++) { |
| 250 StringConstantValue key = constant.keys[i]; | 264 StringConstantValue key = constant.keys[i]; |
| 251 if (key.primitiveValue == JavaScriptMapConstant.PROTO_PROPERTY) { | 265 if (key.primitiveValue == JavaScriptMapConstant.PROTO_PROPERTY) { |
| 252 continue; | 266 continue; |
| 253 } | 267 } |
| 254 | 268 |
| 255 // Keys in literal maps must be emitted in place. | 269 // Keys in literal maps must be emitted in place. |
| 256 jsAst.Literal keyExpression = _visit(key); | 270 jsAst.Literal keyExpression = _visit(key); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 new jsAst.New(getJsConstructor(classElement), arguments); | 332 new jsAst.New(getJsConstructor(classElement), arguments); |
| 319 return maybeAddTypeArguments(constant.type, value); | 333 return maybeAddTypeArguments(constant.type, value); |
| 320 } | 334 } |
| 321 | 335 |
| 322 JavaScriptBackend get backend => compiler.backend; | 336 JavaScriptBackend get backend => compiler.backend; |
| 323 | 337 |
| 324 jsAst.PropertyAccess getHelperProperty(Element helper) { | 338 jsAst.PropertyAccess getHelperProperty(Element helper) { |
| 325 return backend.namer.elementAccess(helper); | 339 return backend.namer.elementAccess(helper); |
| 326 } | 340 } |
| 327 | 341 |
| 328 jsAst.Expression visitType(TypeConstantValue constant) { | 342 @override |
| 343 jsAst.Expression visitType(TypeConstantValue constant, [_]) { |
| 329 DartType type = constant.representedType; | 344 DartType type = constant.representedType; |
| 330 String name = namer.getRuntimeTypeName(type.element); | 345 String name = namer.getRuntimeTypeName(type.element); |
| 331 jsAst.Expression typeName = new jsAst.LiteralString("'$name'"); | 346 jsAst.Expression typeName = new jsAst.LiteralString("'$name'"); |
| 332 return new jsAst.Call(getHelperProperty(backend.getCreateRuntimeType()), | 347 return new jsAst.Call(getHelperProperty(backend.getCreateRuntimeType()), |
| 333 [typeName]); | 348 [typeName]); |
| 334 } | 349 } |
| 335 | 350 |
| 336 jsAst.Expression visitInterceptor(InterceptorConstantValue constant) { | 351 @override |
| 352 jsAst.Expression visitInterceptor(InterceptorConstantValue constant, [_]) { |
| 337 return new jsAst.PropertyAccess.field( | 353 return new jsAst.PropertyAccess.field( |
| 338 getJsConstructor(constant.dispatchedType.element), | 354 getJsConstructor(constant.dispatchedType.element), |
| 339 'prototype'); | 355 'prototype'); |
| 340 } | 356 } |
| 341 | 357 |
| 342 jsAst.Expression visitDummy(DummyConstantValue constant) { | 358 @override |
| 359 jsAst.Expression visitDummy(DummyConstantValue constant, [_]) { |
| 343 return new jsAst.LiteralNumber('0'); | 360 return new jsAst.LiteralNumber('0'); |
| 344 } | 361 } |
| 345 | 362 |
| 346 jsAst.Expression visitConstructed(ConstructedConstantValue constant) { | 363 @override |
| 364 jsAst.Expression visitConstructed(ConstructedConstantValue constant, [_]) { |
| 347 Element element = constant.type.element; | 365 Element element = constant.type.element; |
| 348 if (element.isForeign(backend) | 366 if (element.isForeign(backend) |
| 349 && element.name == 'JS_CONST') { | 367 && element.name == 'JS_CONST') { |
| 350 StringConstantValue str = constant.fields[0]; | 368 StringConstantValue str = constant.fields[0]; |
| 351 String value = str.primitiveValue.slowToString(); | 369 String value = str.primitiveValue.slowToString(); |
| 352 return new jsAst.LiteralExpression(stripComments(value)); | 370 return new jsAst.LiteralExpression(stripComments(value)); |
| 353 } | 371 } |
| 354 jsAst.New instantiation = new jsAst.New( | 372 jsAst.New instantiation = new jsAst.New( |
| 355 getJsConstructor(constant.type.element), | 373 getJsConstructor(constant.type.element), |
| 356 _array(constant.fields)); | 374 _array(constant.fields)); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 376 .map((DartType type) => | 394 .map((DartType type) => |
| 377 rti.getTypeRepresentationWithHashes(type, (_){})); | 395 rti.getTypeRepresentationWithHashes(type, (_){})); |
| 378 jsAst.Expression argumentList = | 396 jsAst.Expression argumentList = |
| 379 new jsAst.LiteralString('[${arguments.join(', ')}]'); | 397 new jsAst.LiteralString('[${arguments.join(', ')}]'); |
| 380 return new jsAst.Call(getHelperProperty(backend.getSetRuntimeTypeInfo()), | 398 return new jsAst.Call(getHelperProperty(backend.getSetRuntimeTypeInfo()), |
| 381 [value, argumentList]); | 399 [value, argumentList]); |
| 382 } | 400 } |
| 383 return value; | 401 return value; |
| 384 } | 402 } |
| 385 | 403 |
| 386 jsAst.Expression visitDeferred(DeferredConstantValue constant) { | 404 @override |
| 405 jsAst.Expression visitDeferred(DeferredConstantValue constant, [_]) { |
| 387 return constantEmitter.reference(constant.referenced); | 406 return constantEmitter.reference(constant.referenced); |
| 388 } | 407 } |
| 389 } | 408 } |
| OLD | NEW |