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

Side by Side Diff: lib/src/compiler/code_generator.dart

Issue 1993813003: implement top-level JS annotated getters (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 4 years, 7 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/browser/language_tests.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 import 'dart:collection' show HashMap, HashSet; 5 import 'dart:collection' show HashMap, HashSet;
6 import 'dart:math' show min, max; 6 import 'dart:math' show min, max;
7 7
8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 8 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
9 import 'package:analyzer/dart/ast/ast.dart'; 9 import 'package:analyzer/dart/ast/ast.dart';
10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType; 10 import 'package:analyzer/dart/ast/token.dart' show Token, TokenType;
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
74 /// Usually a [SimpleIdentifier], but it can also be other expressions 74 /// Usually a [SimpleIdentifier], but it can also be other expressions
75 /// that are safe to evaluate multiple times, such as `this`. 75 /// that are safe to evaluate multiple times, such as `this`.
76 Expression _cascadeTarget; 76 Expression _cascadeTarget;
77 77
78 /// The variable for the current catch clause 78 /// The variable for the current catch clause
79 SimpleIdentifier _catchParameter; 79 SimpleIdentifier _catchParameter;
80 80
81 /// In an async* function, this represents the stream controller parameter. 81 /// In an async* function, this represents the stream controller parameter.
82 JS.TemporaryId _asyncStarController; 82 JS.TemporaryId _asyncStarController;
83 83
84 /// The top-level reference to 'self' if this is a library tagged with @JS() 84 /// The top-level reference to 'self' if this is a library tagged with @JS()
Jennifer Messerly 2016/05/18 22:20:26 reword this comment?
Harry Terkelsen 2016/05/19 16:56:18 Done.
85 JS.TemporaryId _self; 85 JS.Expression _jsPrefix;
86 bool libraryTaggedJS = false;
Jennifer Messerly 2016/05/18 22:20:27 Perhaps call this "_isInteropLibrary" Note: I hav
Harry Terkelsen 2016/05/19 16:56:18 Done.
86 87
87 final _privateNames = 88 final _privateNames =
88 new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>(); 89 new HashMap<LibraryElement, HashMap<String, JS.TemporaryId>>();
89 final _initializingFormalTemps = 90 final _initializingFormalTemps =
90 new HashMap<ParameterElement, JS.TemporaryId>(); 91 new HashMap<ParameterElement, JS.TemporaryId>();
91 92
92 final _dartxVar = new JS.Identifier('dartx'); 93 final _dartxVar = new JS.Identifier('dartx');
94 final _dartGlobal = js.call('dart.global');
93 final _runtimeLibVar = new JS.Identifier('dart'); 95 final _runtimeLibVar = new JS.Identifier('dart');
94 final namedArgumentTemp = new JS.TemporaryId('opts'); 96 final namedArgumentTemp = new JS.TemporaryId('opts');
95 97
96 final _hasDeferredSupertype = new HashSet<ClassElement>(); 98 final _hasDeferredSupertype = new HashSet<ClassElement>();
97 99
98 final _eagerTopLevelFields = new HashSet<Element>.identity(); 100 final _eagerTopLevelFields = new HashSet<Element>.identity();
99 101
100 /// The type provider from the current Analysis [context]. 102 /// The type provider from the current Analysis [context].
101 final TypeProvider types; 103 final TypeProvider types;
102 104
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after
219 js.call('const # = Object.create(null)', [libraryTemp]))); 221 js.call('const # = Object.create(null)', [libraryTemp])));
220 222
221 // dart:_runtime has a magic module that holds extenstion method symbols. 223 // dart:_runtime has a magic module that holds extenstion method symbols.
222 // TODO(jmesserly): find a cleaner design for this. 224 // TODO(jmesserly): find a cleaner design for this.
223 if (_isDartRuntime(library)) { 225 if (_isDartRuntime(library)) {
224 items.add(new JS.ExportDeclaration( 226 items.add(new JS.ExportDeclaration(
225 js.call('const # = Object.create(null)', [_dartxVar]))); 227 js.call('const # = Object.create(null)', [_dartxVar])));
226 } 228 }
227 229
228 if (findAnnotation(library, isPublicJSAnnotation) != null) { 230 if (findAnnotation(library, isPublicJSAnnotation) != null) {
229 _self = new JS.TemporaryId('self'); 231 libraryTaggedJS = true;
Jennifer Messerly 2016/05/18 22:20:27 is this attribute per-library or is it global for
Harry Terkelsen 2016/05/19 16:56:18 It's per-library. I made the map.
230 items.add(js.statement('const # = window;', [_self])); 232 var prefix = getAnnotationName(library, isPublicJSAnnotation);
233 if (prefix != null && !prefix.isEmpty) {
Jennifer Messerly 2016/05/18 22:20:27 will we always have a name? in other words does it
Harry Terkelsen 2016/05/19 16:56:19 A @JS annotation on the library is required for js
234 _jsPrefix = js.call(prefix);
Jennifer Messerly 2016/05/18 22:20:27 I feel like we'd be better off validating our user
Harry Terkelsen 2016/05/19 16:56:18 I am just splitting on dots now without validation
235 assert(_isValidJSName(_jsPrefix));
Jennifer Messerly 2016/05/18 22:20:26 Should this be an error we issue? I think of "ass
Harry Terkelsen 2016/05/19 16:56:18 I think you cannot just put arbitrary strings in t
236 }
231 } 237 }
232 } 238 }
233 239
234 // Collect all Element -> Node mappings, in case we need to forward declare 240 // Collect all Element -> Node mappings, in case we need to forward declare
235 // any nodes. 241 // any nodes.
236 var nodes = new HashMap<Element, AstNode>.identity(); 242 var nodes = new HashMap<Element, AstNode>.identity();
237 var sdkBootstrappingFns = new List<FunctionElement>(); 243 var sdkBootstrappingFns = new List<FunctionElement>();
238 for (var unit in compilationUnits) { 244 for (var unit in compilationUnits) {
239 if (_isDartRuntime(unit.element.library)) { 245 if (_isDartRuntime(unit.element.library)) {
240 sdkBootstrappingFns.addAll(unit.element.functions); 246 sdkBootstrappingFns.addAll(unit.element.functions);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
283 List<JS.ModuleItem> result, Iterable<JS.ModuleItem> items) { 289 List<JS.ModuleItem> result, Iterable<JS.ModuleItem> items) {
284 for (var item in items) { 290 for (var item in items) {
285 if (item is JS.Block && !item.isScope) { 291 if (item is JS.Block && !item.isScope) {
286 _copyAndFlattenBlocks(result, item.statements); 292 _copyAndFlattenBlocks(result, item.statements);
287 } else { 293 } else {
288 result.add(item); 294 result.add(item);
289 } 295 }
290 } 296 }
291 } 297 }
292 298
299 /// Returns [true] if [jsName] is a simple identifier, a string with no dots,
300 /// or a property access where the receiver is a valid JS name and the
301 /// selector is a simple identifier.
302 bool _isValidJSName(JS.Expression jsName) {
Jennifer Messerly 2016/05/18 22:20:26 based on suggestion above, I'm not sure you'll nee
Harry Terkelsen 2016/05/19 16:56:19 Done.
303 if (jsName is JS.Identifier) {
304 return true;
305 } else if (jsName is JS.LiteralString) {
306 return !jsName.value.contains('.');
307 } else if (jsName is JS.PropertyAccess) {
308 return (jsName.selector is JS.Identifier ||
309 jsName.selector is JS.LiteralString) &&
310 _isValidJSName(jsName.receiver);
311 } else {
312 return false;
313 }
314 }
315
316 /// Returns the equivalent of separating the given names by a '.'.
317 JS.PropertyAccess _mergeJSNames(Iterable<JS.Expression> names) {
Jennifer Messerly 2016/05/18 22:20:27 same here, I don't think this will be needed
Harry Terkelsen 2016/05/19 16:56:18 Done.
318 assert(names.every(_isValidJSName));
Jennifer Messerly 2016/05/18 22:20:27 (this comment is probably moot based on my other o
Harry Terkelsen 2016/05/19 16:56:18 Done.
319 Iterable<JS.LiteralString> extractParts(JS.Expression name) sync* {
320 if (name == null) return;
321 if (name is JS.LiteralString) {
322 yield name;
323 return;
324 }
325 if (name is JS.Identifier) {
326 yield js.string(name.name);
327 return;
328 }
329 var propertyAccess = name as JS.PropertyAccess;
330 yield* extractParts(propertyAccess.receiver);
331 yield propertyAccess.selector;
332 }
333 return names.expand(extractParts).fold(null, (merged, part) {
334 if (merged == null) {
335 return new JS.Identifier(
336 part.value.substring(1, part.value.length - 1));
337 }
338 return new JS.PropertyAccess(merged, part);
339 });
340 }
341
293 String _libraryToModule(LibraryElement library) { 342 String _libraryToModule(LibraryElement library) {
294 assert(!_libraries.containsKey(library)); 343 assert(!_libraries.containsKey(library));
295 var source = library.source; 344 var source = library.source;
296 // TODO(jmesserly): we need to split out HTML. 345 // TODO(jmesserly): we need to split out HTML.
297 if (source.uri.scheme == 'dart') { 346 if (source.uri.scheme == 'dart') {
298 return 'dart_sdk'; 347 return 'dart_sdk';
299 } 348 }
300 var moduleName = _buildUnit.libraryToModule(source); 349 var moduleName = _buildUnit.libraryToModule(source);
301 if (moduleName == null) { 350 if (moduleName == null) {
302 throw new StateError('Could not find module containing "$library".'); 351 throw new StateError('Could not find module containing "$library".');
(...skipping 2036 matching lines...) Expand 10 before | Expand all | Expand 10 after
2339 return js.call('#(#)', [genericName, jsArgs]); 2388 return js.call('#(#)', [genericName, jsArgs]);
2340 } 2389 }
2341 } 2390 }
2342 2391
2343 return _emitTopLevelName(element); 2392 return _emitTopLevelName(element);
2344 } 2393 }
2345 2394
2346 JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) { 2395 JS.PropertyAccess _emitTopLevelName(Element e, {String suffix: ''}) {
2347 if (e is TopLevelVariableElement && 2396 if (e is TopLevelVariableElement &&
2348 e.getter != null && 2397 e.getter != null &&
2349 findAnnotation(e.getter, isPublicJSAnnotation) != null) { 2398 (findAnnotation(e.getter, isPublicJSAnnotation) != null ||
2399 (libraryTaggedJS && e.getter.isExternal))) {
Jennifer Messerly 2016/05/18 22:20:26 `e.getter.isExternal && _libraryTaggedJS(e.library
Harry Terkelsen 2016/05/19 16:56:19 Done.
2350 var annotationName = getAnnotationName(e.getter, isPublicJSAnnotation); 2400 var annotationName = getAnnotationName(e.getter, isPublicJSAnnotation);
2351 var name = js.string(annotationName ?? e.name); 2401 var name;
2352 return new JS.PropertyAccess(_self, name); 2402 if (annotationName != null && annotationName.contains('.')) {
2403 name = js.call(annotationName);
2404 } else {
2405 name = js.string(annotationName ?? e.name);
2406 }
2407 return _mergeJSNames(
Jennifer Messerly 2016/05/18 22:20:26 rather than merging js_ast structures, IMO it woul
Harry Terkelsen 2016/05/19 16:56:18 Done.
2408 [_dartGlobal, _jsPrefix, name].where((x) => x != null));
Jennifer Messerly 2016/05/18 22:20:27 (probably a moot comment) _jsPrefix is the only o
Harry Terkelsen 2016/05/19 16:56:18 Done.
2353 } 2409 }
2354 String name = getJSExportName(e) + suffix; 2410 String name = getJSExportName(e) + suffix;
2355 return new JS.PropertyAccess( 2411 return new JS.PropertyAccess(
2356 emitLibraryName(e.library), _propertyName(name)); 2412 emitLibraryName(e.library), _propertyName(name));
2357 } 2413 }
2358 2414
2359 @override 2415 @override
2360 JS.Expression visitAssignmentExpression(AssignmentExpression node) { 2416 JS.Expression visitAssignmentExpression(AssignmentExpression node) {
2361 var left = node.leftHandSide; 2417 var left = node.leftHandSide;
2362 var right = node.rightHandSide; 2418 var right = node.rightHandSide;
(...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after
3037 : parent.getSetter(element.name); 3093 : parent.getSetter(element.name);
3038 } 3094 }
3039 return null; 3095 return null;
3040 } 3096 }
3041 3097
3042 JS.Expression _emitConstructorName( 3098 JS.Expression _emitConstructorName(
3043 ConstructorElement element, DartType type, SimpleIdentifier name) { 3099 ConstructorElement element, DartType type, SimpleIdentifier name) {
3044 var classElem = element.enclosingElement; 3100 var classElem = element.enclosingElement;
3045 if (findAnnotation(classElem, isPublicJSAnnotation) != null) { 3101 if (findAnnotation(classElem, isPublicJSAnnotation) != null) {
3046 var annotationName = getAnnotationName(classElem, isPublicJSAnnotation); 3102 var annotationName = getAnnotationName(classElem, isPublicJSAnnotation);
3047 var typeName = js.string(annotationName ?? classElem.name); 3103 var typeName;
Jennifer Messerly 2016/05/18 22:20:27 this code seems duplicated with above. (it sort o
Harry Terkelsen 2016/05/19 16:56:18 Done.
3048 return new JS.PropertyAccess(_self, typeName); 3104 if (annotationName != null && annotationName.contains('.')) {
3105 typeName = js.call(annotationName);
3106 } else {
3107 typeName = js.string(annotationName ?? classElem.name);
3108 }
3109 return _mergeJSNames(
3110 [_dartGlobal, _jsPrefix, typeName].where((x) => x != null));
3049 } 3111 }
3050 var typeName = _emitType(type); 3112 var typeName = _emitType(type);
3051 if (name != null || element.isFactory) { 3113 if (name != null || element.isFactory) {
3052 var namedCtor = _constructorName(element); 3114 var namedCtor = _constructorName(element);
3053 return new JS.PropertyAccess(typeName, namedCtor); 3115 return new JS.PropertyAccess(typeName, namedCtor);
3054 } 3116 }
3055 return typeName; 3117 return typeName;
3056 } 3118 }
3057 3119
3058 @override 3120 @override
(...skipping 1435 matching lines...) Expand 10 before | Expand all | Expand 10 after
4494 } 4556 }
4495 4557
4496 bool isLibraryPrefix(Expression node) => 4558 bool isLibraryPrefix(Expression node) =>
4497 node is SimpleIdentifier && node.staticElement is PrefixElement; 4559 node is SimpleIdentifier && node.staticElement is PrefixElement;
4498 4560
4499 LibraryElement _getLibrary(AnalysisContext c, String uri) => 4561 LibraryElement _getLibrary(AnalysisContext c, String uri) =>
4500 c.computeLibraryElement(c.sourceFactory.forUri(uri)); 4562 c.computeLibraryElement(c.sourceFactory.forUri(uri));
4501 4563
4502 bool _isDartRuntime(LibraryElement l) => 4564 bool _isDartRuntime(LibraryElement l) =>
4503 l.isInSdk && l.source.uri.toString() == 'dart:_runtime'; 4565 l.isInSdk && l.source.uri.toString() == 'dart:_runtime';
OLDNEW
« no previous file with comments | « no previous file | test/browser/language_tests.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698