Fix dumpclass.js and make SourceTracer less dumb

This commit is contained in:
Shu-yu Guo 2012-07-02 15:26:06 -07:00
Родитель e65d000ef1
Коммит 4aa448087c
2 изменённых файлов: 201 добавлений и 204 удалений

Просмотреть файл

@ -20,9 +20,10 @@ load("../../swf/text.js");
load("../util.js");
load("../options.js");
load("../metrics.js");
var Timer = metrics.Timer;
var stdout = new IndentingWriter();
var ArgumentParser = options.ArgumentParser;
var Option = options.Option;
var OptionSet = options.OptionSet;
@ -59,35 +60,22 @@ try {
}
function forEachABC(swf, cb) {
var dictionary = { };
var controlTags = [];
var buffer = snarf(swf, "binary");
SWF.parse(buffer, {
onprogress: function(result) {
var tags = result.tags.slice(i);
var tag = tags[tags.length - 1];
if (!('id' in tag) && !('ref' in tag)) {
var pframes = cast(controlTags.concat(tags), dictionary);
controlTags = [];
var i = 0;
var pframe;
while (pframe = pframes[i++]) {
var blocks = pframe.abcBlocks;
if (blocks) {
var j = 0;
var block;
while (block = blocks[j++]) {
cb(new AbcFile(block));
}
}
SWF.parse(snarf(swf, "binary"), {
oncomplete: function(result) {
var tags = result.tags;
var abcCount = 0;
for (var i = 0, n = tags.length; i < n; i++) {
var tag = tags[i];
if (tag.type === "abc") {
cb(new AbcFile(tag.data));
}
}
},
}
});
}
var writer = new IndentingWriter();
var tracer = new SourceTracer(writer);
forEachABC(swfFile.value, function (abc) {
abc.scripts.forEach(function (script) {
script.traits.traits.forEach(function (trait) {
@ -95,10 +83,10 @@ forEachABC(swfFile.value, function (abc) {
var cname = trait.classInfo.instanceInfo.name;
if (cname.getName() === className.value) {
writer.enter("package " + cname.namespaces[0].originalURI + " {\n");
SourceTracer.traceMetadata(trait.metadata);
SourceTracer.traceClass(trait.classInfo);
tracer.traceMetadata(trait.metadata);
tracer.traceClass(trait.classInfo);
writer.leave("\n}");
SourceTracer.traceClassStub(trait);
tracer.traceClassStub(trait);
}
}
});

Просмотреть файл

@ -206,7 +206,7 @@ MethodInfo.prototype.trace = function trace(writer, abc) {
writer.leave("}");
}
var SourceTracer = (function (writer) {
var SourceTracer = (function () {
function literal(value) {
if (value === undefined) {
return "undefined";
@ -234,207 +234,216 @@ var SourceTracer = (function (writer) {
}).join(", ");
}
function SourceTracer(writer) {
this.writer = writer;
}
function traceTraits(traits, isStatic, inInterfaceNamespace) {
traits.traits.forEach(function (trait) {
var str;
var accessModifier = trait.name.getAccessModifier();
var namespaceName = trait.name.namespaces[0].originalURI;
if (namespaceName) {
if (namespaceName === "http://adobe.com/AS3/2006/builtin") {
namespaceName = "AS3";
}
if (accessModifier === "public") {
str = inInterfaceNamespace === namespaceName ? "" : namespaceName;
SourceTracer.prototype = {
traceTraits: function traceTraits(traits, isStatic, inInterfaceNamespace) {
const writer = this.writer;
const tracer = this;
traits.traits.forEach(function (trait) {
var str;
var accessModifier = trait.name.getAccessModifier();
var namespaceName = trait.name.namespaces[0].originalURI;
if (namespaceName) {
if (namespaceName === "http://adobe.com/AS3/2006/builtin") {
namespaceName = "AS3";
}
if (accessModifier === "public") {
str = inInterfaceNamespace === namespaceName ? "" : namespaceName;
} else {
str = accessModifier;
}
} else {
str = accessModifier;
}
} else {
str = accessModifier;
}
if (isStatic) {
str += " static";
}
if (trait.isSlot() || trait.isConst()) {
traceMetadata(trait.metadata);
if (trait.isConst()) {
str += " const";
} else {
str += " var";
if (isStatic) {
str += " static";
}
str += " " + trait.name.getName();
if (trait.typeName) {
str += ":" + trait.typeName.getName();
}
if (trait.value) {
str += " = " + literal(trait.value);
}
writer.writeLn(str + ";");
} else if (trait.isMethod() || trait.isGetter() || trait.isSetter()) {
traceMetadata(trait.metadata);
var mi = trait.methodInfo;
if (trait.attributes & ATTR_Override) {
str += " override";
}
if (mi.isNative()) {
str += " native";
}
str += " function";
str += trait.isGetter() ? " get" : (trait.isSetter() ? " set" : "");
str += " " + trait.name.getName();
str += "(" + getSignature(mi) + ")";
str += mi.returnType ? ":" + mi.returnType.getName() : "";
if (mi.isNative()) {
if (trait.isSlot() || trait.isConst()) {
tracer.traceMetadata(trait.metadata);
if (trait.isConst()) {
str += " const";
} else {
str += " var";
}
str += " " + trait.name.getName();
if (trait.typeName) {
str += ":" + trait.typeName.getName();
}
if (trait.value) {
str += " = " + literal(trait.value);
}
writer.writeLn(str + ";");
} else {
if (inInterfaceNamespace) {
} else if (trait.isMethod() || trait.isGetter() || trait.isSetter()) {
tracer.traceMetadata(trait.metadata);
var mi = trait.methodInfo;
if (trait.attributes & ATTR_Override) {
str += " override";
}
if (mi.isNative()) {
str += " native";
}
str += " function";
str += trait.isGetter() ? " get" : (trait.isSetter() ? " set" : "");
str += " " + trait.name.getName();
str += "(" + getSignature(mi) + ")";
str += mi.returnType ? ":" + mi.returnType.getName() : "";
if (mi.isNative()) {
writer.writeLn(str + ";");
} else {
writer.writeLn(str + " { notImplemented(\"" + trait.name.getName() + "\"); }");
}
}
} else if (trait.isClass()) {
var className = trait.classInfo.instanceInfo.name;
writer.enter("package " + className.namespaces[0].originalURI + " {\n");
traceMetadata(trait.metadata);
traceClass(trait.classInfo);
writer.leave("\n}");
traceClassStub(trait);
} else {
notImplemented();
}
});
}
function traceClassStub(trait) {
var ci = trait.classInfo;
var ii = ci.instanceInfo;
var name = ii.name.getName();
var native = trait.metadata ? trait.metadata.native : null;
if (!native) {
return;
}
writer.enter("Shumway Stub {");
writer.enter("natives." + native.cls + " = function " + native.cls + "(scope, instance, baseClass) {");
writer.writeLn("// Signature: " + getSignature(ii.init));
var initSignature = getSignature(ii.init, true);
writer.writeLn("function " + name + "(" + initSignature + ") {");
writer.writeLn(" instance.call(this" + (initSignature ? ", " + initSignature : "") + ")");
writer.writeLn("};");
writer.writeLn("var c = new Class(\"" + name + "\", " + name +
", Class.passthroughCallable(" + name + "));");
writer.writeLn("//");
writer.writeLn("// WARNING! This sets:")
writer.writeLn("// " + name + ".prototype = " +
"Object.create(baseClass.instance.prototype)");
writer.writeLn("//");
writer.writeLn("// If you want to manage prototypes manually, do this instead:");
writer.writeLn("// c.baseClass = baseClass");
writer.writeLn("//");
writer.writeLn("c.extend(baseClass);");
function traceTraits(traits, isStatic) {
traits.traits.forEach(function (trait) {
var traitName = trait.name.getName();
if (trait.isMethod() || trait.isGetter() || trait.isSetter()) {
var mi = trait.methodInfo;
if (mi.isNative()) {
var str = isStatic ? "s" : "m";
if (mi.parameters.length) {
var returnTypeStr = "";
if (mi.returnType) {
returnTypeStr = " -> " + mi.returnType.getName();
}
writer.writeLn("// Signature: " + getSignature(mi) + returnTypeStr);
}
var prop;
if (trait.isGetter()) {
prop = "[\"get " + traitName + "\"]";
} else if (trait.isSetter()) {
prop = "[\"set " + traitName + "\"]";
if (inInterfaceNamespace) {
writer.writeLn(str + ";");
} else {
prop = "." + traitName;
writer.writeLn(str + " { notImplemented(\"" + trait.name.getName() + "\"); }");
}
str += prop + " = function " + traitName + "(" + getSignature(mi, true) + ")";
writer.writeLn(str + " {");
writer.writeLn(" notImplemented(\"" + name + "." + traitName + "\"); };");
writer.writeLn("}");
}
} else if (trait.isClass()) {
var className = trait.classInfo.instanceInfo.name;
writer.enter("package " + className.namespaces[0].originalURI + " {\n");
tracer.traceMetadata(trait.metadata);
tracer.traceClass(trait.classInfo);
writer.leave("\n}");
tracer.traceClassStub(trait);
} else {
notImplemented();
}
});
}
},
writer.writeLn("var m = " + name + ".prototype;");
writer.writeLn("var s = {};");
traceClassStub: function traceClassStub(trait) {
const writer = this.writer;
traceTraits(ci.traits, true);
traceTraits(ii.traits);
var ci = trait.classInfo;
var ii = ci.instanceInfo;
var name = ii.name.getName();
var native = trait.metadata ? trait.metadata.native : null;
if (!native) {
return;
}
writer.enter("Shumway Stub {");
writer.enter("natives." + native.cls + " = function " + native.cls + "(scope, instance, baseClass) {");
writer.writeLn("// Signature: " + getSignature(ii.init));
var initSignature = getSignature(ii.init, true);
writer.writeLn("function " + name + "(" + initSignature + ") {");
writer.writeLn(" instance.call(this" + (initSignature ? ", " + initSignature : "") + ")");
writer.writeLn("};");
writer.writeLn("var c = new Class(\"" + name + "\", " + name +
", Class.passthroughCallable(" + name + "));");
writer.writeLn("//");
writer.writeLn("// WARNING! This sets:")
writer.writeLn("// " + name + ".prototype = " +
"Object.create(baseClass.instance.prototype)");
writer.writeLn("//");
writer.writeLn("// If you want to manage prototypes manually, do this instead:");
writer.writeLn("// c.baseClass = baseClass");
writer.writeLn("//");
writer.writeLn("c.extend(baseClass);");
writer.writeLn("c.nativeMethods = m;");
writer.writeLn("c.nativeStatics = s;");
function traceTraits(traits, isStatic) {
traits.traits.forEach(function (trait) {
var traitName = trait.name.getName();
if (trait.isMethod() || trait.isGetter() || trait.isSetter()) {
var mi = trait.methodInfo;
if (mi.isNative()) {
var str = isStatic ? "s" : "m";
if (mi.parameters.length) {
var returnTypeStr = "";
if (mi.returnType) {
returnTypeStr = " -> " + mi.returnType.getName();
}
writer.writeLn("// Signature: " + getSignature(mi) + returnTypeStr);
}
var prop;
if (trait.isGetter()) {
prop = "[\"get " + traitName + "\"]";
} else if (trait.isSetter()) {
prop = "[\"set " + traitName + "\"]";
} else {
prop = "." + traitName;
}
str += prop + " = function " + traitName + "(" + getSignature(mi, true) + ")";
writer.writeLn(str + " {");
writer.writeLn(" notImplemented(\"" + name + "." + traitName + "\"); };");
writer.writeLn("}");
}
}
});
}
writer.writeLn("return c;");
writer.leave("};");
writer.leave("}");
}
writer.writeLn("var m = " + name + ".prototype;");
writer.writeLn("var s = {};");
function traceClass(ci) {
var ii = ci.instanceInfo;
var name = ii.name;
var str = name.getAccessModifier();
if (ii.isFinal()) {
str += " final";
}
if (!ii.isSealed()) {
str += " dynamic";
}
str += ii.isInterface() ? " interface " : " class ";
str += name.getName();
if (ii.superName && ii.superName.getName() !== "Object") {
str += " extends " + ii.superName.getName();
}
if (ii.interfaces.length) {
str += " implements " + ii.interfaces.map(function (x) {
return x.getName();
}).join(", ");
}
writer.enter(str + " {");
if (!ii.isInterface()) {
writer.writeLn("public function " + name.getName() + "(" + getSignature(ii.init) + ") {}");
}
var interfaceNamespace;
if (ii.isInterface()) {
interfaceNamespace = name.namespaces[0].originalURI + ":" + name.name;
}
traceTraits(ci.traits, true, interfaceNamespace);
traceTraits(ii.traits, false, interfaceNamespace);
writer.leave("}");
}
traceTraits(ci.traits, true);
traceTraits(ii.traits);
function traceMetadata(metadata) {
for (var key in metadata) {
if (metadata.hasOwnProperty(key)) {
if (key.indexOf("__") === 0) {
continue;
writer.writeLn("c.nativeMethods = m;");
writer.writeLn("c.nativeStatics = s;");
writer.writeLn("return c;");
writer.leave("};");
writer.leave("}");
},
traceClass: function traceClass(ci) {
const writer = this.writer;
var ii = ci.instanceInfo;
var name = ii.name;
var str = name.getAccessModifier();
if (ii.isFinal()) {
str += " final";
}
if (!ii.isSealed()) {
str += " dynamic";
}
str += ii.isInterface() ? " interface " : " class ";
str += name.getName();
if (ii.superName && ii.superName.getName() !== "Object") {
str += " extends " + ii.superName.getName();
}
if (ii.interfaces.length) {
str += " implements " + ii.interfaces.map(function (x) {
return x.getName();
}).join(", ");
}
writer.enter(str + " {");
if (!ii.isInterface()) {
writer.writeLn("public function " + name.getName() + "(" + getSignature(ii.init) + ") {}");
}
var interfaceNamespace;
if (ii.isInterface()) {
interfaceNamespace = name.namespaces[0].originalURI + ":" + name.name;
}
this.traceTraits(ci.traits, true, interfaceNamespace);
this.traceTraits(ii.traits, false, interfaceNamespace);
writer.leave("}");
},
traceMetadata: function traceMetadata(metadata) {
const writer = this.writer;
for (var key in metadata) {
if (metadata.hasOwnProperty(key)) {
if (key.indexOf("__") === 0) {
continue;
}
writer.writeLn("[" + key + "(" + metadata[key].items.map(function (m) {
var str = m.key ? m.key + "=" : "";
return str + "\"" + m.value + "\"";
}).join(", ") + ")]");
}
writer.writeLn("[" + key + "(" + metadata[key].items.map(function (m) {
var str = m.key ? m.key + "=" : "";
return str + "\"" + m.value + "\"";
}).join(", ") + ")]");
}
}
}
return {
traceMetadata: traceMetadata,
traceTraits: traceTraits,
traceClass: traceClass,
traceClassStub: traceClassStub
};
});
return SourceTracer;
})();
function traceSource(writer, abc) {
var tracer = SourceTracer(writer);
var tracer = new SourceTracer(writer);
abc.scripts.forEach(function (script) {
tracer.traceTraits(script.traits);
});