package com.intellij.lang.javascript.flex.importer;
import com.intellij.openapi.util.text.StringUtil;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.Arrays;
import java.util.Set;
/**
* @author Maxim.Mossienko
* Date: Oct 20, 2008
* Time: 7:02:13 PM
*/
abstract class AbstractDumpProcessor implements FlexByteCodeInformationProcessor {
protected @NonNls StringBuilder sb = new StringBuilder();
private boolean firstMetaDataMember;
final Set<String> classNameTable = new THashSet<>();
String getResult() { return sb.toString(); }
public void append(@NotNull @NonNls String str) {
sb.append(str);
}
public String getParentName(final MemberInfo member) {
String parentName = null;
if (member.parentTraits != null) {
if(member.parentTraits.name instanceof Multiname) {
final Multiname multiname = (Multiname)member.parentTraits.name;
if(multiname.hasNamespace()) {
parentName = multiname.name;
}
}
if (parentName == null) {
parentName = StringUtil.replace(member.parentTraits.name.toString(), "::", ".");
}
}
return parentName;
}
public void addMetaDataValue(String s, String s1) {
append(firstMetaDataMember ? "(":",");
firstMetaDataMember = false;
if (s != null) {
append(s);
append("=");
}
append(s1);
}
public void processVariable(SlotInfo info, String indent, String attr) {
appendFieldSeparator();
attr = appendModifiers(info, attr);
processModifierList(info, attr, indent);
append(indent + attr);
processMemberKindAndName(info);
append(":");
dumpTypeRef(info.type, info.parentTraits.getClassName(), true);
if (info.value != null) processValue(info.type, info.value);
}
public void processFunction(MethodInfo methodInfo, boolean referenceNameRequested, Abc abc, String indent, String attr) {
if (!referenceNameRequested) appendMethodSeparator();
attr = appendModifiers(methodInfo, attr);
processModifierList(methodInfo, attr, indent);
append(indent + attr);
processMemberKindAndName(methodInfo);
final String parentName = methodInfo.getParentName();
processArgumentList(methodInfo, parentName);
append(":");
dumpTypeRef(methodInfo.returnType, parentName, referenceNameRequested);
}
protected void dumpTypeRef(Multiname name, String parentName, boolean referenceNameRequested) {
processMultinameAsPackageName(name, parentName);
}
protected void processMemberKindAndName(@NotNull final MemberInfo member) {
append(Abc.traitKinds[member.kind != null ? member.kind.ordinal():0]);
append(" ");
if (member.name != null) {
processMultinameAsPackageName(member.name, member.parentTraits.getClassName());
} else {
append("undefined");
}
}
protected abstract String appendModifiers(MemberInfo methodInfo, String attr);
protected abstract void processValue(Multiname type, Object value);
protected void processArgumentList(MethodInfo methodInfo, String parentName) {
append("(");
for (int i = 0; i < methodInfo.paramTypes.length; ++i) {
final Multiname paramType = methodInfo.paramTypes[i];
final boolean restParameter = FlexByteCodeInformationProcessor.REST_PARAMETER_TYPE.equals(paramType.name);
if (restParameter && !dumpRestParameter()) break; // original one do not dump
if (i > 0) append(",");
processParameter(
methodInfo.paramNames != null ? methodInfo.paramNames[i] : "a" + (i > 0 ? "" + (i + 1) : ""),
paramType,
parentName,
methodInfo.optionalValues != null && i < methodInfo.optionalValues.length ? methodInfo.optionalValues[i] : null,
restParameter
);
}
append(")");
}
protected abstract boolean dumpRestParameter();
public void processMetadata(MetaData metaData) {
append("[");
append(metaData.name);
firstMetaDataMember = true;
for (String n : metaData.keySet()) {
addMetaDataValue(!"*".equals(n) || doStarMetaAttrNameDump() ? n:null, '"' + quote(metaData.get(n)) + '"');
}
if (!firstMetaDataMember) append(")");
append("]");
}
public void processClass(SlotInfo slotInfo, Abc abc, String attr, String indent) {
append("\n");
@NonNls String def;
final boolean isInterface = slotInfo.isInterfaceClass();
if (isInterface) def = "interface";
else {
def = "class";
}
if (!doStarTypeDumpInExtends()) {
final String ns = slotInfo.name.hasNamespace() ? slotInfo.name.getNsName(slotInfo) : null;
if (ns != null && ns.length() > 0) attr += ns;
else attr+="public";
attr += " ";
}
Traits ct = (Traits)slotInfo.value;
Traits it = ct.itraits;
if (!isInterface) {
if ((it.flags & Abc.CLASS_FLAG_final) != 0) attr += "final ";
if ((it.flags & Abc.CLASS_FLAG_sealed) == 0) attr += "dynamic ";
}
processModifierList(slotInfo, attr, indent);
append(indent + attr + def + " ");
if (slotInfo.name.hasNotEmptyNs()) {
classNameTable.add(slotInfo.name.nsset[0] + ":" + slotInfo.name.name);
}
processMultinameAsPackageName(slotInfo.name, null);
dumpExtendsList(it);
append("\n");
String oldindent = indent;
indent += Abc.TAB;
dumpInterfacesList(indent, it, isInterface);
append(oldindent + "{\n");
setProcessingInterface(isInterface);
if (doDumpMember(it.init)) it.init.dump(abc, indent, "", this);
it.dump(abc, indent, "", this);
ct.dump(abc, indent, "static ", this);
ct.init.dump(abc, indent, "static ", this);
if (ct.usedNamespacesToNamesMap != null) {
String[] strings = new String[ct.usedNamespacesToNamesMap.size()];
ct.usedNamespacesToNamesMap.keySet().toArray(strings);
Arrays.sort(strings);
for(String e: strings) {
SlotInfo info = new SlotInfo(new Multiname(Abc.PRIVATE_NS_SET, ct.usedNamespacesToNamesMap.get(e)), Abc.TraitType.Const);
info.type = NsType;
info.value = e;
info.parentTraits = it;
info.dump(abc, indent, "static ", this);
}
}
append(oldindent + "}\n");
setProcessingInterface(false);
}
private static final Multiname NsType = new Multiname(Abc.PUBLIC_NS_SET, "*");
protected void processModifierList(MemberInfo memberInfo, String attr, String indent) {
memberInfo.dumpMetaData(indent, this);
}
protected void dumpExtendsList(Traits it) {
if (!it.base.isStarReference() || doStarTypeDumpInExtends()) {
append(" extends ");
dumpTypeRef(it.base, null, true);
}
}
protected void dumpInterfacesList(String indent, Traits it, boolean anInterface) {
if (it.interfaces.length > 0) {
append(indent + (anInterface && this instanceof AS3InterfaceDumper ? "extends ":"implements "));
boolean first = true;
for (Multiname name : it.interfaces) {
if (!first) append(",");
first = false;
dumpTypeRef(name,null, true);
}
append("\n");
}
}
protected static String quote(final String s) {
if (s.length() == 0) return s;
final StringBuilder b = new StringBuilder(s.length());
for(int i = 0; i < s.length(); ++i) {
final char ch = s.charAt(i);
if (ch == '\\' || ch == '"') {
b.append('\\');
} else if (ch == '\n') {
b.append("\\n");
continue;
} else if (ch == '\r') {
b.append("\\r");
continue;
}
b.append(ch);
}
return b.toString();
}
}