Chromium Code Reviews| Index: pkg/compiler/lib/src/info/info.dart |
| diff --git a/pkg/compiler/lib/src/info/info.dart b/pkg/compiler/lib/src/info/info.dart |
| index 5aa06f2665d707202012ab70c0b58a060ec51e0e..4100a4baa81db960ae306e6b945a3ff946709be3 100644 |
| --- a/pkg/compiler/lib/src/info/info.dart |
| +++ b/pkg/compiler/lib/src/info/info.dart |
| @@ -33,6 +33,8 @@ abstract class Info { |
| // TODO(sigmund): refactor and put toJson outside the class, so we can have 2 |
| // different serializer/deserializers at once. |
| Map toJson(); |
| + |
| + void accept(InfoVisitor visitor); |
| } |
| /// Common information used for most kind of elements. |
| @@ -41,6 +43,8 @@ abstract class Info { |
| abstract class BasicInfo implements Info { |
| final String kind; |
|
Harry Terkelsen
2015/08/11 01:15:18
consider making kind an enum?
Siggi Cherem (dart-lang)
2015/08/11 16:09:27
It's interesting because I only had in mind to use
Harry Terkelsen
2015/08/11 20:11:55
I've run into the same problem when trying to enum
|
| final int id; |
| + |
| + /// Bytes used in the generated code for the corresponding element. |
| int size; |
| String get serializedId => '$kind/$id'; |
| @@ -53,6 +57,10 @@ abstract class BasicInfo implements Info { |
| BasicInfo(this.kind, this.id, this.name, this.outputUnit, this.size); |
| + BasicInfo._fromId(String serializedId) |
| + : kind = serializedId.substring(0, serializedId.indexOf('/')), |
| + id = int.parse(serializedId.substring(serializedId.indexOf('/') + 1)); |
| + |
| Map toJson() { |
| var res = {'id': serializedId, 'kind': kind, 'name': name, 'size': size}; |
| // TODO(sigmund): omit this also when outputUnit.id == 0 |
| @@ -117,6 +125,8 @@ class AllInfo { |
| AllInfo(); |
| + static AllInfo parseFromJson(Map map) => new _ParseHelper().parseAll(map); |
| + |
| Map _listAsJsonMap(List<Info> list) { |
| var map = <String, Map>{}; |
| for (var info in list) { |
| @@ -136,7 +146,6 @@ class AllInfo { |
| return map; |
| } |
| - // TODO(sigmund): implement fromJson |
| Map toJson() => { |
| 'elements': { |
| 'library': _listAsJsonMap(libraries), |
| @@ -153,6 +162,8 @@ class AllInfo { |
| // TODO(sigmund): change viewer to accept an int? |
| 'program': program.toJson(), |
| }; |
| + |
| + void accept(InfoVisitor visitor) => visitor.visitAll(this); |
| } |
| class ProgramInfo { |
| @@ -186,6 +197,148 @@ class ProgramInfo { |
| 'noSuchMethodEnabled': noSuchMethodEnabled, |
| 'minified': minified, |
| }; |
| + |
| + void accept(InfoVisitor visitor) => visitor.visitProgram(this); |
| +} |
| + |
| +class _ParseHelper { |
|
Johnni Winther
2015/08/11 08:45:37
Do we have a test of the serialization/deserializa
Siggi Cherem (dart-lang)
2015/08/11 16:09:27
Not yet, but we will. Added a TODO
|
| + Map<String, Info> registry = {}; |
| + |
| + AllInfo parseAll(Map json) { |
| + var result = new AllInfo(); |
| + var elements = json['elements']; |
| + result.libraries.addAll(elements['library'].values.map(parseLibrary)); |
| + result.classes.addAll(elements['class'].values.map(parseClass)); |
| + result.functions.addAll(elements['function'].values.map(parseFunction)); |
| + result.fields.addAll(elements['field'].values.map(parseField)); |
| + result.typedefs.addAll(elements['typedef'].values.map(parseTypedef)); |
| + |
| + var idMap = {}; |
| + for (var f in result.functions) { |
| + idMap[f.serializedId] = f; |
| + } |
| + for (var f in result.fields) { |
| + idMap[f.serializedId] = f; |
| + } |
| + |
| + json['holding'].forEach((k, deps) { |
| + var src = idMap[k]; |
| + assert (src != null); |
| + for (var dep in deps) { |
| + var target = idMap[dep['id']]; |
| + assert (target != null); |
| + src.uses.add(new DependencyInfo(target, dep['mask'])); |
| + } |
| + }); |
| + |
| + result.program = parseProgram(json['program']); |
| + // todo: version, etc |
| + return result; |
| + } |
| + |
| + LibraryInfo parseLibrary(Map json) { |
| + var result = parseId(json['id']) |
| + ..name = json['name'] |
| + ..uri = Uri.parse(json['canonicalUri']) |
| + ..outputUnit = parseId(json['outputUnit']) |
| + ..size = json['size']; |
| + assert(result.kind == 'library'); |
| + for (var child in json['children'].map(parseId)) { |
| + if (child is FunctionInfo) { |
| + result.topLevelFunctions.add(child); |
| + } else if (child is FieldInfo) { |
| + result.topLevelVariables.add(child); |
| + } else if (child is ClassInfo) { |
| + result.classes.add(child); |
| + } else { |
| + assert(child is TypedefInfo); |
| + result.typedefs.add(child); |
| + } |
| + } |
| + return result; |
| + } |
| + |
| + ClassInfo parseClass(Map json) { |
| + var result = parseId(json['id']) |
| + ..name = json['name'] |
| + ..outputUnit = parseId(json['outputUnit']) |
| + ..size = json['size'] |
| + ..isAbstract = json['modifiers']['abstract'] == true; |
| + assert(result.kind == 'class'); |
| + for (var child in json['children'].map(parseId)) { |
| + if (child is FunctionInfo) { |
| + result.functions.add(child); |
| + } else { |
| + assert(child is FieldInfo); |
| + result.fields.add(child); |
| + } |
| + } |
| + return result; |
| + } |
| + |
| + FieldInfo parseField(Map json) { |
| + return parseId(json['id']) |
| + ..name = json['name'] |
| + ..outputUnit = parseId(json['outputUnit']) |
| + ..size = json['size'] |
| + ..type = json['type'] |
| + ..inferredType = json['inferredType'] |
| + ..code = json['code'] |
| + ..closures = json['children'].map(parseId).toList(); |
| + } |
| + |
| + TypedefInfo parseTypedef(Map json) => parseId(json['id']) |
| + ..name = json['name'] |
| + ..type = json['type'] |
| + ..size = 0; |
| + |
| + ProgramInfo parseProgram(Map json) => |
| + new ProgramInfo()..size = json['size']; |
| + |
| + FunctionInfo parseFunction(Map json) { |
| + return parseId(json['id']) |
| + ..name = json['name'] |
| + ..outputUnit = parseId(json['outputUnit']) |
| + ..size = json['size'] |
| + ..type = json['type'] |
| + ..returnType = json['returnType'] |
| + ..inferredReturnType = json['inferredReturnType'] |
| + ..parameters = json['parameters'].map(parseParameter).toList() |
| + ..code = json['code'] |
| + ..sideEffects = json['sideEffects'] |
| + ..modifiers = parseModifiers(json['modifiers']) |
| + ..closures = json['children'].map(parseId).toList(); |
| + } |
| + |
| + ParameterInfo parseParameter(Map json) => |
| + new ParameterInfo(json['name'], json['type'], json['declaredType']); |
| + |
| + FunctionModifiers parseModifiers(Map<String, bool> json) { |
| + return new FunctionModifiers( |
| + isStatic: json['static'] == true, |
| + isConst: json['const'] == true, |
| + isFactory: json['factory'] == true, |
| + isExternal: json['external'] == true); |
| + } |
| + |
| + Info parseId(String serializedId) => registry.putIfAbsent(serializedId, () { |
| + if (serializedId == null) { |
| + return null; |
| + } else if (serializedId.startsWith('function/')) { |
| + return new FunctionInfo._(serializedId); |
| + } else if (serializedId.startsWith('library/')) { |
| + return new LibraryInfo._(serializedId); |
| + } else if (serializedId.startsWith('class/')) { |
| + return new ClassInfo._(serializedId); |
| + } else if (serializedId.startsWith('field/')) { |
| + return new FieldInfo._(serializedId); |
| + } else if (serializedId.startsWith('typedef/')) { |
| + return new TypedefInfo._(serializedId); |
| + } else if (serializedId.startsWith('outputUnit/')) { |
| + return new OutputUnitInfo._(serializedId); |
| + } |
| + assert(false); |
| + }); |
| } |
| class LibraryInfo extends BasicInfo { |
| @@ -203,6 +356,8 @@ class LibraryInfo extends BasicInfo { |
| LibraryInfo(String name, this.uri, OutputUnitInfo outputUnit, int size) |
| : super('library', _id++, name, outputUnit, size); |
| + LibraryInfo._(String serializedId) : super._fromId(serializedId); |
| + |
| Map toJson() => super.toJson() |
| ..addAll({ |
| 'children': [] |
| @@ -212,12 +367,18 @@ class LibraryInfo extends BasicInfo { |
| ..addAll(typedefs.map((t) => t.serializedId)), |
| 'canonicalUri': '$uri', |
| }); |
| + |
| + void accept(InfoVisitor visitor) => visitor.visitLibrary(this); |
| } |
| class OutputUnitInfo extends BasicInfo { |
| static int _ids = 0; |
| OutputUnitInfo(String name, int size) |
| : super('outputUnit', _ids++, name, null, size); |
| + |
| + OutputUnitInfo._(String serializedId) : super._fromId(serializedId); |
| + |
| + void accept(InfoVisitor visitor) => visitor.visitOutput(this); |
| } |
| class ClassInfo extends BasicInfo { |
| @@ -232,6 +393,8 @@ class ClassInfo extends BasicInfo { |
| {String name, this.isAbstract, OutputUnitInfo outputUnit, int size: 0}) |
| : super('class', _ids++, name, outputUnit, size); |
| + ClassInfo._(String serializedId) : super._fromId(serializedId); |
| + |
| Map toJson() => super.toJson() |
| ..addAll({ |
| // TODO(sigmund): change format, include only when abstract is true. |
| @@ -240,6 +403,8 @@ class ClassInfo extends BasicInfo { |
| ..addAll(fields.map((f) => f.serializedId)) |
| ..addAll(functions.map((m) => m.serializedId)) |
| }); |
| + |
| + void accept(InfoVisitor visitor) => visitor.visitClass(this); |
| } |
| class FieldInfo extends BasicInfo with CodeInfo { |
| @@ -259,6 +424,8 @@ class FieldInfo extends BasicInfo with CodeInfo { |
| OutputUnitInfo outputUnit}) |
| : super('field', _ids++, name, outputUnit, size); |
| + FieldInfo._(String serializedId) : super._fromId(serializedId); |
| + |
| Map toJson() => super.toJson() |
| ..addAll({ |
| 'children': closures.map((i) => i.serializedId).toList(), |
| @@ -266,6 +433,8 @@ class FieldInfo extends BasicInfo with CodeInfo { |
| 'code': code, |
| 'type': type, |
| }); |
| + |
| + void accept(InfoVisitor visitor) => visitor.visitField(this); |
| } |
| class TypedefInfo extends BasicInfo { |
| @@ -275,7 +444,11 @@ class TypedefInfo extends BasicInfo { |
| TypedefInfo(String name, this.type, OutputUnitInfo outputUnit) |
| : super('typedef', _ids++, name, outputUnit, 0); |
| + TypedefInfo._(String serializedId) : super._fromId(serializedId); |
| + |
| Map toJson() => super.toJson()..['type'] = '$type'; |
| + |
| + void accept(InfoVisitor visitor) => visitor.visitTypedef(this); |
| } |
| class FunctionInfo extends BasicInfo with CodeInfo { |
| @@ -286,10 +459,10 @@ class FunctionInfo extends BasicInfo with CodeInfo { |
| static int _ids = 0; |
| /// Kind of function (top-level function, closure, method, or constructor). |
| - final int functionKind; |
| + int functionKind; |
| /// Modifiers applied to this function. |
| - final FunctionModifiers modifiers; |
| + FunctionModifiers modifiers; |
| /// Nested closures that appear within the body of this function. |
| List<FunctionInfo> closures; |
| @@ -332,6 +505,8 @@ class FunctionInfo extends BasicInfo with CodeInfo { |
| this.code}) |
| : super('function', _ids++, name, outputUnit, size); |
| + FunctionInfo._(String serializedId) : super._fromId(serializedId); |
| + |
| Map toJson() => super.toJson() |
| ..addAll({ |
| 'children': closures.map((i) => i.serializedId).toList(), |
| @@ -346,6 +521,8 @@ class FunctionInfo extends BasicInfo with CodeInfo { |
| // Note: version 3.2 of dump-info serializes `uses` in a section called |
| // `holding` at the top-level. |
| }); |
| + |
| + void accept(InfoVisitor visitor) => visitor.visitFunction(this); |
| } |
| /// Information about how a dependency is used. |
| @@ -403,3 +580,52 @@ class FunctionModifiers { |
| 'external': isExternal, |
| }; |
| } |
| + |
| +/// A simple visitor for information produced by the dart2js compiler. |
| +class InfoVisitor { |
| + visitAll(AllInfo info) {} |
| + visitProgram(ProgramInfo info) {} |
| + visitLibrary(LibraryInfo info) {} |
| + visitClass(ClassInfo info) {} |
| + visitField(FieldInfo info) {} |
| + visitFunction(FunctionInfo info) {} |
| + visitTypedef(TypedefInfo info) {} |
| + visitOutput(OutputUnitInfo info) {} |
| +} |
| + |
| +/// A visitor that recursively walks each portion of the program. Because the |
| +/// info representation is redundant, this visitor only walks the structure of |
| +/// the program and skips some redundant links. For example, even though |
| +/// visitAll contains references to functions, this visitor only recurses to |
| +/// visit libraries, then from each library we visit functions and classes, and |
| +/// so on. |
| +class RecursiveInfoVisitor extends InfoVisitor { |
| + visitAll(AllInfo info) { |
| + // Note: we don't visit functions, fields, classes, and typedefs because |
| + // they are reachable from the library info. |
| + info.libraries.forEach(visitLibrary); |
| + } |
| + |
| + visitLibrary(LibraryInfo info) { |
| + info.topLevelFunctions.forEach(visitFunction); |
| + info.topLevelVariables.forEach(visitField); |
| + info.classes.forEach(visitClass); |
| + info.typedefs.forEach(visitTypedef); |
| + } |
| + |
| + visitClass(ClassInfo info) { |
| + info.functions.forEach(visitFunction); |
| + info.fields.forEach(visitField); |
| + } |
| + |
| + visitField(FieldInfo info) { |
| + info.closures.forEach(visitFunction); |
| + } |
| + |
| + visitFunction(FunctionInfo info) { |
| + info.closures.forEach(visitFunction); |
| + } |
| + |
| + visitTypedef(TypedefInfo info) {} |
|
Harry Terkelsen
2015/08/11 01:15:18
remove or make InfoVisitor abstract
Siggi Cherem (dart-lang)
2015/08/11 16:09:27
Done.
|
| + visitOutput(OutputUnitInfo info) {} |
|
Harry Terkelsen
2015/08/11 01:15:18
ditto
Siggi Cherem (dart-lang)
2015/08/11 16:09:27
Done.
|
| +} |