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

Unified Diff: lib/compiler/implementation/emitter.dart

Issue 10310060: Generate getters and setters dynamically. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Simplify by using a bool. Created 8 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | lib/compiler/implementation/namer.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/compiler/implementation/emitter.dart
diff --git a/lib/compiler/implementation/emitter.dart b/lib/compiler/implementation/emitter.dart
index 0b6b4ea5ac3c01c8f09fc0ea052501b6ee219005..9693497f1787bbfe98ecaa4a94f1b86d344164ad 100644
--- a/lib/compiler/implementation/emitter.dart
+++ b/lib/compiler/implementation/emitter.dart
@@ -52,6 +52,10 @@ class CodeEmitterTask extends CompilerTask {
String get isolatePropertiesName()
=> '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}';
+ final String GETTER_SUFFIX = "?";
+ final String SETTER_SUFFIX = "!";
+ final String GETTER_SETTER_SUFFIX = "=";
+
String get defineClassFunction() {
// First the class name, then the super class name, followed by the fields
// (in an array) and the members (inside an Object literal).
@@ -76,8 +80,27 @@ function(cls, superclass, fields, prototype) {
var body = "";
for (var i = 0; i < fields.length; i++) {
if (i != 0) str += ", ";
- str += fields[i];
- body += "this." + fields[i] + " = " + fields[i] + ";\\n";
+ var field = fields[i];
+ var len = field.length;
+ var lastChar = field[len - 1];
+ var needsGetter = false;
+ var needsSetter = false;
+ switch (lastChar) {
+ case '$GETTER_SUFFIX': needsGetter = true; break;
kasperl 2012/05/09 14:07:49 Indent cases.
floitsch 2012/05/09 14:11:19 Done.
+ case '$GETTER_SETTER_SUFFIX': needsGetter = true; // fallthrough.
kasperl 2012/05/09 14:07:49 fallthrough -> Fall-through
floitsch 2012/05/09 14:11:19 Done.
+ case '$SETTER_SUFFIX': needsSetter = true;
+ }
+ if (needsGetter || needsSetter) field = field.substring(0, len - 1);
+ str += field;
+ body += "this." + field + " = " + field + ";\\n";
+ if (needsGetter) {
+ var getterString = "return this." + field + ";";
+ prototype["get\$" + field] = new Function(getterString);
+ }
+ if (needsSetter) {
+ var setterString = "this." + field + " = v;";
+ prototype["set\$" + field] = new Function("v", setterString);
+ }
}
str += ") {" + body + "})";
constructor = eval(str);
@@ -326,7 +349,26 @@ function() {
}
}
+ bool instanceFieldNeedsGetter(Element member) {
+ assert(member.kind === ElementKind.FIELD);
+ return compiler.universe.hasGetter(member, compiler);
+ }
+
+ bool instanceFieldNeedsSetter(Element member) {
+ assert(member.kind === ElementKind.FIELD);
+ return (member.modifiers === null || !member.modifiers.isFinal())
+ && compiler.universe.hasSetter(member, compiler);
+ }
+
+ String compiledFieldName(Element member) {
+ assert(member.kind === ElementKind.FIELD);
+ return member.isNative()
+ ? member.name.slowToString()
+ : namer.getName(member);
+ }
+
void addInstanceMember(Element member,
+ bool needGettersAndSetters,
void defineInstanceMember(String invocationName,
String definition)) {
// TODO(floitsch): we don't need to deal with members of
@@ -350,22 +392,19 @@ function() {
addParameterStubs(member, defineInstanceMember);
}
} else if (member.kind === ElementKind.FIELD) {
- // TODO(ngeoffray): Have another class generate the code for the
- // fields.
- if ((member.modifiers === null || !member.modifiers.isFinal()) &&
- compiler.universe.hasSetter(member, compiler)) {
- String setterName = namer.setterName(member.getLibrary(), member.name);
- String name = member.isNative()
- ? member.name.slowToString()
- : namer.getName(member);
- defineInstanceMember(setterName, "function(v) { this.$name = v; }");
- }
- if (compiler.universe.hasGetter(member, compiler)) {
- String getterName = namer.getterName(member.getLibrary(), member.name);
- String name = member.isNative()
- ? member.name.slowToString()
- : namer.getName(member);
- defineInstanceMember(getterName, "function() { return this.$name; }");
+ // Getters and setters for non native members are generated dynamically.
kasperl 2012/05/09 14:07:49 non-native
floitsch 2012/05/09 14:11:19 forgot to upload latest cosmetic changes patchset.
+ if (needGettersAndSetters) {
+ if (instanceFieldNeedsGetter(member)) {
+ String getter = namer.getterName(member.getLibrary(), member.name);
+ String name = compiledFieldName(member);
+ defineInstanceMember(getter, "function() { return this.$name; }");
+ }
+
+ if (instanceFieldNeedsSetter(member)) {
+ String setter = namer.setterName(member.getLibrary(), member.name);
+ String name = compiledFieldName(member);
+ defineInstanceMember(setter, "function(v) { this.$name = v; }");
+ }
}
} else {
compiler.internalError('unexpected kind: "${member.kind}"',
@@ -374,54 +413,60 @@ function() {
emitExtraAccessors(member, defineInstanceMember);
}
- List<String> generateFieldList(ClassElement classElement) {
- List<String> result = <String>[];
+ Set<Element> emitClassFields(ClassElement classElement, StringBuffer buffer) {
+ // If the class is never instantiated we still need to set it up for
+ // inheritance purposes, but we can simplify its JavaScript constructor.
+ bool isInstantiated =
+ compiler.universe.instantiatedClasses.contains(classElement);
+
+ bool isFirstField = true;
void addField(ClassElement enclosingClass, Element member) {
- result.add(namer.instanceFieldName(member.getLibrary(), member.name));
+ assert(!member.isNative());
+ LibraryElement library = member.getLibrary();
+ SourceString name = member.name;
+ String fieldName = namer.instanceFieldName(library, name);
+ // See if we can dynamically create getters and setters.
+ // We can only generate getters and setters for [classElement] since
+ // the fields of super classes could be overwritten with getters or
+ // setters.
+ bool needsDynamicGetter = false;
+ bool needsDynamicSetter = false;
+ if (enclosingClass === classElement) {
+ needsDynamicGetter = instanceFieldNeedsGetter(member);
+ needsDynamicSetter = instanceFieldNeedsSetter(member);
+ }
+
+ if (isInstantiated || needsDynamicGetter || needsDynamicSetter) {
+ if (isFirstField) {
+ isFirstField = false;
+ } else {
+ buffer.add(", ");
+ }
+ // Getters and setters with suffixes will be generated dynamically.
+ buffer.add('"$fieldName');
+ if (needsDynamicGetter || needsDynamicSetter) {
+ if (needsDynamicGetter && needsDynamicSetter) {
+ buffer.add(GETTER_SETTER_SUFFIX);
+ } else if (needsDynamicGetter) {
+ buffer.add(GETTER_SUFFIX);
+ } else {
+ buffer.add(SETTER_SUFFIX);
+ }
+ }
+ buffer.add('"');
+ }
}
+ // If a class is not instantiated then we add the field just so we can
+ // generate the field getter/setter dynamically. Since this is only
+ // allowed on fields that are in [classElement] we don't need to visit
+ // superclasses for non-instantiated classes.
classElement.forEachInstanceField(addField,
includeBackendMembers: true,
- includeSuperMembers: true);
- return result;
+ includeSuperMembers: isInstantiated);
}
- void generateClass(ClassElement classElement, StringBuffer buffer) {
- needsDefineClass = true;
-
- if (classElement.isNative()) {
- nativeEmitter.generateNativeClass(classElement);
- return;
- } else {
- // TODO(ngeoffray): Instead of switching between buffer, we
- // should create code sections, and decide where to emit them at
- // the end.
- buffer = mainBuffer;
- }
-
- String className = namer.getName(classElement);
- ClassElement superclass = classElement.superclass;
- String superName = "";
- if (superclass !== null) {
- superName = namer.getName(superclass);
- }
- String constructorName = namer.safeName(classElement.name.slowToString());
- buffer.add('$defineClassName("$className", "$superName", ');
- // If the class is never instantiated we still need to set it up for
- // inheritance purposes, but we can simplify its JavaScript constructor.
- if (!compiler.universe.instantiatedClasses.contains(classElement)) {
- buffer.add("[]");
- } else {
- List<String> fields = generateFieldList(classElement);
- buffer.add('[');
- for (int i = 0; i < fields.length; i++) {
- if (i != 0) buffer.add(", ");
- buffer.add('"${fields[i]}"');
- }
- buffer.add(']');
- }
- buffer.add(', {\n');
-
+ void emitInstanceMembers(ClassElement classElement, StringBuffer buffer) {
void defineInstanceMember(String name, String value) {
buffer.add(' $name: $value,\n');
}
@@ -429,7 +474,10 @@ function() {
classElement.forEachMember(includeBackendMembers: true,
f: (ClassElement enclosing, Element member) {
if (member.isInstanceMember()) {
- addInstanceMember(member, defineInstanceMember);
+ // All getters and setters for non-native classes are generated
+ // dynamically.
+ bool needGettersAndSetters = false;
+ addInstanceMember(member, needGettersAndSetters, defineInstanceMember);
}
});
@@ -449,6 +497,33 @@ function() {
// script.
emitNoSuchMethodCalls(defineInstanceMember);
}
+ }
+
+ void generateClass(ClassElement classElement, StringBuffer buffer) {
+ needsDefineClass = true;
+
+ if (classElement.isNative()) {
+ nativeEmitter.generateNativeClass(classElement);
+ return;
+ } else {
+ // TODO(ngeoffray): Instead of switching between buffer, we
+ // should create code sections, and decide where to emit them at
+ // the end.
+ buffer = mainBuffer;
+ }
+
+ String className = namer.getName(classElement);
+ ClassElement superclass = classElement.superclass;
+ String superName = "";
+ if (superclass !== null) {
+ superName = namer.getName(superclass);
+ }
+ String constructorName = namer.safeName(classElement.name.slowToString());
+
+ buffer.add('$defineClassName("$className", "$superName", [');
+ emitClassFields(classElement, buffer);
+ buffer.add('], {\n');
+ emitInstanceMembers(classElement, buffer);
buffer.add('});\n\n');
}
« no previous file with comments | « no previous file | lib/compiler/implementation/namer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698