Chromium Code Reviews| Index: tool/input_sdk/private/debugger.dart |
| diff --git a/tool/input_sdk/private/debugger.dart b/tool/input_sdk/private/debugger.dart |
| index 252b2c84e9ccd1fe459af121085b60105bedbfa7..a6f137bf170163ee88edab38aea055a3f050c24e 100644 |
| --- a/tool/input_sdk/private/debugger.dart |
| +++ b/tool/input_sdk/private/debugger.dart |
| @@ -28,10 +28,10 @@ class JsonMLConfig { |
| static const none = const JsonMLConfig("none"); |
| static const skipDart = const JsonMLConfig("skipDart"); |
| static const keyToString = const JsonMLConfig("keyToString"); |
| + static const renderAsClass = const JsonMLConfig("renderAsClass"); |
|
Jacob
2016/08/02 01:45:11
no need for the word render. These are all options
bmilligan
2016/08/02 16:28:39
Done.
|
| } |
| int _maxSpanLength = 100; |
| - |
| var _devtoolsFormatter = new JsonMLFormatter(new DartFormatter()); |
| String _typeof(object) => JS('String', 'typeof #', object); |
| @@ -51,6 +51,13 @@ class JSNative { |
| JS('', '#[#]=#', object, name, value); |
| } |
| +void addMetadataChildren(object, Set<NameValuePair> ret) { |
| + ret.add(new NameValuePair( |
| + name: getTypeName(_getType(object)), |
| + value: object, |
| + config: JsonMLConfig.renderAsClass)); |
| +} |
| + |
| String getObjectTypeName(object) { |
| var reifiedType = dart.getReifiedType(object); |
| if (reifiedType == null) { |
| @@ -73,6 +80,9 @@ String getTypeName(Type type) { |
| return name; |
| } |
| +Object _getType(object) => |
| + object is Type ? object : dart.getReifiedType(object); |
| + |
| String safePreview(object) { |
| try { |
| var preview = _devtoolsFormatter._simpleFormatter.preview(object); |
| @@ -183,17 +193,6 @@ class NamedConstructor { |
| final Object object; |
| } |
| -class ClassMetadata { |
| - ClassMetadata(this.object, {this.name}); |
| - |
| - final Object object; |
| - final String name; |
| - |
| - String get typeName => |
| - name ?? |
| - getTypeName(object is Type ? object : dart.getReifiedType(object)); |
| -} |
| - |
| class HeritageClause { |
| HeritageClause(this.name, this.types); |
| @@ -201,7 +200,7 @@ class HeritageClause { |
| final List types; |
| } |
| -Object safeGetProperty(Object protoChain, String name) { |
| +Object safeGetProperty(Object protoChain, Object name) { |
| try { |
| return JSNative.getProperty(protoChain, name); |
| } catch (e) { |
| @@ -300,8 +299,7 @@ class JsonMLFormatter { |
| if (config == JsonMLConfig.skipDart || isNativeJavaScriptObject(object)) { |
| return null; |
| } |
| - |
| - var c = _simpleFormatter.preview(object); |
| + var c = _simpleFormatter.preview(object, config: config); |
| if (c == null) return null; |
| if (config == JsonMLConfig.keyToString) { |
| @@ -317,9 +315,10 @@ class JsonMLFormatter { |
| return element.toJsonML(); |
| } |
| - bool hasBody(object) => _simpleFormatter.hasChildren(object); |
| + bool hasBody(object, config) => |
| + _simpleFormatter.hasChildren(object, config: config); |
| - body(object) { |
| + body(object, config) { |
| var body = new JsonMLElement('ol') |
| ..setStyle('list-style-type: none;' |
| 'padding-left: 0px;' |
| @@ -329,7 +328,7 @@ class JsonMLFormatter { |
| if (object is StackTrace) { |
| body.addStyle('color: rgb(196, 26, 22);'); |
| } |
| - var children = _simpleFormatter.children(object); |
| + var children = _simpleFormatter.children(object, config: config); |
| for (NameValuePair child in children) { |
| var li = body.createChild('li'); |
| var nameSpan = new JsonMLElement('span') |
| @@ -343,7 +342,7 @@ class JsonMLFormatter { |
| li.appendChild(nameSpan); |
| var objectTag = li.createObjectTag(child.value); |
| objectTag.addAttribute('config', child.config); |
| - if (!_simpleFormatter.hasChildren(child.value)) { |
| + if (!_simpleFormatter.hasChildren(child.value, config: child.config)) { |
| li.setStyle("padding-left: 13px;"); |
| } |
| } else { |
| @@ -371,14 +370,14 @@ class DartFormatter { |
| // The order of formatters matters as formatters earlier in the list take |
| // precedence. |
| _formatters = [ |
| + new ClassFormatter(), |
| new NamedConstructorFormatter(), |
| - new FunctionFormatter(), |
| new MapFormatter(), |
| new IterableFormatter(), |
| - new MapEntryFormatter(), |
| new IterableSpanFormatter(), |
| + new MapEntryFormatter(), |
| new StackTraceFormatter(), |
| - new ClassMetadataFormatter(), |
| + new FunctionFormatter(), |
| new HeritageClauseFormatter(), |
| new LibraryModuleFormatter(), |
| new LibraryFormatter(), |
| @@ -386,7 +385,7 @@ class DartFormatter { |
| ]; |
| } |
| - String preview(object) { |
| + String preview(object, {config: JsonMLConfig.none}) { |
| try { |
| if (object == null || |
| object is num || |
| @@ -394,7 +393,8 @@ class DartFormatter { |
| isNativeJavaScriptObject(object)) { |
| return object.toString(); |
| } |
| - |
| + if (config == JsonMLConfig.renderAsClass) |
| + return new ClassFormatter().preview(object); |
| for (var formatter in _formatters) { |
| if (formatter.accept(object)) return formatter.preview(object); |
| } |
| @@ -407,9 +407,11 @@ class DartFormatter { |
| return null; |
| } |
| - bool hasChildren(object) { |
| + bool hasChildren(object, {config: JsonMLConfig.none}) { |
| if (object == null) return false; |
| try { |
| + if (config == JsonMLConfig.renderAsClass) |
|
Jacob
2016/08/02 01:45:12
instead of special casing ClassFormatter here, pas
bmilligan
2016/08/02 16:28:39
Done.
|
| + return new ClassFormatter().hasChildren(object); |
| for (var formatter in _formatters) { |
| if (formatter.accept(object)) return formatter.hasChildren(object); |
| } |
| @@ -421,9 +423,11 @@ class DartFormatter { |
| return false; |
| } |
| - List<NameValuePair> children(object) { |
| + List<NameValuePair> children(object, {config: JsonMLConfig.none}) { |
| try { |
| if (object != null) { |
| + if (config == JsonMLConfig.renderAsClass) |
| + return new ClassFormatter().children(object); |
| for (var formatter in _formatters) { |
| if (formatter.accept(object)) return formatter.children(object); |
| } |
| @@ -504,15 +508,10 @@ class ObjectFormatter extends Formatter { |
| return properties.toList(); |
| } |
| - |
| - addMetadataChildren(object, Set<NameValuePair> ret) { |
| - var child = new ClassMetadata(object); |
| - ret.add(new NameValuePair(name: child.typeName, value: child)); |
| - } |
| } |
| /// Formatter for module Dart Library objects. |
| -class LibraryModuleFormatter extends ObjectFormatter { |
| +class LibraryModuleFormatter implements Formatter { |
| String libraryName; |
| accept(object) { |
| @@ -548,8 +547,7 @@ class LibraryModuleFormatter extends ObjectFormatter { |
| } |
| } |
| -/// Formatter for Dart Library objects. |
| -class LibraryFormatter extends ObjectFormatter { |
| +class LibraryFormatter implements Formatter { |
| var genericParameters = new HashMap<String, String>(); |
| accept(object) => object is Library; |
| @@ -599,9 +597,9 @@ class LibraryFormatter extends ObjectFormatter { |
| var parameterName = '$name\$'; |
| if (genericParameters.keys.contains(parameterName)) { |
| typeName = '$typeName<${genericParameters[parameterName]}>'; |
| + JSNative.setProperty(child, 'genericTypeName', typeName); |
| } |
| - return new NameValuePair( |
| - name: typeName, value: new ClassMetadata(child, name: typeName)); |
| + return new NameValuePair(name: typeName, value: child); |
| } |
| } |
| @@ -609,7 +607,7 @@ class LibraryFormatter extends ObjectFormatter { |
| /// Dart functions happen to be regular JavaScript Function objects but |
| /// we can distinguish them based on whether they have been tagged with |
| /// runtime type information. |
| -class FunctionFormatter extends Formatter { |
| +class FunctionFormatter implements Formatter { |
| accept(object) { |
| if (_typeof(object) != 'function') return false; |
| return dart.getReifiedType(object) != null; |
| @@ -631,7 +629,7 @@ class FunctionFormatter extends Formatter { |
| } |
| /// Formatter for Dart Map objects. |
| -class MapFormatter extends ObjectFormatter { |
| +class MapFormatter implements Formatter { |
| accept(object) => object is Map; |
| bool hasChildren(object) => true; |
| @@ -658,7 +656,7 @@ class MapFormatter extends ObjectFormatter { |
| } |
| /// Formatter for Dart Iterable objects including List and Set. |
| -class IterableFormatter extends ObjectFormatter { |
| +class IterableFormatter implements Formatter { |
| bool accept(object) => object is Iterable; |
| String preview(object) { |
| @@ -687,86 +685,6 @@ class IterableFormatter extends ObjectFormatter { |
| } |
| } |
| -// This class does double duting displaying metadata for |
| -class ClassMetadataFormatter implements Formatter { |
| - accept(object) => object is ClassMetadata; |
| - |
| - Object _getType(object) { |
| - if (object is Type) return object; |
| - return dart.getReifiedType(object); |
| - } |
| - |
| - String preview(object) { |
| - ClassMetadata entry = object; |
| - var type = |
| - entry.object is Type ? entry.object : dart.getReifiedType(entry.object); |
| - var implements = dart.getImplements(type); |
| - if (implements != null) { |
| - var typeNames = implements().map(getTypeName); |
| - return '${entry.typeName} implements ${typeNames.join(", ")}'; |
| - } else { |
| - return entry.typeName; |
| - } |
| - } |
| - |
| - bool hasChildren(object) => true; |
| - |
| - List<NameValuePair> children(object) { |
| - ClassMetadata entry = object; |
| - var classObject = entry.object; |
| - // TODO(jacobr): add other entries describing the class such as |
| - // links to the superclass, mixins, implemented interfaces, and methods. |
| - var type = _getType(classObject); |
| - var children = <NameValuePair>[]; |
| - |
| - var mixins = dart.getMixins(type); |
| - if (mixins != null && mixins.isNotEmpty) { |
| - children.add(new NameValuePair( |
| - name: '[[Mixins]]', value: new HeritageClause('mixins', mixins))); |
| - } |
| - |
| - var hiddenProperties = ['length', 'name', 'prototype']; |
| - // Addition of NameValuePairs for static variables and named constructors. |
| - for (var name in getOwnPropertyNames(classObject)) { |
| - // TODO(bmilligan): Perform more principled checks to filter out spurious |
| - // members. |
| - if (hiddenProperties.contains(name)) continue; |
| - var value = safeGetProperty(classObject, name); |
| - if (value != null && dart.getIsNamedConstructor(value) != null) { |
| - value = new NamedConstructor(value); |
| - name = '${entry.typeName}.$name'; |
| - } |
| - children.add(new NameValuePair(name: name, value: value)); |
| - } |
| - |
| - // TODO(bmilligan): Replace the hard coding of $identityHash. |
| - var hiddenPrototypeProperties = ['constructor', 'new', r'$identityHash']; |
| - // Addition of class methods. |
| - var prototype = JS('var', '#["prototype"]', classObject); |
| - if (prototype != null) { |
| - for (var name in getOwnPropertyNames(prototype)) { |
| - if (hiddenPrototypeProperties.contains(name)) continue; |
| - // Simulate dart.bind by using dart.tag and tear off the function |
| - // so it will be recognized by the FunctionFormatter. |
| - var function = safeGetProperty(prototype, name); |
| - var constructor = safeGetProperty(prototype, 'constructor'); |
| - var sigObj = dart.getMethodSig(constructor); |
| - if (sigObj != null) { |
| - var value = safeGetProperty(sigObj, name); |
| - if (getTypeName(dart.getReifiedType(value)) != 'Null') { |
| - dart.tag(function, value); |
| - children.add(new NameValuePair(name: name, value: function)); |
| - } |
| - } |
| - } |
| - } |
| - // TODO(jacobr): provide a link to the base class or perhaps the entire |
| - // base class hierarchy as a flat list. |
| - // TODO(jacobr): add constructors, methods, extended class, and static |
| - return children; |
| - } |
| -} |
| - |
| class NamedConstructorFormatter implements Formatter { |
| accept(object) => object is NamedConstructor; |
| @@ -819,7 +737,8 @@ class HeritageClauseFormatter implements Formatter { |
| HeritageClause clause = object; |
| var children = <NameValuePair>[]; |
| for (var type in clause.types) { |
| - children.add(new NameValuePair(value: new ClassMetadata(type))); |
| + children.add( |
| + new NameValuePair(value: type, config: JsonMLConfig.renderAsClass)); |
| } |
| return children; |
| } |
| @@ -858,6 +777,78 @@ class StackTraceFormatter implements Formatter { |
| .toList(); |
| } |
| +class ClassFormatter implements Formatter { |
| + accept(object) => object is Type; |
|
Jacob
2016/08/02 01:45:11
change this accept method to take the JSONMLConfig
bmilligan
2016/08/02 16:28:39
Done.
|
| + |
| + String preview(object) { |
| + // TODO(bmilligan): Tag classes with generic types with a Symbol at their |
|
Jacob
2016/08/02 01:45:12
this comment is obsolete
bmilligan
2016/08/02 16:28:39
The emphasis on this comment is on the "generic ty
Jacob
2016/08/02 16:39:44
Acknowledged.
|
| + // creation so they can be recognized by the ClassFormatter. |
| + var typeName = safeGetProperty(object, 'genericTypeName'); |
| + if (typeName != null) return typeName; |
| + var type = _getType(object); |
| + var implements = dart.getImplements(type); |
| + typeName = getTypeName(type); |
| + if (implements != null) { |
| + var typeNames = implements().map(getTypeName); |
| + return '${typeName} implements ${typeNames.join(", ")}'; |
| + } else { |
| + return typeName; |
| + } |
| + } |
| + |
| + bool hasChildren(object) => true; |
| + |
| + List<NameValuePair> children(object) { |
| + // TODO(jacobr): add other entries describing the class such as |
| + // links to the superclass, mixins, implemented interfaces, and methods. |
| + var type = _getType(object); |
| + var children = <NameValuePair>[]; |
| + var typeName = getTypeName(_getType(object)); |
| + var mixins = dart.getMixins(type); |
| + if (mixins != null && mixins.isNotEmpty) { |
| + children.add(new NameValuePair( |
| + name: '[[Mixins]]', value: new HeritageClause('mixins', mixins))); |
| + } |
| + |
| + var hiddenProperties = ['length', 'name', 'prototype', 'genericTypeName']; |
| + // Addition of NameValuePairs for static variables and named constructors. |
| + for (var name in getOwnPropertyNames(object)) { |
| + // TODO(bmilligan): Perform more principled checks to filter out spurious |
| + // members. |
| + if (hiddenProperties.contains(name)) continue; |
| + var value = safeGetProperty(object, name); |
| + if (value != null && dart.getIsNamedConstructor(value) != null) { |
| + value = new NamedConstructor(value); |
| + name = '${typeName}.$name'; |
| + } |
| + children.add(new NameValuePair(name: name, value: value)); |
| + } |
| + |
| + // TODO(bmilligan): Replace the hard coding of $identityHash. |
| + var hiddenPrototypeProperties = ['constructor', 'new', r'$identityHash']; |
| + // Addition of class methods. |
| + var prototype = JS('var', '#["prototype"]', object); |
| + if (prototype != null) { |
| + for (var name in getOwnPropertyNames(prototype)) { |
| + if (hiddenPrototypeProperties.contains(name)) continue; |
| + // Simulate dart.bind by using dart.tag and tear off the function |
| + // so it will be recognized by the FunctionFormatter. |
| + var function = safeGetProperty(prototype, name); |
| + var constructor = safeGetProperty(prototype, 'constructor'); |
| + var sigObj = dart.getMethodSig(constructor); |
| + if (sigObj != null) { |
| + var value = safeGetProperty(sigObj, name); |
| + if (getTypeName(dart.getReifiedType(value)) != 'Null') { |
| + dart.tag(function, value); |
| + children.add(new NameValuePair(name: name, value: function)); |
| + } |
| + } |
| + } |
| + } |
| + return children; |
| + } |
| +} |
| + |
| /// This entry point is automatically invoked by the code generated by |
| /// Dart Dev Compiler |
| registerDevtoolsFormatter() { |