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 /// Whether the backend is currently processing the codegen queue. | |
43 bool _inCodegen = false; | |
44 | |
45 JsInteropAnalysis(this.backend); | |
46 | |
47 void onQueueClosed() { | |
48 if (_inCodegen) return; | |
49 | |
50 if (backend.jsAnnotationClass != null) { | |
51 nameField = backend.jsAnnotationClass.lookupMember('name'); | |
52 backend.compiler.libraryLoader.libraries | |
53 .forEach(processJsInteropAnnotationsInLibrary); | |
54 } | |
55 } | |
56 | |
57 void onCodegenStart() { | |
58 _inCodegen = true; | |
59 } | |
60 | |
61 void processJsInteropAnnotation(Element e) { | |
62 for (MetadataAnnotation annotation in e.implementation.metadata) { | |
63 ConstantValue constant = backend.compiler.constants.getConstantValue( | |
64 annotation.constant); | |
65 if (constant == null || constant is! ConstructedConstantValue) continue; | |
66 ConstructedConstantValue constructedConstant = constant; | |
67 if (constructedConstant.type.element == backend.jsAnnotationClass) { | |
68 ConstantValue value = constructedConstant.fields[nameField]; | |
69 if (value.isString) { | |
70 StringConstantValue stringValue = value; | |
71 e.setJsInteropName(stringValue.primitiveValue.slowToString()); | |
72 } else { | |
73 assert(value.isNull); | |
sra1
2015/10/13 03:31:36
@Js(1)
external method();
Should generate an
| |
74 e.setJsInteropName(''); | |
75 } | |
76 enabledJsInterop = true; | |
77 return; | |
78 } | |
79 } | |
80 } | |
81 | |
82 void processJsInteropAnnotationsInLibrary(LibraryElement library) { | |
83 processJsInteropAnnotation(library); | |
84 library.implementation.forEachLocalMember((Element element) { | |
85 processJsInteropAnnotation(element); | |
86 if (!element.isClass || !element.isJsInterop) return; | |
87 | |
88 ClassElement classElement = element; | |
89 | |
90 if (!classElement | |
91 .implementsInterface(backend.jsJavaScriptObjectClass)) { | |
92 backend.compiler.reportErrorMessage(classElement, | |
93 MessageKind.JS_INTEROP_CLASS_CANNOT_EXTEND_DART_CLASS, { | |
94 'cls': classElement.name, | |
95 'superclass': classElement.superclass.name | |
96 }); | |
97 } | |
98 | |
99 classElement.forEachMember( | |
100 (ClassElement classElement, Element member) { | |
101 processJsInteropAnnotation(member); | |
102 | |
103 if (!member.isSynthesized && | |
104 classElement.isJsInterop && | |
105 member is FunctionElement) { | |
106 FunctionElement fn = member; | |
107 if (!fn.isExternal && !fn.isAbstract) { | |
108 backend.compiler.reportErrorMessage( | |
109 fn, | |
110 MessageKind.JS_INTEROP_CLASS_NON_EXTERNAL_MEMBER, | |
111 {'cls': classElement.name, 'member': member.name}); | |
112 } | |
113 } | |
114 }); | |
115 }); | |
116 } | |
117 | |
118 jsAst.Statement buildJsInteropBootstrap() { | |
119 if (!enabledJsInterop) return null; | |
120 List<jsAst.Statement> statements = <jsAst.Statement>[]; | |
121 backend.compiler.codegenWorld.forEachInvokedName( | |
122 (String name, Map<Selector, SelectorConstraints> selectors) { | |
123 selectors.forEach((Selector selector, SelectorConstraints constraints) { | |
124 if (selector.isClosureCall) { | |
125 // TODO(jacobr): support named arguments. | |
126 if (selector.namedArgumentCount > 0) return; | |
127 int argumentCount = selector.argumentCount; | |
128 var candidateParameterNames = | |
129 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLOMOPQRSTUVWXYZ'; | |
130 var parameters = new List<String>.generate( | |
131 argumentCount, (i) => candidateParameterNames[i]); | |
132 | |
133 var name = backend.namer.invocationName(selector); | |
134 statements.add(js.statement( | |
135 'Function.prototype.# = function(#) { return this(#) }', | |
136 [name, parameters, parameters])); | |
137 } | |
138 }); | |
139 }); | |
140 return new jsAst.Block(statements); | |
141 } | |
142 } | |
OLD | NEW |