Chromium Code Reviews| 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 dart2js.serialization.resolved_ast; | |
| 6 | |
| 7 import '../common.dart'; | |
| 8 import '../common/resolution.dart'; | |
| 9 import '../constants/expressions.dart'; | |
| 10 import '../dart_types.dart'; | |
| 11 import '../diagnostics/diagnostic_listener.dart'; | |
| 12 import '../elements/elements.dart'; | |
| 13 import '../parser/parser.dart' show | |
| 14 Parser; | |
| 15 import '../parser/listener.dart' show | |
| 16 ParserError; | |
| 17 import '../parser/node_listener.dart' show | |
| 18 NodeListener; | |
| 19 import '../resolution/enum_creator.dart'; | |
| 20 import '../resolution/send_structure.dart'; | |
| 21 import '../resolution/tree_elements.dart'; | |
| 22 import '../tree/tree.dart'; | |
| 23 import '../tokens/token.dart'; | |
| 24 import '../universe/selector.dart'; | |
| 25 import 'keys.dart'; | |
| 26 import 'serialization.dart'; | |
| 27 import 'serialization_util.dart'; | |
| 28 | |
| 29 /// Visitor that computes a node-index mapping. | |
| 30 class AstIndexComputer extends Visitor { | |
| 31 final Map<Node, int> nodeIndices = <Node, int>{}; | |
| 32 final List<Node> nodeList = <Node>[]; | |
| 33 | |
| 34 @override | |
| 35 visitNode(Node node) { | |
| 36 nodeIndices.putIfAbsent(node, () { | |
| 37 // Some nodes (like Modifier and empty NodeList) can be reused. | |
| 38 nodeList.add(node); | |
| 39 return nodeIndices.length; | |
| 40 }); | |
| 41 node.visitChildren(this); | |
| 42 } | |
| 43 } | |
| 44 | |
| 45 /// The kind of AST node. Used for determining how to deserialize | |
| 46 /// [ResolvedAst]s. | |
| 47 enum AstKind { | |
| 48 ENUM_CONSTRUCTOR, | |
| 49 ENUM_CONSTANT, | |
| 50 ENUM_INDEX_FIELD, | |
| 51 ENUM_VALUES_FIELD, | |
| 52 ENUM_TO_STRING, | |
| 53 FACTORY, | |
| 54 FIELD, | |
| 55 FUNCTION, | |
| 56 } | |
| 57 | |
| 58 /// Serializer for [ResolvedAst]s. | |
| 59 class ResolvedAstSerializer extends Visitor { | |
| 60 final ObjectEncoder objectEncoder; | |
| 61 final ResolvedAst resolvedAst; | |
| 62 final AstIndexComputer indexComputer = new AstIndexComputer(); | |
| 63 final Map<int, ObjectEncoder> nodeData = <int, ObjectEncoder>{}; | |
| 64 ListEncoder _nodeDataEncoder; | |
| 65 | |
| 66 ResolvedAstSerializer(this.objectEncoder, this.resolvedAst); | |
| 67 | |
| 68 AstElement get element => resolvedAst.element; | |
| 69 | |
| 70 TreeElements get elements => resolvedAst.elements; | |
| 71 | |
| 72 Node get root => resolvedAst.node; | |
| 73 | |
| 74 Map<Node, int> get nodeIndices => indexComputer.nodeIndices; | |
| 75 List<Node> get nodeList => indexComputer.nodeList; | |
| 76 | |
| 77 /// Serializes [resolvedAst] into [objectEncoder]. | |
| 78 void serialize() { | |
| 79 objectEncoder.setUri(Key.URI, | |
| 80 elements.analyzedElement.compilationUnit.script.resourceUri, | |
|
Siggi Cherem (dart-lang)
2016/04/08 16:55:33
eventually we should look into what URI to use - r
Johnni Winther
2016/04/11 08:54:04
This is a known issue for the serialization itself
Siggi Cherem (dart-lang)
2016/04/11 17:48:07
could we file a bug/add a todo to track this issue
Johnni Winther
2016/04/12 08:05:47
Done: #26244
| |
| 81 elements.analyzedElement.compilationUnit.script.resourceUri); | |
| 82 AstKind kind; | |
| 83 if (element.enclosingClass is EnumClassElement) { | |
| 84 if (element.name == 'index') { | |
| 85 kind = AstKind.ENUM_INDEX_FIELD; | |
| 86 } else if (element.name == 'values') { | |
| 87 kind = AstKind.ENUM_VALUES_FIELD; | |
| 88 } else if (element.name == 'toString') { | |
| 89 kind = AstKind.ENUM_TO_STRING; | |
| 90 } else if (element.isConstructor) { | |
| 91 kind = AstKind.ENUM_CONSTRUCTOR; | |
| 92 } else { | |
| 93 assert(invariant(element, element.isConst, | |
| 94 message: "Unexpected enum member: $element")); | |
| 95 kind = AstKind.ENUM_CONSTANT; | |
| 96 } | |
| 97 } else if (element.isFactoryConstructor) { | |
|
Siggi Cherem (dart-lang)
2016/04/08 16:55:33
nit: small refactor just to make it more self expl
Johnni Winther
2016/04/11 08:54:04
Done.
| |
| 98 objectEncoder.setInt(Key.OFFSET, root.getBeginToken().charOffset); | |
| 99 kind = AstKind.FACTORY; | |
| 100 } else if (element.isField) { | |
| 101 objectEncoder.setInt(Key.OFFSET, root.getBeginToken().charOffset); | |
|
Siggi Cherem (dart-lang)
2016/04/08 16:55:33
question: as we make progress we'll drop the token
Johnni Winther
2016/04/11 08:54:04
Yes. Source information such replace tokens/nodes
| |
| 102 kind = AstKind.FIELD; | |
| 103 } else { | |
| 104 objectEncoder.setInt(Key.OFFSET, root.getBeginToken().charOffset); | |
| 105 kind = AstKind.FUNCTION; | |
| 106 FunctionExpression functionExpression = root.asFunctionExpression(); | |
| 107 if (functionExpression.getOrSet != null) { | |
| 108 objectEncoder.setInt( | |
| 109 Key.GET_OR_SET, functionExpression.getOrSet.charOffset); | |
|
Siggi Cherem (dart-lang)
2016/04/08 16:55:33
follow up question: this seems trickier to do with
Johnni Winther
2016/04/11 08:54:04
This is only for reparsing. When we have a complet
| |
| 110 } | |
| 111 } | |
| 112 objectEncoder.setEnum(Key.KIND, kind); | |
| 113 root.accept(indexComputer); | |
| 114 root.accept(this); | |
| 115 } | |
| 116 | |
| 117 /// Computes the [ListEncoder] for serializing data for nodes. | |
| 118 ListEncoder get nodeDataEncoder { | |
| 119 if (_nodeDataEncoder == null) { | |
| 120 _nodeDataEncoder = objectEncoder.createList(Key.DATA); | |
| 121 } | |
| 122 return _nodeDataEncoder; | |
| 123 } | |
| 124 | |
| 125 /// Computes the [ObjectEncoder] for serializing data for [node]. | |
| 126 ObjectEncoder getNodeDataEncoder(Node node) { | |
| 127 int id = nodeIndices[node]; | |
| 128 return nodeData.putIfAbsent(id, () { | |
| 129 ObjectEncoder objectEncoder = nodeDataEncoder.createObject(); | |
| 130 objectEncoder.setInt(Key.ID, id); | |
| 131 return objectEncoder; | |
| 132 }); | |
| 133 } | |
| 134 | |
| 135 @override | |
| 136 visitNode(Node node) { | |
| 137 Element nodeElement = elements[node]; | |
| 138 if (nodeElement != null) { | |
| 139 if (nodeElement.enclosingClass != null && | |
| 140 nodeElement.enclosingClass.isUnnamedMixinApplication) { | |
| 141 // TODO(johnniwinther): Handle references to members of unnamed mixin | |
| 142 // applications. | |
| 143 } else { | |
| 144 getNodeDataEncoder(node).setElement(Key.ELEMENT, nodeElement); | |
| 145 } | |
| 146 } | |
| 147 DartType type = elements.getType(node); | |
| 148 if (type != null) { | |
| 149 getNodeDataEncoder(node).setType(Key.TYPE, type); | |
| 150 } | |
| 151 Selector selector = elements.getSelector(node); | |
| 152 if (selector != null) { | |
| 153 serializeSelector( | |
| 154 selector, | |
| 155 getNodeDataEncoder(node).createObject(Key.SELECTOR)); | |
| 156 } | |
| 157 ConstantExpression constant = elements.getConstant(node); | |
| 158 if (constant != null) { | |
| 159 getNodeDataEncoder(node).setConstant(Key.CONSTANT, constant); | |
| 160 } | |
| 161 DartType cachedType = elements.typesCache[node]; | |
| 162 if (cachedType != null) { | |
| 163 getNodeDataEncoder(node).setType(Key.CACHED_TYPE, cachedType); | |
| 164 } | |
| 165 // TODO(johnniwinther): Serialize [JumpTarget]s. | |
| 166 node.visitChildren(this); | |
| 167 } | |
| 168 | |
| 169 @override | |
| 170 visitSend(Send node) { | |
| 171 visitExpression(node); | |
| 172 SendStructure structure = elements.getSendStructure(node); | |
| 173 if (structure != null) { | |
| 174 serializeSendStructure(structure, | |
| 175 getNodeDataEncoder(node).createObject(Key.SEND_STRUCTURE)); | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 @override | |
| 180 visitNewExpression(NewExpression node) { | |
| 181 visitExpression(node); | |
| 182 NewStructure structure = elements.getNewStructure(node); | |
| 183 if (structure != null) { | |
| 184 serializeNewStructure(structure, | |
| 185 getNodeDataEncoder(node).createObject(Key.NEW_STRUCTURE)); | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 @override | |
| 190 visitGotoStatement(GotoStatement node) { | |
| 191 visitStatement(node); | |
| 192 // TODO(johnniwinther): Serialize [JumpTarget]s and [LabelDefinition]s. | |
| 193 } | |
| 194 | |
| 195 @override | |
| 196 visitLabel(Label node) { | |
| 197 visitNode(node); | |
| 198 // TODO(johnniwinther): Serialize[LabelDefinition]s. | |
| 199 } | |
| 200 } | |
| 201 | |
| 202 class ResolvedAstDeserializer { | |
| 203 /// Find the [Token] at [offset] searching through successors of [token]. | |
| 204 static Token findTokenInStream(Token token, int offset) { | |
| 205 while (token.charOffset <= offset && token.next != token) { | |
| 206 if (token.charOffset == offset) { | |
| 207 return token; | |
| 208 } | |
| 209 token = token.next; | |
| 210 } | |
| 211 return null; | |
| 212 } | |
| 213 | |
| 214 /// Deserializes the [ResolvedAst] for [element] from [objectDecoder]. | |
| 215 /// [parsing] and [getBeginToken] are used for parsing the [Node] for | |
| 216 /// [element] from its source code. | |
| 217 static ResolvedAst deserialize( | |
| 218 Element element, | |
| 219 ObjectDecoder objectDecoder, | |
| 220 Parsing parsing, | |
| 221 Token getBeginToken(Uri uri, int charOffset)) { | |
| 222 CompilationUnitElement compilationUnit = element.compilationUnit; | |
| 223 DiagnosticReporter reporter = parsing.reporter; | |
| 224 | |
| 225 /// Returns the first [Token] for parsing the [Node] for [element]. | |
| 226 Token readBeginToken() { | |
| 227 Uri uri = objectDecoder.getUri(Key.URI); | |
| 228 int charOffset = objectDecoder.getInt(Key.OFFSET); | |
| 229 Token beginToken = getBeginToken(uri, charOffset); | |
| 230 if (beginToken == null) { | |
| 231 reporter.internalError( | |
| 232 element, "No token found for $element in $uri @ $charOffset"); | |
| 233 } | |
| 234 return beginToken; | |
| 235 } | |
| 236 | |
| 237 /// Create the [Node] for the element by parsing the source code. | |
| 238 Node doParse(parse(Parser parser)) { | |
| 239 return parsing.measure(() { | |
| 240 return reporter.withCurrentElement(element, () { | |
| 241 CompilationUnitElement unit = element.compilationUnit; | |
| 242 NodeListener listener = new NodeListener( | |
| 243 parsing.getScannerOptionsFor(element), reporter, null); | |
| 244 listener.memberErrors = listener.memberErrors.prepend(false); | |
| 245 try { | |
| 246 Parser parser = new Parser(listener, parsing.parserOptions); | |
| 247 parse(parser); | |
| 248 } on ParserError catch (e) { | |
| 249 reporter.internalError(element, '$e'); | |
| 250 } | |
| 251 return listener.popNode(); | |
| 252 }); | |
| 253 }); | |
| 254 } | |
| 255 | |
| 256 /// Computes the [Node] for the element based on the [AstKind]. | |
| 257 Node computeNode(AstKind kind) { | |
| 258 switch (kind) { | |
| 259 case AstKind.ENUM_INDEX_FIELD: | |
| 260 AstBuilder builder = new AstBuilder(element.sourcePosition.begin); | |
| 261 Identifier identifier = builder.identifier('index'); | |
| 262 VariableDefinitions node = new VariableDefinitions( | |
| 263 null, | |
| 264 builder.modifiers(isFinal: true), | |
| 265 new NodeList.singleton(identifier)); | |
| 266 return node; | |
| 267 case AstKind.ENUM_VALUES_FIELD: | |
| 268 EnumClassElement enumClass = element.enclosingClass; | |
| 269 AstBuilder builder = new AstBuilder(element.sourcePosition.begin); | |
| 270 List<FieldElement> enumValues = <FieldElement>[]; | |
| 271 List<Node> valueReferences = <Node>[]; | |
| 272 for (EnumConstantElement enumConstant in enumClass.enumValues) { | |
| 273 AstBuilder valueBuilder = | |
| 274 new AstBuilder(enumConstant.sourcePosition.begin); | |
| 275 Identifier name = valueBuilder.identifier(enumConstant.name); | |
| 276 | |
| 277 // Add reference for the `values` field. | |
| 278 valueReferences.add(valueBuilder.reference(name)); | |
| 279 } | |
| 280 | |
| 281 Identifier valuesIdentifier = builder.identifier('values'); | |
| 282 // TODO(johnniwinther): Add type argument. | |
| 283 Expression initializer = builder.listLiteral( | |
| 284 valueReferences, isConst: true); | |
| 285 | |
| 286 Node definition = | |
| 287 builder.createDefinition(valuesIdentifier, initializer); | |
| 288 VariableDefinitions node = new VariableDefinitions( | |
| 289 null, | |
| 290 builder.modifiers(isStatic: true, isConst: true), | |
| 291 new NodeList.singleton(definition)); | |
| 292 return node; | |
| 293 case AstKind.ENUM_TO_STRING: | |
| 294 EnumClassElement enumClass = element.enclosingClass; | |
| 295 AstBuilder builder = new AstBuilder(element.sourcePosition.begin); | |
| 296 List<LiteralMapEntry> mapEntries = <LiteralMapEntry>[]; | |
| 297 for (EnumConstantElement enumConstant in enumClass.enumValues) { | |
| 298 AstBuilder valueBuilder = | |
| 299 new AstBuilder(enumConstant.sourcePosition.begin); | |
| 300 Identifier name = valueBuilder.identifier(enumConstant.name); | |
| 301 | |
| 302 // Add map entry for `toString` implementation. | |
| 303 mapEntries.add(valueBuilder.mapLiteralEntry( | |
| 304 valueBuilder.literalInt(enumConstant.index), | |
| 305 valueBuilder.literalString( | |
| 306 '${enumClass.name}.${name.source}'))); | |
| 307 } | |
| 308 | |
| 309 // TODO(johnniwinther): Support return type. Note `String` might be | |
| 310 // prefixed or not imported within the current library. | |
| 311 FunctionExpression toStringNode = builder.functionExpression( | |
| 312 Modifiers.EMPTY, | |
| 313 'toString', | |
| 314 builder.argumentList([]), | |
| 315 builder.returnStatement( | |
| 316 builder.indexGet( | |
| 317 builder.mapLiteral(mapEntries, isConst: true), | |
| 318 builder.reference(builder.identifier('index'))) | |
| 319 ) | |
| 320 ); | |
| 321 return toStringNode; | |
| 322 case AstKind.ENUM_CONSTRUCTOR: | |
| 323 AstBuilder builder = new AstBuilder(element.sourcePosition.begin); | |
| 324 VariableDefinitions indexDefinition = | |
| 325 builder.initializingFormal('index'); | |
| 326 FunctionExpression constructorNode = builder.functionExpression( | |
| 327 builder.modifiers(isConst: true), | |
| 328 element.enclosingClass.name, | |
| 329 builder.argumentList([indexDefinition]), | |
| 330 builder.emptyStatement()); | |
| 331 return constructorNode; | |
| 332 case AstKind.ENUM_CONSTANT: | |
| 333 EnumConstantElement enumConstant = element; | |
| 334 EnumClassElement enumClass = element.enclosingClass; | |
| 335 int index = enumConstant.index; | |
| 336 AstBuilder builder = new AstBuilder(element.sourcePosition.begin); | |
| 337 Identifier name = builder.identifier(element.name); | |
| 338 | |
| 339 Expression initializer = builder.newExpression( | |
| 340 enumClass.name, | |
| 341 builder.argumentList([builder.literalInt(index)]), | |
| 342 isConst: true); | |
| 343 SendSet definition = builder.createDefinition(name, initializer); | |
| 344 | |
| 345 VariableDefinitions node = new VariableDefinitions( | |
| 346 null, | |
| 347 builder.modifiers(isStatic: true, isConst: true), | |
| 348 new NodeList.singleton(definition)); | |
| 349 return node; | |
| 350 case AstKind.FACTORY: | |
| 351 Token beginToken = readBeginToken(); | |
| 352 return doParse((parser) => parser.parseFactoryMethod(beginToken)); | |
| 353 case AstKind.FIELD: | |
| 354 Token beginToken = readBeginToken(); | |
| 355 return doParse((parser) => parser.parseMember(beginToken)); | |
| 356 case AstKind.FUNCTION: | |
| 357 Token beginToken = readBeginToken(); | |
| 358 int getOrSetOffset = | |
| 359 objectDecoder.getInt(Key.GET_OR_SET, isOptional: true); | |
| 360 Token getOrSet; | |
| 361 if (getOrSetOffset != null) { | |
| 362 getOrSet = findTokenInStream(beginToken, getOrSetOffset); | |
| 363 if (getOrSet == null) { | |
| 364 reporter.internalError( | |
| 365 element, | |
| 366 "No token found for $element in " | |
| 367 "${objectDecoder.getUri(Key.URI)} @ $getOrSetOffset"); | |
| 368 } | |
| 369 } | |
| 370 return doParse((parser) { | |
| 371 parser.parseFunction(beginToken, getOrSet); | |
| 372 }); | |
| 373 } | |
| 374 } | |
| 375 | |
| 376 AstKind kind = objectDecoder.getEnum(Key.KIND, AstKind.values); | |
| 377 Node root = computeNode(kind); | |
| 378 TreeElementMapping elements = new TreeElementMapping(element); | |
| 379 AstIndexComputer indexComputer = new AstIndexComputer(); | |
| 380 Map<Node, int> nodeIndices = indexComputer.nodeIndices; | |
| 381 List<Node> nodeList = indexComputer.nodeList; | |
| 382 root.accept(indexComputer); | |
| 383 ListDecoder dataDecoder = objectDecoder.getList(Key.DATA); | |
| 384 if (dataDecoder != null) { | |
| 385 for (int i = 0; i < dataDecoder.length; i++) { | |
| 386 ObjectDecoder objectDecoder = dataDecoder.getObject(i); | |
| 387 int id = objectDecoder.getInt(Key.ID); | |
| 388 Node node = nodeList[id]; | |
| 389 Element nodeElement = | |
| 390 objectDecoder.getElement(Key.ELEMENT, isOptional: true); | |
| 391 if (nodeElement != null) { | |
| 392 elements[node] = nodeElement; | |
| 393 } | |
| 394 DartType type = objectDecoder.getType(Key.TYPE, isOptional: true); | |
| 395 if (type != null) { | |
| 396 elements.setType(node, type); | |
| 397 } | |
| 398 ObjectDecoder selectorDecoder = | |
| 399 objectDecoder.getObject(Key.SELECTOR, isOptional: true); | |
| 400 if (selectorDecoder != null) { | |
| 401 elements.setSelector(node, deserializeSelector(selectorDecoder)); | |
| 402 } | |
| 403 ConstantExpression constant = | |
| 404 objectDecoder.getConstant(Key.CONSTANT, isOptional: true); | |
| 405 if (constant != null) { | |
| 406 elements.setConstant(node, constant); | |
| 407 } | |
| 408 DartType cachedType = | |
| 409 objectDecoder.getType(Key.CACHED_TYPE, isOptional: true); | |
| 410 if (cachedType != null) { | |
| 411 elements.typesCache[node] = cachedType; | |
| 412 } | |
| 413 ObjectDecoder sendStructureDecoder = | |
| 414 objectDecoder.getObject(Key.SEND_STRUCTURE, isOptional: true); | |
| 415 if (sendStructureDecoder != null) { | |
| 416 elements.setSendStructure(node, | |
| 417 deserializeSendStructure(sendStructureDecoder)); | |
| 418 } | |
| 419 ObjectDecoder newStructureDecoder = | |
| 420 objectDecoder.getObject(Key.NEW_STRUCTURE, isOptional: true); | |
| 421 if (newStructureDecoder != null) { | |
| 422 elements.setNewStructure(node, | |
| 423 deserializeNewStructure(newStructureDecoder)); | |
| 424 } | |
| 425 } | |
| 426 } | |
| 427 return new ResolvedAst(element, root, elements); | |
| 428 } | |
| 429 } | |
| 430 | |
| 431 | |
| OLD | NEW |