OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
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. | |
4 | |
5 /// Analysis to determine how to generate code for typed JavaScript interop. | |
6 library compiler.src.js_backend.js_interop_analysis; | |
7 | |
8 import '../common/names.dart' show Identifiers; | |
9 import '../compiler.dart' show Compiler; | |
10 import '../diagnostics/messages.dart' show MessageKind; | |
11 import '../constants/values.dart' | |
12 show | |
13 ConstantValue, | |
14 ConstructedConstantValue, | |
15 ListConstantValue, | |
16 NullConstantValue, | |
17 StringConstantValue, | |
18 TypeConstantValue; | |
19 import '../elements/elements.dart' | |
20 show | |
21 ClassElement, | |
22 Element, | |
23 FieldElement, | |
24 FunctionElement, | |
25 LibraryElement, | |
26 MetadataAnnotation; | |
27 | |
28 import '../js/js.dart' as jsAst; | |
29 import '../js/js.dart' show js; | |
30 import '../universe/selector.dart' show Selector; | |
31 import '../universe/universe.dart' show SelectorConstraints; | |
32 | |
33 import 'js_backend.dart' show JavaScriptBackend; | |
34 | |
35 class JsInteropAnalysis { | |
36 final JavaScriptBackend backend; | |
37 | |
38 /// The resolved [FieldElement] for `Js.name`. | |
39 FieldElement nameField; | |
40 bool enabledJsInterop = false; | |
41 | |
42 JsInteropAnalysis(this.backend); | |
43 | |
44 void onQueueClosed() { | |
45 if (backend.jsAnnotationClass != null) { | |
46 nameField = backend.jsAnnotationClass.lookupMember('name'); | |
47 backend.compiler.libraryLoader.libraries | |
48 .forEach(processJsInteropAnnotationsInLibrary); | |
49 } | |
50 } | |
51 | |
52 void processJsInteropAnnotation(Element e) { | |
53 for (MetadataAnnotation annotation in e.implementation.metadata) { | |
54 ConstructedConstantValue constant = | |
55 backend.compiler.constants.getConstantValue(annotation.constant); | |
Siggi Cherem (dart-lang)
2015/10/13 02:08:53
check first for the type of constant since some an
Jacob
2015/10/13 03:10:42
Done.
| |
56 if (constant != null && | |
Siggi Cherem (dart-lang)
2015/10/13 02:08:53
since you'll have more than one check, consider do
Jacob
2015/10/13 03:10:42
done
| |
57 constant.getType(backend.compiler.coreTypes).element == | |
Siggi Cherem (dart-lang)
2015/10/13 02:08:53
or simply `constant.type.element` (I believe Const
Jacob
2015/10/13 03:10:43
Done.
| |
58 backend.jsAnnotationClass) { | |
59 ConstantValue value = constant.fields[nameField]; | |
60 if (value.isString) { | |
61 StringConstantValue stringValue = value; | |
62 e.setJsInteropName(stringValue.primitiveValue.slowToString()); | |
63 } else { | |
64 assert(value.isNull); | |
65 e.setJsInteropName(''); | |
66 } | |
67 enabledJsInterop = true; | |
68 return; | |
69 } | |
70 } | |
71 } | |
72 | |
73 void processJsInteropAnnotationsInLibrary(LibraryElement library) { | |
74 processJsInteropAnnotation(library); | |
75 library.implementation.forEachLocalMember((Element element) { | |
76 processJsInteropAnnotation(element); | |
77 if (element.isClass) { | |
Siggi Cherem (dart-lang)
2015/10/13 02:08:53
nit: to keep the nesting level below smaller, we c
Jacob
2015/10/13 03:10:42
Done.
| |
78 ClassElement classElement = element; | |
79 if (classElement.isJsInterop) { | |
80 classElement.forEachMember((_, memberElement) { | |
81 processJsInteropAnnotation(memberElement); | |
Siggi Cherem (dart-lang)
2015/10/13 02:08:53
could we move this down and combine with the body
Jacob
2015/10/13 03:10:42
moved it anyway.
i think this is slightly as the
| |
82 }); | |
83 | |
84 if (!classElement | |
85 .implementsInterface(backend.jsJavaScriptObjectClass)) { | |
86 backend.compiler.reportErrorMessage(classElement, | |
87 MessageKind.JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS, { | |
88 'cls': classElement.name, | |
89 'superclass': classElement.superclass.name | |
90 }); | |
91 } | |
92 | |
93 classElement.forEachMember( | |
94 (ClassElement classElement, Element member) { | |
95 if (!member.isSynthesized && | |
96 classElement.isJsInterop && | |
97 member is FunctionElement) { | |
98 FunctionElement fn = member; | |
99 if (!fn.isExternal && !fn.isAbstract) { | |
100 backend.compiler.reportErrorMessage( | |
101 fn, | |
102 MessageKind.JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER, | |
103 {'cls': classElement.name, 'member': member.name}); | |
104 } | |
105 } | |
106 }); | |
107 } | |
108 } | |
109 }); | |
110 } | |
111 | |
112 jsAst.Statement buildJsInteropBootstrap() { | |
113 if (!enabledJsInterop) return null; | |
114 List<jsAst.Statement> statements = <jsAst.Statement>[]; | |
115 backend.compiler.codegenWorld.forEachInvokedName( | |
116 (String name, Map<Selector, SelectorConstraints> selectors) { | |
117 selectors.forEach((Selector selector, SelectorConstraints constraints) { | |
118 if (selector.isClosureCall) { | |
119 // TODO(jacobr): support named arguments. | |
120 if (selector.namedArgumentCount > 0) return; | |
121 int argumentCount = selector.argumentCount; | |
122 var candidateParameterNames = | |
123 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLOMOPQRSTUVWXYZ'; | |
124 var parameters = new List<String>.generate( | |
125 argumentCount, (i) => candidateParameterNames[i]); | |
126 | |
127 var name = backend.namer.invocationName(selector); | |
128 statements.add(js.statement( | |
129 'Function.prototype.# = function(#) { return this(#) }', | |
130 [name, parameters, parameters])); | |
131 } | |
132 }); | |
133 }); | |
134 return new jsAst.Block(statements); | |
135 } | |
136 } | |
OLD | NEW |