From 8e2960c59a136fe80faf34353fee6fde6e46f195 Mon Sep 17 00:00:00 2001 From: Roland Elek Date: Mon, 29 Sep 2014 16:38:15 +0200 Subject: [PATCH 1/7] Begin parsing interfaces This generates broken code, but the problems are dealt with in the next few commits. --- src/gir2java/GirParser.java | 60 +++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/src/gir2java/GirParser.java b/src/gir2java/GirParser.java index 0838bb3..2c32d57 100644 --- a/src/gir2java/GirParser.java +++ b/src/gir2java/GirParser.java @@ -84,6 +84,7 @@ public class GirParser { elementParsers.put("instance-parameter", GirParser.class.getDeclaredMethod("parseParameter", Element.class, ParsingContext.class)); elementParsers.put("constructor", GirParser.class.getDeclaredMethod("parseMethodOrFunction", Element.class, ParsingContext.class)); elementParsers.put("union", GirParser.class.getDeclaredMethod("parseRecordOrClass", Element.class, ParsingContext.class)); + elementParsers.put("virtual-method", GirParser.class.getDeclaredMethod("parseVirtualMethod", Element.class, ParsingContext.class)); //Add other parser methods here } catch (NoSuchMethodException e) { @@ -1010,12 +1011,67 @@ private void parseMethodOrFunction(Element root, ParsingContext context) { } + @SuppressWarnings("unused") + private void parseVirtualMethod(Element root, ParsingContext context) { + String name = root.getAttributeValue("name"); + name = NameUtils.neutralizeKeyword(name); + JDefinedClass enclosing = (JDefinedClass) context.getCmNode(); + + //Add an abstract method to the parent node + //Parse signature like functions, but only make the wrapper, as abstract + + ParsingContext nextContext = context.copy(); + parseElements(root.getChildElements(), nextContext); + + ConvertedType returnType = (ConvertedType) nextContext.getExtra(Constants.CONTEXT_EXTRA_RETURN_TYPE); + List parametersList = (List) nextContext.getExtra(Constants.CONTEXT_EXTRA_PARAM_TYPES); + + if (checkUndefined(root, nextContext)) { + return; + } + + if (checkStructByValue(returnType, parametersList)) { + System.out.println("Skipped " + name + "() because it takes or returns struct by value"); + return; + } + + //Explicitly declared public abstract because the enclosing class is not guaranteed to be an interface. + //It can also be an abstract class. + JMethod method = enclosing.method(JMod.PUBLIC | JMod.ABSTRACT, returnType.getJType(), name); + + if (parametersList != null) { + for (ParameterDescriptor paramDesc : parametersList) { + if (paramDesc.isInstance()) { + //FIXME: what to do with the this parameter? just skip, and pass in implementors? + } else if (paramDesc.isVarargs()) { + JVar param = method.varParam(Object.class, "varargs"); + } else { + JVar param = method.param(paramDesc.getType().getJType(), paramDesc.getName()); + } + } + } + + } + @SuppressWarnings("unused") private void parseInterface(Element root, ParsingContext context) { - // only log the fact that we have found this type for now String name = root.getAttributeValue("name"); Set foundTypes = (Set)context.getExtra(Constants.CONTEXT_EXTRA_DEFINED_TYPES); foundTypes.add("" + context.getExtra(Constants.CONTEXT_EXTRA_NAMESPACE) + '.' + name); + + String className = context.getCurrentPackage() + '.' + context.getExtra(Constants.CONTEXT_EXTRA_PREFIX) + NameUtils.neutralizeKeyword(name); + JDefinedClass iface; + try { + iface = context.getCm()._class(className, ClassType.INTERFACE); + } catch (JClassAlreadyExistsException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return; + } + + ParsingContext nextContext = context.withCmNode(iface); + parseElements(root.getChildElements(), nextContext); + ConvertedType convType = new ConvertedType( context.getCm(), (String)context.getExtra(Constants.CONTEXT_EXTRA_NAMESPACE), @@ -1023,7 +1079,7 @@ private void parseInterface(Element root, ParsingContext context) { root.getAttributeValue("type",Constants.GIR_XMLNS_C), false ); - convType.setJType(context.getCm().ref(Object.class)); + convType.setJType(iface); context.registerType(convType); } From be38bfce8284bbb23395fb3a66f672d140d091db Mon Sep 17 00:00:00 2001 From: Roland Elek Date: Tue, 30 Sep 2014 16:37:18 +0200 Subject: [PATCH 2/7] Put non-abstract methods from interfaces into the namespace class --- src/gir2java/GirParser.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/gir2java/GirParser.java b/src/gir2java/GirParser.java index 2c32d57..db32db0 100644 --- a/src/gir2java/GirParser.java +++ b/src/gir2java/GirParser.java @@ -824,6 +824,11 @@ private boolean checkStructByValue(ConvertedType returnType, List Date: Tue, 30 Sep 2014 16:52:47 +0200 Subject: [PATCH 3/7] Do not parse gtype structs for interfaces --- src/gir2java/Constants.java | 1 + src/gir2java/GirParser.java | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/gir2java/Constants.java b/src/gir2java/Constants.java index 430665d..fd917a6 100644 --- a/src/gir2java/Constants.java +++ b/src/gir2java/Constants.java @@ -4,6 +4,7 @@ public class Constants { //Should we get this from the individual girs instead? public static final String GIR_XMLNS_C = "http://www.gtk.org/introspection/c/1.0"; + public static final String GIR_XMLNS_GLIB = "http://www.gtk.org/introspection/glib/1.0"; public static final String CONTEXT_EXTRA_NAMESPACE = "namespace"; public static final String CONTEXT_EXTRA_TYPE_REGISTRY = "types"; diff --git a/src/gir2java/GirParser.java b/src/gir2java/GirParser.java index db32db0..f5dc5fc 100644 --- a/src/gir2java/GirParser.java +++ b/src/gir2java/GirParser.java @@ -503,6 +503,10 @@ private void parseRecordOrClass(Element root, ParsingContext context) { * an opaque struct. Classes have their own element, which is very similar, and also parsed here. */ + if (root.getAttribute("is-gtype-struct-for", Constants.GIR_XMLNS_GLIB) != null) { + return; + } + JCodeModel cm = (JCodeModel) context.getCmNode(); String name = root.getAttributeValue("name"); From bf51352bff6ed5bd5f57d66cc5ca6304180b5c4d Mon Sep 17 00:00:00 2001 From: Roland Elek Date: Tue, 30 Sep 2014 20:40:48 +0200 Subject: [PATCH 4/7] Do not generate duplicate methods There are cases where multiple methods are indicated in the gir files to map to the same native function. If these are generated into the same class, the generated code breaks. An example is when a non-virtual method is defined globally, and also in an interface. Both are generated into the namespace-wide catch-all class. This commit prevents the generation of these duplicates. --- src/gir2java/GirParser.java | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/gir2java/GirParser.java b/src/gir2java/GirParser.java index f5dc5fc..8f75e7a 100644 --- a/src/gir2java/GirParser.java +++ b/src/gir2java/GirParser.java @@ -921,7 +921,27 @@ private void parseMethodOrFunction(Element root, ParsingContext context) { int staticModifier = ParameterDescriptor.containsInstanceParameter(parametersList) ? 0 : JMod.STATIC; int nativeModifiers = nativeVisibility | staticModifier | JMod.NATIVE; - JMethod nativeMethod; + List parametersListJTypes = new ArrayList((parametersList == null) ? 0 : parametersList.size()); + + if (parametersList != null) { //null if the function has no arguments + for (ParameterDescriptor paramDesc : parametersList) { + if (paramDesc.isVarargs()) { + //XXX not entirely sure about this... + parametersListJTypes.add(paramDesc.getType().getJType().array()); + } else if (paramDesc.getType().isPointer()) { + parametersListJTypes.add(nextContext.getCm()._ref(long.class)); + } else { + parametersListJTypes.add(paramDesc.getType().getJType()); + } + } + } + + JMethod nativeMethod = enclosing.getMethod(nativeName, parametersListJTypes.toArray(new JType[0])); + if (nativeMethod != null) { + //This can occur in the original girs + return; + } + if (returnsPointer) { nativeMethod = enclosing.method(nativeModifiers | JMod.NATIVE, long.class, nativeName); nativeMethod.annotate(Ptr.class); @@ -1023,7 +1043,6 @@ private void parseMethodOrFunction(Element root, ParsingContext context) { wrapper.body()._return(nativeCall); } } - } @SuppressWarnings("unused") From 5e1a8beb2d235ed55999b94af410c4ffce00ffc5 Mon Sep 17 00:00:00 2001 From: Roland Elek Date: Tue, 30 Sep 2014 21:45:01 +0200 Subject: [PATCH 5/7] Do not automatically pass this in relocated methods An example of a relocated method is a non-abstract method found in an interface, which is generated into the namespace-wide catch-all class instead. --- src/gir2java/GirParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gir2java/GirParser.java b/src/gir2java/GirParser.java index 8f75e7a..e3010e0 100644 --- a/src/gir2java/GirParser.java +++ b/src/gir2java/GirParser.java @@ -984,7 +984,7 @@ private void parseMethodOrFunction(Element root, ParsingContext context) { } if (parametersList != null) { for (ParameterDescriptor paramDesc : parametersList) { - if (paramDesc.isInstance()) { + if (paramDesc.isInstance() && (foundIn.equals(enclosing)) ) { //pass a pointer to this nativeCall.arg( nextContext From 4b686c42a8cfe1acdd13cec6fbabc5e4fa9fb617 Mon Sep 17 00:00:00 2001 From: Roland Elek Date: Wed, 15 Oct 2014 10:53:12 +0200 Subject: [PATCH 6/7] Various changes related to interfaces Mostly a mechanism to actually call the pointed virtual functions, and the parsing of anonymous callbacks. This is a quick commit to share these changes, and really needs cleaning up before pushing to master... --- src/gir2java/Constants.java | 2 + src/gir2java/GirParser.java | 396 +++++++++++++++++++++--------------- 2 files changed, 231 insertions(+), 167 deletions(-) diff --git a/src/gir2java/Constants.java b/src/gir2java/Constants.java index fd917a6..3baab1f 100644 --- a/src/gir2java/Constants.java +++ b/src/gir2java/Constants.java @@ -17,5 +17,7 @@ public class Constants { public static final String CONTEXT_EXTRA_UNDEFINED = "undefined"; public static final String CONTEXT_EXTRA_PREFIX = "prefix"; public static final String CONTEXT_EXTRA_NAMESPACE_TO_LIB = "ns-to-lib"; + public static final String CONTEXT_EXTRA_LOCAL_CALLBACK = "local-cb"; + public static final String CONTEXT_EXTRA_FIELD_NAME = "field-name"; } diff --git a/src/gir2java/GirParser.java b/src/gir2java/GirParser.java index e3010e0..b59b10b 100644 --- a/src/gir2java/GirParser.java +++ b/src/gir2java/GirParser.java @@ -495,7 +495,7 @@ private void parseEnumMember(Element root, ParsingContext context) { enumConstant.arg(JExpr.lit(value)); System.out.println("--> " + enumConstant.getName() + " (" + value + ")"); } - + @SuppressWarnings("unused") private void parseRecordOrClass(Element root, ParsingContext context) { /* @@ -507,7 +507,7 @@ private void parseRecordOrClass(Element root, ParsingContext context) { return; } - JCodeModel cm = (JCodeModel) context.getCmNode(); + JCodeModel cm = (JCodeModel) context.getCm(); String name = root.getAttributeValue("name"); //Check if this is a retry @@ -716,6 +716,10 @@ private ConvertedType findType(Element root, ParsingContext context) { } System.out.println("found an array, treating it as " + convType); break; + } else if (childQualName.equals("callback")) { + parseElement(child, context); + convType = (ConvertedType) context.getExtra(Constants.CONTEXT_EXTRA_LOCAL_CALLBACK); + break; } } @@ -737,17 +741,21 @@ private ConvertedType findType(Element root, ParsingContext context) { private void parseRecordField(Element root, ParsingContext context) { JDefinedClass record = (JDefinedClass) context.getCmNode(); + String origName = root.getAttributeValue("name"); String name = record.name().toLowerCase() + "_field_" + root.getAttributeValue("name"); int fieldIdx = (int)context.getExtra(Constants.CONTEXT_EXTRA_NEXT_FIELD_INDEX); - ConvertedType convType = findType(root, context); + ParsingContext nextContext = context.copy(); + nextContext.putExtra(Constants.CONTEXT_EXTRA_FIELD_NAME, origName); + ConvertedType convType = findType(root, nextContext); - if (checkUndefined(root, context)) { + if (checkUndefined(root, nextContext)) { return; } if (convType == null) { + record.javadoc().add("Field " + origName + " skipped because no mapping was found\n"); return; } @@ -869,179 +877,184 @@ private String disambiguateMethodName(String name, JClass enclosing) { @SuppressWarnings("unused") private void parseMethodOrFunction(Element root, ParsingContext context) { - ParsingContext nextContext = context.copy(); - - String name = root.getAttributeValue("name"); - String nativeName = root.getAttributeValue("identifier", Constants.GIR_XMLNS_C); - Object cmNode = nextContext.getCmNode(); - - JDefinedClass enclosing; - JDefinedClass foundIn; - if (cmNode instanceof JDefinedClass) { - enclosing = (JDefinedClass) cmNode; - foundIn = enclosing; - if (((JDefinedClass) cmNode).isInterface()) { - enclosing = context.getCurrentNamespaceClass(); //don't put non-abstract methods in interfaces - } - } else { - enclosing = context.getCurrentNamespaceClass(); - foundIn = enclosing; - } - - parseElements(root.getChildElements(), nextContext); - /* The context should now have the return type, and parameter list. - * If one of these is a Pointer, wrap, if not, then native method only - */ - - ConvertedType returnType = (ConvertedType) nextContext.getExtra(Constants.CONTEXT_EXTRA_RETURN_TYPE); - List parametersList = (List) nextContext.getExtra(Constants.CONTEXT_EXTRA_PARAM_TYPES); - - if (checkUndefined(root, nextContext)) { - return; - } - - if (checkStructByValue(returnType, parametersList)) { - System.out.println("Skipped " + nativeName + "() because it takes or returns struct by value"); - return; - } - - boolean returnsPointer = returnType.isPointer(); - boolean takesPointer = false; - - if (parametersList != null) { - for (ParameterDescriptor paramDesc : parametersList) { - if ((paramDesc.getType()) != null && paramDesc.getType().isPointer()) { - takesPointer = true; - break; + try { + ParsingContext nextContext = context.copy(); + + String name = root.getAttributeValue("name"); + String nativeName = root.getAttributeValue("identifier", Constants.GIR_XMLNS_C); + Object cmNode = nextContext.getCmNode(); + + JDefinedClass enclosing; + JDefinedClass foundIn; + if (cmNode instanceof JDefinedClass) { + enclosing = (JDefinedClass) cmNode; + foundIn = enclosing; + if (((JDefinedClass) cmNode).isInterface()) { + enclosing = context.getCurrentNamespaceClass(); //don't put non-abstract methods in interfaces } + } else { + enclosing = context.getCurrentNamespaceClass(); + foundIn = enclosing; } - } - - int nativeVisibility = (returnsPointer || takesPointer) ? JMod.PROTECTED : JMod.PUBLIC; - int staticModifier = ParameterDescriptor.containsInstanceParameter(parametersList) ? 0 : JMod.STATIC; - int nativeModifiers = nativeVisibility | staticModifier | JMod.NATIVE; - - List parametersListJTypes = new ArrayList((parametersList == null) ? 0 : parametersList.size()); - - if (parametersList != null) { //null if the function has no arguments - for (ParameterDescriptor paramDesc : parametersList) { - if (paramDesc.isVarargs()) { - //XXX not entirely sure about this... - parametersListJTypes.add(paramDesc.getType().getJType().array()); - } else if (paramDesc.getType().isPointer()) { - parametersListJTypes.add(nextContext.getCm()._ref(long.class)); - } else { - parametersListJTypes.add(paramDesc.getType().getJType()); - } + + parseElements(root.getChildElements(), nextContext); + /* The context should now have the return type, and parameter list. + * If one of these is a Pointer, wrap, if not, then native method only + */ + + ConvertedType returnType = (ConvertedType) nextContext.getExtra(Constants.CONTEXT_EXTRA_RETURN_TYPE); + List parametersList = (List) nextContext.getExtra(Constants.CONTEXT_EXTRA_PARAM_TYPES); + + if (checkUndefined(root, nextContext)) { + return; } - } - - JMethod nativeMethod = enclosing.getMethod(nativeName, parametersListJTypes.toArray(new JType[0])); - if (nativeMethod != null) { - //This can occur in the original girs - return; - } - - if (returnsPointer) { - nativeMethod = enclosing.method(nativeModifiers | JMod.NATIVE, long.class, nativeName); - nativeMethod.annotate(Ptr.class); - } else { - nativeMethod = enclosing.method(nativeModifiers | JMod.NATIVE, returnType.getJType(), nativeName); - } - - if (parametersList != null) { //null if the function has no arguments - for (ParameterDescriptor paramDesc : parametersList) { - if (paramDesc.isVarargs()) { - nativeMethod.varParam(Object.class, "varargs"); - } else if (paramDesc.getType().isPointer()) { - JType paramJType = nextContext.getCm()._ref(long.class); - JVar param = nativeMethod.param(paramJType, paramDesc.getName()); - param.annotate(Ptr.class); - } else { - //primitives only? - nativeMethod.param(paramDesc.getType().getJType(), paramDesc.getName()); - } + + if (checkStructByValue(returnType, parametersList)) { + System.out.println("Skipped " + nativeName + "() because it takes or returns struct by value"); + return; } - } - - //nativeMethod.javadoc().add(root.toXML()); - - //if there was any Pointer replaced above, here comes a pretty wrapper that wraps/unwraps between @Ptr long and Pointer - if (takesPointer || returnsPointer) { - if ("".equals(name)) { - name = nativeName; + + boolean returnsPointer = returnType.isPointer(); + boolean takesPointer = false; + + if (parametersList != null) { + for (ParameterDescriptor paramDesc : parametersList) { + if ((paramDesc.getType()) != null && paramDesc.getType().isPointer()) { + takesPointer = true; + break; + } + } + } + + int nativeVisibility = (returnsPointer || takesPointer) ? JMod.PROTECTED : JMod.PUBLIC; + int staticModifier = ParameterDescriptor.containsInstanceParameter(parametersList) ? 0 : JMod.STATIC; + int nativeModifiers = nativeVisibility | staticModifier | JMod.NATIVE; + + List parametersListJTypes = new ArrayList((parametersList == null) ? 0 : parametersList.size()); + + if (parametersList != null) { //null if the function has no arguments + for (ParameterDescriptor paramDesc : parametersList) { + if (paramDesc.isVarargs()) { + //XXX not entirely sure about this... + parametersListJTypes.add(cm._ref(Object[].class)); + } else if (paramDesc.getType().isPointer()) { + parametersListJTypes.add(nextContext.getCm()._ref(long.class)); + } else { + parametersListJTypes.add(paramDesc.getType().getJType()); + } + } } - name = NameUtils.neutralizeKeyword(name); - name = disambiguateMethodName(name, foundIn); - JMethod wrapper = enclosing.method(JMod.PUBLIC | staticModifier, returnType.getJType(), name); + JMethod nativeMethod = enclosing.getMethod(nativeName, parametersListJTypes.toArray(new JType[0])); + if (nativeMethod != null) { + //This can occur in the original girs + return; + } - JInvocation nativeCall; - if (staticModifier == 0) { - nativeCall = JExpr._this().invoke(nativeMethod); + if (returnsPointer) { + nativeMethod = enclosing.method(nativeModifiers | JMod.NATIVE, long.class, nativeName); + nativeMethod.annotate(Ptr.class); } else { - nativeCall = enclosing.staticInvoke(nativeMethod); + nativeMethod = enclosing.method(nativeModifiers | JMod.NATIVE, returnType.getJType(), nativeName); } - if (parametersList != null) { + + if (parametersList != null) { //null if the function has no arguments for (ParameterDescriptor paramDesc : parametersList) { - if (paramDesc.isInstance() && (foundIn.equals(enclosing)) ) { - //pass a pointer to this - nativeCall.arg( - nextContext - .getCm() - .ref(Pointer.class) - .staticInvoke("pointerTo") - .arg(JExpr._this()) - .arg(enclosing.dotclass()) - .invoke("getPeer") - ); - } else if (paramDesc.isVarargs()) { - JVar param = wrapper.varParam(Object.class, "varargs"); - nativeCall.arg(param); + if (paramDesc.isVarargs()) { + nativeMethod.varParam(Object.class, "varargs"); } else if (paramDesc.getType().isPointer()) { - JVar param = wrapper.param(paramDesc.getType().getJType(), paramDesc.getName()); - nativeCall.arg(context.getCm().ref(Pointer.class).staticInvoke("getPeer").arg(param)); + JType paramJType = nextContext.getCm()._ref(long.class); + JVar param = nativeMethod.param(paramJType, paramDesc.getName()); + param.annotate(Ptr.class); } else { - JVar param = wrapper.param(paramDesc.getType().getJType(), paramDesc.getName()); - nativeCall.arg(param); + //primitives only? + nativeMethod.param(paramDesc.getType().getJType(), paramDesc.getName()); } } } - if (returnsPointer) { - // Pointer.pointerToAddress(native(...), ReturnType.class) - ConvertedType returnConvType = returnType.forCType(nextContext, returnType.getCtype()); - JClass returnClass = (JClass)returnConvType.getJType(); + //nativeMethod.javadoc().add(root.toXML()); + + //if there was any Pointer replaced above, here comes a pretty wrapper that wraps/unwraps between @Ptr long and Pointer + if (takesPointer || returnsPointer) { + if ("".equals(name)) { + name = nativeName; + } + name = NameUtils.neutralizeKeyword(name); + name = disambiguateMethodName(name, foundIn); - JInvocation pointerToAddressCall = - context - .getCm() - .ref(Pointer.class) - .staticInvoke("pointerToAddress") - .arg(nativeCall); + JMethod wrapper = enclosing.method(JMod.PUBLIC | staticModifier, returnType.getJType(), name); - if (returnClass.isParameterized()) { - JClass parameter = returnClass.getTypeParameters().get(0); - if (parameter.isParameterized()) { - JInvocation paramTypeCall = context - .getCm() - .ref(DefaultParameterizedType.class) - .staticInvoke("paramType") - .arg(parameter.dotclass()) - .arg( parameter.getTypeParameters().get(0).dotclass() ); - - pointerToAddressCall.arg(paramTypeCall); - } else { - pointerToAddressCall.arg(parameter.dotclass()); + JInvocation nativeCall; + if (staticModifier == 0) { + nativeCall = JExpr._this().invoke(nativeMethod); + } else { + nativeCall = enclosing.staticInvoke(nativeMethod); + } + if (parametersList != null) { + for (ParameterDescriptor paramDesc : parametersList) { + if (paramDesc.isInstance() && (foundIn.equals(enclosing)) ) { + //pass a pointer to this + nativeCall.arg( + nextContext + .getCm() + .ref(Pointer.class) + .staticInvoke("pointerTo") + .arg(JExpr._this()) + .arg(enclosing.dotclass()) + .invoke("getPeer") + ); + } else if (paramDesc.isVarargs()) { + JVar param = wrapper.varParam(Object.class, "varargs"); + nativeCall.arg(param); + } else if (paramDesc.getType().isPointer()) { + JVar param = wrapper.param(paramDesc.getType().getJType(), paramDesc.getName()); + nativeCall.arg(context.getCm().ref(Pointer.class).staticInvoke("getPeer").arg(param)); + } else { + JVar param = wrapper.param(paramDesc.getType().getJType(), paramDesc.getName()); + nativeCall.arg(param); + } } } - wrapper.body()._return(pointerToAddressCall); - } else if ( "void".equals(returnType.getCtype()) ) { - wrapper.body().add(nativeCall); - } else { - wrapper.body()._return(nativeCall); + if (returnsPointer) { + // Pointer.pointerToAddress(native(...), ReturnType.class) + ConvertedType returnConvType = returnType.forCType(nextContext, returnType.getCtype()); + JClass returnClass = (JClass)returnConvType.getJType(); + + JInvocation pointerToAddressCall = + context + .getCm() + .ref(Pointer.class) + .staticInvoke("pointerToAddress") + .arg(nativeCall); + + if (returnClass.isParameterized()) { + JClass parameter = returnClass.getTypeParameters().get(0); + if (parameter.isParameterized()) { + JInvocation paramTypeCall = context + .getCm() + .ref(DefaultParameterizedType.class) + .staticInvoke("paramType") + .arg(parameter.dotclass()) + .arg( parameter.getTypeParameters().get(0).dotclass() ); + + pointerToAddressCall.arg(paramTypeCall); + } else { + pointerToAddressCall.arg(parameter.dotclass()); + } + } + + wrapper.body()._return(pointerToAddressCall); + } else if ( "void".equals(returnType.getCtype()) ) { + wrapper.body().add(nativeCall); + } else { + wrapper.body()._return(nativeCall); + } } + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); } } @@ -1052,7 +1065,10 @@ private void parseVirtualMethod(Element root, ParsingContext context) { JDefinedClass enclosing = (JDefinedClass) context.getCmNode(); //Add an abstract method to the parent node + //For interfaces: //Parse signature like functions, but only make the wrapper, as abstract + //For normal classes: + //Same, plus a body that calls the function through the pointer field ParsingContext nextContext = context.copy(); parseElements(root.getChildElements(), nextContext); @@ -1069,9 +1085,7 @@ private void parseVirtualMethod(Element root, ParsingContext context) { return; } - //Explicitly declared public abstract because the enclosing class is not guaranteed to be an interface. - //It can also be an abstract class. - JMethod method = enclosing.method(JMod.PUBLIC | JMod.ABSTRACT, returnType.getJType(), name); + JMethod method = enclosing.method(JMod.PUBLIC, returnType.getJType(), name); if (parametersList != null) { for (ParameterDescriptor paramDesc : parametersList) { @@ -1085,6 +1099,20 @@ private void parseVirtualMethod(Element root, ParsingContext context) { } } + if (! (enclosing.isInterface()) ) { + JBlock body = method.body(); + JInvocation fptrGetterCall = body.invoke(enclosing.name().toLowerCase() + "_field_" + name); + JInvocation callbackCall = fptrGetterCall.invoke("apply"); + for (JVar param : method.params()) { + callbackCall.arg(param); + } + + if (!returnType.getType().equals("none")) { + //virtual function is not void, we need to return the result + body._return(callbackCall); + } + } + } @SuppressWarnings("unused") @@ -1153,21 +1181,50 @@ private void parseCallback(Element root, ParsingContext context) { //Abstract class //XXX: why neutralize, or why not together with the prefix? - String className = context.getCurrentPackage() + '.' + context.getExtra(Constants.CONTEXT_EXTRA_PREFIX) + NameUtils.neutralizeKeyword(name); - JDefinedClass callbackType; + JDefinedClass callbackType = null; + boolean local = false; + boolean ready = false; try { - callbackType = context.getCm()._class(JMod.PUBLIC | JMod.ABSTRACT, className, ClassType.CLASS); + if (context.getCmNode() instanceof JDefinedClass) { + JDefinedClass enclosing = (JDefinedClass) context.getCmNode(); + String className = context.getExtra(Constants.CONTEXT_EXTRA_FIELD_NAME) + "_callback"; + Iterator it = enclosing.classes(); + + //may already exist in the second pass + while (it.hasNext()) { + JDefinedClass nested = it.next(); + if (nested.name().equals(className)) { + callbackType = nested; + ready = true; + break; + } + } + + if (callbackType == null) { + callbackType = enclosing._class(JMod.PUBLIC | JMod.ABSTRACT, className, ClassType.CLASS); + } + + local = true; + } else { + String className = context.getCurrentPackage() + '.' + context.getExtra(Constants.CONTEXT_EXTRA_PREFIX) + NameUtils.neutralizeKeyword(name); + callbackType = context.getCm()._class(JMod.PUBLIC | JMod.ABSTRACT, className, ClassType.CLASS); + } } catch (JClassAlreadyExistsException e) { // TODO Auto-generated catch block e.printStackTrace(); return; } - callbackType._extends(context.getCm().ref(Callback.class).narrow(callbackType)); - //apply() method - JMethod applyMethod = callbackType.method(JMod.PUBLIC | JMod.ABSTRACT, returnType.getJType(), "apply"); - for (ParameterDescriptor param : parametersList) { - applyMethod.param(param.getType().getJType(), param.getName()); + if (!ready) { + callbackType._extends(context.getCm().ref(Callback.class).narrow(callbackType)); + + //apply() method + JMethod applyMethod = callbackType.method(JMod.PUBLIC | JMod.ABSTRACT, returnType.getJType(), "apply"); + if (parametersList != null) { + for (ParameterDescriptor param : parametersList) { + applyMethod.param(param.getType().getJType(), param.getName()); + } + } } ConvertedType convType = new ConvertedType( @@ -1178,6 +1235,11 @@ private void parseCallback(Element root, ParsingContext context) { false ); convType.setJType(context.getCm().ref(Pointer.class).narrow(callbackType)); - context.registerType(convType); + + if (local) { + context.putExtra(Constants.CONTEXT_EXTRA_LOCAL_CALLBACK, convType); + } else { + context.registerType(convType); + } } } From b9ddbdcee1cab1ade9c67776efd6848ec1d13e26 Mon Sep 17 00:00:00 2001 From: Roland Elek Date: Wed, 15 Oct 2014 10:56:38 +0200 Subject: [PATCH 7/7] Add debug options to javac build tasks Not sure when the default changed, or if it changed at all, but I recently noticed there were no line numbers in exception stack traces. This solves the problem. --- build.xml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/build.xml b/build.xml index 0199eb3..ee521aa 100644 --- a/build.xml +++ b/build.xml @@ -22,7 +22,8 @@ - + @@ -51,7 +52,8 @@ description="Compile the generated bindings sources" depends="generate-bindings-sources"> - + @@ -62,7 +64,8 @@ description="Compile the tests" depends="compile-bindings" > - +