Milán Major

netscape-revival

1 branch
Code

sun-java/classsrc/netscape/tools/jmc/InterfaceGenerator.java

// Copyright (c) 1995 Netscape Communications Corporation. All rights reserved. 

package netscape.tools.jmc;

import netscape.tools.jmc.*;
import netscape.tools.jric.*;
import netscape.tools.ClassFileParser.*;
import java.io.*;
import java.util.Vector;

public 
class InterfaceGenerator extends JMCGenerator {

    public InterfaceGenerator(netscape.tools.jmc.Main global, ClassDef clazz) {
	super(global, clazz);
    }

    protected String getFileName() {
	return "M" + clazz.getPrefix() + ".h";
    }

    protected String getHeaderString() {
	return clazz.name + " interface file\n * Generated by jmc";
    }

    static final int N_RESERVED_SLOTS	= 4;
    int operationCount			= N_RESERVED_SLOTS;

    protected void generateOutput() throws IOException {
	int i;

	Vector interfaces = getInterfaces(clazz);
        String prefix = clazz.getPrefix();

	out.println("#ifndef _M" + clazzCName + "_H_");
	out.println("#define _M" + clazzCName + "_H_\n");

	out.println("#include \"jmc.h\"\n");

	out.println("#ifdef __cplusplus");
	out.println("extern \"C\" {");
	out.println("#endif /* __cplusplus */\n");

	// Calculate the start index of the vtable operations given the
	// number of operations in the inherited interfaces:
	for (i = 1; i < interfaces.size(); i++) {
	    ClassDef ifDef = (ClassDef)interfaces.elementAt(i);
	    for (int j = 0; j < ifDef.methods.length; j++) {
		operationCount += (ifDef.methods[j].isVararg() ? 3 : 1);
	    }
	}

	printBlockComment(clazzCName);

	out.println("/* The type of the " + clazzCName + " interface. */");
	out.println("typedef struct " + clazzCName
		    + "Interface\t" + clazzCName + "Interface;\n");

	out.println("/* The type of a " + clazzCName + " instance. */");
	out.println("typedef struct " + clazz.name.replace('/', '_') + " {");
        out.println("\t" + clazzCName + "Interface*\tvtable;");
        out.println("\tjint\trefcount;");
        out.println("} " + clazzCName + ";\n");

	out.println("/* The inteface ID of the " + clazzCName + " interface. */");
	out.println("extern JRIInterfaceID " + clazzCName + "ID;\n");

	out.println("extern const char* " + clazzCName + "Descriptor[];\n");

	// Operations
	printBlockComment(clazzCName + " Operations");

	out.println("#define " + prefix
		    + "_GetInterface(self, interfaceID)\t\\");
	out.println("\t(((self)->vtable->GetInterface)(self, "
		    + prefix + "_GetInterface_op, interfaceID))\n");

	out.println("#define " + prefix
		    + "_AddRef(self)\t\\");
	out.println("\t(((self)->vtable->AddRef)(self, "
		    + prefix + "_AddRef_op))\n");

	out.println("#define " + prefix
		    + "_Release(self)\t\\");
	out.println("\t(((self)->vtable->Release)(self, "
		    + prefix + "_Release_op))\n");

	out.println("#define " + prefix
		    + "_Description(self)\t\\");
	out.println("\t(((self)->vtable->Description)(self, "
		    + prefix + "_Description_op))\n");

	for (i = 0; i < clazz.methods.length; i++) {
	    MethodDef method = clazz.methods[i];
	    printMethodMacro(prefix, method, i);
	}

	// Operation Codes
	printBlockComment(clazzCName + " Operation IDs");

	out.println("typedef enum " + clazzCName + "Operations {");
	out.println("\t" + prefix + "_GetInterface_op,");
	out.println("\t" + prefix + "_AddRef_op,");
	out.println("\t" + prefix + "_Release_op,");
	out.print("\t" + prefix + "_Description_op");

	for (i = interfaces.size() - 1; i >= 0; i--) {
	    ClassDef intf = (ClassDef)interfaces.elementAt(i);
	    int j;
	    for (j = 0; j < intf.methods.length; j++) {
		MethodDef method = intf.methods[j];
		printMethodOp(prefix, method, j);
	    }
	}
	out.println("\n} " + clazzCName + "Operations;\n");

	// Interface
	printBlockComment(clazzCName + " Interface");

	for (i = interfaces.size() - 1; i >= 0; i--) {
	    ClassDef intf = (ClassDef)interfaces.elementAt(i);
	    for (int j = 0; j < intf.methods.length; j++) {
		MethodDef method = intf.methods[j];
		forwardDeclare(method);
	    }
	}
	out.println();

	// Operation Table
	out.println("struct " + clazzCName + "Interface {");
	out.println("\tvoid*\t(*GetInterface)("
		    + clazzCName + "* self, jint op, jint a);");
	out.println("\tvoid\t(*AddRef)("
		    + clazzCName + "* self, jint op);");
	out.println("\tvoid\t(*Release)("
		    + clazzCName + "* self, jint op);");
	out.println("\tconst char**\t(*Description)("
		    + clazzCName + "* self, jint op);");

	for (i = interfaces.size() - 1; i >= 0; i--) {
	    ClassDef intf = (ClassDef)interfaces.elementAt(i);
	    int j;
	    for (j = 0; j < intf.methods.length; j++) {
		MethodDef method = intf.methods[j];
		printMethodType(method, j);
	    }
	}
	out.println("};\n");

	out.println("#ifdef __cplusplus");
	out.println("} /* extern \"C\" */");
	out.println("#endif /* __cplusplus */\n");

	out.println("#endif /* _M" + clazzCName + "_H_ */");
    }

