Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 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 | 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 import 'dart:collection' show HashMap, HashSet; | 5 import 'dart:collection' show HashMap, HashSet; |
| 6 import 'dart:math' show min, max; | 6 import 'dart:math' show min, max; |
| 7 | 7 |
| 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; | 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; |
| 9 import 'package:analyzer/dart/ast/ast.dart'; | 9 import 'package:analyzer/dart/ast/ast.dart'; |
| 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; | 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 74 /// Usually a [SimpleIdentifier], but it can also be other expressions | 74 /// Usually a [SimpleIdentifier], but it can also be other expressions |
| 75 /// that are safe to evaluate multiple times, such as `this`. | 75 /// that are safe to evaluate multiple times, such as `this`. |
| 76 Expression _cascadeTarget; | 76 Expression _cascadeTarget; |
| 77 | 77 |
| 78 /// The variable for the current catch clause | 78 /// The variable for the current catch clause |
| 79 SimpleIdentifier _catchParameter; | 79 SimpleIdentifier _catchParameter; |
| 80 | 80 |
| 81 /// In an async* function, this represents the stream controller parameter. | 81 /// In an async* function, this represents the stream controller parameter. |
| 82 JS.TemporaryId _asyncStarController; | 82 JS.TemporaryId _asyncStarController; |
| 83 | 83 |
| 84 /// The top-level reference to 'self' if this is a library tagged with @JS() | 84 /// 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.
| |
| 85 JS.TemporaryId _self; | 85 JS.Expression _jsPrefix; |
| 86 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.
| |
| 86 | 87 |
| 87 final _privateNames = | 88 final _privateNames = |
| 88 new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>(); | 89 new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>(); |
| 89 final _initializingFormalTemps = | 90 final _initializingFormalTemps = |
| 90 new HashMap<ParameterElement, JS.TemporaryId>(); | 91 new HashMap<ParameterElement, JS.TemporaryId>(); |
| 91 | 92 |
| 92 final _dartxVar = new JS.Identifier('dartx'); | 93 final _dartxVar = new JS.Identifier('dartx'); |
| 94 final _dartGlobal = js.call('dart.global'); | |
| 93 final _runtimeLibVar = new JS.Identifier('dart'); | 95 final _runtimeLibVar = new JS.Identifier('dart'); |
| 94 final namedArgumentTemp = new JS.TemporaryId('opts'); | 96 final namedArgumentTemp = new JS.TemporaryId('opts'); |
| 95 | 97 |
| 96 final _hasDeferredSupertype = new HashSet<ClassElement>(); | 98 final _hasDeferredSupertype = new HashSet<ClassElement>(); |
| 97 | 99 |
| 98 final _eagerTopLevelFields = new HashSet<Element>.identity(); | 100 final _eagerTopLevelFields = new HashSet<Element>.identity(); |
| 99 | 101 |
| 100 /// The type provider from the current Analysis [context]. | 102 /// The type provider from the current Analysis [context]. |
| 101 final TypeProvider types; | 103 final TypeProvider types; |
| 102 | 104 |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 219 js.call('const # = Object.create(null)', [libraryTemp]))); | 221 js.call('const # = Object.create(null)', [libraryTemp]))); |
| 220 | 222 |
| 221 // dart:_runtime has a magic module that holds extenstion method symbols. | 223 // dart:_runtime has a magic module that holds extenstion method symbols. |
| 222 // TODO(jmesserly): find a cleaner design for this. | 224 // TODO(jmesserly): find a cleaner design for this. |
| 223 if (_isDartRuntime(library)) { | 225 if (_isDartRuntime(library)) { |
| 224 items.add(new JS.ExportDeclaration( | 226 items.add(new JS.ExportDeclaration( |
| 225 js.call('const # = Object.create(null)', [_dartxVar]))); | 227 js.call('const # = Object.create(null)', [_dartxVar]))); |
| 226 } | 228 } |
| 227 | 229 |
| 228 if (findAnnotation(library, isPublicJSAnnotation) != null) { | 230 if (findAnnotation(library, isPublicJSAnnotation) != null) { |
| 229 _self = new JS.TemporaryId('self'); | 231 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.
| |
| 230 items.add(js.statement('const # = window;', [_self])); | 232 var prefix = getAnnotationName(library, isPublicJSAnnotation); |
| 233 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
| |
| 234 _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
| |
| 235 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
| |
| 236 } | |
| 231 } | 237 } |
| 232 } | 238 } |
| 233 | 239 |
| 234 // Collect all Element -> Node mappings, in case we need to forward declare | 240 // Collect all Element -> Node mappings, in case we need to forward declare |
| 235 // any nodes. | 241 // any nodes. |
| 236 var nodes = new HashMap<Element, AstNode>.identity(); | 242 var nodes = new HashMap<Element, AstNode>.identity(); |
| 237 var sdkBootstrappingFns = new List<FunctionElement>(); | 243 var sdkBootstrappingFns = new List<FunctionElement>(); |
| 238 for (var unit in compilationUnits) { | 244 for (var unit in compilationUnits) { |
| 239 if (_isDartRuntime(unit.element.library)) { | 245 if (_isDartRuntime(unit.element.library)) { |
| 240 sdkBootstrappingFns.addAll(unit.element.functions); | 246 sdkBootstrappingFns.addAll(unit.element.functions); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 283 List<JS.ModuleItem> result, Iterable<JS.ModuleItem> items) { | 289 List<JS.ModuleItem> result, Iterable<JS.ModuleItem> items) { |
| 284 for (var item in items) { | 290 for (var item in items) { |
| 285 if (item is JS.Block && !item.isScope) { | 291 if (item is JS.Block && !item.isScope) { |
| 286 _copyAndFlattenBlocks(result, item.statements); | 292 _copyAndFlattenBlocks(result, item.statements); |
| 287 } else { | 293 } else { |
| 288 result.add(item); | 294 result.add(item); |
| 289 } | 295 } |
| 290 } | 296 } |
| 291 } | 297 } |
| 292 | 298 |
| 299 /// Returns [true] if [jsName] is a simple identifier, a string with no dots, | |
| 300 /// or a property access where the receiver is a valid JS name and the | |
| 301 /// selector is a simple identifier. | |
| 302 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.
| |
| 303 if (jsName is JS.Identifier) { | |
| 304 return true; | |
| 305 } else if (jsName is JS.LiteralString) { | |
| 306 return !jsName.value.contains('.'); | |
| 307 } else if (jsName is JS.PropertyAccess) { | |
| 308 return (jsName.selector is JS.Identifier || | |
| 309 jsName.selector is JS.LiteralString) && | |
| 310 _isValidJSName(jsName.receiver); | |
| 311 } else { | |
| 312 return false; | |
| 313 } | |
| 314 } | |
| 315 | |
| 316 /// Returns the equivalent of separating the given names by a '.'. | |
| 317 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.
| |
| 318 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.
| |
| 319 Iterable<JS.LiteralString> extractParts(JS.Expression name) sync* { | |
| 320 if (name == null) return; | |
| 321 if (name is JS.LiteralString) { | |
| 322 yield name; | |
| 323 return; | |
| 324 } | |
| 325 if (name is JS.Identifier) { | |
| 326 yield js.string(name.name); | |
| 327 return; | |
| 328 } | |
| 329 var propertyAccess = name as JS.PropertyAccess; | |
| 330 yield* extractParts(propertyAccess.receiver); | |
| 331 yield propertyAccess.selector; | |
| 332 } | |
| 333 return names.expand(extractParts).fold(null, (merged, part) { | |
| 334 if (merged == null) { | |
| 335 return new JS.Identifier( | |
| 336 part.value.substring(1, part.value.length - 1)); | |
| 337 } | |
| 338 return new JS.PropertyAccess(merged, part); | |
| 339 }); | |
| 340 } | |
| 341 | |
| 293 String _libraryToModule(LibraryElement library) { | 342 String _libraryToModule(LibraryElement library) { |
| 294 assert(!_libraries.containsKey(library)); | 343 assert(!_libraries.containsKey(library)); |
| 295 var source = library.source; | 344 var source = library.source; |
| 296 // TODO(jmesserly): we need to split out HTML. | 345 // TODO(jmesserly): we need to split out HTML. |
| 297 if (source.uri.scheme == 'dart') { | 346 if (source.uri.scheme == 'dart') { |
| 298 return 'dart_sdk'; | 347 return 'dart_sdk'; |
| 299 } | 348 } |
| 300 var moduleName = _buildUnit.libraryToModule(source); | 349 var moduleName = _buildUnit.libraryToModule(source); |
| 301 if (moduleName == null) { | 350 if (moduleName == null) { |
| 302 throw new StateError('Could not find module containing "$library".'); | 351 throw new StateError('Could not find module containing "$library".'); |
| (...skipping 2036 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2339 return js.call('#(#)', [genericName, jsArgs]); | 2388 return js.call('#(#)', [genericName, jsArgs]); |
| 2340 } | 2389 } |
| 2341 } | 2390 } |
| 2342 | 2391 |
| 2343 return _emitTopLevelName(element); | 2392 return _emitTopLevelName(element); |
| 2344 } | 2393 } |
| 2345 | 2394 |
| 2346 JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) { | 2395 JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) { |
| 2347 if (e is TopLevelVariableElement && | 2396 if (e is TopLevelVariableElement && |
| 2348 e.getter != null && | 2397 e.getter != null && |
| 2349 findAnnotation(e.getter, isPublicJSAnnotation) != null) { | 2398 (findAnnotation(e.getter, isPublicJSAnnotation) != null || |
| 2399 (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.
| |
| 2350 var annotationName = getAnnotationName(e.getter, isPublicJSAnnotation); | 2400 var annotationName = getAnnotationName(e.getter, isPublicJSAnnotation); |
| 2351 var name = js.string(annotationName ?? e.name); | 2401 var name; |
| 2352 return new JS.PropertyAccess(_self, name); | 2402 if (annotationName != null && annotationName.contains('.')) { |
| 2403 name = js.call(annotationName); | |
| 2404 } else { | |
| 2405 name = js.string(annotationName ?? e.name); | |
| 2406 } | |
| 2407 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.
| |
| 2408 [_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.
| |
| 2353 } | 2409 } |
| 2354 String name = getJSExportName(e) + suffix; | 2410 String name = getJSExportName(e) + suffix; |
| 2355 return new JS.PropertyAccess( | 2411 return new JS.PropertyAccess( |
| 2356 emitLibraryName(e.library), _propertyName(name)); | 2412 emitLibraryName(e.library), _propertyName(name)); |
| 2357 } | 2413 } |
| 2358 | 2414 |
| 2359 @override | 2415 @override |
| 2360 JS.Expression visitAssignmentExpression(AssignmentExpression node) { | 2416 JS.Expression visitAssignmentExpression(AssignmentExpression node) { |
| 2361 var left = node.leftHandSide; | 2417 var left = node.leftHandSide; |
| 2362 var right = node.rightHandSide; | 2418 var right = node.rightHandSide; |
| (...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3037 : parent.getSetter(element.name); | 3093 : parent.getSetter(element.name); |
| 3038 } | 3094 } |
| 3039 return null; | 3095 return null; |
| 3040 } | 3096 } |
| 3041 | 3097 |
| 3042 JS.Expression _emitConstructorName( | 3098 JS.Expression _emitConstructorName( |
| 3043 ConstructorElement element, DartType type, SimpleIdentifier name) { | 3099 ConstructorElement element, DartType type, SimpleIdentifier name) { |
| 3044 var classElem = element.enclosingElement; | 3100 var classElem = element.enclosingElement; |
| 3045 if (findAnnotation(classElem, isPublicJSAnnotation) != null) { | 3101 if (findAnnotation(classElem, isPublicJSAnnotation) != null) { |
| 3046 var annotationName = getAnnotationName(classElem, isPublicJSAnnotation); | 3102 var annotationName = getAnnotationName(classElem, isPublicJSAnnotation); |
| 3047 var typeName = js.string(annotationName ?? classElem.name); | 3103 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.
| |
| 3048 return new JS.PropertyAccess(_self, typeName); | 3104 if (annotationName != null && annotationName.contains('.')) { |
| 3105 typeName = js.call(annotationName); | |
| 3106 } else { | |
| 3107 typeName = js.string(annotationName ?? classElem.name); | |
| 3108 } | |
| 3109 return _mergeJSNames( | |
| 3110 [_dartGlobal, _jsPrefix, typeName].where((x) => x != null)); | |
| 3049 } | 3111 } |
| 3050 var typeName = _emitType(type); | 3112 var typeName = _emitType(type); |
| 3051 if (name != null || element.isFactory) { | 3113 if (name != null || element.isFactory) { |
| 3052 var namedCtor = _constructorName(element); | 3114 var namedCtor = _constructorName(element); |
| 3053 return new JS.PropertyAccess(typeName, namedCtor); | 3115 return new JS.PropertyAccess(typeName, namedCtor); |
| 3054 } | 3116 } |
| 3055 return typeName; | 3117 return typeName; |
| 3056 } | 3118 } |
| 3057 | 3119 |
| 3058 @override | 3120 @override |
| (...skipping 1435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4494 } | 4556 } |
| 4495 | 4557 |
| 4496 bool isLibraryPrefix(Expression node) => | 4558 bool isLibraryPrefix(Expression node) => |
| 4497 node is SimpleIdentifier && node.staticElement is PrefixElement; | 4559 node is SimpleIdentifier && node.staticElement is PrefixElement; |
| 4498 | 4560 |
| 4499 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 4561 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
| 4500 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 4562 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
| 4501 | 4563 |
| 4502 bool _isDartRuntime(LibraryElement l) => | 4564 bool _isDartRuntime(LibraryElement l) => |
| 4503 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 4565 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
| OLD | NEW |