Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(73)

Unified Diff: tool/input_sdk/private/debugger.dart

Issue 2164763005: Library custom formatters (Closed) Base URL: https://github.com/dart-lang/dev_compiler.git@master
Patch Set: Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: tool/input_sdk/private/debugger.dart
diff --git a/tool/input_sdk/private/debugger.dart b/tool/input_sdk/private/debugger.dart
index 4c29b9e1bd8bd7ec86c03646c9243abfe96dd8e4..4072a5a0268f3294ccf05e9f6893f99aa5b4e047 100644
--- a/tool/input_sdk/private/debugger.dart
+++ b/tool/input_sdk/private/debugger.dart
@@ -126,17 +126,69 @@ class MapEntry {
}
class IterableSpan {
- IterableSpan({this.start, this.end, this.iterable});
+ IterableSpan(this.start, this.end, this.iterable);
final int start;
final int end;
final Iterable iterable;
+ int get length => end - start;
+
+ /// Using length - .5, a list of length 10000 results in a
+ /// maxPowerOfSubsetSize of 1, so the list will be broken up into 100,
+ /// 100-length subsets. A list of length 10001 results in a
+ /// maxPowerOfSubsetSize of 2, so the list will be broken up into 1
+ /// 10000-length subset and 1 1-length subset.
+ int get maxPowerOfSubsetSize =>
+ (log(length - .5) / log(_maxSpanLength)).truncate();
+ int get subsetSize => pow(_maxSpanLength, maxPowerOfSubsetSize);
+
+ Map<int, dynamic> asMap() =>
+ iterable.skip(start).take(length).toList().asMap();
Jacob 2016/07/21 02:10:31 nice!
bmilligan 2016/07/22 18:25:18 Acknowledged.
+
+ List<NameValuePair> children() {
+ var ret = <NameValuePair>[];
+ if (length <= _maxSpanLength) {
+ asMap().forEach((i, element) {
+ ret.add(
+ new NameValuePair(name: (i + start).toString(), value: element));
+ });
+ } else {
+ for (var i = start; i < end; i += subsetSize) {
+ var subSpan = new IterableSpan(i, min(end, subsetSize + i), iterable);
+ if (subSpan.length == 1) {
+ ret.add(new NameValuePair(
+ name: i.toString(), value: iterable.elementAt(i)));
+ } else {
+ ret.add(new NameValuePair(
+ name: '[${i}...${subSpan.end - 1}]',
+ value: subSpan,
+ hideName: true));
+ }
+ }
+ }
+ return ret;
+ }
+}
+
+class Library {
Jacob 2016/07/21 02:10:32 do you need to wrap the libraries? I would expect
bmilligan 2016/07/22 18:25:18 The symbol for the libraries is on the library mod
Jacob 2016/07/22 19:17:50 Acknowledged.
+ Library(this.name, this.object);
+
+ final String name;
+ final Object object;
+}
+
+class NamedConstructor {
+ NamedConstructor(this.object);
+
+ final Object object;
}
class ClassMetadata {
ClassMetadata(this.object);
final Object object;
+ String get name =>
+ getTypeName(object is Type ? object : dart.getReifiedType(object));
}
class HeritageClause {
@@ -218,6 +270,8 @@ class JsonMLFormatter {
// DartFormatter.
DartFormatter _simpleFormatter;
+ bool customFormattersOn = false;
+
JsonMLFormatter(this._simpleFormatter);
void setMaxSpanLengthForTestingOnly(int spanLength) {
@@ -225,6 +279,7 @@ class JsonMLFormatter {
}
header(object, config) {
+ customFormattersOn = true;
if (config == JsonMLConfig.skipDart || isNativeJavaScriptObject(object)) {
return null;
}
@@ -293,9 +348,10 @@ class DartFormatter {
List<Formatter> _formatters;
DartFormatter() {
- // The order of formatters matters as formatters later in the list take
- // precidence.
+ // The order of formatters matters as formatters earlier in the list take
+ // precedence.
Jacob 2016/07/21 02:10:31 good catch :)
bmilligan 2016/07/22 18:25:17 Acknowledged.
_formatters = [
+ new NamedConstructorFormatter(),
new FunctionFormatter(),
new MapFormatter(),
new IterableFormatter(),
@@ -303,6 +359,8 @@ class DartFormatter {
new IterableSpanFormatter(),
new ClassMetadataFormatter(),
new HeritageClauseFormatter(),
+ new ModuleLibraryFormatter(),
+ new LibraryFormatter(),
new ObjectFormatter(),
];
}
@@ -374,16 +432,8 @@ class ObjectFormatter extends Formatter {
// Set of property names used to avoid duplicates.
addMetadataChildren(object, properties);
- /// Helper to add members walking up the prototype chain being careful
- /// to avoid properties that are Dart methods.
- var protoChain = <Object>[];
var current = object;
- while (current != null &&
- !isNativeJavaScriptObject(current) &&
- JS("bool", "# !== Object.prototype", current)) {
- protoChain.add(current);
- current = JSNative.getProperty(current, '__proto__');
- }
+ var protoChain = getProtoChain(current);
// We walk the prototype chain for symbol properties because they take
// priority and are accessed instead of Dart properties according to Dart
@@ -405,12 +455,7 @@ class ObjectFormatter extends Formatter {
// start with an _
continue;
}
- var value;
- try {
- value = JSNative.getProperty(object, symbol);
- } catch (e) {
- value = '<Exception thrown> $e';
- }
+ var value = getPropertyValue(object, symbol);
properties.add(new NameValuePair(name: dartName, value: value));
}
}
@@ -424,12 +469,7 @@ class ObjectFormatter extends Formatter {
if (hasMethod(object, name)) {
continue;
}
- var value;
- try {
- value = JSNative.getProperty(object, name);
- } catch (e) {
- value = '<Exception thrown> $e';
- }
+ var value = getPropertyValue(object, name);
properties.add(new NameValuePair(name: name, value: value));
}
}
@@ -438,8 +478,100 @@ class ObjectFormatter extends Formatter {
}
addMetadataChildren(object, Set<NameValuePair> ret) {
- ret.add(
- new NameValuePair(name: '[[class]]', value: new ClassMetadata(object)));
Jacob 2016/07/21 02:10:31 btw the reason I have to create a ClassMetadata ob
bmilligan 2016/07/22 18:25:17 Acknowledged.
+ var value = new ClassMetadata(object);
+ ret.add(new NameValuePair(name: value.name, value: value));
+ }
+
+ Object getPropertyValue(Object object, String name) {
Jacob 2016/07/21 02:10:31 call this safeGetProperty and make it a top level
bmilligan 2016/07/22 18:25:17 Done.
+ var value;
+ try {
+ value = JSNative.getProperty(object, name);
+ } catch (e) {
+ value = '<Exception thrown> $e';
+ }
+ return value;
+ }
+
+ /// Helper to add members walking up the prototype chain being careful
+ /// to avoid properties that are Dart methods.
+ List<Object> getProtoChain(var current) {
+ var protoChain = <Object>[];
+ while (current != null &&
+ !isNativeJavaScriptObject(current) &&
+ JS("bool", "# !== Object.prototype", current)) {
+ protoChain.add(current);
+ current = JSNative.getProperty(current, '__proto__');
+ }
+ return protoChain;
+ }
+}
+
+/// Formatter for module Dart Library objects.
+class ModuleLibraryFormatter extends ObjectFormatter {
+ String libraryName;
+
+ accept(object) {
+ var current = object;
+ var protoChain = getProtoChain(current);
+ for (current in protoChain) {
+ for (var symbol in getOwnPropertySymbols(current)) {
+ if (symbolName(symbol) == 'dartLibraryName') {
Jacob 2016/07/21 02:10:31 you will be able to match the actual symbol instea
bmilligan 2016/07/22 18:25:18 Done.
+ libraryName = JSNative.getProperty(current, symbol);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ bool hasChildren(object) => true;
+
+ String preview(object) {
+ var libraryNameArray = libraryName.split('/');
Jacob 2016/07/21 02:10:31 I think libraryNameParts would be cleaner
bmilligan 2016/07/22 18:25:17 Done.
+ if (libraryNameArray.length > 1) {
Jacob 2016/07/21 02:10:31 comment why you are stripping the last entry
bmilligan 2016/07/22 18:25:18 Done.
+ libraryNameArray[libraryNameArray.length - 1] = '';
Jacob 2016/07/21 02:10:31 libraryNameParts.last = ''
bmilligan 2016/07/22 18:25:18 '.last' cannot be used as a setter, which is why I
Jacob 2016/07/22 19:17:50 Acknowledged.
+ }
+ return 'Library Module: ${libraryNameArray.join('/')}';
+ }
+
+ List<NameValuePair> children(object) {
+ var properties = new LinkedHashSet<NameValuePair>();
+ for (var name in getOwnPropertyNames(object)) {
+ var value = JSNative.getProperty(object, name);
+ name = name.replaceAll('__', '/') + '.dart';
Jacob 2016/07/21 02:10:31 prefer string interoplation. So name = "${name.rep
bmilligan 2016/07/22 18:25:18 Done.
+ properties.add(new NameValuePair(
+ name: name, value: new Library(name, value), hideName: true));
+ }
+ return properties.toList();
+ }
+}
+
+/// Formatter for Dart Library objects.
+class LibraryFormatter extends ObjectFormatter {
+ accept(object) => object is Library;
+
+ bool hasChildren(object) => true;
+
+ String preview(object) => object.name;
+
+ List<NameValuePair> children(object) {
+ var properties = new LinkedHashSet<NameValuePair>();
+ var entry = object.object;
+ for (var name in getOwnPropertyNames(entry)) {
+ var value = getPropertyValue(entry, name);
+ // TODO(bmilligan): Make a note on the corresponding class object that it
+ // has a generic type.
+ if (JSNative.getProperty(value, 'name') == 'makeGenericType') {
Jacob 2016/07/21 16:19:00 this is fragile. is there not an existing symbol t
Jennifer Messerly 2016/07/21 16:20:25 yeah there should be, I know we track type args on
bmilligan 2016/07/22 18:25:17 Done.
bmilligan 2016/07/22 18:25:17 Done.
+ continue;
+ } else if (value is Type) {
+ var classMetadata = new ClassMetadata(value);
+ properties.add(
+ new NameValuePair(name: classMetadata.name, value: classMetadata));
+ } else {
+ properties.add(new NameValuePair(name: name, value: value));
+ }
+ }
+ return properties.toList();
}
}
@@ -517,8 +649,7 @@ class IterableFormatter extends ObjectFormatter {
// TODO(jacobr): handle large Iterables better.
// TODO(jacobr): consider only using numeric indices
var ret = new LinkedHashSet<NameValuePair>();
- ret.addAll(childrenHelper(
- new IterableSpan(start: 0, end: object.length, iterable: object)));
+ ret.addAll((new IterableSpan(0, object.length, object)).children());
Jacob 2016/07/21 16:18:59 remove unneeded extra set of parens.
bmilligan 2016/07/22 18:25:18 Done.
// TODO(jacobr): provide a link to show regular class properties here.
// required for subclasses of iterable, etc.
addMetadataChildren(object, ret);
@@ -527,7 +658,7 @@ class IterableFormatter extends ObjectFormatter {
}
// This class does double duting displaying metadata for
-class ClassMetadataFormatter implements Formatter {
+class ClassMetadataFormatter extends ObjectFormatter {
Jacob 2016/07/21 16:18:59 why is this now an extends instead of implements r
bmilligan 2016/07/22 18:25:18 There was a function I had in ObjectFormatter that
accept(object) => object is ClassMetadata;
_getType(object) {
Jacob 2016/07/21 16:18:58 is the return type of this method Type?
bmilligan 2016/07/22 18:25:18 rtti.dart says getReifiedType "returns the runtime
Jacob 2016/07/22 19:17:50 Acknowledged.
@@ -537,47 +668,96 @@ class ClassMetadataFormatter implements Formatter {
String preview(object) {
ClassMetadata entry = object;
- return getTypeName(_getType(entry.object));
+ var type =
+ entry.object is Type ? entry.object : dart.getReifiedType(entry.object);
+ var implements = dart.getImplements(type);
+ var ret = getTypeName(type);
+ if (implements != null) {
+ var typeNames = implements().map((type) => getTypeName(type));
+ return ret + ' implements ${typeNames.join(", ")}';
+ } else {
+ return ret;
+ }
}
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(entry.object);
+ var type = _getType(classObject);
var ret = <NameValuePair>[];
- var implements = dart.getImplements(type);
- if (implements != null) {
- ret.add(new NameValuePair(
- name: '[[Implements]]',
- value: new HeritageClause('implements', implements())));
- }
+
var mixins = dart.getMixins(type);
if (mixins != null && mixins.isNotEmpty) {
ret.add(new NameValuePair(
name: '[[Mixins]]', value: new HeritageClause('mixins', mixins)));
}
- ret.add(new NameValuePair(
- name: '[[JavaScript View]]',
- value: entry.object,
- config: JsonMLConfig.skipDart));
- // TODO(jacobr): provide a link to the base class or perhaps the entire
- // base class hierarchy as a flat list.
+ // Addition of NameValuePairs for static variables and named constructors.
+ for (var name in getOwnPropertyNames(classObject)) {
+ if (name == 'length' || name == 'name' || name == 'prototype') continue;
Jacob 2016/07/21 16:19:00 why are we removing length and name? I would add a
bmilligan 2016/07/22 18:25:17 Length is always = 0, and name is redundant as it'
+ var value = getPropertyValue(classObject, name);
+ for (var symbol in getOwnPropertySymbols(value)) {
+ if (symbolName(symbol) == 'isNamedConstructor') {
+ value = new NamedConstructor(value);
+ name = entry.name + '.' + name;
Jacob 2016/07/21 16:18:58 I think it is cleaner to write name = '${entry.nam
bmilligan 2016/07/22 18:25:18 Done.
+ }
+ }
+ ret.add(new NameValuePair(name: name, value: value));
+ }
- if (entry.object is! Type) {
- ret.add(new NameValuePair(
- name: '[[JavaScript Constructor]]',
- value: JSNative.getProperty(entry.object, 'constructor'),
- config: JsonMLConfig.skipDart));
- // TODO(jacobr): add constructors, methods, extended class, and static
+ // Addition of class methods.
+ var prototype = JS('var', '#["prototype"]', classObject);
+ if (prototype != null) {
+ for (var name in getOwnPropertyNames(prototype)) {
+ if (name == 'constructor' ||
+ name == 'new' ||
+ name == r'$identityHash') {
Jacob 2016/07/21 16:18:59 $identityHash is a little scary. Add a TODO to not
bmilligan 2016/07/22 18:25:18 Done. Is it because the name is fragile?
Jacob 2016/07/22 19:17:50 yeah. someone might well change it to $identity or
bmilligan 2016/07/22 20:10:24 Acknowledged.
+ continue;
+ }
+ // Simulate dart.bind by using dart.tag and tear off the function
+ // so it will be recognized by the FunctionFormatter.
+ var function = getPropertyValue(prototype, name);
+ var constructor = getPropertyValue(prototype, 'constructor');
+ for (var symbol in getOwnPropertySymbols(constructor)) {
+ if (symbolName(symbol) == 'sig') {
Jacob 2016/07/21 16:18:59 should not be using symbolName. You should be able
bmilligan 2016/07/22 18:25:18 Done.
+ var sigObj = getPropertyValue(constructor, symbol);
+ var value = getPropertyValue(sigObj, name);
+ if (getTypeName(dart.getReifiedType(value)) != 'Null') {
+ dart.tag(function, value);
+ ret.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 ret;
}
}
+class NamedConstructorFormatter implements Formatter {
+ accept(object) => object is NamedConstructor;
+
+ // TODO(bmilligan): Display the signature of the named constructor as the
+ // preview.
+ String preview(object) => 'Named Constructor';
bmilligan 2016/07/21 01:59:27 I'm working on getting this to display the signatu
Jacob 2016/07/21 16:18:59 Sounds good.
bmilligan 2016/07/22 18:25:18 Acknowledged.
+
+ bool hasChildren(object) => true;
+
+ List<NameValuePair> children(object) => <NameValuePair>[
+ new NameValuePair(
+ name: 'JavaScript Function',
+ value: object,
+ config: JsonMLConfig.skipDart)
+ ];
+}
+
/// Formatter for synthetic MapEntry objects used to display contents of a Map
/// cleanly.
class MapEntryFormatter implements Formatter {
@@ -625,50 +805,12 @@ class IterableSpanFormatter implements Formatter {
accept(object) => object is IterableSpan;
String preview(object) {
- IterableSpan entry = object;
return '[${object.start}...${object.end-1}]';
}
bool hasChildren(object) => true;
- List<NameValuePair> children(object) => childrenHelper(object);
-}
-
-List<NameValuePair> childrenHelper(IterableSpan span) {
- var length = span.end - span.start;
- var ret = new List<NameValuePair>();
- if (length <= _maxSpanLength) {
- for (var i = span.start; i < span.end; i++) {
- /// TODO(bmilligan): Stop using elementAt if it becomes a performance
- /// bottleneck in the future.
- ret.add(new NameValuePair(
- name: i.toString(), value: span.iterable.elementAt(i)));
- }
- } else {
- /// Using length - .5, a list of length 10000 results in a
- /// maxPowerOfSubsetSize of 1, so the list will be broken up into 100,
- /// 100-length subsets. A list of length 10001 results in a
- /// maxPowerOfSubsetSize of 2, so the list will be broken up into 1
- /// 10000-length subset and 1 1-length subset.
- var maxPowerOfSubsetSize =
- (log(length - .5) / log(_maxSpanLength)).truncate();
- var subsetSize = pow(_maxSpanLength, maxPowerOfSubsetSize);
- for (var i = span.start; i < span.end; i += subsetSize) {
- var endIndex = min(span.end, subsetSize + i);
- if (endIndex - i == 1)
- ret.add(new NameValuePair(
- name: i.toString(), value: span.iterable.elementAt(i)));
- else {
- var entryWrapper =
- new IterableSpan(start: i, end: endIndex, iterable: span.iterable);
- ret.add(new NameValuePair(
- name: '[${i}...${endIndex - 1}]',
- value: entryWrapper,
- hideName: true));
- }
- }
- }
- return ret;
+ List<NameValuePair> children(object) => object.children();
}
/// This entry point is automatically invoked by the code generated by

Powered by Google App Engine
This is Rietveld 408576698