Chromium Code Reviews

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

Issue 1095563003: [refactor] js_codegen: remove currentClass, simplify visitSimpleIdentifier (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.
Jump to:
View unified diff |
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 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 38 matching lines...)
49 final TypeRules rules; 49 final TypeRules rules;
50 50
51 /// The global extension method table. 51 /// The global extension method table.
52 final HashMap<String, List<InterfaceType>> _extensionMethods; 52 final HashMap<String, List<InterfaceType>> _extensionMethods;
53 53
54 /// The variable for the target of the current `..` cascade expression. 54 /// The variable for the target of the current `..` cascade expression.
55 SimpleIdentifier _cascadeTarget; 55 SimpleIdentifier _cascadeTarget;
56 /// The variable for the current catch clause 56 /// The variable for the current catch clause
57 SimpleIdentifier _catchParameter; 57 SimpleIdentifier _catchParameter;
58 58
59 ClassDeclaration currentClass;
60 ConstantEvaluator _constEvaluator; 59 ConstantEvaluator _constEvaluator;
61 60
62 final _exports = new Set<String>(); 61 final _exports = new Set<String>();
63 final _lazyFields = <VariableDeclaration>[]; 62 final _lazyFields = <VariableDeclaration>[];
64 final _properties = <FunctionDeclaration>[]; 63 final _properties = <FunctionDeclaration>[];
65 final _privateNames = new HashMap<String, JSTemporary>(); 64 final _privateNames = new HashMap<String, JSTemporary>();
66 final _pendingPrivateNames = <JSTemporary>[]; 65 final _pendingPrivateNames = <JSTemporary>[];
67 final _extensionMethodNames = new HashSet<String>(); 66 final _extensionMethodNames = new HashSet<String>();
68 final _pendingExtensionMethodNames = <String>[]; 67 final _pendingExtensionMethodNames = <String>[];
69 final _temps = new HashMap<Element, JSTemporary>(); 68 final _temps = new HashMap<Element, JSTemporary>();
(...skipping 246 matching lines...)
316 315
317 @override 316 @override
318 JS.Statement visitClassDeclaration(ClassDeclaration node) { 317 JS.Statement visitClassDeclaration(ClassDeclaration node) {
319 // If we've already emitted this class, skip it. 318 // If we've already emitted this class, skip it.
320 var type = node.element.type; 319 var type = node.element.type;
321 if (_pendingClasses.remove(node.element) == null) return null; 320 if (_pendingClasses.remove(node.element) == null) return null;
322 321
323 var jsName = getAnnotationValue(node, _isJsNameAnnotation); 322 var jsName = getAnnotationValue(node, _isJsNameAnnotation);
324 if (jsName != null) return _emitJsType(node.name.name, jsName); 323 if (jsName != null) return _emitJsType(node.name.name, jsName);
325 324
326 currentClass = node;
327
328 var ctors = <ConstructorDeclaration>[]; 325 var ctors = <ConstructorDeclaration>[];
329 var fields = <FieldDeclaration>[]; 326 var fields = <FieldDeclaration>[];
330 var staticFields = <FieldDeclaration>[]; 327 var staticFields = <FieldDeclaration>[];
331 for (var member in node.members) { 328 for (var member in node.members) {
332 if (member is ConstructorDeclaration) { 329 if (member is ConstructorDeclaration) {
333 ctors.add(member); 330 ctors.add(member);
334 } else if (member is FieldDeclaration) { 331 } else if (member is FieldDeclaration) {
335 (member.isStatic ? staticFields : fields).add(member); 332 (member.isStatic ? staticFields : fields).add(member);
336 } 333 }
337 } 334 }
338 335
339 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name), 336 var classExpr = new JS.ClassExpression(new JS.Identifier(type.name),
340 _classHeritage(node), _emitClassMethods(node, ctors, fields)); 337 _classHeritage(node), _emitClassMethods(node, ctors, fields));
341 338
342 var body = 339 var body =
343 _finishClassMembers(node.element, classExpr, ctors, staticFields); 340 _finishClassMembers(node.element, classExpr, ctors, staticFields);
344 currentClass = null;
345 341
346 return _finishClassDef(type, body); 342 return _finishClassDef(type, body);
347 } 343 }
348 344
349 @override 345 @override
350 JS.Statement visitEnumDeclaration(EnumDeclaration node) => 346 JS.Statement visitEnumDeclaration(EnumDeclaration node) =>
351 _unimplementedCall("Unimplemented enum: $node").toStatement(); 347 _unimplementedCall("Unimplemented enum: $node").toStatement();
352 348
353 /// Given a class element and body, complete the class declaration. 349 /// Given a class element and body, complete the class declaration.
354 /// This handles generic type parameters, laziness (in library-cycle cases), 350 /// This handles generic type parameters, laziness (in library-cycle cases),
(...skipping 627 matching lines...)
982 return new JS.Block([ 978 return new JS.Block([
983 js.comment("// Function ${func.name.name}: ${func.element.type}\n"), 979 js.comment("// Function ${func.name.name}: ${func.element.type}\n"),
984 new JS.FunctionDeclaration(name, _visit(func.functionExpression)) 980 new JS.FunctionDeclaration(name, _visit(func.functionExpression))
985 ]); 981 ]);
986 } 982 }
987 983
988 /// Writes a simple identifier. This can handle implicit `this` as well as 984 /// Writes a simple identifier. This can handle implicit `this` as well as
989 /// going through the qualified library name if necessary. 985 /// going through the qualified library name if necessary.
990 @override 986 @override
991 JS.Expression visitSimpleIdentifier(SimpleIdentifier node) { 987 JS.Expression visitSimpleIdentifier(SimpleIdentifier node) {
992 var e = node.staticElement; 988 var accessor = node.staticElement;
993 if (e == null) { 989 if (accessor == null) {
994 return js.commentExpression( 990 return js.commentExpression(
995 'Unimplemented unknown name', new JS.Identifier(node.name)); 991 'Unimplemented unknown name', new JS.Identifier(node.name));
996 } 992 }
997 993
998 var variable = e is PropertyAccessorElement ? e.variable : e; 994 // Get the original declaring element. If we had a property accessor, this
Jennifer Messerly 2015/04/16 22:50:30 "variable" was misleading ... this is just the "re
999 var name = variable.name; 995 // indirects back to a (possibly synthetic) field.
996 var element = accessor;
997 if (element is PropertyAccessorElement) element = accessor.variable;
Jennifer Messerly 2015/04/16 22:50:30 after this point we always use `element`.
998 var name = element.name;
1000 999
1001 // library member 1000 // library member
1002 if (e.enclosingElement is CompilationUnitElement && 1001 if (element.enclosingElement is CompilationUnitElement &&
1003 (e.library != libraryInfo.library || 1002 (element.library != libraryInfo.library ||
1004 variable is TopLevelVariableElement && !variable.isConst)) { 1003 element is TopLevelVariableElement && !element.isConst)) {
1005 return js.call('#.#', [_libraryName(e.library), name]); 1004 return js.call('#.#', [_libraryName(element.library), name]);
1006 } 1005 }
1007 1006
1008 // instance member 1007 // Unqualified class member. This could mean implicit-this, or implicit
1009 if (currentClass != null && _needsImplicitThis(e)) { 1008 // call to a static from the same class.
1010 return js.call( 1009 if (element is ClassMemberElement && element is! ConstructorElement) {
1011 'this.#', _emitMemberName(name, type: currentClass.element.type)); 1010 bool isStatic = element.isStatic;
1012 } 1011 var type = element.enclosingElement.type;
1013 1012
1014 // static member 1013 // For instance methods, we add implicit-this.
1015 if (e is ExecutableElement && 1014 // For static methods, we add the raw type name, without generics or
1016 e.isStatic && 1015 // library prefix. We don't need those because static calls can't use
1017 variable.enclosingElement is ClassElement) { 1016 // the generic type.
1018 var className = (variable.enclosingElement as ClassElement).name; 1017 var target = isStatic ? new JS.Identifier(type.name) : new JS.This();
1019 return js.call('#.#', [className, _emitMemberName(name, isStatic: true)]); 1018 var member = _emitMemberName(name, isStatic: isStatic, type: type);
1019 return new JS.PropertyAccess(target, member);
1020 } 1020 }
1021 1021
1022 // initializing formal parameter, e.g. `Point(this.x)` 1022 // initializing formal parameter, e.g. `Point(this.x)`
1023 if (e is ParameterElement && e.isInitializingFormal && e.isPrivate) { 1023 if (element is ParameterElement &&
1024 element.isInitializingFormal &&
1025 element.isPrivate) {
1024 /// Rename private names so they don't shadow the private field symbol. 1026 /// Rename private names so they don't shadow the private field symbol.
1025 /// The renamer would handle this, but it would prefer to rename the 1027 /// The renamer would handle this, but it would prefer to rename the
1026 /// temporary used for the private symbol. Instead rename the parameter. 1028 /// temporary used for the private symbol. Instead rename the parameter.
1027 return _getTemp(e, '${name.substring(1)}'); 1029 return _getTemp(element, '${name.substring(1)}');
1028 } 1030 }
1029 1031
1030 if (_isTemporary(e)) { 1032 if (_isTemporary(element)) {
1031 if (name[0] == '#') { 1033 if (name[0] == '#') {
1032 return new JS.InterpolatedExpression(name.substring(1)); 1034 return new JS.InterpolatedExpression(name.substring(1));
1033 } else { 1035 } else {
1034 return _getTemp(e, name); 1036 return _getTemp(element, name);
1035 } 1037 }
1036 } 1038 }
1037 1039
1038 return new JS.Identifier(name); 1040 return new JS.Identifier(name);
1039 } 1041 }
1040 1042
1041 JSTemporary _getTemp(Object key, String name) => 1043 JSTemporary _getTemp(Object key, String name) =>
1042 _temps.putIfAbsent(key, () => new JSTemporary(name)); 1044 _temps.putIfAbsent(key, () => new JSTemporary(name));
1043 1045
1044 JS.ArrayInitializer _emitTypeNames(List<DartType> types) { 1046 JS.ArrayInitializer _emitTypeNames(List<DartType> types) {
(...skipping 1235 matching lines...)
2280 2282
2281 /// Choose a canonical name from the library element. 2283 /// Choose a canonical name from the library element.
2282 /// This never uses the library's name (the identifier in the `library` 2284 /// This never uses the library's name (the identifier in the `library`
2283 /// declaration) as it doesn't have any meaningful rules enforced. 2285 /// declaration) as it doesn't have any meaningful rules enforced.
2284 JS.Identifier _libraryName(LibraryElement library) { 2286 JS.Identifier _libraryName(LibraryElement library) {
2285 if (library == libraryInfo.library) return _exportsVar; 2287 if (library == libraryInfo.library) return _exportsVar;
2286 return new JS.Identifier(jsLibraryName(library)); 2288 return new JS.Identifier(jsLibraryName(library));
2287 } 2289 }
2288 2290
2289 DartType getStaticType(Expression e) => rules.getStaticType(e); 2291 DartType getStaticType(Expression e) => rules.getStaticType(e);
2290
2291 static bool _needsImplicitThis(Element e) =>
2292 e is PropertyAccessorElement && !e.variable.isStatic ||
2293 e is ClassMemberElement && !e.isStatic && e is! ConstructorElement;
2294 } 2292 }
2295 2293
2296 class JSGenerator extends CodeGenerator { 2294 class JSGenerator extends CodeGenerator {
2297 final JSCodeOptions options; 2295 final JSCodeOptions options;
2298 2296
2299 /// For fast lookup of extension methods, we first check the name, then do a 2297 /// For fast lookup of extension methods, we first check the name, then do a
2300 /// (possibly expensive) subtype test to see if it matches one of the types 2298 /// (possibly expensive) subtype test to see if it matches one of the types
2301 /// that declares that method. 2299 /// that declares that method.
2302 final _extensionMethods = new HashMap<String, List<InterfaceType>>(); 2300 final _extensionMethods = new HashMap<String, List<InterfaceType>>();
2303 2301
(...skipping 55 matching lines...)
2359 return filepath; 2357 return filepath;
2360 } 2358 }
2361 2359
2362 // TODO(jmesserly): validate the library. See issue #135. 2360 // TODO(jmesserly): validate the library. See issue #135.
2363 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName'; 2361 bool _isJsNameAnnotation(DartObjectImpl value) => value.type.name == 'JsName';
2364 2362
2365 // TODO(jacobr): we would like to do something like the following 2363 // TODO(jacobr): we would like to do something like the following
2366 // but we don't have summary support yet. 2364 // but we don't have summary support yet.
2367 // bool _supportJsExtensionMethod(AnnotatedNode node) => 2365 // bool _supportJsExtensionMethod(AnnotatedNode node) =>
2368 // _getAnnotation(node, "SupportJsExtensionMethod") != null; 2366 // _getAnnotation(node, "SupportJsExtensionMethod") != null;
OLDNEW

Powered by Google App Engine