| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 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. |
| 4 |
| 5 library serialization.summarize_const_expr; |
| 6 |
| 7 import 'package:analyzer/src/generated/ast.dart'; |
| 8 import 'package:analyzer/src/generated/scanner.dart'; |
| 9 import 'package:analyzer/src/summary/format.dart'; |
| 10 |
| 11 /** |
| 12 * Instances of this class keep track of intermediate state during |
| 13 * serialization of a single constant [Expression]. |
| 14 */ |
| 15 abstract class AbstractConstExprSerializer { |
| 16 /** |
| 17 * See [UnlinkedConstBuilder.operations]. |
| 18 */ |
| 19 final List<UnlinkedConstOperation> operations = <UnlinkedConstOperation>[]; |
| 20 |
| 21 /** |
| 22 * See [UnlinkedConstBuilder.ints]. |
| 23 */ |
| 24 final List<int> ints = <int>[]; |
| 25 |
| 26 /** |
| 27 * See [UnlinkedConstBuilder.doubles]. |
| 28 */ |
| 29 final List<double> doubles = <double>[]; |
| 30 |
| 31 /** |
| 32 * See [UnlinkedConstBuilder.strings]. |
| 33 */ |
| 34 final List<String> strings = <String>[]; |
| 35 |
| 36 /** |
| 37 * See [UnlinkedConstBuilder.references]. |
| 38 */ |
| 39 final List<UnlinkedTypeRefBuilder> references = <UnlinkedTypeRefBuilder>[]; |
| 40 |
| 41 /** |
| 42 * Serialize the given [expr] expression into this serializer state. |
| 43 */ |
| 44 void serialize(Expression expr) { |
| 45 if (expr is IntegerLiteral) { |
| 46 _pushInt(expr.value); |
| 47 } else if (expr is DoubleLiteral) { |
| 48 operations.add(UnlinkedConstOperation.pushDouble); |
| 49 doubles.add(expr.value); |
| 50 } else if (expr is BooleanLiteral) { |
| 51 if (expr.value) { |
| 52 operations.add(UnlinkedConstOperation.pushTrue); |
| 53 } else { |
| 54 operations.add(UnlinkedConstOperation.pushFalse); |
| 55 } |
| 56 } else if (expr is StringLiteral) { |
| 57 _serializeString(expr); |
| 58 } else if (expr is SymbolLiteral) { |
| 59 strings.add(expr.components.map((token) => token.lexeme).join('.')); |
| 60 operations.add(UnlinkedConstOperation.pushString); |
| 61 operations.add(UnlinkedConstOperation.makeSymbol); |
| 62 } else if (expr is NullLiteral) { |
| 63 operations.add(UnlinkedConstOperation.pushNull); |
| 64 } else if (expr is Identifier) { |
| 65 references.add(serializeIdentifier(expr)); |
| 66 } else if (expr is InstanceCreationExpression) { |
| 67 _serializeInstanceCreation(expr); |
| 68 } else if (expr is ListLiteral) { |
| 69 _serializeListLiteral(expr); |
| 70 } else if (expr is MapLiteral) { |
| 71 _serializeMapLiteral(expr); |
| 72 } else if (expr is MethodInvocation) { |
| 73 String name = expr.methodName.name; |
| 74 if (name != 'identical') { |
| 75 throw new _ConstExprSerializationError( |
| 76 'Only "identity" function invocation is allowed.'); |
| 77 } |
| 78 if (expr.argumentList == null || |
| 79 expr.argumentList.arguments.length != 2) { |
| 80 throw new _ConstExprSerializationError( |
| 81 'The function "identity" requires exactly 2 arguments.'); |
| 82 } |
| 83 expr.argumentList.arguments.forEach(serialize); |
| 84 operations.add(UnlinkedConstOperation.identical); |
| 85 } else if (expr is BinaryExpression) { |
| 86 _serializeBinaryExpression(expr); |
| 87 } else if (expr is ConditionalExpression) { |
| 88 serialize(expr.condition); |
| 89 serialize(expr.thenExpression); |
| 90 serialize(expr.elseExpression); |
| 91 operations.add(UnlinkedConstOperation.conditional); |
| 92 } else if (expr is PrefixExpression) { |
| 93 _serializePrefixExpression(expr); |
| 94 } else if (expr is PropertyAccess && expr.propertyName.name == 'length') { |
| 95 serialize(expr.target); |
| 96 operations.add(UnlinkedConstOperation.length); |
| 97 } else if (expr is ParenthesizedExpression) { |
| 98 serialize(expr.expression); |
| 99 } else { |
| 100 throw new _ConstExprSerializationError('Unknown expression type: $expr'); |
| 101 } |
| 102 } |
| 103 |
| 104 /** |
| 105 * Return [UnlinkedTypeRefBuilder] that corresponds to the given [identifier]. |
| 106 */ |
| 107 UnlinkedTypeRefBuilder serializeIdentifier(Identifier identifier); |
| 108 |
| 109 /** |
| 110 * Return [UnlinkedTypeRefBuilder] that corresponds to the given [type]. |
| 111 */ |
| 112 UnlinkedTypeRefBuilder serializeType(TypeName type); |
| 113 |
| 114 /** |
| 115 * Return the [UnlinkedConstBuilder] that corresponds to the state of this |
| 116 * serializer. |
| 117 */ |
| 118 UnlinkedConstBuilder toBuilder() { |
| 119 return new UnlinkedConstBuilder( |
| 120 operations: operations, |
| 121 ints: ints, |
| 122 doubles: doubles, |
| 123 strings: strings, |
| 124 references: references); |
| 125 } |
| 126 |
| 127 void _pushInt(int value) { |
| 128 // TODO(scheglov) add support for arbitrary precision ints |
| 129 assert(value.abs() < (2 << 31)); |
| 130 ints.add(value & 0xFFFFFFFF); |
| 131 operations.add(UnlinkedConstOperation.pushInt); |
| 132 } |
| 133 |
| 134 void _serializeBinaryExpression(BinaryExpression expr) { |
| 135 serialize(expr.leftOperand); |
| 136 serialize(expr.rightOperand); |
| 137 TokenType operator = expr.operator.type; |
| 138 if (operator == TokenType.EQ_EQ) { |
| 139 operations.add(UnlinkedConstOperation.equal); |
| 140 } else if (operator == TokenType.BANG_EQ) { |
| 141 operations.add(UnlinkedConstOperation.equal); |
| 142 operations.add(UnlinkedConstOperation.not); |
| 143 } else if (operator == TokenType.AMPERSAND_AMPERSAND) { |
| 144 operations.add(UnlinkedConstOperation.and); |
| 145 } else if (operator == TokenType.BAR_BAR) { |
| 146 operations.add(UnlinkedConstOperation.or); |
| 147 } else if (operator == TokenType.CARET) { |
| 148 operations.add(UnlinkedConstOperation.bitXor); |
| 149 } else if (operator == TokenType.AMPERSAND) { |
| 150 operations.add(UnlinkedConstOperation.bitAnd); |
| 151 } else if (operator == TokenType.BAR) { |
| 152 operations.add(UnlinkedConstOperation.bitOr); |
| 153 } else if (operator == TokenType.GT_GT) { |
| 154 operations.add(UnlinkedConstOperation.bitShiftRight); |
| 155 } else if (operator == TokenType.LT_LT) { |
| 156 operations.add(UnlinkedConstOperation.bitShiftLeft); |
| 157 } else if (operator == TokenType.PLUS) { |
| 158 operations.add(UnlinkedConstOperation.add); |
| 159 } else if (operator == TokenType.MINUS) { |
| 160 operations.add(UnlinkedConstOperation.subtract); |
| 161 } else if (operator == TokenType.STAR) { |
| 162 operations.add(UnlinkedConstOperation.multiply); |
| 163 } else if (operator == TokenType.SLASH) { |
| 164 operations.add(UnlinkedConstOperation.divide); |
| 165 } else if (operator == TokenType.TILDE_SLASH) { |
| 166 operations.add(UnlinkedConstOperation.floorDivide); |
| 167 } else if (operator == TokenType.GT) { |
| 168 operations.add(UnlinkedConstOperation.greater); |
| 169 } else if (operator == TokenType.LT) { |
| 170 operations.add(UnlinkedConstOperation.less); |
| 171 } else if (operator == TokenType.GT_EQ) { |
| 172 operations.add(UnlinkedConstOperation.greaterEqual); |
| 173 } else if (operator == TokenType.LT_EQ) { |
| 174 operations.add(UnlinkedConstOperation.lessEqual); |
| 175 } else if (operator == TokenType.PERCENT) { |
| 176 operations.add(UnlinkedConstOperation.modulo); |
| 177 } else { |
| 178 throw new _ConstExprSerializationError('Unknown operator: $operator'); |
| 179 } |
| 180 } |
| 181 |
| 182 void _serializeInstanceCreation(InstanceCreationExpression expr) { |
| 183 ConstructorName constructor = expr.constructorName; |
| 184 List<Expression> arguments = expr.argumentList.arguments; |
| 185 arguments.forEach(serialize); |
| 186 operations.add(UnlinkedConstOperation.invokeConstructor); |
| 187 references.add(serializeType(constructor.type)); |
| 188 if (constructor.name != null) { |
| 189 strings.add(constructor.name.name); |
| 190 } else { |
| 191 strings.add(''); |
| 192 } |
| 193 // TODO(scheglov) named arguments? |
| 194 ints.add(arguments.length); |
| 195 } |
| 196 |
| 197 void _serializeListLiteral(ListLiteral expr) { |
| 198 List<Expression> elements = expr.elements; |
| 199 elements.forEach(serialize); |
| 200 TypeName typeArgument; |
| 201 if (expr.typeArguments != null && |
| 202 expr.typeArguments.arguments.length == 1) { |
| 203 typeArgument = expr.typeArguments.arguments[0]; |
| 204 } |
| 205 references.add(serializeType(typeArgument)); |
| 206 ints.add(elements.length); |
| 207 operations.add(UnlinkedConstOperation.makeList); |
| 208 } |
| 209 |
| 210 void _serializeMapLiteral(MapLiteral expr) { |
| 211 for (MapLiteralEntry entry in expr.entries) { |
| 212 serialize(entry.key); |
| 213 serialize(entry.value); |
| 214 } |
| 215 TypeName keyTypeArgument; |
| 216 TypeName valueTypeArgument; |
| 217 if (expr.typeArguments != null && |
| 218 expr.typeArguments.arguments.length == 2) { |
| 219 keyTypeArgument = expr.typeArguments.arguments[0]; |
| 220 valueTypeArgument = expr.typeArguments.arguments[1]; |
| 221 } |
| 222 references.add(serializeType(keyTypeArgument)); |
| 223 references.add(serializeType(valueTypeArgument)); |
| 224 ints.add(expr.entries.length); |
| 225 operations.add(UnlinkedConstOperation.makeMap); |
| 226 } |
| 227 |
| 228 void _serializePrefixExpression(PrefixExpression expr) { |
| 229 serialize(expr.operand); |
| 230 TokenType operator = expr.operator.type; |
| 231 if (operator == TokenType.BANG) { |
| 232 operations.add(UnlinkedConstOperation.not); |
| 233 } else if (operator == TokenType.MINUS) { |
| 234 operations.add(UnlinkedConstOperation.negate); |
| 235 } else if (operator == TokenType.TILDE) { |
| 236 operations.add(UnlinkedConstOperation.complement); |
| 237 } else { |
| 238 throw new _ConstExprSerializationError('Unknown operator: $operator'); |
| 239 } |
| 240 } |
| 241 |
| 242 void _serializeString(StringLiteral expr) { |
| 243 if (expr is AdjacentStrings) { |
| 244 if (expr.strings.every((string) => string is SimpleStringLiteral)) { |
| 245 operations.add(UnlinkedConstOperation.pushString); |
| 246 strings.add(expr.stringValue); |
| 247 } else { |
| 248 expr.strings.forEach(_serializeString); |
| 249 operations.add(UnlinkedConstOperation.concatenate); |
| 250 ints.add(expr.strings.length); |
| 251 } |
| 252 } else if (expr is SimpleStringLiteral) { |
| 253 operations.add(UnlinkedConstOperation.pushString); |
| 254 strings.add(expr.value); |
| 255 } else { |
| 256 StringInterpolation interpolation = expr as StringInterpolation; |
| 257 for (InterpolationElement element in interpolation.elements) { |
| 258 if (element is InterpolationString) { |
| 259 operations.add(UnlinkedConstOperation.pushString); |
| 260 strings.add(element.value); |
| 261 } else { |
| 262 serialize((element as InterpolationExpression).expression); |
| 263 } |
| 264 } |
| 265 operations.add(UnlinkedConstOperation.concatenate); |
| 266 ints.add(interpolation.elements.length); |
| 267 } |
| 268 } |
| 269 } |
| 270 |
| 271 /** |
| 272 * Error that describes a problem during a constant expression serialization. |
| 273 */ |
| 274 class _ConstExprSerializationError { |
| 275 final String message; |
| 276 |
| 277 _ConstExprSerializationError(this.message); |
| 278 |
| 279 @override |
| 280 String toString() => message; |
| 281 } |
| OLD | NEW |