| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library dart2js.constants.expressions; | 5 library dart2js.constants.expressions; |
| 6 | 6 |
| 7 import '../constants/constant_system.dart'; | 7 import '../constants/constant_system.dart'; |
| 8 import '../core_types.dart'; | 8 import '../core_types.dart'; |
| 9 import '../dart2jslib.dart' show assertDebugMode, Compiler; | 9 import '../dart2jslib.dart' show assertDebugMode; |
| 10 import '../dart_types.dart'; | 10 import '../dart_types.dart'; |
| 11 import '../elements/elements.dart' show | 11 import '../elements/elements.dart' show |
| 12 ConstructorElement, | 12 ConstructorElement, |
| 13 Element, | 13 Element, |
| 14 FieldElement, | 14 FieldElement, |
| 15 FunctionElement, | 15 FunctionElement, |
| 16 PrefixElement, | 16 PrefixElement, |
| 17 VariableElement; | 17 VariableElement; |
| 18 import '../resolution/operators.dart'; | 18 import '../resolution/operators.dart'; |
| 19 import '../tree/tree.dart' show DartString; | 19 import '../tree/tree.dart' show DartString; |
| 20 import '../universe/universe.dart' show CallStructure; | 20 import '../universe/universe.dart' show CallStructure; |
| 21 import '../util/util.dart'; | 21 import 'evaluation.dart'; |
| 22 import 'values.dart'; | 22 import 'values.dart'; |
| 23 | 23 |
| 24 enum ConstantExpressionKind { | 24 enum ConstantExpressionKind { |
| 25 BINARY, | 25 BINARY, |
| 26 BOOL, | 26 BOOL, |
| 27 BOOL_FROM_ENVIRONMENT, | 27 BOOL_FROM_ENVIRONMENT, |
| 28 CONCATENATE, | 28 CONCATENATE, |
| 29 CONDITIONAL, | 29 CONDITIONAL, |
| 30 CONSTRUCTED, | 30 CONSTRUCTED, |
| 31 DEFERRED, | 31 DEFERRED, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 44 SYMBOL, | 44 SYMBOL, |
| 45 SYNTHETIC, | 45 SYNTHETIC, |
| 46 TYPE, | 46 TYPE, |
| 47 UNARY, | 47 UNARY, |
| 48 VARIABLE, | 48 VARIABLE, |
| 49 | 49 |
| 50 POSITIONAL_REFERENCE, | 50 POSITIONAL_REFERENCE, |
| 51 NAMED_REFERENCE, | 51 NAMED_REFERENCE, |
| 52 } | 52 } |
| 53 | 53 |
| 54 /// Environment used for evaluating constant expressions. | |
| 55 abstract class Environment { | |
| 56 // TODO(johnniwinther): Replace this with [CoreTypes] and maybe [Backend]. | |
| 57 Compiler get compiler; | |
| 58 | |
| 59 /// Read environments string passed in using the '-Dname=value' option. | |
| 60 String readFromEnvironment(String name); | |
| 61 } | |
| 62 | |
| 63 /// The normalized arguments passed to a const constructor computed from the | |
| 64 /// actual [arguments] and the [defaultValues] of the called construrctor. | |
| 65 class NormalizedArguments { | |
| 66 final Map<dynamic/*int|String*/, ConstantExpression> defaultValues; | |
| 67 final CallStructure callStructure; | |
| 68 final List<ConstantExpression> arguments; | |
| 69 | |
| 70 NormalizedArguments(this.defaultValues, this.callStructure, this.arguments); | |
| 71 | |
| 72 /// Returns the normalized named argument [name]. | |
| 73 ConstantExpression getNamedArgument(String name) { | |
| 74 int index = callStructure.namedArguments.indexOf(name); | |
| 75 if (index == -1) { | |
| 76 // The named argument is not provided. | |
| 77 return defaultValues[name]; | |
| 78 } | |
| 79 return arguments[index + callStructure.positionalArgumentCount]; | |
| 80 } | |
| 81 | |
| 82 /// Returns the normalized [index]th positional argument. | |
| 83 ConstantExpression getPositionalArgument(int index) { | |
| 84 if (index >= callStructure.positionalArgumentCount) { | |
| 85 // The positional argument is not provided. | |
| 86 return defaultValues[index]; | |
| 87 } | |
| 88 return arguments[index]; | |
| 89 } | |
| 90 } | |
| 91 | |
| 92 enum ConstantConstructorKind { | |
| 93 GENERATIVE, | |
| 94 REDIRECTING_GENERATIVE, | |
| 95 REDIRECTING_FACTORY, | |
| 96 } | |
| 97 | |
| 98 /// Definition of a constant constructor. | |
| 99 abstract class ConstantConstructor { | |
| 100 ConstantConstructorKind get kind; | |
| 101 | |
| 102 /// Computes the type of the instance created in a const constructor | |
| 103 /// invocation with type [newType]. | |
| 104 InterfaceType computeInstanceType(InterfaceType newType); | |
| 105 | |
| 106 /// Computes the constant expressions of the fields of the created instance | |
| 107 /// in a const constructor invocation with [arguments]. | |
| 108 Map<FieldElement, ConstantExpression> computeInstanceFields( | |
| 109 List<ConstantExpression> arguments, | |
| 110 CallStructure callStructure); | |
| 111 | |
| 112 accept(ConstantConstructorVisitor visitor, arg); | |
| 113 } | |
| 114 | |
| 115 abstract class ConstantConstructorVisitor<R, A> { | |
| 116 const ConstantConstructorVisitor(); | |
| 117 | |
| 118 R visit(ConstantConstructor constantConstructor, A context) { | |
| 119 return constantConstructor.accept(this, context); | |
| 120 } | |
| 121 | |
| 122 R visitGenerative(GenerativeConstantConstructor constructor, A arg); | |
| 123 R visitRedirectingGenerative( | |
| 124 RedirectingGenerativeConstantConstructor constructor, A arg); | |
| 125 R visitRedirectingFactory( | |
| 126 RedirectingFactoryConstantConstructor constructor, A arg); | |
| 127 } | |
| 128 | |
| 129 /// A generative constant constructor. | |
| 130 class GenerativeConstantConstructor implements ConstantConstructor{ | |
| 131 final InterfaceType type; | |
| 132 final Map<dynamic/*int|String*/, ConstantExpression> defaultValues; | |
| 133 final Map<FieldElement, ConstantExpression> fieldMap; | |
| 134 final ConstructedConstantExpression superConstructorInvocation; | |
| 135 | |
| 136 GenerativeConstantConstructor( | |
| 137 this.type, | |
| 138 this.defaultValues, | |
| 139 this.fieldMap, | |
| 140 this.superConstructorInvocation); | |
| 141 | |
| 142 ConstantConstructorKind get kind => ConstantConstructorKind.GENERATIVE; | |
| 143 | |
| 144 InterfaceType computeInstanceType(InterfaceType newType) { | |
| 145 return type.substByContext(newType); | |
| 146 } | |
| 147 | |
| 148 Map<FieldElement, ConstantExpression> computeInstanceFields( | |
| 149 List<ConstantExpression> arguments, | |
| 150 CallStructure callStructure) { | |
| 151 NormalizedArguments args = new NormalizedArguments( | |
| 152 defaultValues, callStructure, arguments); | |
| 153 Map<FieldElement, ConstantExpression> appliedFieldMap = | |
| 154 applyFields(args, superConstructorInvocation); | |
| 155 fieldMap.forEach((FieldElement field, ConstantExpression constant) { | |
| 156 appliedFieldMap[field] = constant.apply(args); | |
| 157 }); | |
| 158 return appliedFieldMap; | |
| 159 } | |
| 160 | |
| 161 accept(ConstantConstructorVisitor visitor, arg) { | |
| 162 return visitor.visitGenerative(this, arg); | |
| 163 } | |
| 164 | |
| 165 int get hashCode { | |
| 166 int hash = Hashing.objectHash(type); | |
| 167 hash = Hashing.mapHash(defaultValues, hash); | |
| 168 hash = Hashing.mapHash(fieldMap, hash); | |
| 169 return Hashing.objectHash(superConstructorInvocation, hash); | |
| 170 } | |
| 171 | |
| 172 bool operator ==(other) { | |
| 173 if (identical(this, other)) return true; | |
| 174 if (other is! GenerativeConstantConstructor) return false; | |
| 175 return | |
| 176 type == other.type && | |
| 177 superConstructorInvocation == other.superConstructorInvocation && | |
| 178 mapEquals(defaultValues, other.defaultValues) && | |
| 179 mapEquals(fieldMap, other.fieldMap); | |
| 180 } | |
| 181 | |
| 182 String toString() { | |
| 183 StringBuffer sb = new StringBuffer(); | |
| 184 sb.write("{'type': $type"); | |
| 185 defaultValues.forEach((key, ConstantExpression expression) { | |
| 186 sb.write(",\n 'default:${key}': ${expression.getText()}"); | |
| 187 }); | |
| 188 fieldMap.forEach((FieldElement field, ConstantExpression expression) { | |
| 189 sb.write(",\n 'field:${field}': ${expression.getText()}"); | |
| 190 }); | |
| 191 if (superConstructorInvocation != null) { | |
| 192 sb.write(",\n 'constructor: ${superConstructorInvocation.getText()}"); | |
| 193 } | |
| 194 sb.write("}"); | |
| 195 return sb.toString(); | |
| 196 } | |
| 197 | |
| 198 static bool mapEquals(Map map1, Map map2) { | |
| 199 if (map1.length != map1.length) return false; | |
| 200 for (var key in map1.keys) { | |
| 201 if (map1[key] != map2[key]) { | |
| 202 return false; | |
| 203 } | |
| 204 } | |
| 205 return true; | |
| 206 } | |
| 207 | |
| 208 /// Creates the field-to-constant map from applying [args] to | |
| 209 /// [constructorInvocation]. If [constructorInvocation] is `null`, an empty | |
| 210 /// map is created. | |
| 211 static Map<FieldElement, ConstantExpression> applyFields( | |
| 212 NormalizedArguments args, | |
| 213 ConstructedConstantExpression constructorInvocation) { | |
| 214 Map<FieldElement, ConstantExpression> appliedFieldMap = | |
| 215 <FieldElement, ConstantExpression>{}; | |
| 216 if (constructorInvocation != null) { | |
| 217 Map<FieldElement, ConstantExpression> fieldMap = | |
| 218 constructorInvocation.computeInstanceFields(); | |
| 219 fieldMap.forEach((FieldElement field, ConstantExpression constant) { | |
| 220 appliedFieldMap[field] = constant.apply(args); | |
| 221 }); | |
| 222 } | |
| 223 return appliedFieldMap; | |
| 224 } | |
| 225 } | |
| 226 | |
| 227 /// A redirecting generative constant constructor. | |
| 228 class RedirectingGenerativeConstantConstructor implements ConstantConstructor { | |
| 229 final Map<dynamic/*int|String*/, ConstantExpression> defaultValues; | |
| 230 final ConstructedConstantExpression thisConstructorInvocation; | |
| 231 | |
| 232 RedirectingGenerativeConstantConstructor( | |
| 233 this.defaultValues, | |
| 234 this.thisConstructorInvocation); | |
| 235 | |
| 236 ConstantConstructorKind get kind { | |
| 237 return ConstantConstructorKind.REDIRECTING_GENERATIVE; | |
| 238 } | |
| 239 | |
| 240 InterfaceType computeInstanceType(InterfaceType newType) { | |
| 241 return thisConstructorInvocation.computeInstanceType() | |
| 242 .substByContext(newType); | |
| 243 } | |
| 244 | |
| 245 Map<FieldElement, ConstantExpression> computeInstanceFields( | |
| 246 List<ConstantExpression> arguments, | |
| 247 CallStructure callStructure) { | |
| 248 NormalizedArguments args = | |
| 249 new NormalizedArguments(defaultValues, callStructure, arguments); | |
| 250 Map<FieldElement, ConstantExpression> appliedFieldMap = | |
| 251 GenerativeConstantConstructor.applyFields( | |
| 252 args, thisConstructorInvocation); | |
| 253 return appliedFieldMap; | |
| 254 } | |
| 255 | |
| 256 accept(ConstantConstructorVisitor visitor, arg) { | |
| 257 return visitor.visitRedirectingGenerative(this, arg); | |
| 258 } | |
| 259 | |
| 260 int get hashCode { | |
| 261 int hash = Hashing.objectHash(thisConstructorInvocation); | |
| 262 return Hashing.mapHash(defaultValues, hash); | |
| 263 } | |
| 264 | |
| 265 bool operator ==(other) { | |
| 266 if (identical(this, other)) return true; | |
| 267 if (other is! RedirectingGenerativeConstantConstructor) return false; | |
| 268 return | |
| 269 thisConstructorInvocation == other.thisConstructorInvocation && | |
| 270 GenerativeConstantConstructor.mapEquals( | |
| 271 defaultValues, other.defaultValues); | |
| 272 } | |
| 273 | |
| 274 String toString() { | |
| 275 StringBuffer sb = new StringBuffer(); | |
| 276 sb.write("{'type': ${thisConstructorInvocation.type}"); | |
| 277 defaultValues.forEach((key, ConstantExpression expression) { | |
| 278 sb.write(",\n 'default:${key}': ${expression.getText()}"); | |
| 279 }); | |
| 280 sb.write(",\n 'constructor': ${thisConstructorInvocation.getText()}"); | |
| 281 sb.write("}"); | |
| 282 return sb.toString(); | |
| 283 } | |
| 284 } | |
| 285 | |
| 286 /// A redirecting factory constant constructor. | |
| 287 class RedirectingFactoryConstantConstructor implements ConstantConstructor { | |
| 288 final ConstructedConstantExpression targetConstructorInvocation; | |
| 289 | |
| 290 RedirectingFactoryConstantConstructor(this.targetConstructorInvocation); | |
| 291 | |
| 292 ConstantConstructorKind get kind { | |
| 293 return ConstantConstructorKind.REDIRECTING_FACTORY; | |
| 294 } | |
| 295 | |
| 296 InterfaceType computeInstanceType(InterfaceType newType) { | |
| 297 return targetConstructorInvocation.computeInstanceType() | |
| 298 .substByContext(newType); | |
| 299 } | |
| 300 | |
| 301 Map<FieldElement, ConstantExpression> computeInstanceFields( | |
| 302 List<ConstantExpression> arguments, | |
| 303 CallStructure callStructure) { | |
| 304 ConstantConstructor constantConstructor = | |
| 305 targetConstructorInvocation.target.constantConstructor; | |
| 306 return constantConstructor.computeInstanceFields(arguments, callStructure); | |
| 307 } | |
| 308 | |
| 309 accept(ConstantConstructorVisitor visitor, arg) { | |
| 310 return visitor.visitRedirectingFactory(this, arg); | |
| 311 } | |
| 312 | |
| 313 int get hashCode { | |
| 314 return Hashing.objectHash(targetConstructorInvocation); | |
| 315 } | |
| 316 | |
| 317 bool operator ==(other) { | |
| 318 if (identical(this, other)) return true; | |
| 319 if (other is! RedirectingFactoryConstantConstructor) return false; | |
| 320 return targetConstructorInvocation == other.targetConstructorInvocation; | |
| 321 } | |
| 322 | |
| 323 String toString() { | |
| 324 StringBuffer sb = new StringBuffer(); | |
| 325 sb.write("{"); | |
| 326 sb.write("'constructor': ${targetConstructorInvocation.getText()}"); | |
| 327 sb.write("}"); | |
| 328 return sb.toString(); | |
| 329 } | |
| 330 } | |
| 331 | |
| 332 /// An expression that is a compile-time constant. | 54 /// An expression that is a compile-time constant. |
| 333 /// | 55 /// |
| 334 /// Whereas [ConstantValue] represent a compile-time value, a | 56 /// Whereas [ConstantValue] represent a compile-time value, a |
| 335 /// [ConstantExpression] represents an expression for creating a constant. | 57 /// [ConstantExpression] represents an expression for creating a constant. |
| 336 /// | 58 /// |
| 337 /// There is no one-to-one mapping between [ConstantExpression] and | 59 /// There is no one-to-one mapping between [ConstantExpression] and |
| 338 /// [ConstantValue], because different expressions can denote the same constant. | 60 /// [ConstantValue], because different expressions can denote the same constant. |
| 339 /// For instance, multiple `const` constructors may be used to create the same | 61 /// For instance, multiple `const` constructors may be used to create the same |
| 340 /// object, and different `const` variables may hold the same value. | 62 /// object, and different `const` variables may hold the same value. |
| 341 abstract class ConstantExpression { | 63 abstract class ConstantExpression { |
| (...skipping 1533 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1875 visit(exp.name); | 1597 visit(exp.name); |
| 1876 if (exp.defaultValue != null) { | 1598 if (exp.defaultValue != null) { |
| 1877 sb.write(', defaultValue: '); | 1599 sb.write(', defaultValue: '); |
| 1878 visit(exp.defaultValue); | 1600 visit(exp.defaultValue); |
| 1879 } | 1601 } |
| 1880 sb.write(')'); | 1602 sb.write(')'); |
| 1881 } | 1603 } |
| 1882 | 1604 |
| 1883 String toString() => sb.toString(); | 1605 String toString() => sb.toString(); |
| 1884 } | 1606 } |
| OLD | NEW |