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

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

Issue 1084783005: use Analyzer's computed constants instead of pattern matching the annotation AST (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 8 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 | lib/src/utils.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; 7 import 'dart:collection' show HashSet, HashMap;
8 import 'dart:io' show Directory, File; 8 import 'dart:io' show Directory, File;
9 9
10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator; 10 import 'package:analyzer/analyzer.dart' hide ConstantEvaluator;
(...skipping 16 matching lines...) Expand all
27 27
28 import 'package:dev_compiler/src/checker/rules.dart'; 28 import 'package:dev_compiler/src/checker/rules.dart';
29 import 'package:dev_compiler/src/info.dart'; 29 import 'package:dev_compiler/src/info.dart';
30 import 'package:dev_compiler/src/options.dart'; 30 import 'package:dev_compiler/src/options.dart';
31 import 'package:dev_compiler/src/utils.dart'; 31 import 'package:dev_compiler/src/utils.dart';
32 32
33 import 'code_generator.dart'; 33 import 'code_generator.dart';
34 import 'js_names.dart'; 34 import 'js_names.dart';
35 import 'js_metalet.dart'; 35 import 'js_metalet.dart';
36 36
37 bool _isAnnotationType(Annotation m, String name) => m.name.name == name;
38
39 Annotation _getAnnotation(AnnotatedNode node, String name) => node.metadata
40 .firstWhere((annotation) => _isAnnotationType(annotation, name),
41 orElse: () => null);
42
43 Annotation _getJsNameAnnotation(AnnotatedNode node) =>
44 _getAnnotation(node, "JsName");
45
46 // TODO(jacobr): we would like to do something like the following
47 // but we don't have summary support yet.
48 // bool _supportJsExtensionMethod(AnnotatedNode node) =>
49 // _getAnnotation(node, "SupportJsExtensionMethod") != null;
50
51 // Various dynamic helpers we call. 37 // Various dynamic helpers we call.
52 // If renaming these, make sure to check other places like the 38 // If renaming these, make sure to check other places like the
53 // dart_runtime.js file and comments. 39 // dart_runtime.js file and comments.
54 // TODO(jmesserly): ideally we'd have a "dynamic call" dart library we can 40 // TODO(jmesserly): ideally we'd have a "dynamic call" dart library we can
55 // import and generate calls to, rather than dart_runtime.js 41 // import and generate calls to, rather than dart_runtime.js
56 const DPUT = 'dput'; 42 const DPUT = 'dput';
57 const DLOAD = 'dload'; 43 const DLOAD = 'dload';
58 const DINDEX = 'dindex'; 44 const DINDEX = 'dindex';
59 const DSETINDEX = 'dsetindex'; 45 const DSETINDEX = 'dsetindex';
60 const DCALL = 'dcall'; 46 const DCALL = 'dcall';
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 85
100 /// Memoized results of [_inLibraryCycle]. 86 /// Memoized results of [_inLibraryCycle].
101 final _libraryCycleMemo = new HashMap<LibraryElement, bool>(); 87 final _libraryCycleMemo = new HashMap<LibraryElement, bool>();
102 88
103 JSCodegenVisitor(this.libraryInfo, this.rules, this._extensionMethods); 89 JSCodegenVisitor(this.libraryInfo, this.rules, this._extensionMethods);
104 90
105 LibraryElement get currentLibrary => libraryInfo.library; 91 LibraryElement get currentLibrary => libraryInfo.library;
106 TypeProvider get types => rules.provider; 92 TypeProvider get types => rules.provider;
107 93
108 JS.Program emitLibrary(LibraryUnit library) { 94 JS.Program emitLibrary(LibraryUnit library) {
109 var jsDefaultValue = '{}'; 95 String jsDefaultValue = null;
110 var unit = library.library; 96 var unit = library.library;
111 if (unit.directives.isNotEmpty) { 97 if (unit.directives.isNotEmpty) {
112 var annotation = _getJsNameAnnotation(unit.directives.first); 98 var libraryDir = unit.directives.first;
113 if (annotation != null) { 99 if (libraryDir is LibraryDirective) {
114 var arguments = annotation.arguments.arguments; 100 var jsName = getAnnotationValue(libraryDir, _isJsNameAnnotation);
115 if (!arguments.isEmpty) { 101 jsDefaultValue = getConstantField(jsName, 'name', types.stringType);
116 var namedExpression = arguments.first as NamedExpression;
117 var literal = namedExpression.expression as SimpleStringLiteral;
118 jsDefaultValue = literal.stringValue;
119 }
120 } 102 }
121 } 103 }
104 if (jsDefaultValue == null) jsDefaultValue = '{}';
105
122 var body = <JS.Statement>[]; 106 var body = <JS.Statement>[];
123 107
124 // Collect classes we need to emit, used for: 108 // Collect classes we need to emit, used for:
125 // * tracks what we've emitted so we don't emit twice 109 // * tracks what we've emitted so we don't emit twice
126 // * provides a mapping from ClassElement back to the ClassDeclaration. 110 // * provides a mapping from ClassElement back to the ClassDeclaration.
127 for (var unit in library.partsThenLibrary) { 111 for (var unit in library.partsThenLibrary) {
128 for (var decl in unit.declarations) { 112 for (var decl in unit.declarations) {
129 if (decl is ClassDeclaration || 113 if (decl is ClassDeclaration ||
130 decl is ClassTypeAlias || 114 decl is ClassTypeAlias ||
131 decl is FunctionTypeAlias) { 115 decl is FunctionTypeAlias) {
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 294
311 var name = node.name.name; 295 var name = node.name.name;
312 var heritage = 296 var heritage =
313 js.call('dart.mixin(#)', [_visitList(node.withClause.mixinTypes)]); 297 js.call('dart.mixin(#)', [_visitList(node.withClause.mixinTypes)]);
314 var classDecl = new JS.ClassDeclaration( 298 var classDecl = new JS.ClassDeclaration(
315 new JS.ClassExpression(new JS.Identifier(name), heritage, [])); 299 new JS.ClassExpression(new JS.Identifier(name), heritage, []));
316 300
317 return _finishClassDef(type, classDecl); 301 return _finishClassDef(type, classDecl);
318 } 302 }
319 303
320 JS.Statement _emitJsType(ClassDeclaration node, Annotation jsName) { 304 JS.Statement _emitJsType(String dartClassName, DartObjectImpl jsName) {
321 var dartName = node.name.name; 305 var jsTypeName = getConstantField(jsName, 'name', types.stringType);
322 var jsTypeName = _getLiteralStringNamedArg(jsName, 'name');
323 306
324 if (jsTypeName != null && jsTypeName != dartName) { 307 if (jsTypeName != null && jsTypeName != dartClassName) {
325 // We export the JS type as if it was a Dart type. For example this allows 308 // We export the JS type as if it was a Dart type. For example this allows
326 // `dom.InputElement` to actually be HTMLInputElement. 309 // `dom.InputElement` to actually be HTMLInputElement.
327 // TODO(jmesserly): if we had the JsName on the Element, we could just 310 // TODO(jmesserly): if we had the JsName on the Element, we could just
328 // generate it correctly when we refer to it. 311 // generate it correctly when we refer to it.
329 if (isPublic(dartName)) _addExport(dartName); 312 if (isPublic(dartClassName)) _addExport(dartClassName);
330 return js.statement('let # = #;', [dartName, jsTypeName]); 313 return js.statement('let # = #;', [dartClassName, jsTypeName]);
331 } 314 }
332 return null; 315 return null;
333 } 316 }
334 317
335 @override 318 @override
336 JS.Statement visitClassDeclaration(ClassDeclaration node) { 319 JS.Statement visitClassDeclaration(ClassDeclaration node) {
337 // If we've already emitted this class, skip it. 320 // If we've already emitted this class, skip it.
338 var type = node.element.type; 321 var type = node.element.type;
339 if (_pendingClasses.remove(node.element) == null) return null; 322 if (_pendingClasses.remove(node.element) == null) return null;
340 323
341 var jsName = _getJsNameAnnotation(node); 324 var jsName = getAnnotationValue(node, _isJsNameAnnotation);
342 if (jsName != null) return _emitJsType(node, jsName); 325 if (jsName != null) return _emitJsType(node.name.name, jsName);
343 326
344 currentClass = node; 327 currentClass = node;
345 328
346 var ctors = <ConstructorDeclaration>[]; 329 var ctors = <ConstructorDeclaration>[];
347 var fields = <FieldDeclaration>[]; 330 var fields = <FieldDeclaration>[];
348 var staticFields = <FieldDeclaration>[]; 331 var staticFields = <FieldDeclaration>[];
349 for (var member in node.members) { 332 for (var member in node.members) {
350 if (member is ConstructorDeclaration) { 333 if (member is ConstructorDeclaration) {
351 ctors.add(member); 334 ctors.add(member);
352 } else if (member is FieldDeclaration) { 335 } else if (member is FieldDeclaration) {
(...skipping 2125 matching lines...) Expand 10 before | Expand all | Expand 10 after
2478 /// This method is conservative: it should never return `true` unless it is 2461 /// This method is conservative: it should never return `true` unless it is
2479 /// certain the [node] is stateless, because generated code may rely on the 2462 /// certain the [node] is stateless, because generated code may rely on the
2480 /// correctness of a `true` value. However it may return `false` for things 2463 /// correctness of a `true` value. However it may return `false` for things
2481 /// that are in fact, stateless. 2464 /// that are in fact, stateless.
2482 bool _isStateless(Expression node, [AstNode context]) { 2465 bool _isStateless(Expression node, [AstNode context]) {
2483 if (node is SimpleIdentifier) { 2466 if (node is SimpleIdentifier) {
2484 var e = node.staticElement; 2467 var e = node.staticElement;
2485 if (e is PropertyAccessorElement) e = e.variable; 2468 if (e is PropertyAccessorElement) e = e.variable;
2486 if (e is VariableElement && !e.isSynthetic) { 2469 if (e is VariableElement && !e.isSynthetic) {
2487 if (e.isFinal) return true; 2470 if (e.isFinal) return true;
2488 2471 if (e is LocalVariableElement || e is ParameterElement) {
2489 // TODO(jmesserly): remove this when isPotentiallyMutated* is available
2490 // without the implementation class. Technically we shouldn't hit the
2491 // ParameterMember case based on current usage of _isStateless, but this
2492 // makes it clear we shouldn't rely on *Impl class.
2493 if (e is Member) e = e.baseElement;
2494
2495 if (e is LocalVariableElementImpl || e is ParameterElementImpl) {
2496 // make sure the local isn't mutated in the context. 2472 // make sure the local isn't mutated in the context.
2497 return !_isPotentiallyMutated(e, context); 2473 return !_isPotentiallyMutated(e, context);
2498 } 2474 }
2499 } 2475 }
2500 } 2476 }
2501 return false; 2477 return false;
2502 } 2478 }
2503 2479
2504 /// Returns true if the local variable is potentially mutated within [context]. 2480 /// Returns true if the local variable is potentially mutated within [context].
2505 /// This accounts for closures that may have been created outside of [context]. 2481 /// This accounts for closures that may have been created outside of [context].
2506 bool _isPotentiallyMutated(VariableElementImpl e, [AstNode context]) { 2482 bool _isPotentiallyMutated(VariableElement e, [AstNode context]) {
2507 if (e.isPotentiallyMutatedInClosure) { 2483 if (e.isPotentiallyMutatedInClosure) return true;
2508 // TODO(jmesserly): this returns true incorrectly in some cases, because
2509 // VariableResolverVisitor only checks that enclosingElement is not the
2510 // function element, but enclosingElement can be something else in some
2511 // cases (the block scope?). So it's more conservative than it could be.
2512 return true;
2513 }
2514 if (e.isPotentiallyMutatedInScope) { 2484 if (e.isPotentiallyMutatedInScope) {
2515 // Need to visit the context looking for assignment to this local. 2485 // Need to visit the context looking for assignment to this local.
2516 if (context != null) { 2486 if (context != null) {
2517 var visitor = new _AssignmentFinder(e); 2487 var visitor = new _AssignmentFinder(e);
2518 context.accept(visitor); 2488 context.accept(visitor);
2519 return visitor._potentiallyMutated; 2489 return visitor._potentiallyMutated;
2520 } 2490 }
2521 return true; 2491 return true;
2522 } 2492 }
2523 return false; 2493 return false;
2524 } 2494 }
2525 2495
2526 /// Adapted from VariableResolverVisitor. Finds an assignment to a given 2496 /// Adapted from VariableResolverVisitor. Finds an assignment to a given
2527 /// local variable. 2497 /// local variable.
2528 // TODO(jmesserly): change type annotation to not be *Impl once 2498 // TODO(jmesserly): change type annotation to not be *Impl once
2529 // isPotentiallyMutated is available on VariableElement. 2499 // isPotentiallyMutated is available on VariableElement.
2530 class _AssignmentFinder extends RecursiveAstVisitor { 2500 class _AssignmentFinder extends RecursiveAstVisitor {
2531 final VariableElementImpl _variable; 2501 final VariableElement _variable;
2532 bool _potentiallyMutated = false; 2502 bool _potentiallyMutated = false;
2533 2503
2534 _AssignmentFinder(this._variable); 2504 _AssignmentFinder(this._variable);
2535 2505
2536 @override 2506 @override
2537 visitSimpleIdentifier(SimpleIdentifier node) { 2507 visitSimpleIdentifier(SimpleIdentifier node) {
2538 // Ignore if qualified. 2508 // Ignore if qualified.
2539 AstNode parent = node.parent; 2509 AstNode parent = node.parent;
2540 if (parent is PrefixedIdentifier && 2510 if (parent is PrefixedIdentifier &&
2541 identical(parent.identifier, node)) return; 2511 identical(parent.identifier, node)) return;
2542 if (parent is PropertyAccess && 2512 if (parent is PropertyAccess &&
2543 identical(parent.propertyName, node)) return; 2513 identical(parent.propertyName, node)) return;
2544 if (parent is MethodInvocation && 2514 if (parent is MethodInvocation &&
2545 identical(parent.methodName, node)) return; 2515 identical(parent.methodName, node)) return;
2546 if (parent is ConstructorName) return; 2516 if (parent is ConstructorName) return;
2547 if (parent is Label) return; 2517 if (parent is Label) return;
2548 2518
2549 if (node.inSetterContext() && node.staticElement == _variable) { 2519 if (node.inSetterContext() && node.staticElement == _variable) {
2550 _potentiallyMutated = true; 2520 _potentiallyMutated = true;
2551 } 2521 }
2552 } 2522 }
2553 } 2523 }
2554 2524
2555 String _getLiteralStringNamedArg(Annotation annotation, String argName) { 2525 // TODO(jmesserly): validate the library. See issue #135.
Jacob 2015/04/15 00:34:41 Is this the style we're following for referencing
Jennifer Messerly 2015/04/15 00:38:39 No idea. I used to paste full links, but other git
2556 if (annotation.arguments != null) { 2526 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName';
2557 var args = annotation.arguments.arguments; 2527
2558 if (args.isNotEmpty && args[0] is NamedExpression) { 2528 // TODO(jacobr): we would like to do something like the following
2559 NamedExpression named = args[0]; 2529 // but we don't have summary support yet.
2560 if (named.name.label.name == argName && 2530 // bool _supportJsExtensionMethod(AnnotatedNode node) =>
2561 named.expression is StringLiteral) { 2531 // _getAnnotation(node, "SupportJsExtensionMethod") != null;
2562 return (named.expression as StringLiteral).stringValue;
2563 }
2564 }
2565 }
2566 return null;
2567 }
OLDNEW
« no previous file with comments | « no previous file | lib/src/utils.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698