Chromium Code Reviews| Index: lib/src/compiler/code_generator.dart |
| diff --git a/lib/src/compiler/code_generator.dart b/lib/src/compiler/code_generator.dart |
| index 05d603f8de8c428c91f543740d95d541006ad1c7..945945d0d38ecc2b8c2ed53b56d89b85ba4976b5 100644 |
| --- a/lib/src/compiler/code_generator.dart |
| +++ b/lib/src/compiler/code_generator.dart |
| @@ -82,7 +82,8 @@ class CodeGenerator extends GeneralizingAstVisitor |
| JS.TemporaryId _asyncStarController; |
| /// The top-level reference to 'self' if this is a library tagged with @JS() |
|
Jennifer Messerly
2016/05/18 22:20:26
reword this comment?
Harry Terkelsen
2016/05/19 16:56:18
Done.
|
| - JS.TemporaryId _self; |
| + JS.Expression _jsPrefix; |
| + bool libraryTaggedJS = false; |
|
Jennifer Messerly
2016/05/18 22:20:27
Perhaps call this "_isInteropLibrary"
Note: I hav
Harry Terkelsen
2016/05/19 16:56:18
Done.
|
| final _privateNames = |
| new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>(); |
| @@ -90,6 +91,7 @@ class CodeGenerator extends GeneralizingAstVisitor |
| new HashMap<ParameterElement, JS.TemporaryId>(); |
| final _dartxVar = new JS.Identifier('dartx'); |
| + final _dartGlobal = js.call('dart.global'); |
| final _runtimeLibVar = new JS.Identifier('dart'); |
| final namedArgumentTemp = new JS.TemporaryId('opts'); |
| @@ -226,8 +228,12 @@ class CodeGenerator extends GeneralizingAstVisitor |
| } |
| if (findAnnotation(library, isPublicJSAnnotation) != null) { |
| - _self = new JS.TemporaryId('self'); |
| - items.add(js.statement('const # = window;', [_self])); |
| + libraryTaggedJS = true; |
|
Jennifer Messerly
2016/05/18 22:20:27
is this attribute per-library or is it global for
Harry Terkelsen
2016/05/19 16:56:18
It's per-library. I made the map.
|
| + var prefix = getAnnotationName(library, isPublicJSAnnotation); |
| + if (prefix != null && !prefix.isEmpty) { |
|
Jennifer Messerly
2016/05/18 22:20:27
will we always have a name? in other words does it
Harry Terkelsen
2016/05/19 16:56:19
A @JS annotation on the library is required for js
|
| + _jsPrefix = js.call(prefix); |
|
Jennifer Messerly
2016/05/18 22:20:27
I feel like we'd be better off validating our user
Harry Terkelsen
2016/05/19 16:56:18
I am just splitting on dots now without validation
|
| + assert(_isValidJSName(_jsPrefix)); |
|
Jennifer Messerly
2016/05/18 22:20:26
Should this be an error we issue?
I think of "ass
Harry Terkelsen
2016/05/19 16:56:18
I think you cannot just put arbitrary strings in t
|
| + } |
| } |
| } |
| @@ -290,6 +296,49 @@ class CodeGenerator extends GeneralizingAstVisitor |
| } |
| } |
| + /// Returns [true] if [jsName] is a simple identifier, a string with no dots, |
| + /// or a property access where the receiver is a valid JS name and the |
| + /// selector is a simple identifier. |
| + bool _isValidJSName(JS.Expression jsName) { |
|
Jennifer Messerly
2016/05/18 22:20:26
based on suggestion above, I'm not sure you'll nee
Harry Terkelsen
2016/05/19 16:56:19
Done.
|
| + if (jsName is JS.Identifier) { |
| + return true; |
| + } else if (jsName is JS.LiteralString) { |
| + return !jsName.value.contains('.'); |
| + } else if (jsName is JS.PropertyAccess) { |
| + return (jsName.selector is JS.Identifier || |
| + jsName.selector is JS.LiteralString) && |
| + _isValidJSName(jsName.receiver); |
| + } else { |
| + return false; |
| + } |
| + } |
| + |
| + /// Returns the equivalent of separating the given names by a '.'. |
| + JS.PropertyAccess _mergeJSNames(Iterable<JS.Expression> names) { |
|
Jennifer Messerly
2016/05/18 22:20:27
same here, I don't think this will be needed
Harry Terkelsen
2016/05/19 16:56:18
Done.
|
| + assert(names.every(_isValidJSName)); |
|
Jennifer Messerly
2016/05/18 22:20:27
(this comment is probably moot based on my other o
Harry Terkelsen
2016/05/19 16:56:18
Done.
|
| + Iterable<JS.LiteralString> extractParts(JS.Expression name) sync* { |
| + if (name == null) return; |
| + if (name is JS.LiteralString) { |
| + yield name; |
| + return; |
| + } |
| + if (name is JS.Identifier) { |
| + yield js.string(name.name); |
| + return; |
| + } |
| + var propertyAccess = name as JS.PropertyAccess; |
| + yield* extractParts(propertyAccess.receiver); |
| + yield propertyAccess.selector; |
| + } |
| + return names.expand(extractParts).fold(null, (merged, part) { |
| + if (merged == null) { |
| + return new JS.Identifier( |
| + part.value.substring(1, part.value.length - 1)); |
| + } |
| + return new JS.PropertyAccess(merged, part); |
| + }); |
| + } |
| + |
| String _libraryToModule(LibraryElement library) { |
| assert(!_libraries.containsKey(library)); |
| var source = library.source; |
| @@ -2346,10 +2395,17 @@ class CodeGenerator extends GeneralizingAstVisitor |
| JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) { |
| if (e is TopLevelVariableElement && |
| e.getter != null && |
| - findAnnotation(e.getter, isPublicJSAnnotation) != null) { |
| + (findAnnotation(e.getter, isPublicJSAnnotation) != null || |
| + (libraryTaggedJS && e.getter.isExternal))) { |
|
Jennifer Messerly
2016/05/18 22:20:26
`e.getter.isExternal && _libraryTaggedJS(e.library
Harry Terkelsen
2016/05/19 16:56:19
Done.
|
| var annotationName = getAnnotationName(e.getter, isPublicJSAnnotation); |
| - var name = js.string(annotationName ?? e.name); |
| - return new JS.PropertyAccess(_self, name); |
| + var name; |
| + if (annotationName != null && annotationName.contains('.')) { |
| + name = js.call(annotationName); |
| + } else { |
| + name = js.string(annotationName ?? e.name); |
| + } |
| + return _mergeJSNames( |
|
Jennifer Messerly
2016/05/18 22:20:26
rather than merging js_ast structures, IMO it woul
Harry Terkelsen
2016/05/19 16:56:18
Done.
|
| + [_dartGlobal, _jsPrefix, name].where((x) => x != null)); |
|
Jennifer Messerly
2016/05/18 22:20:27
(probably a moot comment) _jsPrefix is the only o
Harry Terkelsen
2016/05/19 16:56:18
Done.
|
| } |
| String name = getJSExportName(e) + suffix; |
| return new JS.PropertyAccess( |
| @@ -3044,8 +3100,14 @@ class CodeGenerator extends GeneralizingAstVisitor |
| var classElem = element.enclosingElement; |
| if (findAnnotation(classElem, isPublicJSAnnotation) != null) { |
| var annotationName = getAnnotationName(classElem, isPublicJSAnnotation); |
| - var typeName = js.string(annotationName ?? classElem.name); |
| - return new JS.PropertyAccess(_self, typeName); |
| + var typeName; |
|
Jennifer Messerly
2016/05/18 22:20:27
this code seems duplicated with above.
(it sort o
Harry Terkelsen
2016/05/19 16:56:18
Done.
|
| + if (annotationName != null && annotationName.contains('.')) { |
| + typeName = js.call(annotationName); |
| + } else { |
| + typeName = js.string(annotationName ?? classElem.name); |
| + } |
| + return _mergeJSNames( |
| + [_dartGlobal, _jsPrefix, typeName].where((x) => x != null)); |
| } |
| var typeName = _emitType(type); |
| if (name != null || element.isFactory) { |