    //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\

    void printMethodMacro(String prefix, MethodDef method, int methodIndex) 
		throws IOException {
	if (method.isVararg()) {
	    printMethodMacro(prefix, method, methodIndex, VARARGS_ELIPSIS);
	    printMethodMacro(prefix, method, methodIndex, VARARGS_VA_LIST);
	    printMethodMacro(prefix, method, methodIndex, VARARGS_ARRAY);
	}
	else 
	    printMethodMacro(prefix, method, methodIndex, VARARGS_NONE);
	out.println();
    }

    void printMethodMacro(String prefix, MethodDef method, int methodIndex, byte varargsType) 
		throws IOException {
	String resultType = getResultTypeName(method);
	out.print("#define " + prefix + "_" + method.getCName(methodIndex));
	if (varargsType == VARARGS_ELIPSIS) {
	    out.println("(self)\t((self)->vtable->" + 
			method.getCName(methodIndex) + ")");
	    // Increment the operationCount since we're not going to 
	    // printInterfaceArgUse and we need to keep the count in sync:
	    operationCount++;
	}
	else {
	    switch (varargsType) {
	      case VARARGS_VA_LIST:
		out.print("V");
		break;
	      case VARARGS_ARRAY:
		out.print("A");
		break;
	    }
	    printInterfaceArgUse(prefix, method, -1, varargsType);
	    out.print("\t\\\n\t(((");
	    if (method.hasAccess(ClassFileParser.ACC_STATIC) || method.isConstructor())
		out.print("clazz");
	    else
		out.print("self");
	    out.print(")->vtable->" + method.getCName(methodIndex));
	    switch (varargsType) {
	      case VARARGS_VA_LIST:
		out.print("V)");
		break;
	      case VARARGS_ARRAY:
		out.print("A)");
		break;
	      default:
		out.print(")");
		break;
	    }
	    printInterfaceArgUse(prefix, method, methodIndex, varargsType);
	    out.println(")");
	}
    }

    void printMethodType(MethodDef method, int methodIndex) 
		throws IOException {
	if (method.isVararg()) {
	    printMethodType(method, methodIndex, VARARGS_ELIPSIS);
	    printMethodType(method, methodIndex, VARARGS_VA_LIST);
	    printMethodType(method, methodIndex, VARARGS_ARRAY);
	}
	else 
	    printMethodType(method, methodIndex, VARARGS_NONE);
    }

    void printMethodType(MethodDef method, int methodIndex, byte varargsType) 
		throws IOException {
	String resultType = getResultTypeName(method);
	String str;
	switch (varargsType) {
	  case VARARGS_VA_LIST:
	    str = "V)";
	    break;
	  case VARARGS_ARRAY:
	    str = "A)";
	    break;
	  default:
	    str = ")";
	    break;
	}
	out.print("\t" + resultType + "\t(*" + 
		  method.getCName(methodIndex) + str);
	printInterfaceArgDecl(method, methodIndex, varargsType);
	out.println(";");
    }

    protected String getMethodOp(String prefix, MethodDef method, int methodIndex, byte varargsType) 
		throws IOException {
	String result = prefix + "_" + method.getCName(methodIndex) + "_op";
	switch (varargsType) {
	  case VARARGS_VA_LIST:
	    result += "_va_list";
	    break;
	  case VARARGS_ARRAY:
	    result += "_array";
	    break;
	}
	return result;
    }

    void printMethodOp(String prefix, MethodDef method, int methodIndex) 
		throws IOException {
	if (method.isVararg()) {
	    out.print(",\n\t" + getMethodOp(prefix, method, methodIndex, VARARGS_ELIPSIS));
	    out.print(",\n\t" + getMethodOp(prefix, method, methodIndex, VARARGS_VA_LIST));
	    out.print(",\n\t" + getMethodOp(prefix, method, methodIndex, VARARGS_ARRAY));
	}
	else 
	    out.print(",\n\t" + getMethodOp(prefix, method, methodIndex, VARARGS_NONE));
    }

    void printInterfaceArgUse(String prefix, MethodDef method, int methodIndex, byte varargsType)
		throws IOException {
	if (method.hasAccess(ClassFileParser.ACC_STATIC) || method.isConstructor())
	    out.print("(clazz");
	else
	    out.print("(self");
	if (methodIndex != -1)
	    out.print(", " + getMethodOp(prefix, method, methodIndex, varargsType));
	int i = 1;
	String sig = method.signature;
	String[] args = method.getParamNames();
	char dummyArg = 'a';
	boolean isStatic = method.hasAccess(ClassFileParser.ACC_STATIC);
	int j = (isStatic ? 0 : 1);	// start with 1 to avoid 'this'
	while (sig.charAt(i) != ClassFileParser.SIG_ENDMETHOD) {
	    String arg;
	    if (args != null)
		arg = args[j++];
	    else
		arg = String.valueOf(dummyArg++);
	    out.print(", ");
	    boolean isArray = sig.charAt(i) == ClassFileParser.SIG_ARRAY;
	    if (isArray) i++;
	    String type = getTypeName(sig, i);
	    i = consumeArg(sig, i);
	    if (type.equals("struct netscape_tools_jmc_Varargs*")) {
		switch (varargsType) {
		  case VARARGS_ELIPSIS:
		    throw new IOException("Can't have '...' in method call");
		  default:
		    out.print("" + arg);
		    break;
		}
	    }
	    else 
		out.print("" + arg);
	    if (isArray)
		out.print(", " + arg + "_length");
	}
	String[] exceptions = method.getExceptionsThrown();
	if (exceptions != null) {
	    out.print(", exceptionThrown");
	}
	out.print(")");
    }

}