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

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

Issue 967713002: fixes #69, avoid module name inside module scope (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 9 months 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 | test/codegen/expect/BenchmarkBase/BenchmarkBase.js » ('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 ddc.src.codegen.js_codegen; 5 library ddc.src.codegen.js_codegen;
6 6
7 import 'dart:io' show Directory, File; 7 import 'dart:io' show Directory, File;
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 12 matching lines...) Expand all
23 import 'package:dev_compiler/src/report.dart'; 23 import 'package:dev_compiler/src/report.dart';
24 import 'package:dev_compiler/src/utils.dart'; 24 import 'package:dev_compiler/src/utils.dart';
25 import 'code_generator.dart'; 25 import 'code_generator.dart';
26 26
27 // This must match the optional parameter name used in runtime.js 27 // This must match the optional parameter name used in runtime.js
28 const String _jsNamedParameterName = r'opt$'; 28 const String _jsNamedParameterName = r'opt$';
29 29
30 class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor { 30 class JSCodegenVisitor extends GeneralizingAstVisitor with ConversionVisitor {
31 final LibraryInfo libraryInfo; 31 final LibraryInfo libraryInfo;
32 final TypeRules rules; 32 final TypeRules rules;
33 final String _libraryName;
34 33
35 /// The variable for the target of the current `..` cascade expression. 34 /// The variable for the target of the current `..` cascade expression.
36 SimpleIdentifier _cascadeTarget; 35 SimpleIdentifier _cascadeTarget;
37 36
38 ClassDeclaration currentClass; 37 ClassDeclaration currentClass;
39 ConstantEvaluator _constEvaluator; 38 ConstantEvaluator _constEvaluator;
40 39
41 final _exports = <String>[]; 40 final _exports = <String>[];
42 final _lazyFields = <VariableDeclaration>[]; 41 final _lazyFields = <VariableDeclaration>[];
43 final _properties = <FunctionDeclaration>[]; 42 final _properties = <FunctionDeclaration>[];
44 43
45 JSCodegenVisitor(LibraryInfo libraryInfo, TypeRules rules) 44 JSCodegenVisitor(LibraryInfo libraryInfo, TypeRules rules)
46 : libraryInfo = libraryInfo, 45 : libraryInfo = libraryInfo,
47 rules = rules, 46 rules = rules;
48 _libraryName = jsLibraryName(libraryInfo.library);
49 47
50 Element get currentLibrary => libraryInfo.library; 48 Element get currentLibrary => libraryInfo.library;
51 49
52 JS.Block generateLibrary( 50 JS.Block generateLibrary(
53 Iterable<CompilationUnit> units, CheckerReporter reporter) { 51 Iterable<CompilationUnit> units, CheckerReporter reporter) {
54 var body = <JS.Statement>[]; 52 var body = <JS.Statement>[];
55 for (var unit in units) { 53 for (var unit in units) {
56 // TODO(jmesserly): this is needed because RestrictedTypeRules can send 54 // TODO(jmesserly): this is needed because RestrictedTypeRules can send
57 // messages to CheckerReporter, for things like missing types. 55 // messages to CheckerReporter, for things like missing types.
58 // We should probably refactor so this can't happen. 56 // We should probably refactor so this can't happen.
59 var source = unit.element.source; 57 var source = unit.element.source;
60 _constEvaluator = new ConstantEvaluator(source, rules.provider); 58 _constEvaluator = new ConstantEvaluator(source, rules.provider);
61 reporter.enterSource(source); 59 reporter.enterSource(source);
62 body.add(unit.accept(this)); 60 body.add(unit.accept(this));
63 reporter.leaveSource(); 61 reporter.leaveSource();
64 } 62 }
65 63
66 if (_exports.isNotEmpty) body.add(js.comment('Exports:')); 64 if (_exports.isNotEmpty) body.add(js.comment('Exports:'));
67 65
68 // TODO(jmesserly): make these immutable in JS? 66 // TODO(jmesserly): make these immutable in JS?
69 for (var name in _exports) { 67 for (var name in _exports) {
70 body.add(js.statement('#.# = #;', [_libraryName, name, name])); 68 body.add(js.statement('$_EXPORTS.# = #;', [name, name]));
71 } 69 }
72 70
73 var name = _libraryName; 71 var name = jsLibraryName(libraryInfo.library);
74 return new JS.Block([ 72 return new JS.Block([
75 js.statement('var #;', name), 73 js.statement('var #;', name),
76 js.statement(''' 74 js.statement('''
77 (function (#) { 75 (function ($_EXPORTS) {
78 'use strict'; 76 'use strict';
79 #; 77 #;
80 })(# || (# = {})); 78 })(# || (# = {}));
81 ''', [name, body, name, name]) 79 ''', [body, name, name])
82 ]); 80 ]);
83 } 81 }
84 82
85 @override 83 @override
86 JS.Statement visitCompilationUnit(CompilationUnit node) { 84 JS.Statement visitCompilationUnit(CompilationUnit node) {
87 // TODO(jmesserly): scriptTag, directives. 85 // TODO(jmesserly): scriptTag, directives.
88 var body = <JS.Statement>[]; 86 var body = <JS.Statement>[];
89 for (var child in node.declarations) { 87 for (var child in node.declarations) {
90 // Attempt to group adjacent fields/properties. 88 // Attempt to group adjacent fields/properties.
91 if (child is! TopLevelVariableDeclaration) _flushLazyFields(body); 89 if (child is! TopLevelVariableDeclaration) _flushLazyFields(body);
(...skipping 539 matching lines...) Expand 10 before | Expand all | Expand 10 after
631 @override 629 @override
632 JS.Expression visitSimpleIdentifier(SimpleIdentifier node) { 630 JS.Expression visitSimpleIdentifier(SimpleIdentifier node) {
633 var e = node.staticElement; 631 var e = node.staticElement;
634 if (e == null) { 632 if (e == null) {
635 return js.commentExpression( 633 return js.commentExpression(
636 'Unimplemented unknown name', new JS.VariableUse(node.name)); 634 'Unimplemented unknown name', new JS.VariableUse(node.name));
637 } 635 }
638 var name = node.name; 636 var name = node.name;
639 if (e.enclosingElement is CompilationUnitElement && 637 if (e.enclosingElement is CompilationUnitElement &&
640 (e.library != libraryInfo.library || _needsModuleGetter(e))) { 638 (e.library != libraryInfo.library || _needsModuleGetter(e))) {
641 return js.call('#.#', [jsLibraryName(e.library), name]); 639 return js.call('#.#', [_libraryName(e.library), name]);
642 } else if (currentClass != null && _needsImplicitThis(e)) { 640 } else if (currentClass != null && _needsImplicitThis(e)) {
643 return js.call('this.#', name); 641 return js.call('this.#', name);
644 } 642 }
645 return new JS.VariableUse(name); 643 return new JS.VariableUse(name);
646 } 644 }
647 645
648 JS.Expression _emitTypeName(DartType type) { 646 JS.Expression _emitTypeName(DartType type) {
649 var name = type.name; 647 var name = type.name;
650 var lib = type.element.library; 648 var lib = type.element.library;
651 if (name == '') { 649 if (name == '') {
652 // TODO(jmesserly): remove when we're using coercion reifier. 650 // TODO(jmesserly): remove when we're using coercion reifier.
653 return _unimplementedCall('Unimplemented type $type'); 651 return _unimplementedCall('Unimplemented type $type');
654 } 652 }
655 653
656 var typeArgs = null; 654 var typeArgs = null;
657 if (type is ParameterizedType) { 655 if (type is ParameterizedType) {
658 // TODO(jmesserly): this is a workaround for an analyzer bug, see: 656 // TODO(jmesserly): this is a workaround for an analyzer bug, see:
659 // https://github.com/dart-lang/dart-dev-compiler/commit/a212d59ad046085a6 26dd8d16881cdb8e8b9c3fa 657 // https://github.com/dart-lang/dart-dev-compiler/commit/a212d59ad046085a6 26dd8d16881cdb8e8b9c3fa
660 if (type is! FunctionType || type.element is FunctionTypeAlias) { 658 if (type is! FunctionType || type.element is FunctionTypeAlias) {
661 var args = type.typeArguments; 659 var args = type.typeArguments;
662 if (args.any((a) => a != rules.provider.dynamicType)) { 660 if (args.any((a) => a != rules.provider.dynamicType)) {
663 name = '$name\$'; 661 name = '$name\$';
664 typeArgs = args.map(_emitTypeName); 662 typeArgs = args.map(_emitTypeName);
665 } 663 }
666 } 664 }
667 } 665 }
668 666
669 JS.Expression result; 667 JS.Expression result;
670 if (lib != currentLibrary && lib != null) { 668 if (lib != currentLibrary && lib != null) {
671 result = js.call('#.#', [jsLibraryName(lib), name]); 669 result = js.call('#.#', [_libraryName(lib), name]);
672 } else { 670 } else {
673 result = new JS.VariableUse(name); 671 result = new JS.VariableUse(name);
674 } 672 }
675 673
676 if (typeArgs != null) { 674 if (typeArgs != null) {
677 result = js.call('#(#)', [result, typeArgs]); 675 result = js.call('#(#)', [result, typeArgs]);
678 } 676 }
679 return result; 677 return result;
680 } 678 }
681 679
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after
951 } 949 }
952 950
953 JS.Expression _visitInitializer(VariableDeclaration node) { 951 JS.Expression _visitInitializer(VariableDeclaration node) {
954 var value = _visit(node.initializer); 952 var value = _visit(node.initializer);
955 // explicitly initialize to null, to avoid getting `undefined`. 953 // explicitly initialize to null, to avoid getting `undefined`.
956 // TODO(jmesserly): do this only for vars that aren't definitely assigned. 954 // TODO(jmesserly): do this only for vars that aren't definitely assigned.
957 return value != null ? value : new JS.LiteralNull(); 955 return value != null ? value : new JS.LiteralNull();
958 } 956 }
959 957
960 void _flushLazyFields(List<JS.Statement> body) { 958 void _flushLazyFields(List<JS.Statement> body) {
961 var code = _emitLazyFields(_libraryName, _lazyFields); 959 var code = _emitLazyFields(_EXPORTS, _lazyFields);
962 if (code != null) body.add(code); 960 if (code != null) body.add(code);
963 _lazyFields.clear(); 961 _lazyFields.clear();
964 } 962 }
965 963
966 JS.Statement _emitLazyFields( 964 JS.Statement _emitLazyFields(
967 String objExpr, List<VariableDeclaration> fields) { 965 String objExpr, List<VariableDeclaration> fields) {
968 if (fields.isEmpty) return null; 966 if (fields.isEmpty) return null;
969 967
970 var methods = []; 968 var methods = [];
971 for (var node in fields) { 969 for (var node in fields) {
972 var name = node.name.name; 970 var name = node.name.name;
973 methods.add(new JS.Method(new JS.PropertyName(name), 971 methods.add(new JS.Method(new JS.PropertyName(name),
974 js.call('function() { return #; }', node.initializer.accept(this)), 972 js.call('function() { return #; }', node.initializer.accept(this)),
975 isGetter: true)); 973 isGetter: true));
976 974
977 // TODO(jmesserly): use a dummy setter to indicate writable. 975 // TODO(jmesserly): use a dummy setter to indicate writable.
978 if (!node.isFinal) { 976 if (!node.isFinal) {
979 methods.add(new JS.Method( 977 methods.add(new JS.Method(
980 new JS.PropertyName(name), js.call('function() {}'), 978 new JS.PropertyName(name), js.call('function() {}'),
981 isSetter: true)); 979 isSetter: true));
982 } 980 }
983 } 981 }
984 982
985 return js.statement( 983 return js.statement(
986 'dart.defineLazyProperties(#, { # })', [objExpr, methods]); 984 'dart.defineLazyProperties(#, { # })', [objExpr, methods]);
987 } 985 }
988 986
989 void _flushLibraryProperties(List<JS.Statement> body) { 987 void _flushLibraryProperties(List<JS.Statement> body) {
990 if (_properties.isEmpty) return; 988 if (_properties.isEmpty) return;
991 body.add(js.statement('dart.copyProperties(#, { # });', [ 989 body.add(js.statement('dart.copyProperties($_EXPORTS, { # });', [
992 _libraryName,
993 _properties.map(_emitTopLevelProperty) 990 _properties.map(_emitTopLevelProperty)
994 ])); 991 ]));
995 _properties.clear(); 992 _properties.clear();
996 } 993 }
997 994
998 @override 995 @override
999 JS.Statement visitVariableDeclarationStatement( 996 JS.Statement visitVariableDeclarationStatement(
1000 VariableDeclarationStatement node) => 997 VariableDeclarationStatement node) =>
1001 _expressionStatement(node.variables.accept(this)); 998 _expressionStatement(node.variables.accept(this));
1002 999
(...skipping 620 matching lines...) Expand 10 before | Expand all | Expand 10 after
1623 if (name == '[]=') return 'set'; 1620 if (name == '[]=') return 'set';
1624 return name; 1621 return name;
1625 } 1622 }
1626 1623
1627 bool _externalOrNative(node) => 1624 bool _externalOrNative(node) =>
1628 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody; 1625 node.externalKeyword != null || _functionBody(node) is NativeFunctionBody;
1629 1626
1630 FunctionBody _functionBody(node) => 1627 FunctionBody _functionBody(node) =>
1631 node is FunctionDeclaration ? node.functionExpression.body : node.body; 1628 node is FunctionDeclaration ? node.functionExpression.body : node.body;
1632 1629
1630 /// Choose a canonical name from the library element.
1631 /// This never uses the library's name (the identifier in the `library`
1632 /// declaration) as it doesn't have any meaningful rules enforced.
1633 String _libraryName(LibraryElement library) {
1634 if (library == libraryInfo.library) return _EXPORTS;
1635 return jsLibraryName(library);
1636 }
1637
1633 String _maybeBindThis(node) { 1638 String _maybeBindThis(node) {
1634 if (currentClass == null) return ''; 1639 if (currentClass == null) return '';
1635 var visitor = _BindThisVisitor._instance; 1640 var visitor = _BindThisVisitor._instance;
1636 visitor._bindThis = false; 1641 visitor._bindThis = false;
1637 node.accept(visitor); 1642 node.accept(visitor);
1638 return visitor._bindThis ? '.bind(this)' : ''; 1643 return visitor._bindThis ? '.bind(this)' : '';
1639 } 1644 }
1640 1645
1646 /// The name for the library's exports inside itself.
1647 /// This much be a constant because we interpolate it into template strings,
1648 /// and otherwise it would break caching for them.
1649 /// `exports` was chosen as the most similar to ES module patterns.
1650 static const String _EXPORTS = 'exports';
1651
1641 static bool _needsImplicitThis(Element e) => 1652 static bool _needsImplicitThis(Element e) =>
1642 e is PropertyAccessorElement && !e.variable.isStatic || 1653 e is PropertyAccessorElement && !e.variable.isStatic ||
1643 e is ClassMemberElement && !e.isStatic && e is! ConstructorElement; 1654 e is ClassMemberElement && !e.isStatic && e is! ConstructorElement;
1644 } 1655 }
1645 1656
1646 /// Returns true if the local variable is potentially mutated within [context]. 1657 /// Returns true if the local variable is potentially mutated within [context].
1647 /// This accounts for closures that may have been created outside of [context]. 1658 /// This accounts for closures that may have been created outside of [context].
1648 bool _isPotentiallyMutated(VariableElementImpl e, [AstNode context]) { 1659 bool _isPotentiallyMutated(VariableElementImpl e, [AstNode context]) {
1649 if (e.isPotentiallyMutatedInClosure) { 1660 if (e.isPotentiallyMutatedInClosure) {
1650 // TODO(jmesserly): this returns true incorrectly in some cases, because 1661 // TODO(jmesserly): this returns true incorrectly in some cases, because
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
1735 /// Choose a canonical name from the library element. 1746 /// Choose a canonical name from the library element.
1736 /// This never uses the library's name (the identifier in the `library` 1747 /// This never uses the library's name (the identifier in the `library`
1737 /// declaration) as it doesn't have any meaningful rules enforced. 1748 /// declaration) as it doesn't have any meaningful rules enforced.
1738 String jsLibraryName(LibraryElement library) => canonicalLibraryName(library); 1749 String jsLibraryName(LibraryElement library) => canonicalLibraryName(library);
1739 1750
1740 /// Path to file that will be generated for [info]. 1751 /// Path to file that will be generated for [info].
1741 // TODO(jmesserly): library directory should be relative to its package 1752 // TODO(jmesserly): library directory should be relative to its package
1742 // root. For example, "package:dev_compiler/src/codegen/js_codegen.dart" would b e: 1753 // root. For example, "package:dev_compiler/src/codegen/js_codegen.dart" would b e:
1743 // "ddc/src/codegen/js_codegen.js" under the output directory. 1754 // "ddc/src/codegen/js_codegen.js" under the output directory.
1744 String jsOutputPath(LibraryInfo info) => '${info.name}/${info.name}.js'; 1755 String jsOutputPath(LibraryInfo info) => '${info.name}/${info.name}.js';
OLDNEW
« no previous file with comments | « no previous file | test/codegen/expect/BenchmarkBase/BenchmarkBase.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698