Chromium Code Reviews| Index: sdk/lib/js/dart2js/js_dart2js.dart |
| diff --git a/sdk/lib/js/dart2js/js_dart2js.dart b/sdk/lib/js/dart2js/js_dart2js.dart |
| index 7f806b73f3744794eeca4b725e61093b6cf12008..25d46e66ae74951b1e244429118d0f275b5e26dd 100644 |
| --- a/sdk/lib/js/dart2js/js_dart2js.dart |
| +++ b/sdk/lib/js/dart2js/js_dart2js.dart |
| @@ -4,6 +4,7 @@ |
| library dart.js; |
| +import 'dart:collection' show ListMixin, Maps; |
| import 'dart:_foreign_helper' show JS; |
| import 'dart:_js_helper' show convertDartClosureToJS; |
| @@ -101,7 +102,7 @@ return ret; |
| })()''', constr, constr, args)); |
| } |
| - factory JsObject._json(data) => new JsObject._fromJs(_convertDataTree(data)); |
| + factory JsObject._json(data) => _convertToDart(_convertDataTree(data)); |
| static _convertDataTree(data) { |
| if (data is Map) { |
| @@ -154,6 +155,8 @@ return ret; |
| _convertToDart(JS('=Object', '#[#].apply(#, #)', _convertToJS(this), name, |
| _convertToJS(this), |
| args == null ? null : args.map(_convertToJS).toList())); |
| + |
| + Map<String, dynamic> asJsMap() => new _JsObjectAsMap(this); |
| } |
| class JsFunction extends JsObject implements Serializable<JsFunction> { |
| @@ -164,6 +167,90 @@ class JsFunction extends JsObject implements Serializable<JsFunction> { |
| args == null ? null : args.map(_convertToJS).toList())); |
| } |
| +/// A [JsObject] subtype for JavaScript arrays. |
| +class JsArray extends JsObject with ListMixin { |
| + JsArray._fromJs(jsObject) : super._fromJs(jsObject); |
| + |
| + // Iterable |
| + /*@override*/ int get length => super['length']; |
| + |
| + // Collection |
| + /*@override*/ void add(value) { callMethod('push', [value]); } |
| + |
| + // List |
| + /*@override*/ operator [](index) { |
| + if (index is int && (index < 0 || index >= this.length)) { |
|
vsm
2013/08/20 15:44:13
Should JsArray throw on non-int indices?
alexandre.ardhuin
2013/08/20 20:58:55
In Js an array is an object. So it's possible to s
|
| + throw new RangeError.value(index); |
| + } |
| + return super[index]; |
| + } |
| + /*@override*/ void operator []=(index, value) { |
| + if (index is int && (index < 0 || index >= this.length)) { |
| + throw new RangeError.value(index); |
| + } |
| + super[index] = value; |
| + } |
| + /*@override*/ void set length(int length) { super['length'] = length; } |
| + /*@override*/ void sort([int compare(a, b)]) { |
| + final sortedList = toList()..sort(compare); |
| + setRange(0, sortedList.length, sortedList); |
| + } |
| + /*@override*/ void insert(int index, element) { |
| + callMethod('splice', [index, 0, element]); |
| + } |
| + /*@override*/ removeAt(int index) { |
| + if (index < 0 || index >= this.length) throw new RangeError.value(index); |
| + return callMethod('splice', [index, 1])[0]; |
| + } |
| + /*@override*/ removeLast() => callMethod('pop'); |
| + /*@override*/ void setRange(int start, int length, List from, |
| + [int startFrom = 0]) { |
| + final args = [start, length]; |
| + for(int i = startFrom; i < startFrom + length; i++) { |
| + args.add(from[i]); |
| + } |
| + callMethod('splice', args); |
| + } |
| + /*@override*/ void removeRange(int start, int end) { |
| + callMethod('splice', [start, end - start]); |
| + } |
| +} |
| + |
| +class _JsObjectAsMap implements Map<String, dynamic> { |
| + JsObject _jsObject; |
|
vsm
2013/08/20 15:44:13
It seems odd that Array extends JsObject while Map
alexandre.ardhuin
2013/08/20 20:58:55
Ideally I would have made JsObject implementing Ma
|
| + |
| + _JsObjectAsMap(this._jsObject); |
| + |
| + /*@override*/ operator [](String key) => _jsObject[key]; |
| + /*@override*/ void operator []=(String key, value) { |
| + _jsObject[key] = value; |
| + } |
| + /*@override*/ remove(String key) { |
| + final value = this[key]; |
| + _jsObject.deleteProperty(key); |
| + return value; |
| + } |
| + /*@override*/ Iterable<String> get keys => |
| + context['Object'].callMethod('keys', [_jsObject]); |
| + |
| + // use Maps to implement functions |
| + /*@override*/ bool containsValue(value) => Maps.containsValue(this, value); |
| + /*@override*/ bool containsKey(String key) => Maps.containsKey(this, key); |
| + /*@override*/ putIfAbsent(String key, ifAbsent()) => |
| + Maps.putIfAbsent(this, key, ifAbsent); |
| + /*@override*/ void addAll(Map<String, dynamic> other) { |
| + if (other != null) { |
| + other.forEach((k,v) => this[k] = v); |
| + } |
| + } |
| + /*@override*/ void clear() => Maps.clear(this); |
| + /*@override*/ void forEach(void f(String key, value)) => Maps.forEach(this, f); |
| + /*@override*/ Iterable get values => Maps.getValues(this); |
| + /*@override*/ int get length => Maps.length(this); |
| + /*@override*/ bool get isEmpty => Maps.isEmpty(this); |
| + /*@override*/ bool get isNotEmpty => Maps.isNotEmpty(this); |
| +} |
| + |
| abstract class Serializable<T> { |
| T toJs(); |
| } |
| @@ -179,6 +266,10 @@ dynamic _convertToJS(dynamic o) { |
| return _convertToJS(o.toJs()); |
| } else if (o is Function) { |
| return _convertToJS(new Callback(o)); |
| + } else if (o is Map) { |
| + return _convertToJS(jsify(o)); |
| + } else if (o is Iterable) { |
| + return _convertToJS(jsify(o)); |
| } else { |
| return JS('=Object', 'new DartProxy(#)', o); |
| } |
| @@ -193,6 +284,8 @@ dynamic _convertToDart(dynamic o) { |
| return o; |
| } else if (JS('bool', '# instanceof Function', o)) { |
| return new JsFunction._fromJs(JS('=Object', '#', o)); |
| + } else if (JS('bool', '# instanceof Array', o)) { |
| + return new JsArray._fromJs(JS('=Object', '#', o)); |
|
vsm
2013/08/20 15:44:13
After talking to sra, I think the right to put her
alexandre.ardhuin
2013/08/20 20:58:55
Done
|
| } else if (JS('bool', '# instanceof DartProxy', o)) { |
| return JS('var', '#.o', o); |
| } else { |