Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(71)

Side by Side Diff: lib/src/codegen/js_codegen.dart

Issue 1424133007: Compile package:js.{rest, spread} helpers (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Use freshly released version 0.6.0-beta.6 of package:js ran formatter Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | lib/src/codegen/js_interop.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 library dev_compiler.src.codegen.js_codegen; 5 library dev_compiler.src.codegen.js_codegen;
6 6
7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet; 7 import 'dart:collection' show HashSet, HashMap, SplayTreeSet;
8 8
9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 9 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator; 10 import 'package:analyzer/src/generated/ast.dart' hide ConstantEvaluator;
(...skipping 13 matching lines...) Expand all
24 import '../js/js_ast.dart' show js; 24 import '../js/js_ast.dart' show js;
25 25
26 import '../closure/closure_annotator.dart' show ClosureAnnotator; 26 import '../closure/closure_annotator.dart' show ClosureAnnotator;
27 import '../compiler.dart' show AbstractCompiler; 27 import '../compiler.dart' show AbstractCompiler;
28 import '../info.dart'; 28 import '../info.dart';
29 import '../options.dart' show CodegenOptions; 29 import '../options.dart' show CodegenOptions;
30 import '../utils.dart'; 30 import '../utils.dart';
31 31
32 import 'code_generator.dart'; 32 import 'code_generator.dart';
33 import 'js_field_storage.dart'; 33 import 'js_field_storage.dart';
34 import 'js_interop.dart';
34 import 'js_names.dart' as JS; 35 import 'js_names.dart' as JS;
35 import 'js_metalet.dart' as JS; 36 import 'js_metalet.dart' as JS;
36 import 'js_module_item_order.dart'; 37 import 'js_module_item_order.dart';
37 import 'js_printer.dart' show writeJsLibrary; 38 import 'js_printer.dart' show writeJsLibrary;
38 import 'side_effect_analysis.dart'; 39 import 'side_effect_analysis.dart';
39 40
40 // Various dynamic helpers we call. 41 // Various dynamic helpers we call.
41 // If renaming these, make sure to check other places like the 42 // If renaming these, make sure to check other places like the
42 // _runtime.js file and comments. 43 // _runtime.js file and comments.
43 // TODO(jmesserly): ideally we'd have a "dynamic call" dart library we can 44 // TODO(jmesserly): ideally we'd have a "dynamic call" dart library we can
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 if (node is! FunctionDeclaration) _flushLibraryProperties(_moduleItems); 241 if (node is! FunctionDeclaration) _flushLibraryProperties(_moduleItems);
241 242
242 var code = _visit(node); 243 var code = _visit(node);
243 if (code != null) _moduleItems.add(code); 244 if (code != null) _moduleItems.add(code);
244 } 245 }
245 246
246 @override 247 @override
247 void visitLibraryDirective(LibraryDirective node) { 248 void visitLibraryDirective(LibraryDirective node) {
248 assert(_jsModuleValue == null); 249 assert(_jsModuleValue == null);
249 250
250 var jsName = findAnnotation(node.element, _isJsNameAnnotation); 251 var jsName = findAnnotation(node.element, isJsNameAnnotation);
251 _jsModuleValue = 252 _jsModuleValue =
252 getConstantField(jsName, 'name', types.stringType)?.toStringValue(); 253 getConstantField(jsName, 'name', types.stringType)?.toStringValue();
253 } 254 }
254 255
255 @override 256 @override
256 void visitImportDirective(ImportDirective node) { 257 void visitImportDirective(ImportDirective node) {
257 // Nothing to do yet, but we'll want to convert this to an ES6 import once 258 // Nothing to do yet, but we'll want to convert this to an ES6 import once
258 // we have support for modules. 259 // we have support for modules.
259 } 260 }
260 261
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
413 if (isPublic(dartClassName)) _addExport(dartClassName); 414 if (isPublic(dartClassName)) _addExport(dartClassName);
414 return js.statement('let # = #;', [dartClassName, jsTypeName]); 415 return js.statement('let # = #;', [dartClassName, jsTypeName]);
415 } 416 }
416 return null; 417 return null;
417 } 418 }
418 419
419 @override 420 @override
420 JS.Statement visitClassDeclaration(ClassDeclaration node) { 421 JS.Statement visitClassDeclaration(ClassDeclaration node) {
421 var classElem = node.element; 422 var classElem = node.element;
422 var type = classElem.type; 423 var type = classElem.type;
423 var jsName = findAnnotation(classElem, _isJsNameAnnotation); 424 var jsName = findAnnotation(classElem, isJsNameAnnotation);
424 425
425 if (jsName != null) return _emitJsType(node.name.name, jsName); 426 if (jsName != null) return _emitJsType(node.name.name, jsName);
426 427
427 var ctors = <ConstructorDeclaration>[]; 428 var ctors = <ConstructorDeclaration>[];
428 var fields = <FieldDeclaration>[]; 429 var fields = <FieldDeclaration>[];
429 var methods = <MethodDeclaration>[]; 430 var methods = <MethodDeclaration>[];
430 for (var member in node.members) { 431 for (var member in node.members) {
431 if (member is ConstructorDeclaration) { 432 if (member is ConstructorDeclaration) {
432 ctors.add(member); 433 ctors.add(member);
433 } else if (member is FieldDeclaration && !member.isStatic) { 434 } else if (member is FieldDeclaration && !member.isStatic) {
434 fields.add(member); 435 fields.add(member);
435 } else if (member is MethodDeclaration) { 436 } else if (member is MethodDeclaration) {
436 methods.add(member); 437 methods.add(member);
437 } 438 }
438 } 439 }
439 440
440 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), 441 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name),
441 _classHeritage(classElem), _emitClassMethods(node, ctors, fields)); 442 _classHeritage(classElem), _emitClassMethods(node, ctors, fields));
442 443
443 String jsPeerName; 444 String jsPeerName;
444 var jsPeer = findAnnotation(classElem, _isJsPeerInterface); 445 var jsPeer = findAnnotation(classElem, isJsPeerInterface);
445 if (jsPeer != null) { 446 if (jsPeer != null) {
446 jsPeerName = 447 jsPeerName =
447 getConstantField(jsPeer, 'name', types.stringType)?.toStringValue(); 448 getConstantField(jsPeer, 'name', types.stringType)?.toStringValue();
448 } 449 }
449 450
450 var body = _finishClassMembers(classElem, classExpr, ctors, fields, methods, 451 var body = _finishClassMembers(classElem, classExpr, ctors, fields, methods,
451 node.metadata, jsPeerName); 452 node.metadata, jsPeerName);
452 453
453 var result = _finishClassDef(type, body); 454 var result = _finishClassDef(type, body);
454 455
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
589 var type = element.type; 590 var type = element.type;
590 var isObject = type.isObject; 591 var isObject = type.isObject;
591 592
592 // Iff no constructor is specified for a class C, it implicitly has a 593 // Iff no constructor is specified for a class C, it implicitly has a
593 // default constructor `C() : super() {}`, unless C is class Object. 594 // default constructor `C() : super() {}`, unless C is class Object.
594 var jsMethods = <JS.Method>[]; 595 var jsMethods = <JS.Method>[];
595 if (ctors.isEmpty && !isObject) { 596 if (ctors.isEmpty && !isObject) {
596 jsMethods.add(_emitImplicitConstructor(node, fields)); 597 jsMethods.add(_emitImplicitConstructor(node, fields));
597 } 598 }
598 599
599 bool hasJsPeer = findAnnotation(element, _isJsPeerInterface) != null; 600 bool hasJsPeer = findAnnotation(element, isJsPeerInterface) != null;
600 601
601 bool hasIterator = false; 602 bool hasIterator = false;
602 for (var m in node.members) { 603 for (var m in node.members) {
603 if (m is ConstructorDeclaration) { 604 if (m is ConstructorDeclaration) {
604 jsMethods.add(_emitConstructor(m, type, fields, isObject)); 605 jsMethods.add(_emitConstructor(m, type, fields, isObject));
605 } else if (m is MethodDeclaration) { 606 } else if (m is MethodDeclaration) {
606 jsMethods.add(_emitMethodDeclaration(type, m)); 607 jsMethods.add(_emitMethodDeclaration(type, m));
607 608
608 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') { 609 if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') {
609 hasIterator = true; 610 hasIterator = true;
(...skipping 1236 matching lines...) Expand 10 before | Expand all | Expand 10 after
1846 return js.call(code, [_visit(node.function), _visit(node.argumentList)]); 1847 return js.call(code, [_visit(node.function), _visit(node.argumentList)]);
1847 } 1848 }
1848 1849
1849 @override 1850 @override
1850 List<JS.Expression> visitArgumentList(ArgumentList node) { 1851 List<JS.Expression> visitArgumentList(ArgumentList node) {
1851 var args = <JS.Expression>[]; 1852 var args = <JS.Expression>[];
1852 var named = <JS.Property>[]; 1853 var named = <JS.Property>[];
1853 for (var arg in node.arguments) { 1854 for (var arg in node.arguments) {
1854 if (arg is NamedExpression) { 1855 if (arg is NamedExpression) {
1855 named.add(_visit(arg)); 1856 named.add(_visit(arg));
1857 } else if (arg is MethodInvocation && isJsSpreadInvocation(arg)) {
1858 args.add(
1859 new JS.RestParameter(_visit(arg.argumentList.arguments.single)));
1856 } else { 1860 } else {
1857 args.add(_visit(arg)); 1861 args.add(_visit(arg));
1858 } 1862 }
1859 } 1863 }
1860 if (named.isNotEmpty) { 1864 if (named.isNotEmpty) {
1861 args.add(new JS.ObjectInitializer(named)); 1865 args.add(new JS.ObjectInitializer(named));
1862 } 1866 }
1863 return args; 1867 return args;
1864 } 1868 }
1865 1869
1866 @override 1870 @override
1867 JS.Property visitNamedExpression(NamedExpression node) { 1871 JS.Property visitNamedExpression(NamedExpression node) {
1868 assert(node.parent is ArgumentList); 1872 assert(node.parent is ArgumentList);
1869 return new JS.Property( 1873 return new JS.Property(
1870 _propertyName(node.name.label.name), _visit(node.expression)); 1874 _propertyName(node.name.label.name), _visit(node.expression));
1871 } 1875 }
1872 1876
1873 @override 1877 @override
1874 List<JS.Identifier> visitFormalParameterList(FormalParameterList node) { 1878 List<JS.Parameter> visitFormalParameterList(FormalParameterList node) {
1875 var result = <JS.Identifier>[]; 1879 var result = <JS.Parameter>[];
1876 for (FormalParameter param in node.parameters) { 1880 for (FormalParameter param in node.parameters) {
1877 if (param.kind == ParameterKind.NAMED) { 1881 if (param.kind == ParameterKind.NAMED) {
1878 result.add(_namedArgTemp); 1882 result.add(_namedArgTemp);
1879 break; 1883 break;
1880 } 1884 }
1881 result.add(_visit(param)); 1885 result.add(_visit(param));
1882 } 1886 }
1883 return result; 1887 return result;
1884 } 1888 }
1885 1889
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after
2512 _cascadeTarget = savedCascadeTemp; 2516 _cascadeTarget = savedCascadeTemp;
2513 return result; 2517 return result;
2514 } 2518 }
2515 2519
2516 @override 2520 @override
2517 visitParenthesizedExpression(ParenthesizedExpression node) => 2521 visitParenthesizedExpression(ParenthesizedExpression node) =>
2518 // The printer handles precedence so we don't need to. 2522 // The printer handles precedence so we don't need to.
2519 _visit(node.expression); 2523 _visit(node.expression);
2520 2524
2521 @override 2525 @override
2522 visitFormalParameter(FormalParameter node) => 2526 visitFormalParameter(FormalParameter node) {
2523 visitSimpleIdentifier(node.identifier); 2527 var id = visitSimpleIdentifier(node.identifier);
2528
2529 var isRestArg = findAnnotation(node.element, isJsRestAnnotation) != null;
2530 return isRestArg ? new JS.RestParameter(id) : id;
2531 }
2524 2532
2525 @override 2533 @override
2526 JS.This visitThisExpression(ThisExpression node) => new JS.This(); 2534 JS.This visitThisExpression(ThisExpression node) => new JS.This();
2527 2535
2528 @override 2536 @override
2529 JS.Super visitSuperExpression(SuperExpression node) => new JS.Super(); 2537 JS.Super visitSuperExpression(SuperExpression node) => new JS.Super();
2530 2538
2531 @override 2539 @override
2532 visitPrefixedIdentifier(PrefixedIdentifier node) { 2540 visitPrefixedIdentifier(PrefixedIdentifier node) {
2533 if (isLibraryPrefix(node.prefix)) { 2541 if (isLibraryPrefix(node.prefix)) {
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
2675 var target = _getTarget(node); 2683 var target = _getTarget(node);
2676 if (_useNativeJsIndexer(target.staticType)) { 2684 if (_useNativeJsIndexer(target.staticType)) {
2677 return new JS.PropertyAccess(_visit(target), _visit(node.index)); 2685 return new JS.PropertyAccess(_visit(target), _visit(node.index));
2678 } 2686 }
2679 return _emitSend(target, '[]', [node.index]); 2687 return _emitSend(target, '[]', [node.index]);
2680 } 2688 }
2681 2689
2682 // TODO(jmesserly): ideally we'd check the method and see if it is marked 2690 // TODO(jmesserly): ideally we'd check the method and see if it is marked
2683 // `external`, but that doesn't work because it isn't in the element model. 2691 // `external`, but that doesn't work because it isn't in the element model.
2684 bool _useNativeJsIndexer(DartType type) => 2692 bool _useNativeJsIndexer(DartType type) =>
2685 findAnnotation(type.element, _isJsNameAnnotation) != null; 2693 findAnnotation(type.element, isJsNameAnnotation) != null;
2686 2694
2687 /// Gets the target of a [PropertyAccess], [IndexExpression], or 2695 /// Gets the target of a [PropertyAccess], [IndexExpression], or
2688 /// [MethodInvocation]. These three nodes can appear in a [CascadeExpression]. 2696 /// [MethodInvocation]. These three nodes can appear in a [CascadeExpression].
2689 Expression _getTarget(node) { 2697 Expression _getTarget(node) {
2690 assert(node is IndexExpression || 2698 assert(node is IndexExpression ||
2691 node is PropertyAccess || 2699 node is PropertyAccess ||
2692 node is MethodInvocation); 2700 node is MethodInvocation);
2693 return node.isCascaded ? _cascadeTarget : node.target; 2701 return node.isCascaded ? _cascadeTarget : node.target;
2694 } 2702 }
2695 2703
(...skipping 598 matching lines...) Expand 10 before | Expand all | Expand 10 after
3294 /// This never uses the library's name (the identifier in the `library` 3302 /// This never uses the library's name (the identifier in the `library`
3295 /// declaration) as it doesn't have any meaningful rules enforced. 3303 /// declaration) as it doesn't have any meaningful rules enforced.
3296 String jsLibraryName(LibraryElement library) => canonicalLibraryName(library); 3304 String jsLibraryName(LibraryElement library) => canonicalLibraryName(library);
3297 3305
3298 /// Shorthand for identifier-like property names. 3306 /// Shorthand for identifier-like property names.
3299 /// For now, we emit them as strings and the printer restores them to 3307 /// For now, we emit them as strings and the printer restores them to
3300 /// identifiers if it can. 3308 /// identifiers if it can.
3301 // TODO(jmesserly): avoid the round tripping through quoted form. 3309 // TODO(jmesserly): avoid the round tripping through quoted form.
3302 JS.LiteralString _propertyName(String name) => js.string(name, "'"); 3310 JS.LiteralString _propertyName(String name) => js.string(name, "'");
3303 3311
3304 // TODO(jmesserly): validate the library. See issue #135.
3305 bool _isJsNameAnnotation(DartObject value) => value.type.name == 'JsName';
3306
3307 bool _isJsPeerInterface(DartObject value) =>
3308 value.type.name == 'JsPeerInterface';
3309
3310 // TODO(jacobr): we would like to do something like the following 3312 // TODO(jacobr): we would like to do something like the following
3311 // but we don't have summary support yet. 3313 // but we don't have summary support yet.
3312 // bool _supportJsExtensionMethod(AnnotatedNode node) => 3314 // bool _supportJsExtensionMethod(AnnotatedNode node) =>
3313 // _getAnnotation(node, "SupportJsExtensionMethod") != null; 3315 // _getAnnotation(node, "SupportJsExtensionMethod") != null;
3314 3316
3315 /// A special kind of element created by the compiler, signifying a temporary 3317 /// A special kind of element created by the compiler, signifying a temporary
3316 /// variable. These objects use instance equality, and should be shared 3318 /// variable. These objects use instance equality, and should be shared
3317 /// everywhere in the tree where they are treated as the same variable. 3319 /// everywhere in the tree where they are treated as the same variable.
3318 class TemporaryVariableElement extends LocalVariableElementImpl { 3320 class TemporaryVariableElement extends LocalVariableElementImpl {
3319 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); 3321 TemporaryVariableElement.forNode(Identifier name) : super.forNode(name);
3320 3322
3321 int get hashCode => identityHashCode(this); 3323 int get hashCode => identityHashCode(this);
3322 bool operator ==(Object other) => identical(this, other); 3324 bool operator ==(Object other) => identical(this, other);
3323 } 3325 }
OLDNEW
« no previous file with comments | « no previous file | lib/src/codegen/js_interop.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698