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

Side by Side Diff: sdk/lib/js/dartium/js_dartium.dart

Issue 2150313003: Add JSNative utility class with static methods methods to efficiently manipulate typed JSInterop ob… (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: ptal 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 unified diff | Download patch
« no previous file with comments | « sdk/lib/js/dart2js/js_dart2js.dart ('k') | sdk/lib/js_util/dart2js/js_util_dart2js.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /** 5 /**
6 * Support for interoperating with JavaScript. 6 * Support for interoperating with JavaScript.
7 * 7 *
8 * This library provides access to JavaScript objects from Dart, allowing 8 * This library provides access to JavaScript objects from Dart, allowing
9 * Dart code to get and set properties, and call methods of JavaScript objects 9 * Dart code to get and set properties, and call methods of JavaScript objects
10 * and invoke JavaScript functions. The library takes care of converting 10 * and invoke JavaScript functions. The library takes care of converting
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 } 131 }
132 132
133 final _allowedMethods = new Map<Symbol, _DeclarationSet>(); 133 final _allowedMethods = new Map<Symbol, _DeclarationSet>();
134 final _allowedGetters = new Map<Symbol, _DeclarationSet>(); 134 final _allowedGetters = new Map<Symbol, _DeclarationSet>();
135 final _allowedSetters = new Map<Symbol, _DeclarationSet>(); 135 final _allowedSetters = new Map<Symbol, _DeclarationSet>();
136 136
137 final _jsInterfaceTypes = new Set<mirrors.ClassMirror>(); 137 final _jsInterfaceTypes = new Set<mirrors.ClassMirror>();
138 @Deprecated("Internal Use Only") 138 @Deprecated("Internal Use Only")
139 Iterable<mirrors.ClassMirror> get jsInterfaceTypes => _jsInterfaceTypes; 139 Iterable<mirrors.ClassMirror> get jsInterfaceTypes => _jsInterfaceTypes;
140 140
141 class _StringLiteralEscape {
142 // Character code constants.
143 static const int BACKSPACE = 0x08;
144 static const int TAB = 0x09;
145 static const int NEWLINE = 0x0a;
146 static const int CARRIAGE_RETURN = 0x0d;
147 static const int FORM_FEED = 0x0c;
148 static const int QUOTE = 0x22;
149 static const int CHAR_$ = 0x24;
150 static const int CHAR_0 = 0x30;
151 static const int BACKSLASH = 0x5c;
152 static const int CHAR_b = 0x62;
153 static const int CHAR_f = 0x66;
154 static const int CHAR_n = 0x6e;
155 static const int CHAR_r = 0x72;
156 static const int CHAR_t = 0x74;
157 static const int CHAR_u = 0x75;
158
159 final StringSink _sink;
160
161 _StringLiteralEscape(this._sink);
162
163 void writeString(String string) {
164 _sink.write(string);
165 }
166
167 void writeStringSlice(String string, int start, int end) {
168 _sink.write(string.substring(start, end));
169 }
170
171 void writeCharCode(int charCode) {
172 _sink.writeCharCode(charCode);
173 }
174
175 /// ('0' + x) or ('a' + x - 10)
176 static int hexDigit(int x) => x < 10 ? 48 + x : 87 + x;
177
178 /// Write, and suitably escape, a string's content as a JSON string literal.
179 void writeStringContent(String s) {
180 // Identical to JSON string lieral escaping except that we also escape $.
sra1 2016/07/22 20:16:32 lieral?
Jacob 2016/07/25 16:31:58 Done.
181 int offset = 0;
182 final int length = s.length;
183 for (int i = 0; i < length; i++) {
184 int charCode = s.codeUnitAt(i);
185 if (charCode > BACKSLASH) continue;
186 if (charCode < 32) {
187 if (i > offset) writeStringSlice(s, offset, i);
188 offset = i + 1;
189 writeCharCode(BACKSLASH);
190 switch (charCode) {
191 case BACKSPACE:
192 writeCharCode(CHAR_b);
193 break;
194 case TAB:
195 writeCharCode(CHAR_t);
196 break;
197 case NEWLINE:
198 writeCharCode(CHAR_n);
199 break;
200 case FORM_FEED:
201 writeCharCode(CHAR_f);
202 break;
203 case CARRIAGE_RETURN:
204 writeCharCode(CHAR_r);
205 break;
206 default:
207 writeCharCode(CHAR_u);
208 writeCharCode(CHAR_0);
209 writeCharCode(CHAR_0);
210 writeCharCode(hexDigit((charCode >> 4) & 0xf));
211 writeCharCode(hexDigit(charCode & 0xf));
212 break;
213 }
214 } else if (charCode == QUOTE || charCode == BACKSLASH || charCode == CHAR_ $) {
sra1 2016/07/22 20:16:32 line length
Jacob 2016/07/25 16:31:58 done. ran dartfmt
215 if (i > offset) writeStringSlice(s, offset, i);
216 offset = i + 1;
217 writeCharCode(BACKSLASH);
218 writeCharCode(charCode);
219 }
220 }
221 if (offset == 0) {
222 writeString(s);
223 } else if (offset < length) {
224 writeStringSlice(s, offset, length);
225 }
226 }
227
228 /**
229 * Serialize a [num], [String], [bool], [Null], [List] or [Map] value.
230 *
231 * Returns true if the value is one of these types, and false if not.
232 * If a value is both a [List] and a [Map], it's serialized as a [List].
sra1 2016/07/22 20:16:32 This comment is wrong.
233 */
234 bool writeStringLiteral(String str) {
sra1 2016/07/22 20:16:32 Doesn't return anything.
Jacob 2016/07/25 16:31:58 Done.
235 writeString('"');
236 writeStringContent(str);
237 writeString('"');
238 }
239 }
240
241 String _escapeString(String str) {
242 StringBuffer output = new StringBuffer();
243 new _StringLiteralEscape(output)..writeStringLiteral(str);
244 return output.toString();
sra1 2016/07/22 20:16:32 Could you use the JSON codec rather than copy & pa
Jacob 2016/07/25 16:31:58 Can't easily because of $ JSON doesn't need to esc
245 }
246
141 /// A collection of methods where all methods have the same name. 247 /// A collection of methods where all methods have the same name.
142 /// This class is intended to optimize whether a specific invocation is 248 /// This class is intended to optimize whether a specific invocation is
143 /// appropritate for at least some of the methods in the collection. 249 /// appropritate for at least some of the methods in the collection.
144 class _DeclarationSet { 250 class _DeclarationSet {
145 _DeclarationSet() : _members = <mirrors.DeclarationMirror>[]; 251 _DeclarationSet() : _members = <mirrors.DeclarationMirror>[];
146 252
147 static bool _checkType(obj, mirrors.TypeMirror type) { 253 static bool _checkType(obj, mirrors.TypeMirror type) {
148 if (obj == null) return true; 254 if (obj == null) return true;
149 return mirrors.reflectType(obj.runtimeType).isSubtypeOf(type); 255 return mirrors.reflectType(obj.runtimeType).isSubtypeOf(type);
150 } 256 }
(...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 final _UNDEFINED_VAR = "_UNDEFINED_JS_CONST"; 468 final _UNDEFINED_VAR = "_UNDEFINED_JS_CONST";
363 469
364 String _accessJsPath(String path) => _accessJsPathHelper(path.split(".")); 470 String _accessJsPath(String path) => _accessJsPathHelper(path.split("."));
365 471
366 String _accessJsPathHelper(Iterable<String> parts) { 472 String _accessJsPathHelper(Iterable<String> parts) {
367 var sb = new StringBuffer(); 473 var sb = new StringBuffer();
368 sb 474 sb
369 ..write('${_JS_LIBRARY_PREFIX}.JsNative.getProperty(' * parts.length) 475 ..write('${_JS_LIBRARY_PREFIX}.JsNative.getProperty(' * parts.length)
370 ..write("${_JS_LIBRARY_PREFIX}.context"); 476 ..write("${_JS_LIBRARY_PREFIX}.context");
371 for (var p in parts) { 477 for (var p in parts) {
372 sb.write(", '$p')"); 478 sb.write(", ${_escapeString(p)})");
373 } 479 }
374 return sb.toString(); 480 return sb.toString();
375 } 481 }
376 482
377 // TODO(jacobr): remove these helpers and add JsNative.setPropertyDotted, 483 // TODO(jacobr): remove these helpers and add JsNative.setPropertyDotted,
378 // getPropertyDotted, and callMethodDotted helpers that would be simpler 484 // getPropertyDotted, and callMethodDotted helpers that would be simpler
379 // and more efficient. 485 // and more efficient.
380 String _accessJsPathSetter(String path) { 486 String _accessJsPathSetter(String path) {
381 var parts = path.split("."); 487 var parts = path.split(".");
382 return "${_JS_LIBRARY_PREFIX}.JsNative.setProperty(${_accessJsPathHelper(parts .getRange(0, parts.length - 1)) 488 return "${_JS_LIBRARY_PREFIX}.JsNative.setProperty(${_accessJsPathHelper(parts .getRange(0, parts.length - 1))
383 }, '${parts.last}', v)"; 489 }, ${_escapeString(parts.last)}, v)";
384 } 490 }
385 491
386 String _accessJsPathCallMethodHelper(String path) { 492 String _accessJsPathCallMethodHelper(String path) {
387 var parts = path.split("."); 493 var parts = path.split(".");
388 return "${_JS_LIBRARY_PREFIX}.JsNative.callMethod(${_accessJsPathHelper(parts. getRange(0, parts.length - 1)) 494 return "${_JS_LIBRARY_PREFIX}.JsNative.callMethod(${_accessJsPathHelper(parts. getRange(0, parts.length - 1))
389 }, '${parts.last}',"; 495 }, ${_escapeString(parts.last)},";
390 } 496 }
391 497
392 @Deprecated("Internal Use Only") 498 @Deprecated("Internal Use Only")
393 void addMemberHelper( 499 void addMemberHelper(
394 mirrors.MethodMirror declaration, String path, StringBuffer sb, 500 mirrors.MethodMirror declaration, String path, StringBuffer sb,
395 {bool isStatic: false, String memberName}) { 501 {bool isStatic: false, String memberName}) {
396 if (!declaration.isConstructor) { 502 if (!declaration.isConstructor) {
397 var jsName = _getJsMemberName(declaration); 503 var jsName = _getJsMemberName(declaration);
398 path = (path != null && path.isNotEmpty) ? "${path}.${jsName}" : jsName; 504 path = (path != null && path.isNotEmpty) ? "${path}.${jsName}" : jsName;
399 } 505 }
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
559 sbPatch.write(") {\n" 665 sbPatch.write(") {\n"
560 " var ret = ${_JS_LIBRARY_PREFIX}.JsNative.newObject();\n "); 666 " var ret = ${_JS_LIBRARY_PREFIX}.JsNative.newObject();\n ");
561 i = 0; 667 i = 0;
562 for (var p in declaration.parameters) { 668 for (var p in declaration.parameters) {
563 assert(p.isNamed); // TODO(jacobr): throw. 669 assert(p.isNamed); // TODO(jacobr): throw.
564 var name = args[i]; 670 var name = args[i];
565 var jsName = _stripReservedNamePrefix( 671 var jsName = _stripReservedNamePrefix(
566 mirrors.MirrorSystem.getName(p.simpleName)); 672 mirrors.MirrorSystem.getName(p.simpleName));
567 sbPatch.write(" if($name != ${_UNDEFINED_VAR}) {\n" 673 sbPatch.write(" if($name != ${_UNDEFINED_VAR}) {\n"
568 " ${_JS_LIBRARY_PREFIX}.safeForTypedInterop($name);\n " 674 " ${_JS_LIBRARY_PREFIX}.safeForTypedInterop($name);\n "
569 " ${_JS_LIBRARY_PREFIX}.JsNative.setProperty(ret, '$j sName', $name);\n" 675 " ${_JS_LIBRARY_PREFIX}.JsNative.setProperty(ret, ${_ escapeString(jsName)}, $name);\n"
570 " }\n"); 676 " }\n");
571 i++; 677 i++;
572 } 678 }
573 679
574 sbPatch.write( 680 sbPatch.write(
575 " return ret;" 681 " return ret;"
576 "}\n"); 682 "}\n");
577 } else if (declaration.isConstructor || 683 } else if (declaration.isConstructor ||
578 declaration.isFactoryConstructor) { 684 declaration.isFactoryConstructor) {
579 sbPatch.write(" "); 685 sbPatch.write(" ");
(...skipping 757 matching lines...) Expand 10 before | Expand all | Expand 10 after
1337 1443
1338 static toTypedObject(JsObject o) native "JSNative_toTypedObject"; 1444 static toTypedObject(JsObject o) native "JSNative_toTypedObject";
1339 1445
1340 /** 1446 /**
1341 * Same behavior as new JsFunction.withThis except that JavaScript "this" is n ot 1447 * Same behavior as new JsFunction.withThis except that JavaScript "this" is n ot
1342 * wrapped. 1448 * wrapped.
1343 */ 1449 */
1344 static JSFunction withThis(Function f) native "JsFunction_withThisNoWrap"; 1450 static JSFunction withThis(Function f) native "JsFunction_withThisNoWrap";
1345 } 1451 }
1346 1452
1347 /// Utility methods to efficiently manipulate typed JSInterop objects in cases
1348 /// where the name to call is not known at runtime. You should only use these
1349 /// methods when the same effect cannot be achieved with @JS annotations.
1350 /// These methods would be extension methods on JSObject if Dart supported
1351 /// extension methods.
1352 class JSNative {
1353 /**
1354 * WARNING: performance of this method is much worse than other methods
1355 * in JSNative. Only use this method as a last resort.
1356 *
1357 * Recursively converts a JSON-like collection of Dart objects to a
1358 * collection of JavaScript objects and returns a [JsObject] proxy to it.
1359 *
1360 * [object] must be a [Map] or [Iterable], the contents of which are also
1361 * converted. Maps and Iterables are copied to a new JavaScript object.
1362 * Primitives and other transferrable values are directly converted to their
1363 * JavaScript type, and all other objects are proxied.
1364 */
1365 static jsify(object) {
1366 if ((object is! Map) && (object is! Iterable)) {
1367 throw new ArgumentError("object must be a Map or Iterable");
1368 }
1369 return _jsify(object);
1370 }
1371
1372 static _jsify(object) native "JSObject_jsify";
1373 static JSObject newObject() native "JSObject_newObject";
1374
1375 static hasProperty(JSObject o, name) => o._hasProperty(name);
1376 static getProperty(JSObject o, name) => o._operator_getter(name);
1377 static setProperty(JSObject o, name, value) => o._operator_setter(name, value) ;
1378 static callMethod(JSObject o, String method, List args) => o._callMethod(metho d, args);
1379 static instanceof(JSObject o, Function type) => o._instanceof(type);
1380 static callConstructor(JSObject constructor, List args) native "JSNative_callC onstructor";
1381 }
1382
1383 /** 1453 /**
1384 * Proxies a JavaScript Function object. 1454 * Proxies a JavaScript Function object.
1385 */ 1455 */
1386 class JsFunction extends JsObject { 1456 class JsFunction extends JsObject {
1387 JsFunction.internal() : super.internal(); 1457 JsFunction.internal() : super.internal();
1388 1458
1389 /** 1459 /**
1390 * Returns a [JsFunction] that captures its 'this' binding and calls [f] 1460 * Returns a [JsFunction] that captures its 'this' binding and calls [f]
1391 * with the value of this passed as the first argument. 1461 * with the value of this passed as the first argument.
1392 */ 1462 */
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after
1606 } else { 1676 } else {
1607 var ret = _interopCaptureThisExpando[f]; 1677 var ret = _interopCaptureThisExpando[f];
1608 if (ret == null) { 1678 if (ret == null) {
1609 // TODO(jacobr): we could optimize this. 1679 // TODO(jacobr): we could optimize this.
1610 ret = JSFunction._createWithThis(f); 1680 ret = JSFunction._createWithThis(f);
1611 _interopCaptureThisExpando[f] = ret; 1681 _interopCaptureThisExpando[f] = ret;
1612 } 1682 }
1613 return ret; 1683 return ret;
1614 } 1684 }
1615 } 1685 }
OLDNEW
« no previous file with comments | « sdk/lib/js/dart2js/js_dart2js.dart ('k') | sdk/lib/js_util/dart2js/js_util_dart2js.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698