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 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
276 return module; | 276 return module; |
277 } | 277 } |
278 } | 278 } |
279 | 279 |
280 List<String> _getJSName(Element e) { | 280 List<String> _getJSName(Element e) { |
281 if (findAnnotation(e.library, isPublicJSAnnotation) == null) { | 281 if (findAnnotation(e.library, isPublicJSAnnotation) == null) { |
282 return null; | 282 return null; |
283 } | 283 } |
284 | 284 |
285 var libraryJSName = getAnnotationName(e.library, isPublicJSAnnotation); | 285 var libraryJSName = getAnnotationName(e.library, isPublicJSAnnotation); |
286 var libraryPrefix = []; | 286 var libraryPrefix = <String>[]; |
287 if (libraryJSName != null && libraryJSName.isNotEmpty) { | 287 if (libraryJSName != null && libraryJSName.isNotEmpty) { |
288 libraryPrefix.addAll(libraryJSName.split('.')); | 288 libraryPrefix.addAll(libraryJSName.split('.')); |
289 } | 289 } |
290 | 290 |
291 var elementJSName; | 291 String elementJSName; |
292 if (findAnnotation(e, isPublicJSAnnotation) != null) { | 292 if (findAnnotation(e, isPublicJSAnnotation) != null) { |
293 elementJSName = getAnnotationName(e, isPublicJSAnnotation) ?? ''; | 293 elementJSName = getAnnotationName(e, isPublicJSAnnotation) ?? ''; |
294 } | 294 } |
295 if (e is TopLevelVariableElement && | 295 if (e is TopLevelVariableElement && |
296 e.getter != null && | 296 e.getter != null && |
297 (e.getter.isExternal || | 297 (e.getter.isExternal || |
298 findAnnotation(e.getter, isPublicJSAnnotation) != null)) { | 298 findAnnotation(e.getter, isPublicJSAnnotation) != null)) { |
299 elementJSName = getAnnotationName(e.getter, isPublicJSAnnotation) ?? ''; | 299 elementJSName = getAnnotationName(e.getter, isPublicJSAnnotation) ?? ''; |
300 } | 300 } |
301 if (elementJSName == null) return null; | 301 if (elementJSName == null) return null; |
302 | 302 |
303 var elementJSParts = []; | 303 var elementJSParts = <String>[]; |
304 if (elementJSName.isNotEmpty) { | 304 if (elementJSName.isNotEmpty) { |
305 elementJSParts.addAll(elementJSName.split('.')); | 305 elementJSParts.addAll(elementJSName.split('.')); |
306 } else { | 306 } else { |
307 elementJSParts.add(e.name); | 307 elementJSParts.add(e.name); |
308 } | 308 } |
309 | 309 |
310 return libraryPrefix..addAll(elementJSParts); | 310 return libraryPrefix..addAll(elementJSParts); |
311 } | 311 } |
312 | 312 |
313 JS.Expression _emitJSInterop(Element e) { | 313 JS.Expression _emitJSInterop(Element e) { |
314 var jsName = _getJSName(e); | 314 var jsName = _getJSName(e); |
315 if (jsName == null) return null; | 315 if (jsName == null) return null; |
316 var fullName = ['global']..addAll(jsName); | 316 var fullName = ['global']..addAll(jsName); |
317 var access = _runtimeLibVar; | 317 JS.Expression access = _runtimeLibVar; |
318 for (var part in fullName) { | 318 for (var part in fullName) { |
319 access = new JS.PropertyAccess(access, js.string(part)); | 319 access = new JS.PropertyAccess(access, js.string(part)); |
320 } | 320 } |
321 return access; | 321 return access; |
322 } | 322 } |
323 | 323 |
324 /// Flattens blocks in [items] to a single list. | 324 /// Flattens blocks in [items] to a single list. |
325 /// | 325 /// |
326 /// This will not flatten blocks that are marked as being scopes. | 326 /// This will not flatten blocks that are marked as being scopes. |
327 void _copyAndFlattenBlocks( | 327 void _copyAndFlattenBlocks( |
(...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
685 | 685 |
686 JS.Expression className; | 686 JS.Expression className; |
687 if (classElem.typeParameters.isNotEmpty) { | 687 if (classElem.typeParameters.isNotEmpty) { |
688 // Generic classes will be defined inside a function that closes over the | 688 // Generic classes will be defined inside a function that closes over the |
689 // type parameter. So we can use their local variable name directly. | 689 // type parameter. So we can use their local variable name directly. |
690 className = new JS.Identifier(classElem.name); | 690 className = new JS.Identifier(classElem.name); |
691 } else { | 691 } else { |
692 className = _emitTopLevelName(classElem); | 692 className = _emitTopLevelName(classElem); |
693 } | 693 } |
694 | 694 |
695 var allFields = new List.from(fields)..addAll(staticFields); | 695 var allFields = fields.toList()..addAll(staticFields); |
696 var superclasses = getSuperclasses(classElem); | 696 var superclasses = getSuperclasses(classElem); |
697 var virtualFields = <FieldElement, JS.TemporaryId>{}; | 697 var virtualFields = <FieldElement, JS.TemporaryId>{}; |
698 var virtualFieldSymbols = <JS.Statement>[]; | 698 var virtualFieldSymbols = <JS.Statement>[]; |
699 var staticFieldOverrides = new HashSet<FieldElement>(); | 699 var staticFieldOverrides = new HashSet<FieldElement>(); |
700 _registerPropertyOverrides(classElem, className, superclasses, allFields, | 700 _registerPropertyOverrides(classElem, className, superclasses, allFields, |
701 virtualFields, virtualFieldSymbols, staticFieldOverrides); | 701 virtualFields, virtualFieldSymbols, staticFieldOverrides); |
702 | 702 |
703 var classExpr = _emitClassExpression(classElem, | 703 var classExpr = _emitClassExpression(classElem, |
704 _emitClassMethods(node, ctors, fields, superclasses, virtualFields), | 704 _emitClassMethods(node, ctors, fields, superclasses, virtualFields), |
705 fields: allFields); | 705 fields: allFields); |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
935 /// conflicts. They will be installed as extension methods on the underlying | 935 /// conflicts. They will be installed as extension methods on the underlying |
936 /// native type. | 936 /// native type. |
937 List<JS.Method> _emitNativeFieldAccessors(FieldDeclaration node) { | 937 List<JS.Method> _emitNativeFieldAccessors(FieldDeclaration node) { |
938 // TODO(vsm): Can this by meta-programmed? | 938 // TODO(vsm): Can this by meta-programmed? |
939 // E.g., dart.nativeField(symbol, jsName) | 939 // E.g., dart.nativeField(symbol, jsName) |
940 // Alternatively, perhaps it could be meta-programmed directly in | 940 // Alternatively, perhaps it could be meta-programmed directly in |
941 // dart.registerExtensions? | 941 // dart.registerExtensions? |
942 var jsMethods = <JS.Method>[]; | 942 var jsMethods = <JS.Method>[]; |
943 if (!node.isStatic) { | 943 if (!node.isStatic) { |
944 for (var decl in node.fields.variables) { | 944 for (var decl in node.fields.variables) { |
945 var field = decl.element; | 945 var field = decl.element as FieldElement; |
946 var name = getAnnotationName(field, isJsName) ?? field.name; | 946 var name = getAnnotationName(field, isJsName) ?? field.name; |
947 // Generate getter | 947 // Generate getter |
948 var fn = new JS.Fun([], js.statement('{ return this.#; }', [name])); | 948 var fn = new JS.Fun([], js.statement('{ return this.#; }', [name])); |
949 var method = | 949 var method = |
950 new JS.Method(_elementMemberName(field.getter), fn, isGetter: true); | 950 new JS.Method(_elementMemberName(field.getter), fn, isGetter: true); |
951 jsMethods.add(method); | 951 jsMethods.add(method); |
952 | 952 |
953 // Generate setter | 953 // Generate setter |
954 if (!decl.isFinal) { | 954 if (!decl.isFinal) { |
955 var value = new JS.TemporaryId('value'); | 955 var value = new JS.TemporaryId('value'); |
(...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1337 List<MethodDeclaration> methods, | 1337 List<MethodDeclaration> methods, |
1338 List<FieldDeclaration> fields, | 1338 List<FieldDeclaration> fields, |
1339 List<JS.Statement> body) { | 1339 List<JS.Statement> body) { |
1340 if (_extensionTypes.hasNativeSubtype(classElem.type)) { | 1340 if (_extensionTypes.hasNativeSubtype(classElem.type)) { |
1341 var dartxNames = <JS.Expression>[]; | 1341 var dartxNames = <JS.Expression>[]; |
1342 for (var m in methods) { | 1342 for (var m in methods) { |
1343 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { | 1343 if (!m.isAbstract && !m.isStatic && m.element.isPublic) { |
1344 dartxNames.add(_elementMemberName(m.element, useExtension: false)); | 1344 dartxNames.add(_elementMemberName(m.element, useExtension: false)); |
1345 } | 1345 } |
1346 } | 1346 } |
1347 for (var f in fields) { | 1347 for (var fieldDecl in fields) { |
1348 if (!f.isStatic) { | 1348 if (!fieldDecl.isStatic) { |
1349 for (var d in f.fields.variables) { | 1349 for (var field in fieldDecl.fields.variables) { |
1350 if (d.element.isPublic) { | 1350 var e = field.element as FieldElement; |
1351 dartxNames.add( | 1351 if (e.isPublic) { |
1352 _elementMemberName(d.element.getter, useExtension: false)); | 1352 dartxNames.add(_elementMemberName(e.getter, useExtension: false)); |
1353 } | 1353 } |
1354 } | 1354 } |
1355 } | 1355 } |
1356 } | 1356 } |
1357 if (dartxNames.isNotEmpty) { | 1357 if (dartxNames.isNotEmpty) { |
1358 body.add(js.statement('dart.defineExtensionNames(#)', | 1358 body.add(js.statement('dart.defineExtensionNames(#)', |
1359 [new JS.ArrayInitializer(dartxNames, multiline: true)])); | 1359 [new JS.ArrayInitializer(dartxNames, multiline: true)])); |
1360 } | 1360 } |
1361 } | 1361 } |
1362 } | 1362 } |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1528 if (jsSuper != null) body.add(jsSuper); | 1528 if (jsSuper != null) body.add(jsSuper); |
1529 | 1529 |
1530 body.add(_visit(node.body)); | 1530 body.add(_visit(node.body)); |
1531 return new JS.Block(body)..sourceInformation = node; | 1531 return new JS.Block(body)..sourceInformation = node; |
1532 } | 1532 } |
1533 | 1533 |
1534 @override | 1534 @override |
1535 JS.Statement visitRedirectingConstructorInvocation( | 1535 JS.Statement visitRedirectingConstructorInvocation( |
1536 RedirectingConstructorInvocation node) { | 1536 RedirectingConstructorInvocation node) { |
1537 var ctor = node.staticElement; | 1537 var ctor = node.staticElement; |
1538 var cls = ctor.enclosingElement as ClassElement; | 1538 var cls = ctor.enclosingElement; |
1539 // We can't dispatch to the constructor with `this.new` as that might hit a | 1539 // We can't dispatch to the constructor with `this.new` as that might hit a |
1540 // derived class constructor with the same name. | 1540 // derived class constructor with the same name. |
1541 return js.statement('#.prototype.#.call(this, #);', [ | 1541 return js.statement('#.prototype.#.call(this, #);', [ |
1542 new JS.Identifier(cls.name), | 1542 new JS.Identifier(cls.name), |
1543 _constructorName(ctor), | 1543 _constructorName(ctor), |
1544 _visit(node.argumentList) | 1544 _visit(node.argumentList) |
1545 ]); | 1545 ]); |
1546 } | 1546 } |
1547 | 1547 |
1548 JS.Statement _superConstructorCall(ClassElement element, | 1548 JS.Statement _superConstructorCall(ClassElement element, |
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1832 assert(node.parent is CompilationUnit); | 1832 assert(node.parent is CompilationUnit); |
1833 | 1833 |
1834 if (_externalOrNative(node)) return null; | 1834 if (_externalOrNative(node)) return null; |
1835 | 1835 |
1836 // If we have a getter/setter pair, they need to be defined together. | 1836 // If we have a getter/setter pair, they need to be defined together. |
1837 if (node.isGetter) { | 1837 if (node.isGetter) { |
1838 PropertyAccessorElement element = node.element; | 1838 PropertyAccessorElement element = node.element; |
1839 var props = <JS.Method>[_emitTopLevelProperty(node)]; | 1839 var props = <JS.Method>[_emitTopLevelProperty(node)]; |
1840 var setter = element.correspondingSetter; | 1840 var setter = element.correspondingSetter; |
1841 if (setter != null) { | 1841 if (setter != null) { |
1842 props.add(_loader.emitDeclaration(setter, _emitTopLevelProperty)); | 1842 props.add(_loader.emitDeclaration( |
1843 setter, (node) => _emitTopLevelProperty(node))); | |
Leaf
2016/05/26 17:53:37
Annoying. I guess alternatively emitDeclaration c
Jennifer Messerly
2016/05/26 18:11:48
yeah, that was my thought too. Seems like either w
| |
1843 } | 1844 } |
1844 return js.statement('dart.copyProperties(#, { # });', | 1845 return js.statement('dart.copyProperties(#, { # });', |
1845 [emitLibraryName(currentLibrary), props]); | 1846 [emitLibraryName(currentLibrary), props]); |
1846 } | 1847 } |
1847 if (node.isSetter) { | 1848 if (node.isSetter) { |
1848 PropertyAccessorElement element = node.element; | 1849 PropertyAccessorElement element = node.element; |
1849 var props = <JS.Method>[_emitTopLevelProperty(node)]; | 1850 var props = <JS.Method>[_emitTopLevelProperty(node)]; |
1850 var getter = element.correspondingGetter; | 1851 var getter = element.correspondingGetter; |
1851 if (getter != null) { | 1852 if (getter != null) { |
1852 props.add(_loader.emitDeclaration(getter, _emitTopLevelProperty)); | 1853 props.add(_loader.emitDeclaration( |
1854 getter, (node) => _emitTopLevelProperty(node))); | |
1853 } | 1855 } |
1854 return js.statement('dart.copyProperties(#, { # });', | 1856 return js.statement('dart.copyProperties(#, { # });', |
1855 [emitLibraryName(currentLibrary), props]); | 1857 [emitLibraryName(currentLibrary), props]); |
1856 } | 1858 } |
1857 | 1859 |
1858 var body = <JS.Statement>[]; | 1860 var body = <JS.Statement>[]; |
1859 var fn = _emitFunction(node.functionExpression); | 1861 var fn = _emitFunction(node.functionExpression); |
1860 | 1862 |
1861 if (currentLibrary.source.isInSystemLibrary && | 1863 if (currentLibrary.source.isInSystemLibrary && |
1862 _isInlineJSFunction(node.functionExpression)) { | 1864 _isInlineJSFunction(node.functionExpression)) { |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1967 @override | 1969 @override |
1968 JS.Expression visitFunctionExpression(FunctionExpression node) { | 1970 JS.Expression visitFunctionExpression(FunctionExpression node) { |
1969 assert(node.parent is! FunctionDeclaration && | 1971 assert(node.parent is! FunctionDeclaration && |
1970 node.parent is! MethodDeclaration); | 1972 node.parent is! MethodDeclaration); |
1971 return _emitFunctionTagged(_emitArrowFunction(node), getStaticType(node), | 1973 return _emitFunctionTagged(_emitArrowFunction(node), getStaticType(node), |
1972 topLevel: _executesAtTopLevel(node)); | 1974 topLevel: _executesAtTopLevel(node)); |
1973 } | 1975 } |
1974 | 1976 |
1975 JS.ArrowFun _emitArrowFunction(FunctionExpression node) { | 1977 JS.ArrowFun _emitArrowFunction(FunctionExpression node) { |
1976 JS.Fun f = _emitFunctionBody(node.element, node.parameters, node.body); | 1978 JS.Fun f = _emitFunctionBody(node.element, node.parameters, node.body); |
1977 var body = f.body; | 1979 JS.Node body = f.body; |
1978 | 1980 |
1979 // Simplify `=> { return e; }` to `=> e` | 1981 // Simplify `=> { return e; }` to `=> e` |
1980 if (body is JS.Block) { | 1982 if (body is JS.Block) { |
1981 JS.Block block = body; | 1983 JS.Block block = body; |
1982 if (block.statements.length == 1) { | 1984 if (block.statements.length == 1) { |
1983 JS.Statement s = block.statements[0]; | 1985 JS.Statement s = block.statements[0]; |
1984 if (s is JS.Return) body = s.value; | 1986 if (s is JS.Return) body = s.value; |
1985 } | 1987 } |
1986 } | 1988 } |
1987 | 1989 |
1988 // Convert `function(...) { ... }` to `(...) => ...` | 1990 // Convert `function(...) { ... }` to `(...) => ...` |
1989 // This is for readability, but it also ensures correct `this` binding. | 1991 // This is for readability, but it also ensures correct `this` binding. |
1990 var fn = new JS.ArrowFun(f.params, body, | 1992 var fn = new JS.ArrowFun(f.params, body, |
1991 typeParams: f.typeParams, returnType: f.returnType); | 1993 typeParams: f.typeParams, returnType: f.returnType); |
1992 | 1994 |
1993 return annotate(_makeGenericFunction(fn), node); | 1995 return annotate(_makeGenericArrowFun(fn), node); |
1994 } | 1996 } |
1995 | 1997 |
1996 JS.FunctionExpression/*=T*/ _makeGenericFunction | 1998 JS.ArrowFun _makeGenericArrowFun(JS.ArrowFun fn) { |
1997 /*<T extends JS.FunctionExpression>*/(JS.FunctionExpression/*=T*/ fn) { | 1999 if (fn.typeParams == null || fn.typeParams.isEmpty) return fn; |
2000 return new JS.ArrowFun(fn.typeParams, fn); | |
2001 } | |
2002 | |
2003 JS.Fun _makeGenericFunction(JS.Fun fn) { | |
1998 if (fn.typeParams == null || fn.typeParams.isEmpty) return fn; | 2004 if (fn.typeParams == null || fn.typeParams.isEmpty) return fn; |
1999 | 2005 |
2000 // TODO(jmesserly): we could make these default to `dynamic`. | 2006 // TODO(jmesserly): we could make these default to `dynamic`. |
2001 var typeParams = fn.typeParams; | |
2002 if (fn is JS.ArrowFun) { | |
2003 return new JS.ArrowFun(typeParams, fn); | |
2004 } | |
2005 var f = fn as JS.Fun; | |
2006 return new JS.Fun( | 2007 return new JS.Fun( |
2007 typeParams, | 2008 fn.typeParams, |
2008 new JS.Block([ | 2009 new JS.Block([ |
2009 // Convert the function to an => function, to ensure `this` binding. | 2010 // Convert the function to an => function, to ensure `this` binding. |
2010 new JS.Return(new JS.ArrowFun(f.params, f.body, | 2011 new JS.Return(new JS.ArrowFun(fn.params, fn.body, |
2011 typeParams: f.typeParams, returnType: f.returnType)) | 2012 typeParams: fn.typeParams, returnType: fn.returnType)) |
2012 ])); | 2013 ])); |
2013 } | 2014 } |
2014 | 2015 |
2015 /// Emits a non-arrow FunctionExpression node. | 2016 /// Emits a non-arrow FunctionExpression node. |
2016 /// | 2017 /// |
2017 /// This should be used for all places in Dart's AST where FunctionExpression | 2018 /// This should be used for all places in Dart's AST where FunctionExpression |
2018 /// appears but the function is not actually in an Expression context, such | 2019 /// appears but the function is not actually in an Expression context, such |
2019 /// as methods, properties, and top-level functions. | 2020 /// as methods, properties, and top-level functions. |
2020 /// | 2021 /// |
2021 /// Contrast with [visitFunctionExpression]. | 2022 /// Contrast with [visitFunctionExpression]. |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2075 // In the body of a `sync*` and `async`, `yield`/`await` are both generated | 2076 // In the body of a `sync*` and `async`, `yield`/`await` are both generated |
2076 // simply as `yield`. | 2077 // simply as `yield`. |
2077 // | 2078 // |
2078 // `async*` uses the `dart.asyncStar` helper, and also has an extra `stream` | 2079 // `async*` uses the `dart.asyncStar` helper, and also has an extra `stream` |
2079 // argument to the generator, which is used for passing values to the | 2080 // argument to the generator, which is used for passing values to the |
2080 // _AsyncStarStreamController implementation type. | 2081 // _AsyncStarStreamController implementation type. |
2081 // `yield` is specially generated inside `async*`, see visitYieldStatement. | 2082 // `yield` is specially generated inside `async*`, see visitYieldStatement. |
2082 // `await` is generated as `yield`. | 2083 // `await` is generated as `yield`. |
2083 // runtime/_generators.js has an example of what the code is generated as. | 2084 // runtime/_generators.js has an example of what the code is generated as. |
2084 var savedController = _asyncStarController; | 2085 var savedController = _asyncStarController; |
2085 List jsParams = visitFormalParameterList(parameters); | 2086 var jsParams = visitFormalParameterList(parameters); |
2086 if (kind == 'asyncStar') { | 2087 if (kind == 'asyncStar') { |
2087 _asyncStarController = new JS.TemporaryId('stream'); | 2088 _asyncStarController = new JS.TemporaryId('stream'); |
2088 jsParams.insert(0, _asyncStarController); | 2089 jsParams.insert(0, _asyncStarController); |
2089 } else { | 2090 } else { |
2090 _asyncStarController = null; | 2091 _asyncStarController = null; |
2091 } | 2092 } |
2092 var savedSuperAllowed = _superAllowed; | 2093 var savedSuperAllowed = _superAllowed; |
2093 _superAllowed = false; | 2094 _superAllowed = false; |
2094 // Visit the body with our async* controller set. | 2095 // Visit the body with our async* controller set. |
2095 var jsBody = _visit(body); | 2096 var jsBody = _visit(body); |
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2269 List<DartType> types, List<FormalParameter> parameters, | 2270 List<DartType> types, List<FormalParameter> parameters, |
2270 {bool nameType: true, bool hoistType: true}) { | 2271 {bool nameType: true, bool hoistType: true}) { |
2271 var result = <JS.Expression>[]; | 2272 var result = <JS.Expression>[]; |
2272 for (int i = 0; i < types.length; ++i) { | 2273 for (int i = 0; i < types.length; ++i) { |
2273 var metadata = | 2274 var metadata = |
2274 parameters != null ? _parameterMetadata(parameters[i]) : []; | 2275 parameters != null ? _parameterMetadata(parameters[i]) : []; |
2275 var typeName = | 2276 var typeName = |
2276 _emitType(types[i], nameType: nameType, hoistType: hoistType); | 2277 _emitType(types[i], nameType: nameType, hoistType: hoistType); |
2277 var value = typeName; | 2278 var value = typeName; |
2278 if (options.emitMetadata && metadata.isNotEmpty) { | 2279 if (options.emitMetadata && metadata.isNotEmpty) { |
2279 metadata = metadata.map(_instantiateAnnotation).toList(); | 2280 value = new JS.ArrayInitializer( |
2280 value = new JS.ArrayInitializer([typeName]..addAll(metadata)); | 2281 [typeName]..addAll(metadata.map(_instantiateAnnotation))); |
2281 } | 2282 } |
2282 result.add(value); | 2283 result.add(value); |
2283 } | 2284 } |
2284 return new JS.ArrayInitializer(result); | 2285 return new JS.ArrayInitializer(result); |
2285 } | 2286 } |
2286 | 2287 |
2287 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { | 2288 JS.ObjectInitializer _emitTypeProperties(Map<String, DartType> types) { |
2288 var properties = <JS.Property>[]; | 2289 var properties = <JS.Property>[]; |
2289 types.forEach((name, type) { | 2290 types.forEach((name, type) { |
2290 var key = _propertyName(name); | 2291 var key = _propertyName(name); |
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2580 | 2581 |
2581 var target = _getTarget(node); | 2582 var target = _getTarget(node); |
2582 if (target == null || isLibraryPrefix(target)) { | 2583 if (target == null || isLibraryPrefix(target)) { |
2583 return _emitFunctionCall(node); | 2584 return _emitFunctionCall(node); |
2584 } | 2585 } |
2585 | 2586 |
2586 return _emitMethodCall(target, node); | 2587 return _emitMethodCall(target, node); |
2587 } | 2588 } |
2588 | 2589 |
2589 JS.Expression _emitMethodCall(Expression target, MethodInvocation node) { | 2590 JS.Expression _emitMethodCall(Expression target, MethodInvocation node) { |
2590 List<JS.Expression> args = _visit(node.argumentList); | 2591 var args = _visit(node.argumentList) as List<JS.Expression>; |
2591 var typeArgs = _emitInvokeTypeArguments(node); | 2592 var typeArgs = _emitInvokeTypeArguments(node); |
2592 | 2593 |
2593 if (target is SuperExpression && !_superAllowed) { | 2594 if (target is SuperExpression && !_superAllowed) { |
2594 return _emitSuperHelperCall(typeArgs, args, target, node); | 2595 return _emitSuperHelperCall(typeArgs, args, target, node); |
2595 } | 2596 } |
2596 | 2597 |
2597 return _emitMethodCallInternal(target, node, args, typeArgs); | 2598 return _emitMethodCallInternal(target, node, args, typeArgs); |
2598 } | 2599 } |
2599 | 2600 |
2600 JS.Expression _emitSuperHelperCall(List<JS.Expression> typeArgs, | 2601 JS.Expression _emitSuperHelperCall(List<JS.Expression> typeArgs, |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2662 jsTarget = new JS.PropertyAccess(jsTarget, memberName); | 2663 jsTarget = new JS.PropertyAccess(jsTarget, memberName); |
2663 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); | 2664 if (typeArgs != null) jsTarget = new JS.Call(jsTarget, typeArgs); |
2664 | 2665 |
2665 return new JS.Call(jsTarget, args); | 2666 return new JS.Call(jsTarget, args); |
2666 } | 2667 } |
2667 | 2668 |
2668 /// Emits a function call, to a top-level function, local function, or | 2669 /// Emits a function call, to a top-level function, local function, or |
2669 /// an expression. | 2670 /// an expression. |
2670 JS.Expression _emitFunctionCall(InvocationExpression node) { | 2671 JS.Expression _emitFunctionCall(InvocationExpression node) { |
2671 var fn = _visit(node.function); | 2672 var fn = _visit(node.function); |
2672 var args = _visit(node.argumentList); | 2673 var args = _visit(node.argumentList) as List<JS.Expression>; |
2673 if (DynamicInvoke.get(node.function)) { | 2674 if (DynamicInvoke.get(node.function)) { |
2674 var typeArgs = _emitInvokeTypeArguments(node); | 2675 var typeArgs = _emitInvokeTypeArguments(node); |
2675 if (typeArgs != null) { | 2676 if (typeArgs != null) { |
2676 return js.call('dart.dgcall(#, #, #)', | 2677 return js.call('dart.dgcall(#, #, #)', |
2677 [fn, new JS.ArrayInitializer(typeArgs), args]); | 2678 [fn, new JS.ArrayInitializer(typeArgs), args]); |
2678 } else { | 2679 } else { |
2679 return js.call('dart.dcall(#, #)', [fn, args]); | 2680 return js.call('dart.dcall(#, #)', [fn, args]); |
2680 } | 2681 } |
2681 } else { | 2682 } else { |
2682 return new JS.Call(_applyInvokeTypeArguments(fn, node), args); | 2683 return new JS.Call(_applyInvokeTypeArguments(fn, node), args); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2739 return f.typeArguments.skip(g.typeArguments.length); | 2740 return f.typeArguments.skip(g.typeArguments.length); |
2740 } | 2741 } |
2741 | 2742 |
2742 /// Emits code for the `JS(...)` macro. | 2743 /// Emits code for the `JS(...)` macro. |
2743 _emitForeignJS(MethodInvocation node) { | 2744 _emitForeignJS(MethodInvocation node) { |
2744 var e = node.methodName.staticElement; | 2745 var e = node.methodName.staticElement; |
2745 if (isInlineJS(e)) { | 2746 if (isInlineJS(e)) { |
2746 var args = node.argumentList.arguments; | 2747 var args = node.argumentList.arguments; |
2747 // arg[0] is static return type, used in `RestrictedStaticTypeAnalyzer` | 2748 // arg[0] is static return type, used in `RestrictedStaticTypeAnalyzer` |
2748 var code = args[1]; | 2749 var code = args[1]; |
2749 var templateArgs; | 2750 List<AstNode> templateArgs; |
2750 var source; | 2751 var source; |
2751 if (code is StringInterpolation) { | 2752 if (code is StringInterpolation) { |
2752 if (args.length > 2) { | 2753 if (args.length > 2) { |
2753 throw new ArgumentError( | 2754 throw new ArgumentError( |
2754 "Can't mix template args and string interpolation in JS calls."); | 2755 "Can't mix template args and string interpolation in JS calls."); |
2755 } | 2756 } |
2756 templateArgs = <Expression>[]; | 2757 templateArgs = <Expression>[]; |
2757 source = code.elements.map((element) { | 2758 source = code.elements.map((element) { |
2758 if (element is InterpolationExpression) { | 2759 if (element is InterpolationExpression) { |
2759 templateArgs.add(element.expression); | 2760 templateArgs.add(element.expression); |
2760 return '#'; | 2761 return '#'; |
2761 } else { | 2762 } else { |
2762 return (element as InterpolationString).value; | 2763 return (element as InterpolationString).value; |
2763 } | 2764 } |
2764 }).join(); | 2765 }).join(); |
2765 } else { | 2766 } else { |
2766 templateArgs = args.skip(2); | 2767 templateArgs = args.skip(2).toList(); |
2767 source = (code as StringLiteral).stringValue; | 2768 source = (code as StringLiteral).stringValue; |
2768 } | 2769 } |
2769 | 2770 |
2770 // TODO(rnystrom): The JS() calls are almost never nested, and probably | 2771 // TODO(rnystrom): The JS() calls are almost never nested, and probably |
2771 // really shouldn't be, but there are at least a couple of calls in the | 2772 // really shouldn't be, but there are at least a couple of calls in the |
2772 // HTML library where an argument to JS() is itself a JS() call. If those | 2773 // HTML library where an argument to JS() is itself a JS() call. If those |
2773 // go away, this can just assert(!_isInForeignJS). | 2774 // go away, this can just assert(!_isInForeignJS). |
2774 // Inside JS(), type names evaluate to the raw runtime type, not the | 2775 // Inside JS(), type names evaluate to the raw runtime type, not the |
2775 // wrapped Type object. | 2776 // wrapped Type object. |
2776 var wasInForeignJS = _isInForeignJS; | 2777 var wasInForeignJS = _isInForeignJS; |
(...skipping 1253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4030 // await iter.cancel(); | 4031 // await iter.cancel(); |
4031 // } | 4032 // } |
4032 // | 4033 // |
4033 // Like the Dart VM, we call cancel() always, as it's safe to call if the | 4034 // Like the Dart VM, we call cancel() always, as it's safe to call if the |
4034 // stream has already been cancelled. | 4035 // stream has already been cancelled. |
4035 // | 4036 // |
4036 // TODO(jmesserly): we may want a helper if these become common. For now the | 4037 // TODO(jmesserly): we may want a helper if these become common. For now the |
4037 // full desugaring seems okay. | 4038 // full desugaring seems okay. |
4038 var streamIterator = rules.instantiateToBounds(_asyncStreamIterator); | 4039 var streamIterator = rules.instantiateToBounds(_asyncStreamIterator); |
4039 var createStreamIter = _emitInstanceCreationExpression( | 4040 var createStreamIter = _emitInstanceCreationExpression( |
4040 streamIterator.element.unnamedConstructor, | 4041 (streamIterator.element as ClassElement).unnamedConstructor, |
4041 streamIterator, | 4042 streamIterator, |
4042 null, | 4043 null, |
4043 AstBuilder.argumentList([node.iterable]), | 4044 AstBuilder.argumentList([node.iterable]), |
4044 false); | 4045 false); |
4045 var iter = _visit(_createTemporary('it', streamIterator, nullable: false)); | 4046 var iter = _visit(_createTemporary('it', streamIterator, nullable: false)); |
4046 | 4047 |
4047 var init = _visit(node.identifier); | 4048 var init = _visit(node.identifier); |
4048 if (init == null) { | 4049 if (init == null) { |
4049 init = js | 4050 init = js |
4050 .call('let # = #.current', [node.loopVariable.identifier.name, iter]); | 4051 .call('let # = #.current', [node.loopVariable.identifier.name, iter]); |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4326 _visit(AstNode node) { | 4327 _visit(AstNode node) { |
4327 if (node == null) return null; | 4328 if (node == null) return null; |
4328 var result = node.accept(this); | 4329 var result = node.accept(this); |
4329 if (result is JS.Node) result = annotate(result, node); | 4330 if (result is JS.Node) result = annotate(result, node); |
4330 return result; | 4331 return result; |
4331 } | 4332 } |
4332 | 4333 |
4333 List/*<T>*/ _visitList/*<T extends AstNode>*/(Iterable/*<T>*/ nodes) { | 4334 List/*<T>*/ _visitList/*<T extends AstNode>*/(Iterable/*<T>*/ nodes) { |
4334 if (nodes == null) return null; | 4335 if (nodes == null) return null; |
4335 var result = /*<T>*/ []; | 4336 var result = /*<T>*/ []; |
4336 for (var node in nodes) result.add(_visit(node)); | 4337 for (var node in nodes) result.add(_visit(node) as dynamic/*=T*/); |
4337 return result; | 4338 return result; |
4338 } | 4339 } |
4339 | 4340 |
4340 /// Visits a list of expressions, creating a comma expression if needed in JS. | 4341 /// Visits a list of expressions, creating a comma expression if needed in JS. |
4341 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) { | 4342 JS.Expression _visitListToBinary(List<Expression> nodes, String operator) { |
4342 if (nodes == null || nodes.isEmpty) return null; | 4343 if (nodes == null || nodes.isEmpty) return null; |
4343 return new JS.Expression.binary( | 4344 return new JS.Expression.binary( |
4344 _visitList(nodes) as List<JS.Expression>, operator); | 4345 _visitList(nodes) as List<JS.Expression>, operator); |
4345 } | 4346 } |
4346 | 4347 |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4459 // conflict. We could use practically any character for this. | 4460 // conflict. We could use practically any character for this. |
4460 name = '+$name'; | 4461 name = '+$name'; |
4461 } | 4462 } |
4462 | 4463 |
4463 var result = _propertyName(name); | 4464 var result = _propertyName(name); |
4464 | 4465 |
4465 if (useExtension == null) { | 4466 if (useExtension == null) { |
4466 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. | 4467 // Dart "extension" methods. Used for JS Array, Boolean, Number, String. |
4467 var baseType = type; | 4468 var baseType = type; |
4468 while (baseType is TypeParameterType) { | 4469 while (baseType is TypeParameterType) { |
4469 baseType = baseType.element.bound; | 4470 baseType = (baseType.element as TypeParameterElement).bound; |
4470 } | 4471 } |
4471 useExtension = baseType != null && | 4472 useExtension = baseType != null && |
4472 _extensionTypes.hasNativeSubtype(baseType) && | 4473 _extensionTypes.hasNativeSubtype(baseType) && |
4473 !isObjectMember(name); | 4474 !isObjectMember(name); |
4474 } | 4475 } |
4475 | 4476 |
4476 return useExtension ? js.call('dartx.#', result) : result; | 4477 return useExtension ? js.call('dartx.#', result) : result; |
4477 } | 4478 } |
4478 | 4479 |
4479 JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) { | 4480 JS.TemporaryId _emitPrivateNameSymbol(LibraryElement library, String name) { |
(...skipping 19 matching lines...) Expand all Loading... | |
4499 return _libraries[library] ?? | 4500 return _libraries[library] ?? |
4500 _imports.putIfAbsent(library, | 4501 _imports.putIfAbsent(library, |
4501 () => new JS.TemporaryId(jsLibraryName(_buildRoot, library))); | 4502 () => new JS.TemporaryId(jsLibraryName(_buildRoot, library))); |
4502 } | 4503 } |
4503 | 4504 |
4504 JS.Node/*=T*/ annotate/*<T extends JS.Node>*/( | 4505 JS.Node/*=T*/ annotate/*<T extends JS.Node>*/( |
4505 JS.Node/*=T*/ node, AstNode original, | 4506 JS.Node/*=T*/ node, AstNode original, |
4506 [Element element]) { | 4507 [Element element]) { |
4507 if (options.closure && element != null) { | 4508 if (options.closure && element != null) { |
4508 node = node.withClosureAnnotation(closureAnnotationFor( | 4509 node = node.withClosureAnnotation(closureAnnotationFor( |
4509 node, original, element, namedArgumentTemp.name)); | 4510 node, original, element, namedArgumentTemp.name)) as dynamic/*=T*/; |
4510 } | 4511 } |
4511 return node..sourceInformation = original; | 4512 return node..sourceInformation = original; |
4512 } | 4513 } |
4513 | 4514 |
4514 /// Returns true if this is any kind of object represented by `Number` in JS. | 4515 /// Returns true if this is any kind of object represented by `Number` in JS. |
4515 /// | 4516 /// |
4516 /// In practice, this is 4 types: num, int, double, and JSNumber. | 4517 /// In practice, this is 4 types: num, int, double, and JSNumber. |
4517 /// | 4518 /// |
4518 /// JSNumber is the type that actually "implements" all numbers, hence it's | 4519 /// JSNumber is the type that actually "implements" all numbers, hence it's |
4519 /// a subtype of int and double (and num). It's in our "dart:_interceptors". | 4520 /// 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... | |
4627 } | 4628 } |
4628 | 4629 |
4629 bool isLibraryPrefix(Expression node) => | 4630 bool isLibraryPrefix(Expression node) => |
4630 node is SimpleIdentifier && node.staticElement is PrefixElement; | 4631 node is SimpleIdentifier && node.staticElement is PrefixElement; |
4631 | 4632 |
4632 LibraryElement _getLibrary(AnalysisContext c, String uri) => | 4633 LibraryElement _getLibrary(AnalysisContext c, String uri) => |
4633 c.computeLibraryElement(c.sourceFactory.forUri(uri)); | 4634 c.computeLibraryElement(c.sourceFactory.forUri(uri)); |
4634 | 4635 |
4635 bool _isDartRuntime(LibraryElement l) => | 4636 bool _isDartRuntime(LibraryElement l) => |
4636 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; | 4637 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; |
OLD | NEW |