Chromium Code Reviews| 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 |