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 /// A mapping of libraries to the contents of their corresponding |
| 85 JS.TemporaryId _self; | 85 /// library-level @JS() annotation, if the library is annotated. The |
| 86 /// @JS annotation contains a dot-separated identifier or is empty. The | |
| 87 /// library is then associated with a list of Strings, which represents | |
| 88 /// the list of dotted identifiers. | |
| 89 final _libraryJsPrefixes = new HashMap<LibraryElement, List<String>>(); | |
|
Jennifer Messerly
2016/05/19 17:38:04
BTW, we're not consistent yet, but naming conventi
Harry Terkelsen
2016/05/19 18:10:10
Done.
| |
| 86 | 90 |
| 87 final _privateNames = | 91 final _privateNames = |
| 88 new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>(); | 92 new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>(); |
| 89 final _initializingFormalTemps = | 93 final _initializingFormalTemps = |
| 90 new HashMap<ParameterElement, JS.TemporaryId>(); | 94 new HashMap<ParameterElement, JS.TemporaryId>(); |
| 91 | 95 |
| 92 final _dartxVar = new JS.Identifier('dartx'); | 96 final _dartxVar = new JS.Identifier('dartx'); |
| 93 final _runtimeLibVar = new JS.Identifier('dart'); | 97 final _runtimeLibVar = new JS.Identifier('dart'); |
| 94 final namedArgumentTemp = new JS.TemporaryId('opts'); | 98 final namedArgumentTemp = new JS.TemporaryId('opts'); |
| 95 | 99 |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 219 js.call('const # = Object.create(null)', [libraryTemp]))); | 223 js.call('const # = Object.create(null)', [libraryTemp]))); |
| 220 | 224 |
| 221 // dart:_runtime has a magic module that holds extenstion method symbols. | 225 // dart:_runtime has a magic module that holds extenstion method symbols. |
| 222 // TODO(jmesserly): find a cleaner design for this. | 226 // TODO(jmesserly): find a cleaner design for this. |
| 223 if (_isDartRuntime(library)) { | 227 if (_isDartRuntime(library)) { |
| 224 items.add(new JS.ExportDeclaration( | 228 items.add(new JS.ExportDeclaration( |
| 225 js.call('const # = Object.create(null)', [_dartxVar]))); | 229 js.call('const # = Object.create(null)', [_dartxVar]))); |
| 226 } | 230 } |
| 227 | 231 |
| 228 if (findAnnotation(library, isPublicJSAnnotation) != null) { | 232 if (findAnnotation(library, isPublicJSAnnotation) != null) { |
| 229 _self = new JS.TemporaryId('self'); | 233 var libraryJsPrefix = <String>[]; |
| 230 items.add(js.statement('const # = window;', [_self])); | 234 var prefix = getAnnotationName(library, isPublicJSAnnotation); |
| 235 if (prefix != null && !prefix.isEmpty) { | |
| 236 libraryJsPrefix.addAll(prefix.split('.')); | |
| 237 } | |
| 238 _libraryJsPrefixes[library] = libraryJsPrefix; | |
|
Jennifer Messerly
2016/05/19 17:38:04
I think you'll need to compute these on-demand, be
Harry Terkelsen
2016/05/19 18:10:10
Done.
| |
| 231 } | 239 } |
| 232 } | 240 } |
| 233 | 241 |
| 234 // Collect all Element -> Node mappings, in case we need to forward declare | 242 // Collect all Element -> Node mappings, in case we need to forward declare |
| 235 // any nodes. | 243 // any nodes. |
| 236 var nodes = new HashMap<Element, AstNode>.identity(); | 244 var nodes = new HashMap<Element, AstNode>.identity(); |
| 237 var sdkBootstrappingFns = new List<FunctionElement>(); | 245 var sdkBootstrappingFns = new List<FunctionElement>(); |
| 238 for (var unit in compilationUnits) { | 246 for (var unit in compilationUnits) { |
| 239 if (_isDartRuntime(unit.element.library)) { | 247 if (_isDartRuntime(unit.element.library)) { |
| 240 sdkBootstrappingFns.addAll(unit.element.functions); | 248 sdkBootstrappingFns.addAll(unit.element.functions); |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 269 switch (options.moduleFormat) { | 277 switch (options.moduleFormat) { |
| 270 case ModuleFormat.legacy: | 278 case ModuleFormat.legacy: |
| 271 return new LegacyModuleBuilder().build(module); | 279 return new LegacyModuleBuilder().build(module); |
| 272 case ModuleFormat.node: | 280 case ModuleFormat.node: |
| 273 return new NodeModuleBuilder().build(module); | 281 return new NodeModuleBuilder().build(module); |
| 274 case ModuleFormat.es6: | 282 case ModuleFormat.es6: |
| 275 return module; | 283 return module; |
| 276 } | 284 } |
| 277 } | 285 } |
| 278 | 286 |
| 287 String _getJsName(Element e) { | |
|
Jennifer Messerly
2016/05/19 17:38:04
_getJSName
Harry Terkelsen
2016/05/19 18:10:10
Done.
| |
| 288 if (!_libraryJsPrefixes.containsKey(e.library)) return null; | |
|
Jennifer Messerly
2016/05/19 17:38:04
I think this is where you can implement the cache,
Harry Terkelsen
2016/05/19 18:10:10
Done.
| |
| 289 if (findAnnotation(e, isPublicJSAnnotation) != null) { | |
| 290 return getAnnotationName(e, isPublicJSAnnotation) ?? ''; | |
| 291 } | |
| 292 if (e is TopLevelVariableElement && | |
| 293 e.getter != null && | |
| 294 (e.getter.isExternal || | |
| 295 findAnnotation(e.getter, isPublicJSAnnotation) != null)) { | |
| 296 return getAnnotationName(e.getter, isPublicJSAnnotation) ?? ''; | |
| 297 } | |
| 298 return null; | |
| 299 } | |
| 300 | |
| 301 JS.Expression _emitJsInterop(Element e) { | |
|
Jennifer Messerly
2016/05/19 17:38:05
_emitJSInterop
Harry Terkelsen
2016/05/19 18:10:10
Done.
| |
| 302 var jsName = _getJsName(e); | |
| 303 if (jsName == null) return null; | |
| 304 var name; | |
| 305 if (jsName.isEmpty) { | |
| 306 name = [e.name]; | |
| 307 } else { | |
| 308 name = jsName.split('.'); | |
| 309 } | |
| 310 var fullName = ['global'] | |
| 311 ..addAll(_libraryJsPrefixes[e.library]) | |
| 312 ..addAll(name); | |
| 313 var access = _runtimeLibVar; | |
| 314 for (var part in fullName) { | |
| 315 access = new JS.PropertyAccess(access, js.string(part)); | |
| 316 } | |
| 317 return access; | |
| 318 } | |
| 319 | |
| 279 /// Flattens blocks in [items] to a single list. | 320 /// Flattens blocks in [items] to a single list. |
| 280 /// | 321 /// |
| 281 /// This will not flatten blocks that are marked as being scopes. | 322 /// This will not flatten blocks that are marked as being scopes. |
| 282 void _copyAndFlattenBlocks( | 323 void _copyAndFlattenBlocks( |
| 283 List<JS.ModuleItem> result, Iterable<JS.ModuleItem> items) { | 324 List<JS.ModuleItem> result, Iterable<JS.ModuleItem> items) { |
| 284 for (var item in items) { | 325 for (var item in items) { |
| 285 if (item is JS.Block && !item.isScope) { | 326 if (item is JS.Block && !item.isScope) { |
| 286 _copyAndFlattenBlocks(result, item.statements); | 327 _copyAndFlattenBlocks(result, item.statements); |
| 287 } else { | 328 } else { |
| 288 result.add(item); | 329 result.add(item); |
| (...skipping 2045 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2334 if (jsArgs != null) { | 2375 if (jsArgs != null) { |
| 2335 var genericName = _emitTopLevelName(element, suffix: '\$'); | 2376 var genericName = _emitTopLevelName(element, suffix: '\$'); |
| 2336 return js.call('#(#)', [genericName, jsArgs]); | 2377 return js.call('#(#)', [genericName, jsArgs]); |
| 2337 } | 2378 } |
| 2338 } | 2379 } |
| 2339 | 2380 |
| 2340 return _emitTopLevelName(element); | 2381 return _emitTopLevelName(element); |
| 2341 } | 2382 } |
| 2342 | 2383 |
| 2343 JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) { | 2384 JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) { |
| 2344 if (e is TopLevelVariableElement && | 2385 var interop = _emitJsInterop(e); |
| 2345 e.getter != null && | 2386 if (interop != null) return interop; |
| 2346 findAnnotation(e.getter, isPublicJSAnnotation) != null) { | |
| 2347 var annotationName = getAnnotationName(e.getter, isPublicJSAnnotation); | |
| 2348 var name = js.string(annotationName ?? e.name); | |
| 2349 return new JS.PropertyAccess(_self, name); | |
| 2350 } | |
| 2351 String name = getJSExportName(e) + suffix; | 2387 String name = getJSExportName(e) + suffix; |
| 2352 return new JS.PropertyAccess( | 2388 return new JS.PropertyAccess( |
| 2353 emitLibraryName(e.library), _propertyName(name)); | 2389 emitLibraryName(e.library), _propertyName(name)); |
| 2354 } | 2390 } |
| 2355 | 2391 |
| 2356 @override | 2392 @override |
| 2357 JS.Expression visitAssignmentExpression(AssignmentExpression node) { | 2393 JS.Expression visitAssignmentExpression(AssignmentExpression node) { |
| 2358 var left = node.leftHandSide; | 2394 var left = node.leftHandSide; |
| 2359 var right = node.rightHandSide; | 2395 var right = node.rightHandSide; |
| 2360 if (node.operator.type == TokenType.EQ) return _emitSet(left, right); | 2396 if (node.operator.type == TokenType.EQ) return _emitSet(left, right); |
| (...skipping 671 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3032 return getter | 3068 return getter |
| 3033 ? parent.getGetter(element.name) | 3069 ? parent.getGetter(element.name) |
| 3034 : parent.getSetter(element.name); | 3070 : parent.getSetter(element.name); |
| 3035 } | 3071 } |
| 3036 return null; | 3072 return null; |
| 3037 } | 3073 } |
| 3038 | 3074 |
| 3039 JS.Expression _emitConstructorName( | 3075 JS.Expression _emitConstructorName( |
| 3040 ConstructorElement element, DartType type, SimpleIdentifier name) { | 3076 ConstructorElement element, DartType type, SimpleIdentifier name) { |
| 3041 var classElem = element.enclosingElement; | 3077 var classElem = element.enclosingElement; |
| 3042 if (findAnnotation(classElem, isPublicJSAnnotation) != null) { | 3078 var interop = _emitJsInterop(classElem); |
| 3043 var annotationName = getAnnotationName(classElem, isPublicJSAnnotation); | 3079 if (interop != null) return interop; |
|
Jennifer Messerly
2016/05/19 17:38:04
fyi Siggi made a change to this in: https://codere
| |
| 3044 var typeName = js.string(annotationName ?? classElem.name); | |
| 3045 return new JS.PropertyAccess(_self, typeName); | |
| 3046 } | |
| 3047 var typeName = _emitType(type); | 3080 var typeName = _emitType(type); |
| 3048 if (name != null || element.isFactory) { | 3081 if (name != null || element.isFactory) { |
| 3049 var namedCtor = _constructorName(element); | 3082 var namedCtor = _constructorName(element); |
| 3050 return new JS.PropertyAccess(typeName, namedCtor); | 3083 return new JS.PropertyAccess(typeName, namedCtor); |
| 3051 } | 3084 } |
| 3052 return typeName; | 3085 return typeName; |
| 3053 } | 3086 } |
| 3054 | 3087 |
| 3055 @override | 3088 @override |
| 3056 visitConstructorName(ConstructorName node) { | 3089 visitConstructorName(ConstructorName node) { |
| (...skipping 1432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4489 } | 4522 } |
| 4490 | 4523 |
| 4491 bool isLibraryPrefix(Expression node) => | 4524 bool isLibraryPrefix(Expression node) => |
| 4492 node is SimpleIdentifier && node.staticElement is PrefixElement; | 4525 node is SimpleIdentifier && node.staticElement is PrefixElement; |
| 4493 | 4526 |
| 4494 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 4527 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
| 4495 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 4528 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
| 4496 | 4529 |
| 4497 bool _isDartRuntime(LibraryElement l) => | 4530 bool _isDartRuntime(LibraryElement l) => |
| 4498 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 4531 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
| OLD | NEW |