org.apache.royale.abc.print.ABCDumpVisitor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of compiler Show documentation
Show all versions of compiler Show documentation
The Apache Royale Compiler
The newest version!
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.royale.abc.print;
import org.apache.royale.abc.ABCConstants;
import org.apache.royale.abc.ABCParser;
import org.apache.royale.abc.PoolingABCVisitor;
import org.apache.royale.abc.graph.IBasicBlock;
import org.apache.royale.abc.graph.IFlowgraph;
import org.apache.royale.abc.semantics.ClassInfo;
import org.apache.royale.abc.semantics.ExceptionInfo;
import org.apache.royale.abc.semantics.InstanceInfo;
import org.apache.royale.abc.semantics.Instruction;
import org.apache.royale.abc.semantics.Label;
import org.apache.royale.abc.semantics.Metadata;
import org.apache.royale.abc.semantics.MethodBodyInfo;
import org.apache.royale.abc.semantics.MethodInfo;
import org.apache.royale.abc.semantics.Name;
import org.apache.royale.abc.semantics.Namespace;
import org.apache.royale.abc.semantics.Nsset;
import org.apache.royale.abc.semantics.ScriptInfo;
import org.apache.royale.abc.semantics.Trait;
import org.apache.royale.abc.semantics.Traits;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import static org.apache.royale.abc.ABCConstants.CONSTANT_Multiname;
import static org.apache.royale.abc.ABCConstants.CONSTANT_MultinameA;
import static org.apache.royale.abc.ABCConstants.CONSTANT_MultinameL;
import static org.apache.royale.abc.ABCConstants.CONSTANT_Namespace;
import static org.apache.royale.abc.ABCConstants.CONSTANT_PackageInternalNs;
import static org.apache.royale.abc.ABCConstants.CONSTANT_PackageNs;
import static org.apache.royale.abc.ABCConstants.CONSTANT_PrivateNs;
import static org.apache.royale.abc.ABCConstants.CONSTANT_ProtectedNs;
import static org.apache.royale.abc.ABCConstants.CONSTANT_Qname;
import static org.apache.royale.abc.ABCConstants.CONSTANT_QnameA;
import static org.apache.royale.abc.ABCConstants.CONSTANT_RTQname;
import static org.apache.royale.abc.ABCConstants.CONSTANT_RTQnameA;
import static org.apache.royale.abc.ABCConstants.CONSTANT_StaticProtectedNs;
import static org.apache.royale.abc.ABCConstants.CONSTANT_TypeName;
import static org.apache.royale.abc.ABCConstants.OP_debugfile;
import static org.apache.royale.abc.ABCConstants.OP_lookupswitch;
import static org.apache.royale.abc.ABCConstants.OP_pushstring;
import static org.apache.royale.abc.ABCConstants.TRAIT_Class;
import static org.apache.royale.abc.ABCConstants.TRAIT_Const;
import static org.apache.royale.abc.ABCConstants.TRAIT_Function;
import static org.apache.royale.abc.ABCConstants.TRAIT_Getter;
import static org.apache.royale.abc.ABCConstants.TRAIT_Method;
import static org.apache.royale.abc.ABCConstants.TRAIT_Setter;
import static org.apache.royale.abc.ABCConstants.TRAIT_Var;
/**
* ABC Visitor implementation that can take an ABC and
* dump out a textual representation of it. Similar to
* abcdump/abcdis in the tamarin project.
*
* To use, construct one of these and pass it ABCParser,
* or whatever is driving the ABC events.
*/
public class ABCDumpVisitor extends PoolingABCVisitor
{
/**
* Constructor
*
* @param p The PrintWriter to write the textual represention of the ABC to
*/
public ABCDumpVisitor (PrintWriter p, boolean sortOption)
{
super();
printer = new IndentingPrinter(p, 0, 2);
dumpedMethods = new HashSet();
this.sortOption = sortOption;
}
private boolean sortOption;
private IndentingPrinter printer;
private Set dumpedMethods;
/**
* Turn a namespace, name pair into a user readable String
*/
private String qnameToString (Namespace ns, String n)
{
if (ns == null)
return n;
if ((ns.getKind() == CONSTANT_PackageNs) && (ns.getName().length() > 0))
return ns.getName() + "::" + n;
String qual = nsQualifierForNamespace(ns);
if (qual.length() > 0)
return n;
if (ns.getName().length() == 0)
return n;
return ns.getName() + "::" + n;
}
/**
* Turn a namespace set into a user readable String
*/
private String nssetToString (Nsset nsSet)
{
String s = "";
for (Namespace ns : nsSet)
{
if (ns.getKind() != CONSTANT_PrivateNs)
s += (ns.getName() + ", ");
else
s += "private, ";
}
return "{" + s + "}";
}
/**
* Turn a Name into a user readable String
*/
private String nameToString (Name n)
{
if (n == null || n.couldBeAnyType())
return "*";
Nsset nsset;
switch (n.getKind())
{
case CONSTANT_Qname:
case CONSTANT_QnameA:
return qnameToString(n.getSingleQualifier(), n.getBaseName());
case CONSTANT_Multiname:
case CONSTANT_MultinameA:
nsset = n.getQualifiers();
if (nsset.length() == 1)
return qnameToString(nsset.iterator().next(), n.getBaseName());
else
return (nssetToString(nsset) + "::") + n.getBaseName();
case CONSTANT_RTQname:
case CONSTANT_RTQnameA:
return " " + n.toString();
case CONSTANT_MultinameL:
return " " + n.toString();
case CONSTANT_TypeName:
Name typeName = n.getTypeNameParameter();
return nameToString(n.getTypeNameBase()) + ".<" + nameToString(typeName) + ">";
}
return " " + n.toString();
}
/**
* Get a String that can be used as the qualifier for a given Name
*/
private String nsQualifierForName (Name n)
{
Nsset nsset;
switch (n.getKind())
{
case CONSTANT_Qname:
case CONSTANT_QnameA:
return nsQualifierForNamespace(n.getSingleQualifier());
case CONSTANT_Multiname:
case CONSTANT_MultinameA:
nsset = n.getQualifiers();
if (nsset.length() == 1)
return nsQualifierForNamespace(nsset.iterator().next());
break;
case CONSTANT_RTQname:
case CONSTANT_RTQnameA:
break;
case CONSTANT_MultinameL:
break;
case CONSTANT_TypeName:
break;
}
return "";
}
/**
* Get a String representing the access modifier(public, private, etc) based on a namespace value
*/
private String nsQualifierForNamespace (Namespace ns)
{
switch (ns.getKind())
{
case CONSTANT_PackageNs:
return "public ";
case CONSTANT_ProtectedNs:
case CONSTANT_StaticProtectedNs:
//case CONSTANT_StaticProtectedNs2:
return "protected ";
case CONSTANT_PackageInternalNs:
return "internal ";
case CONSTANT_PrivateNs:
return "private ";
}
if (ns.getKind() == CONSTANT_Namespace)
{
if (ns.getName().equals("http://adobe.com/AS3/2006/builtin"))
return "AS3 ";
}
return ns.getName() + " ";
}
/**
* Escape a string for displaying better
*/
private String stringToEscapedString (String s)
{
String charsToEscape = "\b\t\n\f\r\"\'\\";
String escapeChars = "btnfr\"\'\\";
int escapeIndex;
char currChar;
String result = "";
for (int i = 0; i < s.length(); ++i)
{
currChar = s.charAt(i);
escapeIndex = charsToEscape.indexOf(currChar);
if (escapeIndex != -1)
result += "\\" + escapeChars.charAt(escapeIndex);
else
result += currChar;
}
return result;
}
/**
* Print the ABC
*/
public void write ()
{
traverse();
writeIterable(getMethodInfos(), new IWriteFunction()
{
public void write (Object v, int index)
{
writeAnonMethodInfo((MethodInfo) v, index);
}
}
);
}
/**
* Walk over the elements of the ABC
* Starts with the Scripts and walks down from there
*/
public void traverse ()
{
int nScripts = getScriptInfos().size();
ScriptInfo si;
if (sortOption)
{
HashMap scripts = new HashMap();
for (int i = 0; i < nScripts; ++i)
{
si = getScriptInfos().get(i);
Iterator traits = si.getTraits().iterator();
Name name = traits.hasNext() ? traits.next().getName() : null;
String scriptName = name != null ? name.getSingleQualifier().getName() + "." + name.getBaseName() : "";
scripts.put(scriptName, si);
}
ArrayList nameList = new ArrayList();
nameList.addAll(scripts.keySet());
Collections.sort(nameList);
for (int i = 0; i < nScripts; ++i)
{
si = scripts.get(nameList.get(i));
traverseScript(i, si);
}
}
else
{
for (int i = 0; i < nScripts; ++i)
{
si = getScriptInfos().get(i);
traverseScript(i, si);
}
}
}
/**
* Traverse a Script, and its traits
*/
protected void traverseScript (int id, ScriptInfo scriptInfo)
{
printer.println("// script " + id);
traverseScriptTraits(scriptInfo.getTraits(), scriptInfo);
MethodInfo initMethodInfo = scriptInfo.getInit();
traverseScriptInit(initMethodInfo, scriptInfo, id);
printer.println("");
}
/**
* Traverse the traits of a script
*/
protected void traverseScriptTraits (Traits traits, ScriptInfo si)
{
for (Trait t : traits)
{
switch (t.getKind())
{
case TRAIT_Const:
traverseScriptConstTrait(t, si);
break;
case TRAIT_Var:
traverseScriptSlotTrait(t, si);
break;
case TRAIT_Method:
traverseScriptMethodTrait(t, si);
break;
case TRAIT_Getter:
traverseScriptGetterTrait(t, si);
break;
case TRAIT_Setter:
traverseScriptSetterTrait(t, si);
break;
case TRAIT_Function:
traverseScriptFunctionTrait(t, si);
break;
case TRAIT_Class:
traverseScriptClassTrait(t, si);
break;
}
}
}
/**
* traverse the traits of an Instance Info
*/
protected void traverseInstanceTraits (Traits traits)
{
for (Trait t : traits)
{
switch (t.getKind())
{
case TRAIT_Const:
traverseInstanceConstTrait(t);
break;
case TRAIT_Var:
traverseInstanceSlotTrait(t);
break;
case TRAIT_Method:
traverseInstanceMethodTrait(t);
break;
case TRAIT_Getter:
traverseInstanceGetterTrait(t);
break;
case TRAIT_Setter:
traverseInstanceSetterTrait(t);
break;
case TRAIT_Function:
traverseInstanceFunctionTrait(t);
break;
}
}
}
/**
* Traverse the traits of a Class Info
*/
protected void traverseClassTraits (Traits traits)
{
for (Trait t : traits)
{
switch (t.getKind())
{
case TRAIT_Const:
traverseClassConstTrait(t);
break;
case TRAIT_Var:
traverseClassSlotTrait(t);
break;
case TRAIT_Method:
traverseClassMethodTrait(t);
break;
case TRAIT_Getter:
traverseClassGetterTrait(t);
break;
case TRAIT_Setter:
traverseClassSetterTrait(t);
break;
case TRAIT_Function:
traverseClassFunctionTrait(t);
break;
}
}
}
/**
* Traverse a slot trait of a script
*/
protected void traverseScriptSlotTrait (Trait trait, ScriptInfo scriptInfo)
{
writeSlotTrait("var", trait, false);
}
/**
* Traverse a const trait of a script
*/
protected void traverseScriptConstTrait (Trait trait, ScriptInfo scriptInfo)
{
writeSlotTrait("const", trait, false);
}
/**
* Traverse a method trait of a script
*/
protected void traverseScriptMethodTrait (Trait trait, ScriptInfo scriptInfo)
{
writeMethodTrait("function", trait, false);
}
/**
* Traverse a getter trait of a script
*/
protected void traverseScriptGetterTrait (Trait trait, ScriptInfo scriptInfo)
{
writeMethodTrait("function get", trait, false);
}
/**
* Traverse a setter trait of a script
*/
protected void traverseScriptSetterTrait (Trait trait, ScriptInfo scriptInfo)
{
writeMethodTrait("function set", trait, false);
}
/**
* Traverse a function trait of a script
*/
protected void traverseScriptFunctionTrait (Trait trait, ScriptInfo scriptInfo)
{
writeMethodTrait("function", trait, false);
}
/**
* Traverse a class trait of a script
*/
protected void traverseScriptClassTrait (Trait trait, ScriptInfo scriptInfo)
{
ClassInfo ci = (ClassInfo) trait.getAttr(Trait.TRAIT_CLASS);
int classIndex = getClassId(ci);
ClassVisitor cv = getDefinedClasses().get(classIndex);
InstanceInfo iinfo = cv.getInstanceInfo();
traverseScriptClassTrait(classIndex, iinfo, ci, trait, scriptInfo);
}
/**
* Traverse a class trait of a script
*/
protected void traverseScriptClassTrait (int classId, InstanceInfo instanceInfo, ClassInfo classInfo, Trait trait, ScriptInfo scriptInfo)
{
printer.println("");
int slotId = 0;
if( trait.hasAttr(Trait.TRAIT_SLOT ))
slotId = trait.getIntAttr(Trait.TRAIT_SLOT);
printer.println("// class_id=" + classId + " slot_id=" + String.valueOf(slotId));
String def;
if (instanceInfo.isInterface())
{
def = "interface";
}
else
{
def = "class";
if (!instanceInfo.isSealed())
def = "dynamic " + def;
if (instanceInfo.isFinal())
def = "final " + def;
}
writeMetaData(trait);
printer.println(nsQualifierForName(trait.getName()) + def + " " + nameToString(trait.getName()) + " extends " + nameToString(instanceInfo.superName));
if (instanceInfo.interfaceNames.length > 0)
{
printer.indent();
List interfaceNames = new ArrayList();
for (Name interfaceName : instanceInfo.interfaceNames)
{
interfaceNames.add(nameToString(interfaceName));
}
printer.println(joinOn(",",interfaceNames));
printer.unindent();
}
printer.println("{");
printer.indent();
traverseInstanceInit(instanceInfo.iInit, instanceInfo, trait, scriptInfo);
traverseInstanceTraits(instanceInfo.traits);
traverseClassInit(classInfo.cInit, classInfo, trait, scriptInfo);
traverseClassTraits(classInfo.classTraits);
printer.unindent();
printer.println("}");
}
/**
* Traverse the Script init method
*/
protected void traverseScriptInit (MethodInfo init, ScriptInfo scriptInfo, int scriptId)
{
printer.println("");
writeMethodInfo("", "script" + scriptId + "$init", "function", init, false, false, false);
}
/**
* Traverse an instance init method
*/
protected void traverseInstanceInit (MethodInfo init, InstanceInfo instanceInfo, Trait classTrait, ScriptInfo scriptInfo)
{
printer.println("");
printer.println("// method_id=" + getMethodInfos().getId(instanceInfo.iInit));
writeMethodInfo("public ", nameToString(classTrait.getName()), "function", init, false, false, false);
}
/**
* Traverse a slot trait of an instance info
*/
protected void traverseInstanceSlotTrait (Trait trait)
{
writeSlotTrait("var", trait, false);
}
/**
* Traverse a const trait of an instance info
*/
protected void traverseInstanceConstTrait (Trait trait)
{
writeSlotTrait("const", trait, false);
}
/**
* Traverse a method trait of an instance info
*/
protected void traverseInstanceMethodTrait (Trait trait)
{
writeMethodTrait("function", trait, false);
}
/**
* Traverse a getter trait of an instance info
*/
protected void traverseInstanceGetterTrait (Trait trait)
{
writeMethodTrait("function get", trait, false);
}
/**
* Traverse a setter trait of an instance info
*/
protected void traverseInstanceSetterTrait (Trait trait)
{
writeMethodTrait("function set", trait, false);
}
/**
* Traverse a function trait of an instance info
*/
protected void traverseInstanceFunctionTrait (Trait trait)
{
writeMethodTrait("function", trait, false);
}
/**
* Traverse a class init method
*/
protected void traverseClassInit (MethodInfo init, ClassInfo classInfo, Trait classTrait, ScriptInfo scriptInfo)
{
printer.println("");
//printer.println("// method_id=" + classInfo.init_index)
writeMethodInfo("public ", nameToString(classTrait.getName()) + "$", "function", init, true, false, false);
}
/**
* Traverse a slot trait of a class info
*/
protected void traverseClassSlotTrait (Trait trait)
{
writeSlotTrait("var", trait, true);
}
/**
* Traverse a const trait of a class info
*/
protected void traverseClassConstTrait (Trait trait)
{
writeSlotTrait("const", trait, true);
}
/**
* Traverse a method trait of a class info
*/
protected void traverseClassMethodTrait (Trait trait)
{
writeMethodTrait("function", trait, true);
}
/**
* Traverse a getter trait of a class info
*/
protected void traverseClassGetterTrait (Trait trait)
{
writeMethodTrait("function get", trait, true);
}
/**
* Traverse a setter trait of a class info
*/
protected void traverseClassSetterTrait (Trait trait)
{
writeMethodTrait("function set", trait, true);
}
/**
* Traverse a function trait of a class info
*/
protected void traverseClassFunctionTrait (Trait trait)
{
writeMethodTrait("function", trait, true);
}
/**
* Write out the metadata for a given Trait
*/
private void writeMetaData (Trait t)
{
if (!t.hasMetadata())
return;
for (Metadata mid : t.getMetadata())
{
List entries = new Vector();
String[] keys = mid.getKeys();
for (int i = 0; i < keys.length; ++i)
{
String key = keys[i];
String value = mid.getValues()[i];
if (key == null || key.length() == 0)
entries.add("\"" + value + "\"");
else
entries.add(key + "=\"" + value + "\"");
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < entries.size(); ++i)
{
sb.append(entries.get(i));
if (i < entries.size() - 1)
sb.append(", ");
}
if (sortOption && mid.getName().contains("_definition_help"))
printer.println("[" + mid.getName() + "(xxxx)]");
else
printer.println("[" + mid.getName() + "(" + sb.toString() + ")]");
}
}
/**
* Write out the method info for an anonymous method
*/
private void writeAnonMethodInfo (MethodInfo mi, int id)
{
if (dumpedMethods.contains(mi))
return;
printer.println("");
printer.println("// " + id + " " + mi.getMethodName());
writeMethodInfo("", "", "function ", mi, false, false, false);
}
/**
* Write out a slot trait
*
* @param kindStr the kind of trait (var or const)
* @param t the trait
* @param isStatic whether the trait is static or not
*/
private void writeSlotTrait (String kindStr, Trait t, boolean isStatic)
{
printer.println("");
String qual = nsQualifierForName(t.getName());
String nameStr = nameToString(t.getName());
Object value = null;
if( t.hasAttr(Trait.SLOT_VALUE) )
value = t.getAttr(Trait.SLOT_VALUE);
String valueStr = "";
if (value instanceof String)
valueStr = " = \"" + value + "\"";
else if (value instanceof Namespace)
valueStr = " = " + ((Namespace) value).getName();
else if (value == ABCConstants.NULL_VALUE)
valueStr = " = null";
else if (value == ABCConstants.UNDEFINED_VALUE)
valueStr = "";
else if (value != null)
valueStr = " = " + value.toString();
String staticStr = isStatic ? "static " : "";
writeMetaData(t);
//printer.println("// name_id=" + t.name_index + " slot_id=" + t.slot_id)
printer.println(qual + staticStr + kindStr + " " + nameStr + ":" + nameToString((Name) t.getAttr(Trait.TRAIT_TYPE)) + valueStr);
}
/**
* Generate a string for displaying a lookupswitch instruction
*
* @param inst the lookupswitch instruction
* @param mb the method body
* @param blockNames a map of IBasicBlock to display name of block
* @param cfg the control flow graph for the current method
* @return a string to use to display the lookupswitch istruction
*/
private String stringForLookupSwitch (Instruction inst, MethodBodyInfo mb, Map blockNames, IFlowgraph cfg)
{
int case_size = inst.getOperandCount() - 1;
// Last label is the default
String defaultStr = "default: " + blockNames.get(cfg.getBlock((Label) inst.getOperand(case_size)));
String maxCaseStr = "maxcase: " + case_size;
List result = new Vector();
result.add(defaultStr);
result.add(maxCaseStr);
for (int i = 0; i < case_size; ++i)
{
result.add(blockNames.get(cfg.getBlock((Label) inst.getOperand(i))));
}
return joinOn(" ", result);
}
/**
* Write out a method info, and it's corresponding body
*/
private void writeMethodInfo (String qualStr, String nameStr, String kindStr, MethodInfo methodInfo, boolean isStatic, boolean isOverride, boolean isFinal)
{
dumpedMethods.add(methodInfo);
List paramTypeStrings = new Vector();
for (Name paramTypeName : methodInfo.getParamTypes())
paramTypeStrings.add(nameToString(paramTypeName));
String staticStr = isStatic ? "static " : "";
String overrideStr = isOverride ? "override " : "";
String nativeStr = methodInfo.isNative() ? "native " : "";
String finalStr = isFinal ? "final " : "";
printer.println(qualStr + staticStr + nativeStr + finalStr + overrideStr + kindStr + " " + nameStr + "(" + joinOn(",", paramTypeStrings) + "):" + nameToString(methodInfo.getReturnType()));
MethodBodyInfo mb = getMethodBodyForMethodInfo(methodInfo);
if (mb != null)
{
printer.println("{");
printer.indent();
TablePrinter tablePrinter = new TablePrinter(3, 2);
tablePrinter.addRow(new String[]{"//", "derivedName", methodInfo.getMethodName()});
tablePrinter.addRow(new String[]{"//", "method_info", String.valueOf(getMethodInfos().getId(mb.getMethodInfo()))});
tablePrinter.addRow(new String[]{"//", "max_stack", String.valueOf(mb.max_stack)});
tablePrinter.addRow(new String[]{"//", "max_regs", String.valueOf(mb.max_local)});
tablePrinter.addRow(new String[]{"//", "scope_depth", String.valueOf(mb.initial_scope)});
tablePrinter.addRow(new String[]{"//", "max_scope", String.valueOf(mb.max_scope)});
tablePrinter.addRow(new String[]{"//", "code_length", String.valueOf(mb.code_len)});
//tablePrinter.addRow(["//", "code_offset", mb.code_offset]);
tablePrinter.print(printer);
if (mb.getTraits() != null && mb.getTraits().getTraitCount() > 0)
{
printer.println("activation_traits {");
printer.indent();
for (Trait trait : mb.getTraits())
{
//var kindStr : String;
switch (trait.getKind())
{
case TRAIT_Var:
kindStr = "var";
break;
case TRAIT_Const:
kindStr = "const";
break;
default:
throw new Error("Illegal activation trait in " + methodInfo.getMethodName());
}
writeSlotTrait(kindStr, trait, false);
}
printer.unindent();
printer.println("}");
}
IFlowgraph cfg = mb.getCfg();
Map blockNames = new HashMap();
int i = 0;
for (IBasicBlock block : cfg.getBlocksInEntryOrder())
{
blockNames.put(block, "bb" + i++);
}
int offset = 0;
for (IBasicBlock block : cfg.getBlocksInEntryOrder())
{
printer.println(blockNames.get(block));
printer.indent();
// TODO: preds
//printer.println("preds=[" + block.getPredeccessor()mb.blocks[i].getPredIds(mb.blocks).join(", ") + "]");
Collection extends IBasicBlock> succs = block.getSuccessors();
List succNames = new ArrayList();
for (IBasicBlock s : succs)
succNames.add(blockNames.get(s));
if (!sortOption)
printer.println("succs=[" + joinOn(",", succNames) + "]");
/*
// TODO: implement this with FrameModelEncoder
if(mb.blocks[i].state != null) {
printer.println("verification = " + (mb.blocks[i].state.verifyError == null ? "ok" : "failed: " + mb.blocks[i].state.verifyError));
}
*/
tablePrinter = new TablePrinter(4, 2);
for (int j = 0; j < block.size(); j++)
{
Instruction inst = block.get(j);
String constantStr = "";
if (inst.hasOperands() && inst.getOperand(0) instanceof Name)
{
constantStr = nameToString((Name) inst.getOperand(0));
}
else if (inst.isBranch() && inst.getOpcode() != OP_lookupswitch)
{
constantStr = blockNames.get(cfg.getBlock((Label) inst.getOperand(0)));
}
else
{
switch (inst.getOpcode())
{
case OP_debugfile:
if (sortOption)
{
String fileName = (String) inst.getOperand(0);
fileName = fileName.substring(fileName.indexOf(";"));
fileName = fileName.replace("\\", "/");
constantStr = "\"" + stringToEscapedString(fileName) + "\"";
}
else
constantStr = "\"" + stringToEscapedString((String) inst.getOperand(0)) + "\"";
break;
case OP_pushstring:
constantStr = "\"" + stringToEscapedString((String) inst.getOperand(0)) + "\"";
break;
case OP_lookupswitch:
constantStr = stringForLookupSwitch(inst, mb, blockNames, cfg);
break;
}
}
tablePrinter.addRow(new String[]{offset + " ",
Instruction.decodeOp(inst.getOpcode()),
constantStr,
inst.isImmediate() ? String.valueOf(inst.getImmediate()) : ""
// TODO : Use FrameModelEncoder to keep track
// TODO: of stack/local values
//(inst.getStackDepth() == null ? "" : "// stack: " + inst.getStackDepth()),
//(inst.getState() == null ? "" : "// stack["+inst.getState().stackDepth+"]: " + inst.getState().stackTypeString()),
//(inst.getState() == null ? "" : "// locals: " + inst.getState().localsTypeString()),
//inst.getVerifyError()
});
offset++;
}
tablePrinter.print(printer);
printer.unindent();
}
printer.unindent();
printer.println("}");
if (mb.getExceptions().size() > 0)
{
tablePrinter = new TablePrinter(7, 2);
tablePrinter.addRow(new String[]{"//", "exception", "start", "end", "target", "type string", "name string"});
for (i = 0; i < mb.getExceptions().size(); i++)
{
ExceptionInfo exception = mb.getExceptions().get(i);
tablePrinter.addRow(new String[]{"//", String.valueOf(i), String.valueOf(exception.getFrom().getPosition()),
String.valueOf(exception.getTo().getPosition()),
String.valueOf(exception.getTarget().getPosition()),
nameToString(exception.getExceptionType()),
nameToString(exception.getCatchVar())});
}
tablePrinter.print(printer);
printer.println("");
}
}
}
/**
* Write out a method trait
*/
private void writeMethodTrait (String kindStr, Trait t, boolean isStatic)
{
String qual = nsQualifierForName(t.getName());
String nameStr = nameToString(t.getName());
MethodInfo methodInfo = (MethodInfo) t.getAttr(Trait.TRAIT_METHOD);
printer.println("");
writeMetaData(t);
//printer.println("// name_id=" + t.name_index + " method_id=" + t.method_info + " disp_id=" + t.disp_id)
writeMethodInfo(qual, nameStr, kindStr, methodInfo, isStatic, t.getBooleanAttr(Trait.TRAIT_OVERRIDE), t.getBooleanAttr(Trait.TRAIT_FINAL));
}
/**
* Helper interface to pass around writers
*/
interface IWriteFunction
{
void write (Object v, int index);
}
/**
* Write an array using the given IWriteFunction
*/
private void writeIterable (Iterable p, IWriteFunction writefunc)
{
int i = 0;
for (Object v : p)
{
writefunc.write(v, i++);
}
}
/**
* Helper class to manage indenting
*/
private static class IndentingPrinter
{
private PrintWriter delegate;
private String currentIndent;
private int indentIncrement;
public IndentingPrinter (PrintWriter delegate, int initialIndent, int indentIncrement)
{
this.delegate = delegate;
this.currentIndent = makeIndentStr(initialIndent);
this.indentIncrement = indentIncrement;
}
private static String makeIndentStr (int indent)
{
String result;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < indent; ++i)
sb.append(" ");
result = sb.toString();
return result;
}
public void println (String s)
{
if (s.length() > 0)
s = currentIndent + s;
delegate.println(s);
}
public void indent ()
{
int newIndent = currentIndent.length() + indentIncrement;
currentIndent = makeIndentStr(newIndent);
}
public void unindent ()
{
int newIndent = currentIndent.length() - indentIncrement;
currentIndent = makeIndentStr(newIndent);
}
public void flush ()
{
delegate.flush();
}
}
/**
* Helper class to display nicely formatted tables of data
*/
public static class TablePrinter
{
public TablePrinter (int nCols, int minPadding)
{
cols = nCols;
this.minPadding = minPadding;
m_rows = new Vector();
}
public void addRow (String[] r)
{
if (r.length != cols)
throw new Error("Invalid row");
m_rows.add(new Row(r));
}
public void print (IndentingPrinter p)
{
int[] colWidths = new int[cols];
int i;
for (i = 0; i < cols; ++i)
colWidths[i] = 0;
for (Row r : m_rows)
r.measure(colWidths, minPadding);
for (Row r : m_rows)
r.print(p, colWidths);
}
private int cols;
private int minPadding;
private Vector m_rows;
private class Row
{
private String[] cells;
public Row (String[] cells)
{
this.cells = cells;
}
public void measure (int[] colWidths, int minPadding)
{
for (int i = 0; i < cells.length; ++i)
colWidths[i] = Math.max(colWidths[i], getRowItemStr(i).length() + minPadding);
}
public void print (IndentingPrinter p, int[] colWidths)
{
String rowStr = "";
for (int i = 0; i < cells.length; ++i)
rowStr += padString(getRowItemStr(i), colWidths[i]);
p.println(rowStr);
}
private String getRowItemStr (int i)
{
if (cells[i] == null)
return "null";
if (i < cells.length)
return cells[i];
return "error - out of range " + i;
}
private String padString (String s, int minLength)
{
while (s.length() < minLength)
s += " ";
return s;
}
}
}
/**
* Entry point for testing
*
* Spits out the dump to System.out
*/
public static void main (String[] args) throws Exception
{
for (String arg : args)
{
File f = new File(arg);
if (f.exists())
{
ABCParser parser = new ABCParser(new BufferedInputStream(new FileInputStream(f)));
PoolingABCVisitor printer = new ABCDumpVisitor(new PrintWriter(System.out), false);
parser.parseABC(printer);
}
}
}
/**
* This implementation will dump out a text representation of the ABC to
* the PrintWriter that was passed in on construction.
*/
public void visitEnd ()
{
write();
printer.flush();
}
/**
* Stringify a collection of items.
* @param separator the separator string.
* @param items the items to stringify.
* @return the items, listed out with a separator in between.
*/
private static String joinOn(String separator, Collection extends Object> items)
{
StringBuilder result = new StringBuilder();
for ( Object item: items )
{
if ( result.length() > 0 )
result.append(separator);
result.append(item);
}
return result.toString();
}
}