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

Side by Side Diff: lib/src/mirrors.dart

Issue 615913004: Add @jsify annotation. Support automatically proxying Lists and Maps to Dart in Proxies. Support co… (Closed) Base URL: https://github.com/dart-lang/js-interop.git@master
Patch Set: Created 6 years, 2 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
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, 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 * This library contains semi-private APIs for implementing typed interfaces and 6 * This library contains semi-private APIs for implementing typed interfaces and
7 * exports. 7 * exports.
8 */ 8 */
9 library js.mirrors; 9 library js.mirrors;
10 10
11 import 'dart:js' as js; 11 import 'dart:js' as js;
12 import 'dart:mirrors'; 12 import 'dart:mirrors';
13 import 'dart:mirrors' as mirrors; 13 import 'dart:mirrors' as mirrors;
14 14
15 import 'package:js/src/metadata.dart'; 15 import 'package:js/src/metadata.dart' as metadata;
16 import 'package:js/src/js_elements.dart'; 16 import 'package:js/src/js_elements.dart';
17 import 'package:js/src/js_impl.dart' as jsi; 17 import 'package:js/src/js_impl.dart' as jsi;
18 import 'package:js/src/js_impl.dart'; 18 import 'package:js/src/js_impl.dart';
19 19
20 // This is the public interface of js.dart 20 // This is the public interface of js.dart
21 // The exports must match those in static.dart 21 // The exports must match those in static.dart
22 export 'package:js/src/js_impl.dart' hide JsInterface; 22 // JsInterface is not include to show the version defined here
23 export 'package:js/src/js_impl.dart' show JsGlobal, toJs, toDart,
24 registerJsConstructorForType, registerFactoryForJsConstructor;
23 export 'dart:js' show JsObject; 25 export 'dart:js' show JsObject;
24 export 'package:js/src/metadata.dart'; 26 export 'package:js/src/metadata.dart';
25 27
26 import 'package:quiver/mirrors.dart'; 28 import 'package:quiver/mirrors.dart';
27 29
28 final _dart = js.context['dart']; 30 final _dart = js.context['dart'];
29 final _obj = js.context['Object']; 31 final _obj = js.context['Object'];
30 32
31 // This is ugly. For each ExportedClass we need a reference to the class mirror 33 // This is ugly. For each ExportedClass we need a reference to the class mirror
32 // to implement constructors, but ExportedClass is used in code generation 34 // to implement constructors, but ExportedClass is used in code generation
33 // as well. 35 // as well.
34 Expando<ClassMirror> _classMirrors = new Expando<ClassMirror>(); 36 Expando<ClassMirror> _classMirrors = new Expando<ClassMirror>();
35 37
36 initializeJavaScript() { 38 initializeJavaScript() {
37 var libraries = currentMirrorSystem().libraries; 39 var libraries = currentMirrorSystem().libraries;
38 40
39 var jsElements = new JsElements(); 41 var jsElements = new JsElements();
40 var jsInterface = reflectType(JsInterface); 42 var jsInterface = reflectType(JsInterface);
41 43
42 for (var library in libraries.values) { 44 for (var library in libraries.values) {
43 var exportedLibrary; 45 var exportedLibrary;
44 var libraryName = _getName(library); 46 var libraryName = _getName(library);
45 var libraryExportAnnotation = _getExportAnnotation(library); 47 var libraryExportAnnotation = _getExportAnnotation(library);
46 if (libraryExportAnnotation != null) { 48 if (libraryExportAnnotation != null) {
47 exportedLibrary = jsElements.getLibrary(libraryName); 49 exportedLibrary = jsElements.getLibrary(libraryName);
48 } 50 }
49 51
50 var classes = library.declarations.values.where((d) => d is ClassMirror); 52 var classes = library.declarations.values.where((d) => d is ClassMirror);
51 for (ClassMirror clazz in classes) { 53 for (ClassMirror clazz in classes) {
52 JsProxy jsProxyAnnotation = _getJsProxyAnnotation(clazz); 54 metadata.JsProxy jsProxyAnnotation = _getJsProxyAnnotation(clazz);
53 if (jsProxyAnnotation != null && jsProxyAnnotation.constructor != null) { 55 if (jsProxyAnnotation != null && jsProxyAnnotation.constructor != null) {
54 _registerProxy(clazz, jsProxyAnnotation); 56 _registerProxy(clazz, jsProxyAnnotation);
55 } 57 }
56 58
57 var classExportAnnotation = _getExportAnnotation(clazz); 59 var classExportAnnotation = _getExportAnnotation(clazz);
58 var classNoExportAnnotation = _getNoExportAnnotation(clazz); 60 var classNoExportAnnotation = _getNoExportAnnotation(clazz);
59 61
60 if (classNoExportAnnotation == null 62 if (classNoExportAnnotation == null
61 && !clazz.isAbstract 63 && !clazz.isAbstract
62 && !classImplements(clazz, jsInterface) 64 && !classImplements(clazz, jsInterface)
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 // remove the class name 130 // remove the class name
129 var name = rawName == c.name ? '' : rawName.substring(c.name.length + 1); 131 var name = rawName == c.name ? '' : rawName.substring(c.name.length + 1);
130 132
131 var parameters = ctor.parameters.map((p) => 133 var parameters = ctor.parameters.map((p) =>
132 new ExportedParameter(_getName(p), _getKind(p), _getType(p))).toList(); 134 new ExportedParameter(_getName(p), _getKind(p), _getType(p))).toList();
133 135
134 c.children[name] = new ExportedConstructor(name, c, parameters); 136 c.children[name] = new ExportedConstructor(name, c, parameters);
135 } 137 }
136 } 138 }
137 139
138 void _registerProxy(ClassMirror clazz, JsProxy jsProxyAnnotation) { 140 void _registerProxy(ClassMirror clazz, metadata.JsProxy jsProxyAnnotation) {
139 var constructorExpr = jsProxyAnnotation.constructor; 141 var constructorExpr = jsProxyAnnotation.constructor;
140 var createdConstructor = clazz.declarations[#created]; 142 var createdConstructor = clazz.declarations[#created];
141 jsi.registerFactoryForJsConstructor( 143 jsi.registerFactoryForJsConstructor(
142 getPath(jsProxyAnnotation.constructor), 144 getPath(jsProxyAnnotation.constructor),
143 (JsObject o) => clazz.newInstance(#created, [o]).reflectee); 145 (JsObject o) => clazz.newInstance(#created, [o]).reflectee);
144 } 146 }
145 147
146 _exportLibrary(ExportedLibrary library, JsObject parent) { 148 _exportLibrary(ExportedLibrary library, JsObject parent) {
147 JsObject libraryJsObj = parent; 149 JsObject libraryJsObj = parent;
148 var parts = library.name.split('.'); 150 var parts = library.name.split('.');
149 parts.forEach((p) { 151 parts.forEach((p) {
150 if (!libraryJsObj.hasProperty(p)) { 152 if (!libraryJsObj.hasProperty(p)) {
151 libraryJsObj = libraryJsObj[p] = new JsObject.jsify({}); 153 libraryJsObj = libraryJsObj[p] = new JsObject(_obj);
152 } else { 154 } else {
153 libraryJsObj = libraryJsObj[p]; 155 libraryJsObj = libraryJsObj[p];
154 } 156 }
155 }); 157 });
156 library.declarations.forEach((n, d) => _exportDeclaration(d, libraryJsObj)); 158 library.declarations.forEach((n, d) => _exportDeclaration(d, libraryJsObj));
157 } 159 }
158 160
159 _exportDeclaration(ExportedElement e, JsObject parent) { 161 _exportDeclaration(ExportedElement e, JsObject parent) {
160 if (e is ExportedClass) { 162 if (e is ExportedClass) {
161 _exportClass(e, parent); 163 _exportClass(e, parent);
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 call() => throw new StateError('There should always been at least 1 parameter' 278 call() => throw new StateError('There should always been at least 1 parameter'
277 '(js this).'); 279 '(js this).');
278 280
279 noSuchMethod(Invocation invocation) { 281 noSuchMethod(Invocation invocation) {
280 var self = invocation.positionalArguments.first; 282 var self = invocation.positionalArguments.first;
281 var args = invocation.positionalArguments.skip(1).toList(); 283 var args = invocation.positionalArguments.skip(1).toList();
282 return f(self, args); 284 return f(self, args);
283 } 285 }
284 } 286 }
285 287
286 Export _getExportAnnotation(DeclarationMirror d) { 288 metadata.Export _getExportAnnotation(DeclarationMirror d) {
287 var m = d.metadata.firstWhere((m) => m.type.reflectedType == Export, 289 var m = d.metadata
288 orElse: () => null); 290 .firstWhere((m) => m.type.reflectedType == metadata.Export,
291 orElse: () => null);
289 return m == null ? null : m.reflectee; 292 return m == null ? null : m.reflectee;
290 } 293 }
291 294
292 NoExport _getNoExportAnnotation(DeclarationMirror d) { 295 metadata.NoExport _getNoExportAnnotation(DeclarationMirror d) {
293 var m = d.metadata.firstWhere((m) => m.type.reflectedType == NoExport, 296 var m = d.metadata
294 orElse: () => null); 297 .firstWhere((m) => m.type.reflectedType == metadata.NoExport,
298 orElse: () => null);
295 return m == null ? null : m.reflectee; 299 return m == null ? null : m.reflectee;
296 } 300 }
297 301
298 String _getName(DeclarationMirror m) => MirrorSystem.getName(m.simpleName); 302 String _getName(DeclarationMirror m) => MirrorSystem.getName(m.simpleName);
299 303
300 ParameterKind _getKind(ParameterMirror p) { 304 ParameterKind _getKind(ParameterMirror p) {
301 if (p.isNamed) return ParameterKind.NAMED; 305 if (p.isNamed) return ParameterKind.NAMED;
302 if (p.isOptional) return ParameterKind.POSITIONAL; 306 if (p.isOptional) return ParameterKind.POSITIONAL;
303 return ParameterKind.REQUIRED; 307 return ParameterKind.REQUIRED;
304 } 308 }
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 } 347 }
344 348
345 if (jsConstructor != null) { 349 if (jsConstructor != null) {
346 // TODO: support constructor expressions 350 // TODO: support constructor expressions
347 var ctor = getPath(jsConstructor); 351 var ctor = getPath(jsConstructor);
348 var jsObj = new JsObject(ctor, args); 352 var jsObj = new JsObject(ctor, args);
349 return classMirror.newInstance(#created, [jsObj]).reflectee; 353 return classMirror.newInstance(#created, [jsObj]).reflectee;
350 } 354 }
351 } 355 }
352 356
353 dynamic noSuchMethod(Invocation i) { 357 dynamic noSuchMethod(Invocation invocation) {
354 var mirror = mirrors.reflect(this); 358 var mirror = mirrors.reflect(this);
355 var decl = getDeclaration(mirror.type, i.memberName); 359 var decl = getDeclaration(mirror.type, invocation.memberName);
356 360
357 if (decl != null) { 361 if (decl != null) {
358 mirrors.MethodMirror method = decl; 362 mirrors.MethodMirror method = decl;
359 String name = mirrors.MirrorSystem.getName(i.memberName); 363 String name = mirrors.MirrorSystem.getName(invocation.memberName);
360 if (i.isGetter) { 364 if (invocation.isGetter) {
361 var o = toDart(toJs(this)[name]); 365 var o = toDart(toJs(this)[name]);
362 assert(o == null || 366 assert(o == null ||
363 mirrors.reflect(o).type.isSubtypeOf(method.returnType)); 367 mirrors.reflect(o).type.isSubtypeOf(method.returnType));
364 return o; 368 return o;
365 } 369 }
366 if (i.isSetter) { 370 if (invocation.isSetter) {
367 // remove the trailing '=' from the setter name 371 // remove the trailing '=' from the setter name
368 name = name.substring(0, name.length - 1); 372 name = name.substring(0, name.length - 1);
369 var v = toJs(i.positionalArguments[0]); 373 var v = toJs(invocation.positionalArguments[0]);
370 toJs(this)[name] = v; 374 toJs(this)[name] = v;
371 return null; 375 return null;
372 } 376 }
373 if (i.isMethod) { 377 if (invocation.isMethod) {
374 var jsArgs = i.positionalArguments.map(toJs).toList(); 378 MethodMirror m = decl;
375 var o = toDart(toJs(this).callMethod(name, jsArgs)); 379 var positionalParams = m.parameters.where((p) => !p.isNamed).toList();
380 var positionalArgs = invocation.positionalArguments;
381 var jsArgs = new List(positionalArgs.length);
382 for (int i = 0; i < positionalArgs.length; i++) {
383 var param = positionalParams[i];
384 var arg = positionalArgs[i];
385 var hasJsify = param.metadata.any((m) => m.reflectee == metadata.jsify );
Siggi Cherem (dart-lang) 2014/10/07 20:41:41 80
justinfagnani 2014/10/08 06:30:02 Done.
386 if (hasJsify) {
387 jsArgs[i] = jsify(arg);
388 } else {
389 jsArgs[i] = toJs(arg);
390 }
391 }
392 var returnType = m.returnType.hasReflectedType
393 ? m.returnType.originalDeclaration.simpleName
394 : null;
395 var o = toDart(toJs(this).callMethod(name, jsArgs), returnType);
376 assert(o == null || 396 assert(o == null ||
377 mirrors.reflect(o).type.isSubtypeOf(method.returnType)); 397 mirrors.reflect(o).type.isSubtypeOf(method.returnType));
378 return o; 398 return o;
379 } 399 }
380 assert(false); 400 assert(false);
381 } 401 }
382 return super.noSuchMethod(i); 402 return super.noSuchMethod(invocation);
383 } 403 }
384 } 404 }
385 405
386 JsProxy _getJsProxyAnnotation(ClassMirror c) { 406 metadata.JsProxy _getJsProxyAnnotation(ClassMirror c) {
387 var jsProxyAnnotationMirror = 407 var jsProxyAnnotationMirror = c.metadata
388 c.metadata 408 .firstWhere((i) => i.reflectee is metadata.JsProxy, orElse: () => null);
389 .firstWhere((i) => i.reflectee is JsProxy, orElse: () => null);
390 409
391 if (jsProxyAnnotationMirror == null) return null; 410 if (jsProxyAnnotationMirror == null) return null;
392 411
393 return jsProxyAnnotationMirror.reflectee; 412 return jsProxyAnnotationMirror.reflectee;
394 } 413 }
395 414
396 415
397 /** 416 /**
398 * Returns all the declarations on [classMirror] and its super classes and 417 * Returns all the declarations on [classMirror] and its super classes and
399 * interfaces. This is difference from [ClassMirror.instanceMembers]. 418 * interfaces. This is difference from [ClassMirror.instanceMembers].
(...skipping 13 matching lines...) Expand all
413 _getDeclarations(classMirror.superclass, declarations); 432 _getDeclarations(classMirror.superclass, declarations);
414 } 433 }
415 // TODO: See if a getter can shadow an implicit setter from a field in a 434 // TODO: See if a getter can shadow an implicit setter from a field in a
416 // superclass. This could happen if a superclass has a field and a subclass 435 // superclass. This could happen if a superclass has a field and a subclass
417 // has a getter with the same name. Since the field doesn't induce a setter 436 // has a getter with the same name. Since the field doesn't induce a setter
418 // in the declarations, the field would be replaced by the getter and there 437 // in the declarations, the field would be replaced by the getter and there
419 // would be no associated setter. The solution would be to create a synthetic 438 // would be no associated setter. The solution would be to create a synthetic
420 // setter if we're adding a getter than shadows a field. 439 // setter if we're adding a getter than shadows a field.
421 declarations.addAll(classMirror.declarations); 440 declarations.addAll(classMirror.declarations);
422 } 441 }
OLDNEW
« lib/src/js_list.dart ('K') | « lib/src/metadata.dart ('k') | lib/src/static.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698