| 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 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 | 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 92 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 103   JS.Program emitLibrary(LibraryUnit library) { | 103   JS.Program emitLibrary(LibraryUnit library) { | 
| 104     String jsDefaultValue = null; | 104     String jsDefaultValue = null; | 
| 105 | 105 | 
| 106     // Modify the AST to make coercions explicit. | 106     // Modify the AST to make coercions explicit. | 
| 107     new CoercionReifier(library, compiler).reify(); | 107     new CoercionReifier(library, compiler).reify(); | 
| 108 | 108 | 
| 109     var unit = library.library; | 109     var unit = library.library; | 
| 110     if (unit.directives.isNotEmpty) { | 110     if (unit.directives.isNotEmpty) { | 
| 111       var libraryDir = unit.directives.first; | 111       var libraryDir = unit.directives.first; | 
| 112       if (libraryDir is LibraryDirective) { | 112       if (libraryDir is LibraryDirective) { | 
| 113         var jsName = getAnnotationValue(libraryDir, _isJsNameAnnotation); | 113         var jsName = findNodeAnnotation(libraryDir, _isJsNameAnnotation); | 
| 114         jsDefaultValue = getConstantField(jsName, 'name', types.stringType); | 114         jsDefaultValue = getConstantField(jsName, 'name', types.stringType); | 
| 115       } | 115       } | 
| 116     } | 116     } | 
| 117     if (jsDefaultValue == null) jsDefaultValue = '{}'; | 117     if (jsDefaultValue == null) jsDefaultValue = '{}'; | 
| 118 | 118 | 
| 119     // TODO(jmesserly): visit scriptTag, directives? | 119     // TODO(jmesserly): visit scriptTag, directives? | 
| 120 | 120 | 
| 121     _loader.collectElements(currentLibrary, library.partsThenLibrary); | 121     _loader.collectElements(currentLibrary, library.partsThenLibrary); | 
| 122 | 122 | 
| 123     for (var unit in library.partsThenLibrary) { | 123     for (var unit in library.partsThenLibrary) { | 
| (...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 322       return js.statement('let # = #;', [dartClassName, jsTypeName]); | 322       return js.statement('let # = #;', [dartClassName, jsTypeName]); | 
| 323     } | 323     } | 
| 324     return null; | 324     return null; | 
| 325   } | 325   } | 
| 326 | 326 | 
| 327   @override | 327   @override | 
| 328   JS.Statement visitClassDeclaration(ClassDeclaration node) { | 328   JS.Statement visitClassDeclaration(ClassDeclaration node) { | 
| 329     // If we've already emitted this class, skip it. | 329     // If we've already emitted this class, skip it. | 
| 330     var classElem = node.element; | 330     var classElem = node.element; | 
| 331     var type = classElem.type; | 331     var type = classElem.type; | 
| 332     var jsName = getAnnotationValue(node, _isJsNameAnnotation); | 332     var jsName = findNodeAnnotation(node, _isJsNameAnnotation); | 
| 333 | 333 | 
| 334     if (jsName != null) return _emitJsType(node.name.name, jsName); | 334     if (jsName != null) return _emitJsType(node.name.name, jsName); | 
| 335 | 335 | 
| 336     var ctors = <ConstructorDeclaration>[]; | 336     var ctors = <ConstructorDeclaration>[]; | 
| 337     var fields = <FieldDeclaration>[]; | 337     var fields = <FieldDeclaration>[]; | 
| 338     for (var member in node.members) { | 338     for (var member in node.members) { | 
| 339       if (member is ConstructorDeclaration) { | 339       if (member is ConstructorDeclaration) { | 
| 340         ctors.add(member); | 340         ctors.add(member); | 
| 341       } else if (member is FieldDeclaration && !member.isStatic) { | 341       } else if (member is FieldDeclaration && !member.isStatic) { | 
| 342         fields.add(member); | 342         fields.add(member); | 
| 343       } | 343       } | 
| 344     } | 344     } | 
| 345 | 345 | 
| 346     var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), | 346     var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), | 
| 347         _classHeritage(classElem), _emitClassMethods(node, ctors, fields)); | 347         _classHeritage(classElem), _emitClassMethods(node, ctors, fields)); | 
| 348 | 348 | 
| 349     String jsPeerName; | 349     String jsPeerName; | 
| 350     var jsPeer = getAnnotationValue(node, _isJsPeerInterface); | 350     var jsPeer = findNodeAnnotation(node, _isJsPeerInterface); | 
| 351     if (jsPeer != null) { | 351     if (jsPeer != null) { | 
| 352       jsPeerName = getConstantField(jsPeer, 'name', types.stringType); | 352       jsPeerName = getConstantField(jsPeer, 'name', types.stringType); | 
| 353     } | 353     } | 
| 354 | 354 | 
| 355     var body = | 355     var body = | 
| 356         _finishClassMembers(classElem, classExpr, ctors, fields, jsPeerName); | 356         _finishClassMembers(classElem, classExpr, ctors, fields, jsPeerName); | 
| 357 | 357 | 
| 358     var result = _finishClassDef(type, body); | 358     var result = _finishClassDef(type, body); | 
| 359 | 359 | 
| 360     if (jsPeerName != null) { | 360     if (jsPeerName != null) { | 
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 466     var isObject = type.isObject; | 466     var isObject = type.isObject; | 
| 467     var name = node.name.name; | 467     var name = node.name.name; | 
| 468 | 468 | 
| 469     // Iff no constructor is specified for a class C, it implicitly has a | 469     // Iff no constructor is specified for a class C, it implicitly has a | 
| 470     // default constructor `C() : super() {}`, unless C is class Object. | 470     // default constructor `C() : super() {}`, unless C is class Object. | 
| 471     var jsMethods = <JS.Method>[]; | 471     var jsMethods = <JS.Method>[]; | 
| 472     if (ctors.isEmpty && !isObject) { | 472     if (ctors.isEmpty && !isObject) { | 
| 473       jsMethods.add(_emitImplicitConstructor(node, name, fields)); | 473       jsMethods.add(_emitImplicitConstructor(node, name, fields)); | 
| 474     } | 474     } | 
| 475 | 475 | 
| 476     bool hasJsPeer = getAnnotationValue(node, _isJsPeerInterface) != null; | 476     bool hasJsPeer = findNodeAnnotation(node, _isJsPeerInterface) != null; | 
| 477 | 477 | 
| 478     bool hasIterator = false; | 478     bool hasIterator = false; | 
| 479     for (var m in node.members) { | 479     for (var m in node.members) { | 
| 480       if (m is ConstructorDeclaration) { | 480       if (m is ConstructorDeclaration) { | 
| 481         jsMethods.add(_emitConstructor(m, name, fields, isObject)); | 481         jsMethods.add(_emitConstructor(m, name, fields, isObject)); | 
| 482       } else if (m is MethodDeclaration) { | 482       } else if (m is MethodDeclaration) { | 
| 483         jsMethods.add(_emitMethodDeclaration(type, m)); | 483         jsMethods.add(_emitMethodDeclaration(type, m)); | 
| 484 | 484 | 
| 485         if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') { | 485         if (!hasJsPeer && m.isGetter && m.name.name == 'iterator') { | 
| 486           hasIterator = true; | 486           hasIterator = true; | 
| (...skipping 690 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1177     var vars = {}; | 1177     var vars = {}; | 
| 1178     var lhs = _bindLeftHandSide(vars, left, context: context); | 1178     var lhs = _bindLeftHandSide(vars, left, context: context); | 
| 1179     var inc = AstBuilder.binaryExpression(lhs, op, right); | 1179     var inc = AstBuilder.binaryExpression(lhs, op, right); | 
| 1180     inc.staticElement = element; | 1180     inc.staticElement = element; | 
| 1181     inc.staticType = getStaticType(left); | 1181     inc.staticType = getStaticType(left); | 
| 1182     return new JS.MetaLet(vars, [_emitSet(lhs, inc)]); | 1182     return new JS.MetaLet(vars, [_emitSet(lhs, inc)]); | 
| 1183   } | 1183   } | 
| 1184 | 1184 | 
| 1185   JS.Expression _emitSet(Expression lhs, Expression rhs) { | 1185   JS.Expression _emitSet(Expression lhs, Expression rhs) { | 
| 1186     if (lhs is IndexExpression) { | 1186     if (lhs is IndexExpression) { | 
| 1187       return _emitSend(_getTarget(lhs), '[]=', [lhs.index, rhs]); | 1187       var target = _getTarget(lhs); | 
|  | 1188       if (_useNativeJsIndexer(target.staticType)) { | 
|  | 1189         return js.call( | 
|  | 1190             '#[#] = #', [_visit(target), _visit(lhs.index), _visit(rhs)]); | 
|  | 1191       } | 
|  | 1192       return _emitSend(target, '[]=', [lhs.index, rhs]); | 
| 1188     } | 1193     } | 
| 1189 | 1194 | 
| 1190     Expression target = null; | 1195     Expression target = null; | 
| 1191     SimpleIdentifier id; | 1196     SimpleIdentifier id; | 
| 1192     if (lhs is PropertyAccess) { | 1197     if (lhs is PropertyAccess) { | 
| 1193       target = _getTarget(lhs); | 1198       target = _getTarget(lhs); | 
| 1194       id = lhs.propertyName; | 1199       id = lhs.propertyName; | 
| 1195     } else if (lhs is PrefixedIdentifier) { | 1200     } else if (lhs is PrefixedIdentifier) { | 
| 1196       target = lhs.prefix; | 1201       target = lhs.prefix; | 
| 1197       id = lhs.identifier; | 1202       id = lhs.identifier; | 
| (...skipping 740 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1938         _visitList(args) | 1943         _visitList(args) | 
| 1939       ]); | 1944       ]); | 
| 1940     } | 1945     } | 
| 1941 | 1946 | 
| 1942     // Generic dispatch to a statically known method. | 1947     // Generic dispatch to a statically known method. | 
| 1943     return js.call('#.#(#)', [_visit(target), memberName, _visitList(args)]); | 1948     return js.call('#.#(#)', [_visit(target), memberName, _visitList(args)]); | 
| 1944   } | 1949   } | 
| 1945 | 1950 | 
| 1946   @override | 1951   @override | 
| 1947   visitIndexExpression(IndexExpression node) { | 1952   visitIndexExpression(IndexExpression node) { | 
| 1948     return _emitSend(_getTarget(node), '[]', [node.index]); | 1953     var target = _getTarget(node); | 
|  | 1954     if (_useNativeJsIndexer(target.staticType)) { | 
|  | 1955       return new JS.PropertyAccess(_visit(target), _visit(node.index)); | 
|  | 1956     } | 
|  | 1957     return _emitSend(target, '[]', [node.index]); | 
| 1949   } | 1958   } | 
| 1950 | 1959 | 
|  | 1960   // TODO(jmesserly): ideally we'd check the method and see if it is marked | 
|  | 1961   // `external`, but that doesn't work because it isn't in the element model. | 
|  | 1962   bool _useNativeJsIndexer(DartType type) => | 
|  | 1963       findElementAnnotation(type.element, _isJsIndexerAnnotation) != null; | 
|  | 1964 | 
| 1951   /// Gets the target of a [PropertyAccess] or [IndexExpression]. | 1965   /// Gets the target of a [PropertyAccess] or [IndexExpression]. | 
| 1952   /// Those two nodes are special because they're both allowed on left side of | 1966   /// Those two nodes are special because they're both allowed on left side of | 
| 1953   /// an assignment expression and cascades. | 1967   /// an assignment expression and cascades. | 
| 1954   Expression _getTarget(node) { | 1968   Expression _getTarget(node) { | 
| 1955     assert(node is IndexExpression || node is PropertyAccess); | 1969     assert(node is IndexExpression || node is PropertyAccess); | 
| 1956     return node.isCascaded ? _cascadeTarget : node.target; | 1970     return node.isCascaded ? _cascadeTarget : node.target; | 
| 1957   } | 1971   } | 
| 1958 | 1972 | 
| 1959   @override | 1973   @override | 
| 1960   visitConditionalExpression(ConditionalExpression node) { | 1974   visitConditionalExpression(ConditionalExpression node) { | 
| (...skipping 497 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 2458     assert(uri.scheme == 'package'); | 2472     assert(uri.scheme == 'package'); | 
| 2459     // filepath is good here, we want the output to start with a directory | 2473     // filepath is good here, we want the output to start with a directory | 
| 2460     // matching the package name. | 2474     // matching the package name. | 
| 2461   } | 2475   } | 
| 2462   return filepath; | 2476   return filepath; | 
| 2463 } | 2477 } | 
| 2464 | 2478 | 
| 2465 // TODO(jmesserly): validate the library. See issue #135. | 2479 // TODO(jmesserly): validate the library. See issue #135. | 
| 2466 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName'; | 2480 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName'; | 
| 2467 | 2481 | 
|  | 2482 bool _isJsIndexerAnnotation(DartObjectImpl value) => | 
|  | 2483     value.type.name == 'JsIndexer'; | 
|  | 2484 | 
| 2468 bool _isJsPeerInterface(DartObjectImpl value) => | 2485 bool _isJsPeerInterface(DartObjectImpl value) => | 
| 2469     value.type.name == 'JsPeerInterface'; | 2486     value.type.name == 'JsPeerInterface'; | 
| 2470 | 2487 | 
| 2471 // TODO(jacobr): we would like to do something like the following | 2488 // TODO(jacobr): we would like to do something like the following | 
| 2472 // but we don't have summary support yet. | 2489 // but we don't have summary support yet. | 
| 2473 // bool _supportJsExtensionMethod(AnnotatedNode node) => | 2490 // bool _supportJsExtensionMethod(AnnotatedNode node) => | 
| 2474 //    _getAnnotation(node, "SupportJsExtensionMethod") != null; | 2491 //    _getAnnotation(node, "SupportJsExtensionMethod") != null; | 
| 2475 | 2492 | 
| 2476 /// A special kind of element created by the compiler, signifying a temporary | 2493 /// A special kind of element created by the compiler, signifying a temporary | 
| 2477 /// variable. These objects use instance equality, and should be shared | 2494 /// variable. These objects use instance equality, and should be shared | 
| 2478 /// everywhere in the tree where they are treated as the same variable. | 2495 /// everywhere in the tree where they are treated as the same variable. | 
| 2479 class TemporaryVariableElement extends LocalVariableElementImpl { | 2496 class TemporaryVariableElement extends LocalVariableElementImpl { | 
| 2480   TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 2497   TemporaryVariableElement.forNode(Identifier name) : super.forNode(name); | 
| 2481 | 2498 | 
| 2482   int get hashCode => identityHashCode(this); | 2499   int get hashCode => identityHashCode(this); | 
| 2483   bool operator ==(Object other) => identical(this, other); | 2500   bool operator ==(Object other) => identical(this, other); | 
| 2484 } | 2501 } | 
| OLD | NEW | 
|---|