/*
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistribution 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 Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
* MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
* ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
* DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
* DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
* ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
* SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed or intended for use
* in the design, construction, operation or maintenance of any nuclear
* facility.
*
* Sun gratefully acknowledges that this software was originally authored
* and developed by Kenneth Bradley Russell and Christopher John Kline.
*/
package net.java.games.gluegen;
import java.util.*;
import java.io.*;
import net.java.games.gluegen.cgram.types.*;
import net.java.games.gluegen.cgram.*;
/**
* An emitter that emits only the interface for a Java<->C JNI binding.
*/
public class JavaMethodBindingEmitter extends FunctionEmitter
{
public static final EmissionModifier PUBLIC = new EmissionModifier("public");
public static final EmissionModifier PROTECTED = new EmissionModifier("protected");
public static final EmissionModifier PRIVATE = new EmissionModifier("private");
public static final EmissionModifier ABSTRACT = new EmissionModifier("abstract");
public static final EmissionModifier FINAL = new EmissionModifier("final");
public static final EmissionModifier NATIVE = new EmissionModifier("native");
public static final EmissionModifier SYNCHRONIZED = new EmissionModifier("synchronized");
protected static final CommentEmitter defaultJavaCommentEmitter = new DefaultCommentEmitter();
protected static final CommentEmitter defaultInterfaceCommentEmitter =
new InterfaceCommentEmitter();
// Exception type raised in the generated code if runtime checks fail
private String runtimeExceptionType;
private MethodBinding binding;
private boolean forNIOBufferBaseRoutine;
// A non-null value indicates that rather than returning a compound
// type accessor we are returning an array of such accessors; this
// expression is a MessageFormat string taking the names of the
// incoming Java arguments as parameters and computing as an int the
// number of elements of the returned array.
private String returnedArrayLengthExpression;
public JavaMethodBindingEmitter(MethodBinding binding, PrintWriter output, String runtimeExceptionType)
{
this(binding, output, runtimeExceptionType, false);
}
public JavaMethodBindingEmitter(MethodBinding binding, PrintWriter output, String runtimeExceptionType, boolean forNIOBufferBaseRoutine)
{
super(output);
this.binding = binding;
this.forNIOBufferBaseRoutine = forNIOBufferBaseRoutine;
this.runtimeExceptionType = runtimeExceptionType;
setCommentEmitter(defaultInterfaceCommentEmitter);
}
public final MethodBinding getBinding() { return binding; }
public final boolean isForNIOBufferBaseRoutine() { return forNIOBufferBaseRoutine; }
public String getName() {
return binding.getName();
}
/** The type of exception (must subclass
java.lang.RuntimeException
) raised if runtime
checks fail in the generated code. */
public String getRuntimeExceptionType() {
return runtimeExceptionType;
}
/** If the underlying function returns an array (currently only
arrays of compound types are supported) as opposed to a pointer
to an object, this method should be called to provide a
MessageFormat string containing an expression that computes the
number of elements of the returned array. The parameters to the
MessageFormat expression are the names of the incoming Java
arguments. */
public void setReturnedArrayLengthExpression(String expr) {
returnedArrayLengthExpression = expr;
}
protected void emitReturnType(PrintWriter writer)
{
writer.print(getReturnTypeString(false));
}
protected String getReturnTypeString(boolean skipArray) {
if (skipArray || (getReturnedArrayLengthExpression() == null && !binding.getJavaReturnType().isArrayOfCompoundTypeWrappers())) {
return binding.getJavaReturnType().getName();
}
return binding.getJavaReturnType().getName() + "[]";
}
protected void emitName(PrintWriter writer)
{
writer.print(binding.getName());
if (forNIOBufferBaseRoutine) {
writer.print("0");
}
}
protected int emitArguments(PrintWriter writer)
{
boolean needComma = false;
int numEmitted = 0;
if (forNIOBufferBaseRoutine && binding.hasContainingType()) {
// Always emit outgoing "this" argument
writer.print("java.nio.Buffer ");
writer.print(javaThisArgumentName());
++numEmitted;
needComma = true;
}
for (int i = 0; i < binding.getNumArguments(); i++) {
JavaType type = binding.getJavaArgumentType(i);
if (type.isVoid()) {
// Make sure this is the only param to the method; if it isn't,
// there's something wrong with our parsing of the headers.
if (binding.getNumArguments() != 1) {
throw new InternalError(
"\"void\" argument type found in " +
"multi-argument function \"" + binding + "\"");
}
continue;
}
if (type.isJNIEnv() || binding.isArgumentThisPointer(i)) {
// Don't need to expose these at the Java level
continue;
}
if (needComma) {
writer.print(", ");
}
writer.print(type.getName());
writer.print(" ");
writer.print(binding.getArgumentName(i));
++numEmitted;
needComma = true;
}
return numEmitted;
}
protected String getImplMethodName()
{
return binding.getName() + "0";
}
protected void emitBody(PrintWriter writer)
{
writer.println(';');
}
protected static String javaThisArgumentName() {
return "jthis0";
}
protected String getCommentStartString() { return "/** "; }
protected String getBaseIndentString() { return " "; }
protected String getReturnedArrayLengthExpression() {
return returnedArrayLengthExpression;
}
/**
* Class that emits a generic comment for JavaMethodBindingEmitters; the comment
* includes the C signature of the native method that is being bound by the
* emitter java method.
*/
protected static class DefaultCommentEmitter implements CommentEmitter {
public void emit(FunctionEmitter emitter, PrintWriter writer) {
emitBeginning(emitter, writer);
emitBindingCSignature(((JavaMethodBindingEmitter)emitter).getBinding(), writer);
emitEnding(emitter, writer);
}
protected void emitBeginning(FunctionEmitter emitter, PrintWriter writer) {
writer.print("Entry point to C language function:
");
}
protected void emitBindingCSignature(MethodBinding binding, PrintWriter writer) {
writer.print(" ");
writer.print(binding.getCSymbol());
writer.print("
");
}
protected void emitEnding(FunctionEmitter emitter, PrintWriter writer) {
// If argument type is a named enum, then emit a comment detailing the
// acceptable values of that enum.
MethodBinding binding = ((JavaMethodBindingEmitter)emitter).getBinding();
for (int i = 0; i < binding.getNumArguments(); i++) {
Type type = binding.getCArgumentType(i);
// don't emit param comments for anonymous enums, since we can't
// distinguish between the values found within multiple anonymous
// enums in the same C translation unit.
if (type.isEnum() && type.getName() != HeaderParser.ANONYMOUS_ENUM_NAME) {
EnumType enumType = (EnumType)type;
writer.println();
writer.print(emitter.getBaseIndentString());
writer.print(" ");
writer.print("@param ");
writer.print(binding.getArgumentName(i));
writer.print(" valid values are: ");
for (int j = 0; j < enumType.getNumEnumerates(); ++j) {
if (j>0) writer.print(", ");
writer.print(enumType.getEnumName(j));
}
writer.println("
");
}
}
}
}
protected static class InterfaceCommentEmitter
extends JavaMethodBindingEmitter.DefaultCommentEmitter
{
protected void emitBeginning(FunctionEmitter emitter,
PrintWriter writer) {
writer.print("Interface to C language function:
");
}
}
}