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 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 return module; | 278 return module; |
279 } | 279 } |
280 } | 280 } |
281 | 281 |
282 List<String> _getJSName(Element e) { | 282 List<String> _getJSName(Element e) { |
283 if (findAnnotation(e.library, isPublicJSAnnotation) == null) { | 283 if (findAnnotation(e.library, isPublicJSAnnotation) == null) { |
284 return null; | 284 return null; |
285 } | 285 } |
286 | 286 |
287 var libraryJSName = getAnnotationName(e.library, isPublicJSAnnotation); | 287 var libraryJSName = getAnnotationName(e.library, isPublicJSAnnotation); |
288 var libraryPrefix = []; | 288 var libraryPrefix = <String>[]; |
289 if (libraryJSName != null && libraryJSName.isNotEmpty) { | 289 if (libraryJSName != null && libraryJSName.isNotEmpty) { |
290 libraryPrefix.addAll(libraryJSName.split('.')); | 290 libraryPrefix.addAll(libraryJSName.split('.')); |
291 } | 291 } |
292 | 292 |
293 var elementJSName; | 293 String elementJSName; |
294 if (findAnnotation(e, isPublicJSAnnotation) != null) { | 294 if (findAnnotation(e, isPublicJSAnnotation) != null) { |
295 elementJSName = getAnnotationName(e, isPublicJSAnnotation) ?? ''; | 295 elementJSName = getAnnotationName(e, isPublicJSAnnotation) ?? ''; |
296 } | 296 } |
297 if (e is TopLevelVariableElement && | 297 if (e is TopLevelVariableElement && |
298 e.getter != null && | 298 e.getter != null && |
299 (e.getter.isExternal || | 299 (e.getter.isExternal || |
300 findAnnotation(e.getter, isPublicJSAnnotation) != null)) { | 300 findAnnotation(e.getter, isPublicJSAnnotation) != null)) { |
301 elementJSName = getAnnotationName(e.getter, isPublicJSAnnotation) ?? ''; | 301 elementJSName = getAnnotationName(e.getter, isPublicJSAnnotation) ?? ''; |
302 } | 302 } |
303 if (elementJSName == null) return null; | 303 if (elementJSName == null) return null; |
304 | 304 |
305 var elementJSParts = []; | 305 var elementJSParts = <String>[]; |
306 if (elementJSName.isNotEmpty) { | 306 if (elementJSName.isNotEmpty) { |
307 elementJSParts.addAll(elementJSName.split('.')); | 307 elementJSParts.addAll(elementJSName.split('.')); |
308 } else { | 308 } else { |
309 elementJSParts.add(e.name); | 309 elementJSParts.add(e.name); |
310 } | 310 } |
311 | 311 |
312 return libraryPrefix..addAll(elementJSParts); | 312 return libraryPrefix..addAll(elementJSParts); |
313 } | 313 } |
314 | 314 |
315 JS.Expression _emitJSInterop(Element e) { | 315 JS.Expression _emitJSInterop(Element e) { |
316 var jsName = _getJSName(e); | 316 var jsName = _getJSName(e); |
317 if (jsName == null) return null; | 317 if (jsName == null) return null; |
318 var fullName = ['global']..addAll(jsName); | 318 var fullName = ['global']..addAll(jsName); |
319 var access = _runtimeLibVar; | 319 JS.Expression access = _runtimeLibVar; |
320 for (var part in fullName) { | 320 for (var part in fullName) { |
321 access = new JS.PropertyAccess(access, js.string(part)); | 321 access = new JS.PropertyAccess(access, js.string(part)); |
322 } | 322 } |
323 return access; | 323 return access; |
324 } | 324 } |
325 | 325 |
326 /// Flattens blocks in [items] to a single list. | 326 /// Flattens blocks in [items] to a single list. |
327 /// | 327 /// |
328 /// This will not flatten blocks that are marked as being scopes. | 328 /// This will not flatten blocks that are marked as being scopes. |
329 void _copyAndFlattenBlocks( | 329 void _copyAndFlattenBlocks( |
(...skipping 362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
692 | 692 |
693 JS.Expression className; | 693 JS.Expression className; |
694 if (classElem.typeParameters.isNotEmpty) { | 694 if (classElem.typeParameters.isNotEmpty) { |
695 // Generic classes will be defined inside a function that closes over the | 695 // Generic classes will be defined inside a function that closes over the |
696 // type parameter. So we can use their local variable name directly. | 696 // type parameter. So we can use their local variable name directly. |
697 className = new JS.Identifier(classElem.name); | 697 className = new JS.Identifier(classElem.name); |
698 } else { | 698 } else { |
699 className = _emitTopLevelName(classElem); | 699 className = _emitTopLevelName(classElem); |
700 } | 700 } |
701 | 701 |
702 var allFields = new List.from(fields)..addAll(staticFields); | 702 var allFields = fields.toList()..addAll(staticFields); |
703 var superclasses = getSuperclasses(classElem); | 703 var superclasses = getSuperclasses(classElem); |
704 var virtualFields = <FieldElement, JS.TemporaryId>{}; | 704 var virtualFields = <FieldElement, JS.TemporaryId>{}; |
705 var virtualFieldSymbols = <JS.Statement>[]; | 705 var virtualFieldSymbols = <JS.Statement>[]; |
706 var staticFieldOverrides = new HashSet<FieldElement>(); | 706 var staticFieldOverrides = new HashSet<FieldElement>(); |
707 _registerPropertyOverrides(classElem, className, superclasses, allFields, | 707 _registerPropertyOverrides(classElem, className, superclasses, allFields, |
708 virtualFields, virtualFieldSymbols, staticFieldOverrides); | 708 virtualFields, virtualFieldSymbols, staticFieldOverrides); |
709 | 709 |
710 var classExpr = _emitClassExpression(classElem, | 710 var classExpr = _emitClassExpression(classElem, |
711 _emitClassMethods(node, ctors, fields, superclasses, virtualFields), | 711 _emitClassMethods(node, ctors, fields, superclasses, virtualFields), |
712 fields: allFields); | 712 fields: allFields); |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
942 /// conflicts. They will be installed as extension methods on the underlying | 942 /// conflicts. They will be installed as extension methods on the underlying |
943 /// native type. | 943 /// native type. |
944 List<JS.Method> _emitNativeFieldAccessors(FieldDeclaration node) { | 944 List<JS.Method> _emitNativeFieldAccessors(FieldDeclaration node) { |
945 // TODO(vsm): Can this by meta-programmed? | 945 // TODO(vsm): Can this by meta-programmed? |
946 // E.g., dart.nativeField(symbol, jsName) | 946 // E.g., dart.nativeField(symbol, jsName) |
947 // Alternatively, perhaps it could be meta-programmed directly in | 947 // Alternatively, perhaps it could be meta-programmed directly in |
948 // dart.registerExtensions? | 948 // dart.registerExtensions? |
949 var jsMethods = <JS.Method>[]; | 949 var jsMethods = <JS.Method>[]; |
950 if (!node.isStatic) { | 950 if (!node.isStatic) { |
951 for (var decl in node.fields.variables) { | 951 for (var decl in node.fields.variables) { |
952 var field = decl.element; | 952 var field = decl.element as FieldElement; |
953 var name = getAnnotationName(field, isJsName) ?? field.name; | 953 var name = getAnnotationName(field, isJsName) ?? field.name; |
954 // Generate getter | 954 // Generate getter |
955 var fn = new JS.Fun([], js.statement('{ return this.#; }', [name])); | 955 var fn = new JS.Fun([], js.statement('{ return this.#; }', [name])); |
956 var method = | 956 var method = |
957 new JS.Method(_elementMemberName(field.getter), fn, isGetter: true); | 957 new JS.Method(_elementMemberName(field.getter), fn, isGetter: true); |
958 jsMethods.add(method); | 958 jsMethods.add(method); |
959 | 959 |
960 // Generate setter | 960 // Generate setter |
961 if (!decl.isFinal) { | 961 if (!decl.isFinal) { |
962 var value = new JS.TemporaryId('value'); | 962 var value = new JS.TemporaryId('value'); |
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1344 List<MethodDeclaration> methods, | 1344 List<MethodDeclaration> methods, |
1345 List<FieldDeclaration> fields, | 1345 List<FieldDeclaration> fields, |
1346 List<JS.Statement> body) { | 1346 List<JS.Statement> body) { |
1347 if (_extensionTypes.hasNativeSubtype(classElem.type)) { | 1347 if (_extensionTypes.hasNativeSubtype(classElem.type)) { |
1348 var dartxNames = <JS.Expression>[]; | 1348 var dartxNames = <JS.Expression>[]; |
1349 for (var m in methods) { | 1349 for (var m in methods) { |
1350 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { | 1350 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { |
1351 dartxNames.add(_elementMemberName(m.element, useExtension: false)); | 1351 dartxNames.add(_elementMemberName(m.element, useExtension: false)); |
1352 } | 1352 } |
1353 } | 1353 } |
1354 for (var f in fields) { | 1354 for (var fieldDecl in fields) { |
1355 if (!f.isStatic) { | 1355 if (!fieldDecl.isStatic) { |
1356 for (var d in f.fields.variables) { | 1356 for (var field in fieldDecl.fields.variables) { |
1357 if (d.element.isPublic) { | 1357 var e = field.element as FieldElement; |
1358 dartxNames.add( | 1358 if (e.isPublic) { |
1359 _elementMemberName(d.element.getter, useExtension: false)); | 1359 dartxNames.add(_elementMemberName(e.getter, useExtension: false)); |
1360 } | 1360 } |
1361 } | 1361 } |
1362 } | 1362 } |
1363 } | 1363 } |
1364 if (dartxNames.isNotEmpty) { | 1364 if (dartxNames.isNotEmpty) { |
1365 body.add(js.statement('dart.defineExtensionNames(#)', | 1365 body.add(js.statement('dart.defineExtensionNames(#)', |
1366 [new JS.ArrayInitializer(dartxNames, multiline: true)])); | 1366 [new JS.ArrayInitializer(dartxNames, multiline: true)])); |
1367 } | 1367 } |
1368 } | 1368 } |
1369 } | 1369 } |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1535 if (jsSuper != null) body.add(jsSuper); | 1535 if (jsSuper != null) body.add(jsSuper); |
1536 | 1536 |
1537 body.add(_visit(node.body)); | 1537 body.add(_visit(node.body)); |
1538 return new JS.Block(body)..sourceInformation = node; | 1538 return new JS.Block(body)..sourceInformation = node; |
1539 } | 1539 } |
1540 | 1540 |
1541 @override | 1541 @override |
1542 JS.Statement visitRedirectingConstructorInvocation( | 1542 JS.Statement visitRedirectingConstructorInvocation( |
1543 RedirectingConstructorInvocation node) { | 1543 RedirectingConstructorInvocation node) { |
1544 var ctor = node.staticElement; | 1544 var ctor = node.staticElement; |
1545 var cls = ctor.enclosingElement as ClassElement; | 1545 var cls = ctor.enclosingElement; |
1546 // We can't dispatch to the constructor with `this.new` as that might hit a | 1546 // We can't dispatch to the constructor with `this.new` as that might hit a |
1547 // derived class constructor with the same name. | 1547 // derived class constructor with the same name. |
1548 return js.statement('#.prototype.#.call(this, #);', [ | 1548 return js.statement('#.prototype.#.call(this, #);', [ |
1549 new JS.Identifier(cls.name), | 1549 new JS.Identifier(cls.name), |
1550 _constructorName(ctor), | 1550 _constructorName(ctor), |
1551 _visit(node.argumentList) | 1551 _visit(node.argumentList) |
1552 ]); | 1552 ]); |
1553 } | 1553 } |
1554 | 1554 |
1555 JS.Statement _superConstructorCall(ClassElement element, | 1555 JS.Statement _superConstructorCall(ClassElement element, |
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1841 assert(node.parent is CompilationUnit); | 1841 assert(node.parent is CompilationUnit); |
1842 | 1842 |
1843 if (_externalOrNative(node)) return null; | 1843 if (_externalOrNative(node)) return null; |
1844 | 1844 |
1845 // If we have a getter/setter pair, they need to be defined together. | 1845 // If we have a getter/setter pair, they need to be defined together. |
1846 if (node.isGetter) { | 1846 if (node.isGetter) { |
1847 PropertyAccessorElement element = node.element; | 1847 PropertyAccessorElement element = node.element; |
1848 var props = <JS.Method>[_emitTopLevelProperty(node)]; | 1848 var props = <JS.Method>[_emitTopLevelProperty(node)]; |
1849 var setter = element.correspondingSetter; | 1849 var setter = element.correspondingSetter; |
1850 if (setter != null) { | 1850 if (setter != null) { |
1851 props.add(_loader.emitDeclaration(setter, _emitTopLevelProperty)); | 1851 props.add(_loader.emitDeclaration( |
| 1852 setter, (node) => _emitTopLevelProperty(node))); |
1852 } | 1853 } |
1853 return js.statement('dart.copyProperties(#, { # });', | 1854 return js.statement('dart.copyProperties(#, { # });', |
1854 [emitLibraryName(currentLibrary), props]); | 1855 [emitLibraryName(currentLibrary), props]); |
1855 } | 1856 } |
1856 if (node.isSetter) { | 1857 if (node.isSetter) { |
1857 PropertyAccessorElement element = node.element; | 1858 PropertyAccessorElement element = node.element; |
1858 var props = <JS.Method>[_emitTopLevelProperty(node)]; | 1859 var props = <JS.Method>[_emitTopLevelProperty(node)]; |
1859 var getter = element.correspondingGetter; | 1860 var getter = element.correspondingGetter; |
1860 if (getter != null) { | 1861 if (getter != null) { |
1861 props.add(_loader.emitDeclaration(getter, _emitTopLevelProperty)); | 1862 props.add(_loader.emitDeclaration( |
| 1863 getter, (node) => _emitTopLevelProperty(node))); |
1862 } | 1864 } |
1863 return js.statement('dart.copyProperties(#, { # });', | 1865 return js.statement('dart.copyProperties(#, { # });', |
1864 [emitLibraryName(currentLibrary), props]); | 1866 [emitLibraryName(currentLibrary), props]); |
1865 } | 1867 } |
1866 | 1868 |
1867 var body = <JS.Statement>[]; | 1869 var body = <JS.Statement>[]; |
1868 var fn = _emitFunction(node.functionExpression); | 1870 var fn = _emitFunction(node.functionExpression); |
1869 | 1871 |
1870 if (currentLibrary.source.isInSystemLibrary && | 1872 if (currentLibrary.source.isInSystemLibrary && |
1871 _isInlineJSFunction(node.functionExpression)) { | 1873 _isInlineJSFunction(node.functionExpression)) { |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1976 @override | 1978 @override |
1977 JS.Expression visitFunctionExpression(FunctionExpression node) { | 1979 JS.Expression visitFunctionExpression(FunctionExpression node) { |
1978 assert(node.parent is! FunctionDeclaration && | 1980 assert(node.parent is! FunctionDeclaration && |
1979 node.parent is! MethodDeclaration); | 1981 node.parent is! MethodDeclaration); |
1980 return _emitFunctionTagged(_emitArrowFunction(node), getStaticType(node), | 1982 return _emitFunctionTagged(_emitArrowFunction(node), getStaticType(node), |
1981 topLevel: _executesAtTopLevel(node)); | 1983 topLevel: _executesAtTopLevel(node)); |
1982 } | 1984 } |
1983 | 1985 |
1984 JS.ArrowFun _emitArrowFunction(FunctionExpression node) { | 1986 JS.ArrowFun _emitArrowFunction(FunctionExpression node) { |
1985 JS.Fun f = _emitFunctionBody(node.element, node.parameters, node.body); | 1987 JS.Fun f = _emitFunctionBody(node.element, node.parameters, node.body); |
1986 var body = f.body; | 1988 JS.Node body = f.body; |
1987 | 1989 |
1988 // Simplify `=> { return e; }` to `=> e` | 1990 // Simplify `=> { return e; }` to `=> e` |
1989 if (body is JS.Block) { | 1991 if (body is JS.Block) { |
1990 JS.Block block = body; | 1992 JS.Block block = body; |
1991 if (block.statements.length == 1) { | 1993 if (block.statements.length == 1) { |
1992 JS.Statement s = block.statements[0]; | 1994 JS.Statement s = block.statements[0]; |
1993 if (s is JS.Return) body = s.value; | 1995 if (s is JS.Return) body = s.value; |
1994 } | 1996 } |
1995 } | 1997 } |
1996 | 1998 |
1997 // Convert `function(...) { ... }` to `(...) => ...` | 1999 // Convert `function(...) { ... }` to `(...) => ...` |
1998 // This is for readability, but it also ensures correct `this` binding. | 2000 // This is for readability, but it also ensures correct `this` binding. |
1999 var fn = new JS.ArrowFun(f.params, body, | 2001 var fn = new JS.ArrowFun(f.params, body, |
2000 typeParams: f.typeParams, returnType: f.returnType); | 2002 typeParams: f.typeParams, returnType: f.returnType); |
2001 | 2003 |
2002 return annotate(_makeGenericFunction(fn), node); | 2004 return annotate(_makeGenericArrowFun(fn), node); |
2003 } | 2005 } |
2004 | 2006 |
2005 JS.FunctionExpression/*=T*/ _makeGenericFunction | 2007 JS.ArrowFun _makeGenericArrowFun(JS.ArrowFun fn) { |
2006 /*<T extends JS.FunctionExpression>*/(JS.FunctionExpression/*=T*/ fn) { | 2008 if (fn.typeParams == null || fn.typeParams.isEmpty) return fn; |
| 2009 return new JS.ArrowFun(fn.typeParams, fn); |
| 2010 } |
| 2011 |
| 2012 JS.Fun _makeGenericFunction(JS.Fun fn) { |
2007 if (fn.typeParams == null || fn.typeParams.isEmpty) return fn; | 2013 if (fn.typeParams == null || fn.typeParams.isEmpty) return fn; |
2008 | 2014 |
2009 // TODO(jmesserly): we could make these default to `dynamic`. | 2015 // TODO(jmesserly): we could make these default to `dynamic`. |
2010 var typeParams = fn.typeParams; | |
2011 if (fn is JS.ArrowFun) { | |
2012 return new JS.ArrowFun(typeParams, fn); | |
2013 } | |
2014 var f = fn as JS.Fun; | |
2015 return new JS.Fun( | 2016 return new JS.Fun( |
2016 typeParams, | 2017 fn.typeParams, |
2017 new JS.Block([ | 2018 new JS.Block([ |
2018 // Convert the function to an => function, to ensure `this` binding. | 2019 // Convert the function to an => function, to ensure `this` binding. |
2019 new JS.Return(new JS.ArrowFun(f.params, f.body, | 2020 new JS.Return(new JS.ArrowFun(fn.params, fn.body, |
2020 typeParams: f.typeParams, returnType: f.returnType)) | 2021 typeParams: fn.typeParams, returnType: fn.returnType)) |
2021 ])); | 2022 ])); |
2022 } | 2023 } |
2023 | 2024 |
2024 /// Emits a non-arrow FunctionExpression node. | 2025 /// Emits a non-arrow FunctionExpression node. |
2025 /// | 2026 /// |
2026 /// This should be used for all places in Dart's AST where FunctionExpression | 2027 /// This should be used for all places in Dart's AST where FunctionExpression |
2027 /// appears but the function is not actually in an Expression context, such | 2028 /// appears but the function is not actually in an Expression context, such |
2028 /// as methods, properties, and top-level functions. | 2029 /// as methods, properties, and top-level functions. |
2029 /// | 2030 /// |
2030 /// Contrast with [visitFunctionExpression]. | 2031 /// Contrast with [visitFunctionExpression]. |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2084 // In the body of a `sync*` and `async`, `yield`/`await` are both generated | 2085 // In the body of a `sync*` and `async`, `yield`/`await` are both generated |
2085 // simply as `yield`. | 2086 // simply as `yield`. |
2086 // | 2087 // |
2087 // `async*` uses the `dart.asyncStar` helper, and also has an extra `stream` | 2088 // `async*` uses the `dart.asyncStar` helper, and also has an extra `stream` |
2088 // argument to the generator, which is used for passing values to the | 2089 // argument to the generator, which is used for passing values to the |
2089 // _AsyncStarStreamController implementation type. | 2090 // _AsyncStarStreamController implementation type. |
2090 // `yield` is specially generated inside `async*`, see visitYieldStatement. | 2091 // `yield` is specially generated inside `async*`, see visitYieldStatement. |
2091 // `await` is generated as `yield`. | 2092 // `await` is generated as `yield`. |
2092 // runtime/_generators.js has an example of what the code is generated as. | 2093 // runtime/_generators.js has an example of what the code is generated as. |
2093 var savedController = _asyncStarController; | 2094 var savedController = _asyncStarController; |
2094 List jsParams = visitFormalParameterList(parameters); | 2095 var jsParams = visitFormalParameterList(parameters); |
2095 if (kind == 'asyncStar') { | 2096 if (kind == 'asyncStar') { |
2096 _asyncStarController = new JS.TemporaryId('stream'); | 2097 _asyncStarController = new JS.TemporaryId('stream'); |
2097 jsParams.insert(0, _asyncStarController); | 2098 jsParams.insert(0, _asyncStarController); |
2098 } else { | 2099 } else { |
2099 _asyncStarController = null; | 2100 _asyncStarController = null; |
2100 } | 2101 } |
2101 var savedSuperAllowed = _superAllowed; | 2102 var savedSuperAllowed = _superAllowed; |
2102 _superAllowed = false; | 2103 _superAllowed = false; |
2103 // Visit the body with our async* controller set. | 2104 // Visit the body with our async* controller set. |
2104 var jsBody = _visit(body); | 2105 var jsBody = _visit(body); |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2278 List<DartType> types, List<FormalParameter> parameters, | 2279 List<DartType> types, List<FormalParameter> parameters, |
2279 {bool nameType: true, bool hoistType: true}) { | 2280 {bool nameType: true, bool hoistType: true}) { |
2280 var result = <JS.Expression>[]; | 2281 var result = <JS.Expression>[]; |
2281 for (int i = 0; i < types.length; ++i) { | 2282 for (int i = 0; i < types.length; ++i) { |
2282 var metadata = | 2283 var metadata = |
2283 parameters != null ? _parameterMetadata(parameters[i]) : []; | 2284 parameters != null ? _parameterMetadata(parameters[i]) : []; |
2284 var typeName = | 2285 var typeName = |
2285 _emitType(types[i], nameType: nameType, hoistType: hoistType); | 2286 _emitType(types[i], nameType: nameType, hoistType: hoistType); |
2286 var value = typeName; | 2287 var value = typeName; |
2287 if (options.emitMetadata && metadata.isNotEmpty) { | 2288 if (options.emitMetadata && metadata.isNotEmpty) { |
2288 metadata = metadata.map(_instantiateAnnotation).toList(); | 2289 value = new JS.ArrayInitializer( |
2289 value = new JS.ArrayInitializer([typeName]..addAll(metadata)); | 2290 [typeName]..addAll(metadata.map(_instantiateAnnotation))); |
2290 } | 2291 } |
2291 result.add(value); | 2292 result.add(value); |
2292 } | 2293 } |
2293 return new JS.ArrayInitializer(result); | 2294 return new JS.ArrayInitializer(result); |
2294 } | 2295 } |
2295 | 2296 |
2296 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { | 2297 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { |
2297 var properties = <JS.Property>[]; | 2298 var properties = <JS.Property>[]; |
2298 types.forEach((name, type) { | 2299 types.forEach((name, type) { |
2299 var key = _propertyName(name); | 2300 var key = _propertyName(name); |
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2592 | 2593 |
2593 var target = _getTarget(node); | 2594 var target = _getTarget(node); |
2594 if (target == null || isLibraryPrefix(target)) { | 2595 if (target == null || isLibraryPrefix(target)) { |
2595 return _emitFunctionCall(node); | 2596 return _emitFunctionCall(node); |
2596 } | 2597 } |
2597 | 2598 |
2598 return _emitMethodCall(target, node); | 2599 return _emitMethodCall(target, node); |
2599 } | 2600 } |
2600 | 2601 |
2601 JS.Expression _emitMethodCall(Expression target, MethodInvocation node) { | 2602 JS.Expression _emitMethodCall(Expression target, MethodInvocation node) { |
2602 List<JS.Expression> args = _visit(node.argumentList); | 2603 var args = _visit(node.argumentList) as List<JS.Expression>; |
2603 var typeArgs = _emitInvokeTypeArguments(node); | 2604 var typeArgs = _emitInvokeTypeArguments(node); |
2604 | 2605 |
2605 if (target is SuperExpression && !_superAllowed) { | 2606 if (target is SuperExpression && !_superAllowed) { |
2606 return _emitSuperHelperCall(typeArgs, args, target, node); | 2607 return _emitSuperHelperCall(typeArgs, args, target, node); |
2607 } | 2608 } |
2608 | 2609 |
2609 return _emitMethodCallInternal(target, node, args, typeArgs); | 2610 return _emitMethodCallInternal(target, node, args, typeArgs); |
2610 } | 2611 } |
2611 | 2612 |
2612 JS.Expression _emitSuperHelperCall(List<JS.Expression> typeArgs, | 2613 JS.Expression _emitSuperHelperCall(List<JS.Expression> typeArgs, |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2679 jsTarget = new JS.PropertyAccess(jsTarget, memberName); | 2680 jsTarget = new JS.PropertyAccess(jsTarget, memberName); |
2680 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); | 2681 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); |
2681 | 2682 |
2682 return new JS.Call(jsTarget, args); | 2683 return new JS.Call(jsTarget, args); |
2683 } | 2684 } |
2684 | 2685 |
2685 /// Emits a function call, to a top-level function, local function, or | 2686 /// Emits a function call, to a top-level function, local function, or |
2686 /// an expression. | 2687 /// an expression. |
2687 JS.Expression _emitFunctionCall(InvocationExpression node) { | 2688 JS.Expression _emitFunctionCall(InvocationExpression node) { |
2688 var fn = _visit(node.function); | 2689 var fn = _visit(node.function); |
2689 var args = _visit(node.argumentList); | 2690 var args = _visit(node.argumentList) as List<JS.Expression>; |
2690 if (DynamicInvoke.get(node.function)) { | 2691 if (DynamicInvoke.get(node.function)) { |
2691 var typeArgs = _emitInvokeTypeArguments(node); | 2692 var typeArgs = _emitInvokeTypeArguments(node); |
2692 if (typeArgs != null) { | 2693 if (typeArgs != null) { |
2693 return js.call('dart.dgcall(#, #, #)', | 2694 return js.call('dart.dgcall(#, #, #)', |
2694 [fn, new JS.ArrayInitializer(typeArgs), args]); | 2695 [fn, new JS.ArrayInitializer(typeArgs), args]); |
2695 } else { | 2696 } else { |
2696 if (_inAngularTemplate) { | 2697 if (_inAngularTemplate) { |
2697 return new JS.Call(fn, args); | 2698 return new JS.Call(fn, args); |
2698 } | 2699 } |
2699 return js.call('dart.dcall(#, #)', [fn, args]); | 2700 return js.call('dart.dcall(#, #)', [fn, args]); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2759 return f.typeArguments.skip(g.typeArguments.length); | 2760 return f.typeArguments.skip(g.typeArguments.length); |
2760 } | 2761 } |
2761 | 2762 |
2762 /// Emits code for the `JS(...)` macro. | 2763 /// Emits code for the `JS(...)` macro. |
2763 _emitForeignJS(MethodInvocation node) { | 2764 _emitForeignJS(MethodInvocation node) { |
2764 var e = node.methodName.staticElement; | 2765 var e = node.methodName.staticElement; |
2765 if (isInlineJS(e)) { | 2766 if (isInlineJS(e)) { |
2766 var args = node.argumentList.arguments; | 2767 var args = node.argumentList.arguments; |
2767 // arg[0] is static return type, used in `RestrictedStaticTypeAnalyzer` | 2768 // arg[0] is static return type, used in `RestrictedStaticTypeAnalyzer` |
2768 var code = args[1]; | 2769 var code = args[1]; |
2769 var templateArgs; | 2770 List<AstNode> templateArgs; |
2770 var source; | 2771 var source; |
2771 if (code is StringInterpolation) { | 2772 if (code is StringInterpolation) { |
2772 if (args.length > 2) { | 2773 if (args.length > 2) { |
2773 throw new ArgumentError( | 2774 throw new ArgumentError( |
2774 "Can't mix template args and string interpolation in JS calls."); | 2775 "Can't mix template args and string interpolation in JS calls."); |
2775 } | 2776 } |
2776 templateArgs = <Expression>[]; | 2777 templateArgs = <Expression>[]; |
2777 source = code.elements.map((element) { | 2778 source = code.elements.map((element) { |
2778 if (element is InterpolationExpression) { | 2779 if (element is InterpolationExpression) { |
2779 templateArgs.add(element.expression); | 2780 templateArgs.add(element.expression); |
2780 return '#'; | 2781 return '#'; |
2781 } else { | 2782 } else { |
2782 return (element as InterpolationString).value; | 2783 return (element as InterpolationString).value; |
2783 } | 2784 } |
2784 }).join(); | 2785 }).join(); |
2785 } else { | 2786 } else { |
2786 templateArgs = args.skip(2); | 2787 templateArgs = args.skip(2).toList(); |
2787 source = (code as StringLiteral).stringValue; | 2788 source = (code as StringLiteral).stringValue; |
2788 } | 2789 } |
2789 | 2790 |
2790 // TODO(rnystrom): The JS() calls are almost never nested, and probably | 2791 // TODO(rnystrom): The JS() calls are almost never nested, and probably |
2791 // really shouldn't be, but there are at least a couple of calls in the | 2792 // really shouldn't be, but there are at least a couple of calls in the |
2792 // HTML library where an argument to JS() is itself a JS() call. If those | 2793 // HTML library where an argument to JS() is itself a JS() call. If those |
2793 // go away, this can just assert(!_isInForeignJS). | 2794 // go away, this can just assert(!_isInForeignJS). |
2794 // Inside JS(), type names evaluate to the raw runtime type, not the | 2795 // Inside JS(), type names evaluate to the raw runtime type, not the |
2795 // wrapped Type object. | 2796 // wrapped Type object. |
2796 var wasInForeignJS = _isInForeignJS; | 2797 var wasInForeignJS = _isInForeignJS; |
(...skipping 1261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4058 // await iter.cancel(); | 4059 // await iter.cancel(); |
4059 // } | 4060 // } |
4060 // | 4061 // |
4061 // Like the Dart VM, we call cancel() always, as it's safe to call if the | 4062 // Like the Dart VM, we call cancel() always, as it's safe to call if the |
4062 // stream has already been cancelled. | 4063 // stream has already been cancelled. |
4063 // | 4064 // |
4064 // TODO(jmesserly): we may want a helper if these become common. For now the | 4065 // TODO(jmesserly): we may want a helper if these become common. For now the |
4065 // full desugaring seems okay. | 4066 // full desugaring seems okay. |
4066 var streamIterator = rules.instantiateToBounds(_asyncStreamIterator); | 4067 var streamIterator = rules.instantiateToBounds(_asyncStreamIterator); |
4067 var createStreamIter = _emitInstanceCreationExpression( | 4068 var createStreamIter = _emitInstanceCreationExpression( |
4068 streamIterator.element.unnamedConstructor, | 4069 (streamIterator.element as ClassElement).unnamedConstructor, |
4069 streamIterator, | 4070 streamIterator, |
4070 null, | 4071 null, |
4071 AstBuilder.argumentList([node.iterable]), | 4072 AstBuilder.argumentList([node.iterable]), |
4072 false); | 4073 false); |
4073 var iter = _visit(_createTemporary('it', streamIterator, nullable: false)); | 4074 var iter = _visit(_createTemporary('it', streamIterator, nullable: false)); |
4074 | 4075 |
4075 var init = _visit(node.identifier); | 4076 var init = _visit(node.identifier); |
4076 if (init == null) { | 4077 if (init == null) { |
4077 init = js | 4078 init = js |
4078 .call('let # = #.current', [node.loopVariable.identifier.name, iter]); | 4079 .call('let # = #.current', [node.loopVariable.identifier.name, iter]); |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4359 _visit(AstNode node) { | 4360 _visit(AstNode node) { |
4360 if (node == null) return null; | 4361 if (node == null) return null; |
4361 var result = node.accept(this); | 4362 var result = node.accept(this); |
4362 if (result is JS.Node) result = annotate(result, node); | 4363 if (result is JS.Node) result = annotate(result, node); |
4363 return result; | 4364 return result; |
4364 } | 4365 } |
4365 | 4366 |
4366 List/*<T>*/ _visitList/*<T extends AstNode>*/(Iterable/*<T>*/ nodes) { | 4367 List/*<T>*/ _visitList/*<T extends AstNode>*/(Iterable/*<T>*/ nodes) { |
4367 if (nodes == null) return null; | 4368 if (nodes == null) return null; |
4368 var result = /*<T>*/ []; | 4369 var result = /*<T>*/ []; |
4369 for (var node in nodes) result.add(_visit(node)); | 4370 for (var node in nodes) result.add(_visit(node) as dynamic/*=T*/); |
4370 return result; | 4371 return result; |
4371 } | 4372 } |
4372 | 4373 |
4373 /// Visits a list of expressions, creating a comma expression if needed in JS. | 4374 /// Visits a list of expressions, creating a comma expression if needed in JS. |
4374 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) { | 4375 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) { |
4375 if (nodes == null || nodes.isEmpty) return null; | 4376 if (nodes == null || nodes.isEmpty) return null; |
4376 return new JS.Expression.binary( | 4377 return new JS.Expression.binary( |
4377 _visitList(nodes) as List<JS.Expression>, operator); | 4378 _visitList(nodes) as List<JS.Expression>, operator); |
4378 } | 4379 } |
4379 | 4380 |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4492 // conflict. We could use practically any character for this. | 4493 // conflict. We could use practically any character for this. |
4493 name = '+$name'; | 4494 name = '+$name'; |
4494 } | 4495 } |
4495 | 4496 |
4496 var result = _propertyName(name); | 4497 var result = _propertyName(name); |
4497 | 4498 |
4498 if (useExtension == null) { | 4499 if (useExtension == null) { |
4499 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. | 4500 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. |
4500 var baseType = type; | 4501 var baseType = type; |
4501 while (baseType is TypeParameterType) { | 4502 while (baseType is TypeParameterType) { |
4502 baseType = baseType.element.bound; | 4503 baseType = (baseType.element as TypeParameterElement).bound; |
4503 } | 4504 } |
4504 useExtension = baseType != null && | 4505 useExtension = baseType != null && |
4505 _extensionTypes.hasNativeSubtype(baseType) && | 4506 _extensionTypes.hasNativeSubtype(baseType) && |
4506 !isObjectMember(name); | 4507 !isObjectMember(name); |
4507 } | 4508 } |
4508 | 4509 |
4509 return useExtension ? js.call('dartx.#', result) : result; | 4510 return useExtension ? js.call('dartx.#', result) : result; |
4510 } | 4511 } |
4511 | 4512 |
4512 JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) { | 4513 JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) { |
(...skipping 19 matching lines...) Expand all Loading... |
4532 return _libraries[library] ?? | 4533 return _libraries[library] ?? |
4533 _imports.putIfAbsent(library, | 4534 _imports.putIfAbsent(library, |
4534 () => new JS.TemporaryId(jsLibraryName(_buildRoot, library))); | 4535 () => new JS.TemporaryId(jsLibraryName(_buildRoot, library))); |
4535 } | 4536 } |
4536 | 4537 |
4537 JS.Node/*=T*/ annotate/*<T extends JS.Node>*/( | 4538 JS.Node/*=T*/ annotate/*<T extends JS.Node>*/( |
4538 JS.Node/*=T*/ node, AstNode original, | 4539 JS.Node/*=T*/ node, AstNode original, |
4539 [Element element]) { | 4540 [Element element]) { |
4540 if (options.closure && element != null) { | 4541 if (options.closure && element != null) { |
4541 node = node.withClosureAnnotation(closureAnnotationFor( | 4542 node = node.withClosureAnnotation(closureAnnotationFor( |
4542 node, original, element, namedArgumentTemp.name)); | 4543 node, original, element, namedArgumentTemp.name)) as dynamic/*=T*/; |
4543 } | 4544 } |
4544 return node..sourceInformation = original; | 4545 return node..sourceInformation = original; |
4545 } | 4546 } |
4546 | 4547 |
4547 /// Returns true if this is any kind of object represented by `Number` in JS. | 4548 /// Returns true if this is any kind of object represented by `Number` in JS. |
4548 /// | 4549 /// |
4549 /// In practice, this is 4 types: num, int, double, and JSNumber. | 4550 /// In practice, this is 4 types: num, int, double, and JSNumber. |
4550 /// | 4551 /// |
4551 /// JSNumber is the type that actually "implements" all numbers, hence it's | 4552 /// JSNumber is the type that actually "implements" all numbers, hence it's |
4552 /// a subtype of int and double (and num). It's in our "dart:_interceptors". | 4553 /// a subtype of int and double (and num). It's in our "dart:_interceptors". |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4660 } | 4661 } |
4661 | 4662 |
4662 bool isLibraryPrefix(Expression node) => | 4663 bool isLibraryPrefix(Expression node) => |
4663 node is SimpleIdentifier && node.staticElement is PrefixElement; | 4664 node is SimpleIdentifier && node.staticElement is PrefixElement; |
4664 | 4665 |
4665 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 4666 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
4666 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 4667 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
4667 | 4668 |
4668 bool _isDartRuntime(LibraryElement l) => | 4669 bool _isDartRuntime(LibraryElement l) => |
4669 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 4670 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
OLD | NEW |