// Copyright (c) 2011, David J. Pearce (djp@ecs.vuw.ac.nz)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the <organization> nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL DAVID J. PEARCE BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package jasm.io;
import jasm.lang.*;
import java.io.*;
import java.util.*;
public class JasmFileWriter {
protected final PrintWriter output;
public JasmFileWriter(OutputStream o) {
output = new PrintWriter(o);
}
public void write(ClassFile cfile) throws IOException {
ArrayList<Constant.Info> constantPool = cfile.constantPool();
HashMap<Constant.Info,Integer> poolMap = new HashMap<Constant.Info,Integer>();
int index = 0;
for(Constant.Info ci : constantPool) {
poolMap.put(ci, index++);
}
index = 0;
for (Constant.Info c : constantPool) {
if (c != null) { // item at index 0 is always null
output.print("#" + ++index + "\t");
output.println(c);
}
}
output.println();
writeModifiers(cfile.modifiers());
output.print("class " + cfile.type() + " ");
if(cfile.superClass() != null) {
output.print(" extends " + cfile.superClass());
}
if(cfile.interfaces().size() > 0) {
output.print(" implements ");
boolean firstTime=true;
for(JvmType.Clazz i : cfile.interfaces()) {
if(!firstTime) {
output.print(", ");
}
firstTime=false;
output.print(i);
}
}
output.println();
for(BytecodeAttribute a : cfile.attributes()) {
a.print(output,poolMap);
}
output.println(" {");
for(ClassFile.Field f : cfile.fields()) {
writeField(f,poolMap);
}
if(!cfile.fields().isEmpty()) {
output.println();
}
for(ClassFile.Method m : cfile.methods()) {
writeMethod(cfile,m,poolMap);
output.println();
}
output.println("}");
output.flush();
}
protected void writeField(ClassFile.Field f,
HashMap<Constant.Info, Integer> poolMap) throws IOException {
output.print(" ");
writeModifiers(f.modifiers());
writeTypeWithoutBounds(f.type());
output.println(" " + f.name() + ";");
for(BytecodeAttribute a : f.attributes()) {
a.print(output,poolMap);
}
}
protected void writeMethod(ClassFile clazz, ClassFile.Method method,
HashMap<Constant.Info, Integer> poolMap) throws IOException {
output.print(" ");
writeModifiers(method.modifiers());
JvmType.Function type = method.type();
List<JvmType.Variable> typeArgs = type.typeArguments();
boolean firstTime=true;
if(typeArgs.size() > 0) {
output.print("<");
for(JvmType.Variable tv : typeArgs) {
if(!firstTime) {
output.print(", ");
}
firstTime=false;
output.print(tv);
}
output.print("> ");
}
writeTypeWithoutBounds(type.returnType());
output.print(" " + method.name());
output.print("(");
firstTime=true;
List<JvmType> paramTypes = type.parameterTypes();
for(int i = 0; i != paramTypes.size();++i) {
if(!firstTime) {
output.print(", ");
}
firstTime=false;
writeTypeWithoutBounds(paramTypes.get(i));
}
output.println(");");
for(BytecodeAttribute a : method.attributes()) {
a.print(output,poolMap);
}
}
protected void writeModifiers(List<Modifier> modifiers) {
writeModifiers(modifiers,output);
}
protected void writeTypeWithoutBounds(JvmType t) {
if(t instanceof JvmType.Variable) {
JvmType.Variable v = (JvmType.Variable) t;
output.write(v.variable());
} else {
output.write(t.toString());
}
}
public static void writeModifiers(List<Modifier> modifiers, PrintWriter output) {
for (Modifier x : modifiers) {
if (x instanceof Modifier.Private) {
output.write("private ");
} else if (x instanceof Modifier.Protected) {
output.write("protected ");
} else if (x instanceof Modifier.Public) {
output.write("public ");
} else if (x instanceof Modifier.Static) {
output.write("static ");
} else if (x instanceof Modifier.Abstract) {
output.write("abstract ");
} else if (x instanceof Modifier.Final) {
output.write("final ");
} else if (x instanceof Modifier.Super) {
output.write("super ");
} else if (x instanceof Modifier.Bridge) {
output.write("bridge ");
} else if (x instanceof Modifier.Enum) {
output.write("enum ");
} else if (x instanceof Modifier.Synthetic) {
output.write("synthetic ");
} else if (x instanceof Modifier.Native) {
output.write("native ");
} else if (x instanceof Modifier.StrictFP) {
output.write("strictfp ");
} else if (x instanceof Modifier.Synchronized) {
output.write("synchronized ");
} else if (x instanceof Modifier.Transient) {
output.write("transient ");
} else if (x instanceof Modifier.Volatile) {
output.write("volatile ");
} else {
output.write("unknown ");
}
}
}
}