/* * Copyright (c) 2002-2008 LWJGL Project * 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 'LWJGL' 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 THE COPYRIGHT OWNER OR * CONTRIBUTORS 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 org.lwjgl.util.generator; /** * * This class generates the methods in the generated java source files. * * @author elias_naur * @version $Revision$ * $Id$ */ import org.lwjgl.PointerBuffer; import org.lwjgl.util.generator.opengl.GLreturn; import com.sun.mirror.apt.*; import com.sun.mirror.declaration.*; import com.sun.mirror.type.*; import java.io.*; import java.util.*; import java.nio.*; public class JavaMethodsGenerator { private static final String SAVED_PARAMETER_POSTFIX = "_saved"; public static void generateMethodsJava(AnnotationProcessorEnvironment env, TypeMap type_map, PrintWriter writer, InterfaceDeclaration interface_decl, boolean generate_error_checks, boolean context_specific) { for (MethodDeclaration method : interface_decl.getMethods()) generateMethodJava(env, type_map, writer, interface_decl, method, generate_error_checks, context_specific); } private static void generateMethodJava(AnnotationProcessorEnvironment env, TypeMap type_map, PrintWriter writer, InterfaceDeclaration interface_decl, MethodDeclaration method, boolean generate_error_checks, boolean context_specific) { writer.println(); if (Utils.isMethodIndirect(generate_error_checks, context_specific, method)) { if (method.getAnnotation(GenerateAutos.class) != null) { printMethodWithMultiType(env, type_map, writer, interface_decl, method, TypeInfo.getDefaultTypeInfoMap(method), Mode.AUTOS, generate_error_checks, context_specific); } Collection> cross_product = TypeInfo.getTypeInfoCrossProduct(type_map, method); for (Map typeinfos_instance : cross_product) { printMethodWithMultiType(env, type_map, writer, interface_decl, method, typeinfos_instance, Mode.NORMAL, generate_error_checks, context_specific); } } if ( method.getAnnotation(CachedResult.class) != null && !method.getAnnotation(CachedResult.class).isRange() ) { printMethodWithMultiType(env, type_map, writer, interface_decl, method, TypeInfo.getDefaultTypeInfoMap(method), Mode.CACHEDRESULT, generate_error_checks, context_specific); } Reuse reuse_annotation = method.getAnnotation(Reuse.class); Alternate alt_annotation = method.getAnnotation(Alternate.class); if ( alt_annotation == null || (alt_annotation.nativeAlt() && !alt_annotation.skipNative()) ) { if ( alt_annotation != null && method.getSimpleName().equals(alt_annotation.value()) ) throw new RuntimeException("An alternate function with native code should have a different name than the main function."); if ( reuse_annotation == null ) printJavaNativeStub(writer, method, Mode.NORMAL, generate_error_checks, context_specific); if (Utils.hasMethodBufferObjectParameter(method)) { printMethodWithMultiType(env, type_map, writer, interface_decl, method, TypeInfo.getDefaultTypeInfoMap(method), Mode.BUFFEROBJECT, generate_error_checks, context_specific); if ( reuse_annotation == null ) printJavaNativeStub(writer, method, Mode.BUFFEROBJECT, generate_error_checks, context_specific); } } } private static void printJavaNativeStub(PrintWriter writer, MethodDeclaration method, Mode mode, boolean generate_error_checks, boolean context_specific) { if (Utils.isMethodIndirect(generate_error_checks, context_specific, method)) { writer.print("\tstatic native "); } else { Utils.printDocComment(writer, method); writer.print("\tpublic static native "); } writer.print(getResultType(method, true)); writer.print(" " + Utils.getSimpleNativeMethodName(method, generate_error_checks, context_specific)); if (mode == Mode.BUFFEROBJECT) writer.print(Utils.BUFFER_OBJECT_METHOD_POSTFIX); writer.print("("); boolean first_parameter = generateParametersJava(writer, method, TypeInfo.getDefaultTypeInfoMap(method), true, true, mode); if (context_specific) { if (!first_parameter) writer.print(", "); writer.print("long " + Utils.FUNCTION_POINTER_VAR_NAME); } writer.println(");"); } private static boolean generateParametersJava(PrintWriter writer, MethodDeclaration method, Map typeinfos_instance, boolean native_stub, final boolean printTypes, Mode mode) { boolean first_parameter = true; for (ParameterDeclaration param : method.getParameters()) { if ( native_stub && (param.getAnnotation(Helper.class) != null && !param.getAnnotation(Helper.class).passToNative()) ) continue; final Constant constant_annotation = param.getAnnotation(Constant.class); if ( constant_annotation != null && constant_annotation.isNative() ) continue; AnnotationMirror auto_annotation_mirror = Utils.getParameterAutoAnnotation(param); boolean hide_auto_parameter = mode == Mode.NORMAL && !native_stub && auto_annotation_mirror != null; if (hide_auto_parameter) { AutoType auto_type_annotation = param.getAnnotation(AutoType.class); if (auto_type_annotation != null) { ParameterDeclaration auto_parameter = Utils.findParameter(method, auto_type_annotation.value()); TypeInfo auto_param_type_info = typeinfos_instance.get(auto_parameter); if (auto_param_type_info.getSignedness() == Signedness.BOTH) { if (!first_parameter) writer.print(", "); first_parameter = false; if ( printTypes ) writer.print("boolean "); writer.print(TypeInfo.UNSIGNED_PARAMETER_NAME); } } } else if ( param.getAnnotation(Result.class) == null && (native_stub || ((param.getAnnotation(Constant.class) == null || param.getAnnotation(Constant.class).keepParam()) && !Utils.isReturnParameter(method, param))) && (mode != Mode.AUTOS || getAutoTypeParameter(method, param) == null) ) { first_parameter = generateParameterJava(writer, param, typeinfos_instance.get(param), native_stub, printTypes, first_parameter, mode); } } CachedResult cached_result_annotation = method.getAnnotation(CachedResult.class); TypeMirror result_type = Utils.getMethodReturnType(method); if ((native_stub && Utils.getNIOBufferType(result_type) != null) || Utils.needResultSize(method)) { AutoSize auto_size_annotation = method.getAnnotation(AutoSize.class); if ( auto_size_annotation == null || !auto_size_annotation.isNative() ) { if (cached_result_annotation == null || !cached_result_annotation.isRange()) { if (!first_parameter) writer.print(", "); first_parameter = false; if ( printTypes ) writer.print("long "); writer.print(Utils.RESULT_SIZE_NAME); } } } if (cached_result_annotation != null) { if (!first_parameter) writer.print(", "); if ( mode == Mode.CACHEDRESULT ) { if ( printTypes ) writer.print("long "); writer.print(Utils.CACHED_BUFFER_LENGTH_NAME + ", "); } first_parameter = false; if ( printTypes ) writer.print(getResultType(method, native_stub)); writer.print(" " + Utils.CACHED_BUFFER_NAME); } return first_parameter; } private static boolean generateParameterJava(PrintWriter writer, ParameterDeclaration param, TypeInfo type_info, boolean native_stub, final boolean printTypes, boolean first_parameter, Mode mode) { Class buffer_type = Utils.getNIOBufferType(param.getType()); if (!first_parameter) writer.print(", "); BufferObject bo_annotation = param.getAnnotation(BufferObject.class); if (bo_annotation != null && mode == Mode.BUFFEROBJECT) { if (buffer_type == null) throw new RuntimeException("type of " + param + " is not a nio Buffer parameter but is annotated as buffer object"); if ( printTypes ) writer.print("long "); writer.print(param.getSimpleName() + Utils.BUFFER_OBJECT_PARAMETER_POSTFIX); } else { if ( native_stub && param.getAnnotation(PointerWrapper.class) != null ) writer.print("long "); else { Class type = type_info.getType(); if ( native_stub && (type == CharSequence.class || type == CharSequence[].class || type == PointerBuffer.class || Buffer.class.isAssignableFrom(type) ) ) writer.print("long "); else if ( printTypes ) writer.print(type_info.getType().getSimpleName() + " "); } AutoSize auto_size_annotation = param.getAnnotation(AutoSize.class); if ( auto_size_annotation != null ) writer.print(auto_size_annotation.value() + "_"); writer.print(param.getSimpleName()); } return false; } private static void printBufferObjectCheck(PrintWriter writer, BufferKind kind, Mode mode, boolean context_specific) { String bo_check_method_name = kind.toString(); writer.print("\t\t" + Utils.CHECKS_CLASS_NAME + ".ensure" + bo_check_method_name); if (mode == Mode.BUFFEROBJECT) writer.print("enabled"); else writer.print("disabled"); if ( context_specific ) writer.println("(caps);"); else writer.println("();"); } private static void printBufferObjectChecks(PrintWriter writer, MethodDeclaration method, Mode mode, boolean context_specific) { EnumSet check_set = EnumSet.noneOf(BufferKind.class); for (ParameterDeclaration param : method.getParameters()) { BufferObject bo_annotation = param.getAnnotation(BufferObject.class); if (bo_annotation != null) check_set.add(bo_annotation.value()); } for (BufferKind kind : check_set) printBufferObjectCheck(writer, kind, mode, context_specific); } private static void printMethodWithMultiType(AnnotationProcessorEnvironment env, TypeMap type_map, PrintWriter writer, InterfaceDeclaration interface_decl, MethodDeclaration method, Map typeinfos_instance, Mode mode, boolean generate_error_checks, boolean context_specific) { Utils.printDocComment(writer, method); if ( method.getAnnotation(Deprecated.class) != null ) writer.println("\t@Deprecated"); if ( interface_decl.getAnnotation(Private.class) == null && method.getAnnotation(Private.class) == null ) writer.print("\tpublic static "); else writer.print("\tstatic "); writer.print(getResultType(method, false)); StripPostfix strip_annotation = method.getAnnotation(StripPostfix.class); String method_name; Alternate alt_annotation = method.getAnnotation(Alternate.class); method_name = alt_annotation == null || alt_annotation.javaAlt() ? method.getSimpleName() : alt_annotation.value(); if (strip_annotation != null && mode == Mode.NORMAL) method_name = getPostfixStrippedName(type_map, interface_decl, method); writer.print(" " + method_name + "("); generateParametersJava(writer, method, typeinfos_instance, false, true, mode); writer.println(") {"); final TypeMirror result_type = Utils.getMethodReturnType(method); boolean has_result = !result_type.equals(env.getTypeUtils().getVoidType()); final Reuse reuse_annotation = method.getAnnotation(Reuse.class); if ( reuse_annotation != null ) { writer.print("\t\t"); if ( has_result || method.getAnnotation(GLreturn.class) != null ) writer.print("return "); writer.print(reuse_annotation.value() + "." + (reuse_annotation.method().length() > 0 ? reuse_annotation.method() : method_name) + "("); generateParametersJava(writer, method, typeinfos_instance, false, false, mode); writer.println(");\n\t}"); return; } if (context_specific) { type_map.printCapabilitiesInit(writer); writer.print("\t\tlong " + Utils.FUNCTION_POINTER_VAR_NAME + " = " + type_map.getCapabilities() + "."); writer.println(Utils.getFunctionAddressName(interface_decl, method, true) + ";"); writer.print("\t\tBufferChecks.checkFunctionAddress("); writer.println(Utils.FUNCTION_POINTER_VAR_NAME + ");"); } final Code code_annotation = method.getAnnotation(Code.class); if (code_annotation != null && code_annotation.value().length() > 0) writer.println(code_annotation.value()); printBufferObjectChecks(writer, method, mode, context_specific); printParameterChecks(writer, method, typeinfos_instance, mode, generate_error_checks); printParameterCaching(writer, interface_decl, method, mode, context_specific); if ( code_annotation != null && code_annotation.javaBeforeNative().length() > 0 ) writer.println(code_annotation.javaBeforeNative()); writer.print("\t\t"); final PointerWrapper pointer_wrapper_annotation = method.getAnnotation(PointerWrapper.class); if (has_result) { writer.print(getResultType(method, false) + " " + Utils.RESULT_VAR_NAME); if ( code_annotation != null && code_annotation.tryBlock() ) { writer.print(" = " + getDefaultResultValue(method)); writer.println(";\n\t\ttry {"); writer.print("\t\t\t" + Utils.RESULT_VAR_NAME); } writer.print(" = "); if ( pointer_wrapper_annotation != null ) { if ( pointer_wrapper_annotation.factory().length() > 0 ) writer.print(pointer_wrapper_annotation.factory() + "("); else writer.print("new " + getResultType(method, false) + "("); } } else if ( method.getAnnotation(GLreturn.class) != null ) { has_result = true; Utils.printGLReturnPre(writer, method, method.getAnnotation(GLreturn.class), type_map); } writer.print(Utils.getSimpleNativeMethodName(method, generate_error_checks, context_specific)); if (mode == Mode.BUFFEROBJECT) writer.print(Utils.BUFFER_OBJECT_METHOD_POSTFIX); writer.print("("); boolean first_parameter = printMethodCallArguments(writer, method, typeinfos_instance, mode, type_map); if (context_specific) { if (!first_parameter) writer.print(", "); writer.print(Utils.FUNCTION_POINTER_VAR_NAME); } if ( has_result && pointer_wrapper_annotation != null ) { writer.print(")"); if ( pointer_wrapper_annotation.params().length() > 0 ) writer.print(", " + pointer_wrapper_annotation.params()); } writer.println(");"); if ( code_annotation != null && code_annotation.javaAfterNative().length() > 0 ) writer.println(code_annotation.javaAfterNative()); final String tabs = code_annotation != null && code_annotation.tryBlock() ? "\t\t\t" : "\t\t"; if (generate_error_checks && method.getAnnotation(NoErrorCheck.class) == null) type_map.printErrorCheckMethod(writer, method, tabs); // DISABLED: indirect buffer support //printNondirectParameterCopies(writer, method, mode); if (has_result) { if ( method.getAnnotation(GLreturn.class) == null ) { if ( ByteBuffer.class.equals(Utils.getJavaType(result_type)) ) writer.println(tabs + "return LWJGLUtil.CHECKS && " + Utils.RESULT_VAR_NAME + " == null ? null : " + Utils.RESULT_VAR_NAME + ".order(ByteOrder.nativeOrder());"); // safeNewBuffer returns a direct ByteBuffer with BIG_ENDIAN order. else writer.println(tabs + "return " + Utils.RESULT_VAR_NAME + ";"); } else Utils.printGLReturnPost(writer, method, method.getAnnotation(GLreturn.class), type_map); } if ( code_annotation != null && code_annotation.tryBlock() ) { writer.println("\t\t} finally {"); writer.println(code_annotation.javaFinally()); writer.println("\t\t}"); } writer.println("\t}"); } private static String getExtensionPostfix(InterfaceDeclaration interface_decl) { String interface_simple_name = interface_decl.getSimpleName(); Extension extension_annotation = interface_decl.getAnnotation(Extension.class); if (extension_annotation == null) { int underscore_index = interface_simple_name.indexOf("_"); if (underscore_index != -1) return interface_simple_name.substring(0, underscore_index); else return ""; } else return extension_annotation.postfix(); } private static ParameterDeclaration getAutoTypeParameter(MethodDeclaration method, ParameterDeclaration target_parameter) { for (ParameterDeclaration param : method.getParameters()) { AnnotationMirror auto_annotation = Utils.getParameterAutoAnnotation(param); if (auto_annotation != null) { Class annotation_type = NativeTypeTranslator.getClassFromType(auto_annotation.getAnnotationType()); String parameter_name; if (annotation_type.equals(AutoType.class)) parameter_name = param.getAnnotation(AutoType.class).value(); else if (annotation_type.equals(AutoSize.class)) parameter_name = param.getAnnotation(AutoSize.class).value(); else throw new RuntimeException("Unknown annotation type " + annotation_type); if (target_parameter.getSimpleName().equals(parameter_name)) return param; } } return null; } private static boolean hasAnyParameterAutoTypeAnnotation(MethodDeclaration method, ParameterDeclaration target_param) { for (ParameterDeclaration param : method.getParameters()) { AutoType auto_type_annotation = param.getAnnotation(AutoType.class); if (auto_type_annotation != null) { ParameterDeclaration type_target_param = Utils.findParameter(method, auto_type_annotation.value()); if (target_param.equals(type_target_param)) return true; } } return false; } private static String getPostfixStrippedName(TypeMap type_map, InterfaceDeclaration interface_decl, MethodDeclaration method) { StripPostfix strip_annotation = method.getAnnotation(StripPostfix.class); ParameterDeclaration postfix_parameter = Utils.findParameter(method, strip_annotation.value()); String postfix = strip_annotation.postfix(); if ( "NULL".equals(postfix) ) { PostfixTranslator translator = new PostfixTranslator(type_map, postfix_parameter); postfix_parameter.getType().accept(translator); postfix = translator.getSignature(); } String method_name; Alternate alt_annotation = method.getAnnotation(Alternate.class); method_name = alt_annotation == null || alt_annotation.javaAlt() ? method.getSimpleName() : alt_annotation.value(); String extension_postfix = "NULL".equals(strip_annotation.extension()) ? getExtensionPostfix(interface_decl) : strip_annotation.extension(); String result; if ( strip_annotation.hasPostfix() && method_name.endsWith(postfix + "v" + extension_postfix)) result = method_name.substring(0, method_name.length() - (postfix.length() + 1 + extension_postfix.length())); else if ( strip_annotation.hasPostfix() && method_name.endsWith(postfix + extension_postfix)) result = method_name.substring(0, method_name.length() - (postfix.length() + extension_postfix.length())); else if ( strip_annotation.hasPostfix() && method_name.endsWith(postfix + "i_v" + extension_postfix) ) result = method_name.substring(0, method_name.length() - (postfix.length() + 3 + extension_postfix.length())); else if ( method_name.endsWith("i_v" + extension_postfix) ) result = method_name.substring(0, method_name.length() - (3 + extension_postfix.length())); else if (method_name.endsWith("v" + extension_postfix)) result = method_name.substring(0, method_name.length() - (1 + extension_postfix.length())); else throw new RuntimeException(method + " is specified as being postfix stripped on parameter " + postfix_parameter + ", but it's postfix is not '" + postfix + "' nor 'v'"); return result + extension_postfix; } private static int getBufferElementSizeExponent(Class c) { if (IntBuffer.class.equals(c)) return 2; else if (LongBuffer.class.equals(c)) return 3; else if (DoubleBuffer.class.equals(c)) return 3; else if (ShortBuffer.class.equals(c)) return 1; else if (ByteBuffer.class.equals(c)) return 0; else if (FloatBuffer.class.equals(c)) return 2; else throw new RuntimeException(c + " is not allowed"); } private static boolean printMethodCallArgument(PrintWriter writer, MethodDeclaration method, ParameterDeclaration param, Map typeinfos_instance, Mode mode, boolean first_parameter, TypeMap type_map) { if (!first_parameter) writer.print(", "); AnnotationMirror auto_annotation = Utils.getParameterAutoAnnotation(param); Constant constant_annotation = param.getAnnotation(Constant.class); if (constant_annotation != null) { writer.print(constant_annotation.value()); } else if (auto_annotation != null && mode == Mode.NORMAL) { Class param_type = NativeTypeTranslator.getClassFromType(auto_annotation.getAnnotationType()); if (AutoType.class.equals(param_type)) { final AutoType auto_type_annotation = param.getAnnotation(AutoType.class); final ParameterDeclaration auto_parameter = Utils.findParameter(method, auto_type_annotation.value()); final String auto_type = typeinfos_instance.get(auto_parameter).getAutoType(); if ( auto_type == null ) throw new RuntimeException("No auto type for parameter " + param.getSimpleName() + " in method " + method); writer.print(auto_type); } else if (AutoSize.class.equals(param_type)) { final AutoSize auto_size_annotation = param.getAnnotation(AutoSize.class); if ( !auto_size_annotation.useExpression() ) { final String auto_parameter_name = auto_size_annotation.value(); final ParameterDeclaration auto_target_param = Utils.findParameter(method, auto_parameter_name); final TypeInfo auto_target_type_info = typeinfos_instance.get(auto_target_param); final boolean shift_remaining = !hasAnyParameterAutoTypeAnnotation(method, auto_target_param) && Utils.isParameterMultiTyped(auto_target_param); int shifting = 0; if ( shift_remaining ) { shifting = getBufferElementSizeExponent(auto_target_type_info.getType()); if ( shifting > 0 ) writer.print("("); } if ( auto_size_annotation.canBeNull() ) writer.print("(" + auto_parameter_name + " == null ? 0 : " + auto_parameter_name + ".remaining())"); else writer.print(auto_parameter_name + ".remaining()"); // Shift the remaining if the target parameter is multityped and there's no AutoType to track type if (shift_remaining && shifting > 0) { writer.print(" << " + shifting); writer.print(")"); } } writer.print(auto_size_annotation.expression()); } else throw new RuntimeException("Unknown auto annotation " + param_type); } else { if (mode == Mode.BUFFEROBJECT && param.getAnnotation(BufferObject.class) != null) { writer.print(param.getSimpleName() + Utils.BUFFER_OBJECT_PARAMETER_POSTFIX); } else { Class type = typeinfos_instance.get(param).getType(); Check check_annotation = param.getAnnotation(Check.class); boolean hide_buffer = mode == Mode.AUTOS && getAutoTypeParameter(method, param) != null; if (hide_buffer) { writer.print("0L"); } else { if ( type == CharSequence.class || type == CharSequence[].class ) { final String offset = Utils.getStringOffset(method, param); writer.print("APIUtil.getBuffer"); if ( param.getAnnotation(NullTerminated.class) != null ) writer.print("NT"); writer.print('('); writer.print(type_map.getAPIUtilParam(true)); writer.print(param.getSimpleName()); if ( offset != null ) writer.print(", " + offset); writer.print(")"); } else { final AutoSize auto_size_annotation = param.getAnnotation(AutoSize.class); if ( auto_size_annotation != null ) writer.print(auto_size_annotation.value() + "_"); final Class buffer_type = Utils.getNIOBufferType(param.getType()); if ( buffer_type == null ) writer.print(param.getSimpleName()); else { writer.print("MemoryUtil.getAddress"); if ( check_annotation != null && check_annotation.canBeNull() ) writer.print("Safe"); writer.print("("); writer.print(param.getSimpleName()); writer.print(")"); } } } if ( type != long.class ) { PointerWrapper pointer_annotation = param.getAnnotation(PointerWrapper.class); if ( pointer_annotation != null ) { if ( pointer_annotation.canBeNull() ) writer.print(" == null ? 0 : " + param.getSimpleName()); writer.print(".getPointer()"); } } } } return false; } private static boolean printMethodCallArguments(PrintWriter writer, MethodDeclaration method, Map typeinfos_instance, Mode mode, TypeMap type_map) { boolean first_parameter = true; for ( ParameterDeclaration param : method.getParameters() ) { if ( param.getAnnotation(Result.class) != null || (param.getAnnotation(Helper.class) != null && !param.getAnnotation(Helper.class).passToNative()) ) continue; final Constant constant_annotation = param.getAnnotation(Constant.class); if ( constant_annotation== null || !constant_annotation.isNative() ) first_parameter = printMethodCallArgument(writer, method, param, typeinfos_instance, mode, first_parameter, type_map); } if (Utils.getNIOBufferType(Utils.getMethodReturnType(method)) != null) { if (method.getAnnotation(CachedResult.class) != null && method.getAnnotation(CachedResult.class).isRange()) { first_parameter = false; Utils.printExtraCallArguments(writer, method, ""); } else { AutoSize auto_size_annotation = method.getAnnotation(AutoSize.class); if ( auto_size_annotation == null || !auto_size_annotation.isNative() ) { if (!first_parameter) writer.print(", "); first_parameter = false; String result_size_expression; if ( mode == Mode.CACHEDRESULT ) result_size_expression = Utils.CACHED_BUFFER_LENGTH_NAME; else if ( auto_size_annotation == null ) result_size_expression = Utils.RESULT_SIZE_NAME; else result_size_expression = auto_size_annotation.value(); Utils.printExtraCallArguments(writer, method, result_size_expression); } } } return first_parameter; } private static void printParameterCaching(PrintWriter writer, InterfaceDeclaration interface_decl, MethodDeclaration method, Mode mode, boolean context_specific) { for (ParameterDeclaration param : method.getParameters()) { Class java_type = Utils.getJavaType(param.getType()); CachedReference cachedReference = param.getAnnotation(CachedReference.class); if (Buffer.class.isAssignableFrom(java_type) && cachedReference != null && (mode != Mode.BUFFEROBJECT || param.getAnnotation(BufferObject.class) == null) && param.getAnnotation(Result.class) == null) { writer.print("\t\tif ( LWJGLUtil.CHECKS ) StateTracker."); if ( context_specific ) writer.print("getReferences(caps)."); else writer.print("getTracker()."); if(cachedReference.name().length() > 0) { writer.print(cachedReference.name()); } else { writer.print(Utils.getReferenceName(interface_decl, method, param)); } if(cachedReference.index().length() > 0) { writer.print("[" + cachedReference.index() + "]"); } writer.println(" = " + param.getSimpleName() + ";"); } } } private static void printParameterChecks(PrintWriter writer, MethodDeclaration method, Map typeinfos, Mode mode, final boolean generate_error_checks) { if ( mode == Mode.NORMAL ) { final GenerateAutos gen_autos_annotation = method.getAnnotation(GenerateAutos.class); if ( gen_autos_annotation != null && gen_autos_annotation.sizeVariables().length > 0 ) { // For the auto-generated parameters, declare and init a size variable (that can be reused by @Code) for ( final ParameterDeclaration param : method.getParameters() ) { if ( Arrays.binarySearch(gen_autos_annotation.sizeVariables(), param.getSimpleName()) >= 0 ) { final int shifting = getBufferElementSizeExponent(typeinfos.get(param).getType()); final Check check_annotation = param.getAnnotation(Check.class); writer.print("\t\tlong " + param.getSimpleName() + "_size = "); if ( check_annotation == null || !check_annotation.canBeNull() ) writer.println(param.getSimpleName() + ".remaining() << " + shifting + ";"); else writer.println(param.getSimpleName() + " == null ? 0 : " + param.getSimpleName() + ".remaining() << " + shifting + ";"); } } } } for (ParameterDeclaration param : method.getParameters()) { Class java_type = Utils.getJavaType(param.getType()); if ( java_type.isArray() || (Utils.isAddressableType(java_type) && (mode != Mode.BUFFEROBJECT || param.getAnnotation(BufferObject.class) == null) && (mode != Mode.AUTOS || getAutoTypeParameter(method, param) == null) && param.getAnnotation(Result.class) == null && !Utils.isReturnParameter(method, param)) ) { String check_value = null; boolean can_be_null = false; Check check_annotation = param.getAnnotation(Check.class); if (check_annotation != null) { check_value = check_annotation.value(); can_be_null = check_annotation.canBeNull(); } if ((Buffer.class.isAssignableFrom(java_type) || PointerBuffer.class.isAssignableFrom(java_type)) && param.getAnnotation(Constant.class) == null) { boolean out_parameter = param.getAnnotation(OutParameter.class) != null; TypeInfo typeinfo = typeinfos.get(param); printParameterCheck(writer, method, param.getSimpleName(), typeinfo.getType().getSimpleName(), check_value, can_be_null, param.getAnnotation(NullTerminated.class), out_parameter, generate_error_checks); } else if ( String.class.equals(java_type)) { if (!can_be_null) writer.println("\t\tBufferChecks.checkNotNull(" + param.getSimpleName() + ");"); } else if ( java_type.isArray() ) { final TypeInfo typeinfo = typeinfos.get(param); printArrayParameterCheck(writer, param.getSimpleName(), typeinfo.getType().getSimpleName(), check_value, can_be_null); } } } if (method.getAnnotation(CachedResult.class) != null) printParameterCheck(writer, method, Utils.CACHED_BUFFER_NAME, null, null, true, null, false, generate_error_checks); } private static void printParameterCheck(PrintWriter writer, MethodDeclaration method, String name, String type, String check_value, boolean can_be_null, NullTerminated null_terminated, boolean out_parameter, boolean generate_error_checks) { String tabs; if (can_be_null) { writer.print("\t\tif (" + name + " != null)"); if ( null_terminated != null ) writer.println(" {"); else writer.println(); tabs = "\t\t\t"; } else tabs = "\t\t"; writer.print(tabs + "BufferChecks.check"); if (check_value != null && check_value.length() > 0) { writer.print("Buffer"); if ( "Buffer".equals(type) ) writer.print("Size"); // Check size only, Buffer.isDirect() was added in 1.6, cannot use yet. TODO: Remove? writer.print("(" + name + ", " + check_value); } else { writer.print("Direct(" + name); } writer.println(");"); if ( can_be_null && generate_error_checks ) { final Check check_annotation = method.getAnnotation(Check.class); if ( check_annotation != null && check_annotation.value().equals(name) ) { writer.println("\t\telse"); writer.println("\t\t\t" + name + " = APIUtil.getBufferIntDebug();"); // Use an exclusive buffer here } } if (null_terminated != null) { writer.print(tabs + "BufferChecks.checkNullTerminated("); writer.print(name); if ( null_terminated.value().length() > 0 ) { writer.print(", "); writer.print(null_terminated.value()); } writer.println(");"); if ( can_be_null ) writer.println("\t\t}"); } } private static void printArrayParameterCheck(PrintWriter writer, String name, String type, String check_value, boolean can_be_null) { String tabs; if ( can_be_null ) { writer.println("\t\tif (" + name + " != null)"); tabs = "\t\t\t"; } else tabs = "\t\t"; writer.print(tabs + "BufferChecks.checkArray(" + name); if ( check_value != null && check_value.length() > 0) writer.print(", " + check_value); writer.println(");"); } private static String getResultType(MethodDeclaration method, boolean native_stub) { if ( native_stub && method.getAnnotation(PointerWrapper.class) != null ) return "long"; else if ( !native_stub && method.getAnnotation(GLreturn.class) != null ) return Utils.getMethodReturnType(method, method.getAnnotation(GLreturn.class), false); else return Utils.getJavaType(Utils.getMethodReturnType(method)).getSimpleName(); } private static String getDefaultResultValue(MethodDeclaration method) { if ( method.getAnnotation(GLreturn.class) != null ) { final String type = Utils.getMethodReturnType(method, method.getAnnotation(GLreturn.class), false); if ( "boolean".equals(type) ) return "false"; else if ( Character.isLowerCase(type.charAt(0)) ) return "0"; else return "null"; } else { final Class type = Utils.getJavaType(Utils.getMethodReturnType(method)); if ( type.isPrimitive() ) { if ( type == boolean.class ) return "false"; else return "0"; } else return "null"; } } }