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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 final HashSet<FieldElement> _fieldsNeedingStorage; | 61 final HashSet<FieldElement> _fieldsNeedingStorage; |
62 | 62 |
63 /// The variable for the target of the current `..` cascade expression. | 63 /// The variable for the target of the current `..` cascade expression. |
64 SimpleIdentifier _cascadeTarget; | 64 SimpleIdentifier _cascadeTarget; |
65 | 65 |
66 /// The variable for the current catch clause | 66 /// The variable for the current catch clause |
67 SimpleIdentifier _catchParameter; | 67 SimpleIdentifier _catchParameter; |
68 | 68 |
69 ConstantEvaluator _constEvaluator; | 69 ConstantEvaluator _constEvaluator; |
70 | 70 |
| 71 ClassElement _currentClassElement = null; |
| 72 |
71 /// Imported libraries, and the temporaries used to refer to them. | 73 /// Imported libraries, and the temporaries used to refer to them. |
72 final _imports = new Map<LibraryElement, JS.TemporaryId>(); | 74 final _imports = new Map<LibraryElement, JS.TemporaryId>(); |
73 final _exports = new Set<String>(); | 75 final _exports = new Set<String>(); |
74 final _lazyFields = <VariableDeclaration>[]; | 76 final _lazyFields = <VariableDeclaration>[]; |
75 final _properties = <FunctionDeclaration>[]; | 77 final _properties = <FunctionDeclaration>[]; |
76 final _privateNames = new HashMap<String, JS.TemporaryId>(); | 78 final _privateNames = new HashMap<String, JS.TemporaryId>(); |
77 final _extensionMethodNames = new HashSet<String>(); | 79 final _extensionMethodNames = new HashSet<String>(); |
78 final _pendingStatements = <JS.Statement>[]; | 80 final _pendingStatements = <JS.Statement>[]; |
79 final _temps = new HashMap<Element, JS.TemporaryId>(); | 81 final _temps = new HashMap<Element, JS.TemporaryId>(); |
80 | 82 |
(...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 JS.Statement visitClassDeclaration(ClassDeclaration node) { | 327 JS.Statement visitClassDeclaration(ClassDeclaration node) { |
326 // If we've already emitted this class, skip it. | 328 // If we've already emitted this class, skip it. |
327 var classElem = node.element; | 329 var classElem = node.element; |
328 var type = classElem.type; | 330 var type = classElem.type; |
329 if (_pendingClasses.remove(classElem) == null) return null; | 331 if (_pendingClasses.remove(classElem) == null) return null; |
330 | 332 |
331 var jsName = getAnnotationValue(node, _isJsNameAnnotation); | 333 var jsName = getAnnotationValue(node, _isJsNameAnnotation); |
332 | 334 |
333 if (jsName != null) return _emitJsType(node.name.name, jsName); | 335 if (jsName != null) return _emitJsType(node.name.name, jsName); |
334 | 336 |
| 337 // Set current class |
| 338 assert(_currentClassElement == null); |
| 339 _currentClassElement = classElem; |
| 340 |
335 var ctors = <ConstructorDeclaration>[]; | 341 var ctors = <ConstructorDeclaration>[]; |
336 var fields = <FieldDeclaration>[]; | 342 var fields = <FieldDeclaration>[]; |
337 var staticFields = <FieldDeclaration>[]; | 343 var staticFields = <FieldDeclaration>[]; |
338 for (var member in node.members) { | 344 for (var member in node.members) { |
339 if (member is ConstructorDeclaration) { | 345 if (member is ConstructorDeclaration) { |
340 ctors.add(member); | 346 ctors.add(member); |
341 } else if (member is FieldDeclaration) { | 347 } else if (member is FieldDeclaration) { |
342 (member.isStatic ? staticFields : fields).add(member); | 348 (member.isStatic ? staticFields : fields).add(member); |
343 } | 349 } |
344 } | 350 } |
345 | 351 |
346 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), | 352 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), |
347 _classHeritage(node), _emitClassMethods(node, ctors, fields)); | 353 _classHeritage(node), _emitClassMethods(node, ctors, fields)); |
348 | 354 |
349 String jsPeerName; | 355 String jsPeerName; |
350 var jsPeer = getAnnotationValue(node, _isJsPeerInterface); | 356 var jsPeer = getAnnotationValue(node, _isJsPeerInterface); |
351 if (jsPeer != null) { | 357 if (jsPeer != null) { |
352 jsPeerName = getConstantField(jsPeer, 'name', types.stringType); | 358 jsPeerName = getConstantField(jsPeer, 'name', types.stringType); |
353 } | 359 } |
354 | 360 |
355 var body = _finishClassMembers( | 361 var body = _finishClassMembers( |
356 classElem, classExpr, ctors, fields, staticFields, jsPeerName); | 362 classElem, classExpr, ctors, fields, staticFields, jsPeerName); |
357 | 363 |
| 364 // Unset current class |
| 365 assert(_currentClassElement == classElem); |
| 366 _currentClassElement = null; |
| 367 |
358 var result = _finishClassDef(type, body); | 368 var result = _finishClassDef(type, body); |
359 | 369 |
360 if (jsPeerName != null) { | 370 if (jsPeerName != null) { |
361 // This class isn't allowed to be lazy, because we need to set up | 371 // This class isn't allowed to be lazy, because we need to set up |
362 // the native JS type eagerly at this point. | 372 // the native JS type eagerly at this point. |
363 // If we wanted to support laziness, we could defer the hookup until | 373 // If we wanted to support laziness, we could defer the hookup until |
364 // the end of the Dart library cycle load. | 374 // the end of the Dart library cycle load. |
365 assert(!_lazyClass(type)); | 375 assert(!_lazyClass(type)); |
366 | 376 |
367 // TODO(jmesserly): this copies the dynamic members. | 377 // TODO(jmesserly): this copies the dynamic members. |
(...skipping 860 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1228 ]); | 1238 ]); |
1229 } | 1239 } |
1230 } | 1240 } |
1231 // TODO(jmesserly): remove when we're using coercion reifier. | 1241 // TODO(jmesserly): remove when we're using coercion reifier. |
1232 return _unimplementedCall('Unimplemented type $type'); | 1242 return _unimplementedCall('Unimplemented type $type'); |
1233 } | 1243 } |
1234 | 1244 |
1235 var typeArgs = null; | 1245 var typeArgs = null; |
1236 if (type is ParameterizedType) { | 1246 if (type is ParameterizedType) { |
1237 var args = type.typeArguments; | 1247 var args = type.typeArguments; |
| 1248 var isCurrentClass = |
| 1249 type is InterfaceType ? type.element == _currentClassElement : false; |
1238 if (args.any((a) => a != types.dynamicType)) { | 1250 if (args.any((a) => a != types.dynamicType)) { |
1239 name = '$name\$'; | 1251 name = '$name\$'; |
1240 typeArgs = args.map(_emitTypeName); | 1252 typeArgs = args.map(_emitTypeName); |
| 1253 } else if (args.isNotEmpty && isCurrentClass) { |
| 1254 // When creating a `new S<dynamic>` we try and use the raw form |
| 1255 // `new S()`, but this does not work if we're inside the same class, |
| 1256 // because `S` refers to the current S<T> we are generating. |
| 1257 name = '$name\$'; |
| 1258 typeArgs = []; |
1241 } | 1259 } |
1242 } | 1260 } |
1243 | 1261 |
1244 JS.Expression result; | 1262 JS.Expression result; |
1245 if (_needQualifiedName(element)) { | 1263 if (_needQualifiedName(element)) { |
1246 result = js.call('#.#', [_libraryName(element.library), name]); | 1264 result = js.call('#.#', [_libraryName(element.library), name]); |
1247 } else { | 1265 } else { |
1248 result = new JS.Identifier(name); | 1266 result = new JS.Identifier(name); |
1249 } | 1267 } |
1250 | 1268 |
(...skipping 1343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2594 // TODO(jmesserly): validate the library. See issue #135. | 2612 // TODO(jmesserly): validate the library. See issue #135. |
2595 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName'; | 2613 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName'; |
2596 | 2614 |
2597 bool _isJsPeerInterface(DartObjectImpl value) => | 2615 bool _isJsPeerInterface(DartObjectImpl value) => |
2598 value.type.name == 'JsPeerInterface'; | 2616 value.type.name == 'JsPeerInterface'; |
2599 | 2617 |
2600 // TODO(jacobr): we would like to do something like the following | 2618 // TODO(jacobr): we would like to do something like the following |
2601 // but we don't have summary support yet. | 2619 // but we don't have summary support yet. |
2602 // bool _supportJsExtensionMethod(AnnotatedNode node) => | 2620 // bool _supportJsExtensionMethod(AnnotatedNode node) => |
2603 // _getAnnotation(node, "SupportJsExtensionMethod") != null; | 2621 // _getAnnotation(node, "SupportJsExtensionMethod") != null; |
OLD | NEW |