Create the JavaScript constructor dynamically.

Review URL: https://chromiumcodereview.appspot.com//10344021

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@7376 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
floitsch@google.com
2012-05-07 13:40:41 +00:00
parent 4e3f5102f9
commit 4175431008
2 changed files with 66 additions and 35 deletions
+38 -35
View File
@@ -53,11 +53,12 @@ class CodeEmitterTask extends CompilerTask {
=> '${namer.ISOLATE}.${namer.ISOLATE_PROPERTIES}';
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).
// The caller can also pass in the constructor as a function if needed.
//
// Example:
// defineClass("A", "B",
// function(x) { /* The JavaScript constructor. */
// this.x = x;
// }, { /* The members inside an Object literal. */
// defineClass("A", "B", ["x", "y"], {
// foo$1: function(y) {
// print(this.x + y);
// },
@@ -66,7 +67,21 @@ class CodeEmitterTask extends CompilerTask {
// },
// });
return """
function(cls, superclass, constructor, prototype) {
function(cls, superclass, fields, prototype) {
var constructor;
if (typeof fields == 'function') {
constructor = fields;
} else {
var str = "(function " + cls + "(";
var body = "";
for (var i = 0; i < fields.length; i++) {
if (i != 0) str += ", ";
str += fields[i];
body += "this." + fields[i] + " = " + fields[i] + ";\\n";
}
str += ") {" + body + "})";
constructor = eval(str);
}
$isolatePropertiesName[cls] = constructor;
constructor.prototype = prototype;
if (superclass !== "") {
@@ -359,30 +374,16 @@ function() {
emitExtraAccessors(member, defineInstanceMember);
}
bool generateFieldInits(ClassElement classElement,
StringBuffer argumentsBuffer,
StringBuffer bodyBuffer) {
bool isFirst = true;
void generateFieldInit(ClassElement enclosingClass, Element member) {
// TODO(floitsch): make sure there are no name clashes.
String className = namer.getName(enclosingClass);
if (!isFirst) argumentsBuffer.add(', ');
isFirst = false;
String memberName = namer.instanceFieldName(member.getLibrary(),
member.name);
String parameter;
if (classElement === enclosingClass) {
parameter = memberName;
} else {
parameter = '${className}_$memberName';
}
argumentsBuffer.add(parameter);
bodyBuffer.add(' this.$memberName = $parameter;\n');
List<String> generateFieldList(ClassElement classElement) {
List<String> result = <String>[];
void addField(ClassElement enclosingClass, Element member) {
result.add(namer.instanceFieldName(member.getLibrary(), member.name));
}
classElement.forEachInstanceField(generateFieldInit,
classElement.forEachInstanceField(addField,
includeBackendMembers: true,
includeSuperMembers: true);
return result;
}
void generateClass(ClassElement classElement, StringBuffer buffer) {
@@ -406,18 +407,20 @@ function() {
}
String constructorName = namer.safeName(classElement.name.slowToString());
buffer.add('$defineClassName("$className", "$superName", ');
buffer.add('function $constructorName(');
StringBuffer bodyBuffer = new StringBuffer();
// If the class is never instantiated we still need to set it up for
// inheritance purposes, but we can leave its JavaScript constructor empty.
if (compiler.universe.instantiatedClasses.contains(classElement)) {
generateFieldInits(classElement, buffer, bodyBuffer);
// 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');
buffer.add(bodyBuffer);
buffer.add(' }, ');
buffer.add('{\n');
buffer.add(', {\n');
void defineInstanceMember(String name, String value) {
buffer.add(' $name: $value,\n');
+28
View File
@@ -0,0 +1,28 @@
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
class A {
A() : x = 3;
foo() => x;
var x;
}
class B extends A {
bar() => 499;
}
class C extends A {
bar() => 42;
}
main() {
// We don't instantiate A, but the codegen still needs to emit (parts of) it
// for inheritence purposes.
var b = new B();
var c = new C();
Expect.equals(3, b.foo());
Expect.equals(3, c.foo());
Expect.equals(499, b.bar());
Expect.equals(42, c.bar());
}