diff --git a/annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/libcurl/Libcurl.java b/annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/libcurl/Libcurl.java index d4cc901..e7f16a0 100644 --- a/annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/libcurl/Libcurl.java +++ b/annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/libcurl/Libcurl.java @@ -11,35 +11,37 @@ import io.github.digitalsmile.annotation.structure.Enums; import io.github.digitalsmile.annotation.structure.Struct; import io.github.digitalsmile.annotation.structure.Structs; -import io.github.digitalsmile.gpio.libcurl.enums.CURLCode; -import io.github.digitalsmile.gpio.libcurl.enums.CURLOption; -import io.github.digitalsmile.gpio.libcurl.opaque.CurlInstance; +import io.github.digitalsmile.gpio.libcurl.enums.CURLcode; +import io.github.digitalsmile.gpio.libcurl.enums.CURLoption; +import io.github.digitalsmile.gpio.libcurl.opaque.CURL; @NativeMemory(headers = "libcurl/curl/include/curl/curl.h") @NativeMemoryOptions(systemIncludes = { - "/usr/lib/gcc/x86_64-linux-gnu/12/include/" -}, debugMode = true, processRootConstants = true) + //"/usr/lib/gcc/x86_64-linux-gnu/12/include/" + "/usr/lib/llvm-15/lib/clang/15.0.7/include/" +}, debugMode = true, processRootConstants = true, systemHeader = true) @Structs({ - @Struct(name = "CURL", javaName = "CurlInstance") + // @Struct(name = "CURL", javaName = "CurlInstance") }) @Enums({ - @Enum(name = "CURLcode", javaName = "CURLCode"), - @Enum(name = "CURLoption", javaName = "CURLOption") +// @Enum(name = "CURLcode", javaName = "CURLCode"), +// @Enum(name = "CURLoption", javaName = "CURLOption") }) +@NativeMemoryLibrary public interface Libcurl { @NativeManualFunction(name = "curl_easy_init", library = "/usr/lib/x86_64-linux-gnu/libcurl.so") - CurlInstance easyInit() throws NativeMemoryException; + CURL easyInit() throws NativeMemoryException; @NativeManualFunction(name = "curl_global_init", library = "/usr/lib/x86_64-linux-gnu/libcurl.so") - CURLCode globalInit(long flags) throws NativeMemoryException; + CURLcode globalInit(long flags) throws NativeMemoryException; @NativeManualFunction(name = "curl_easy_setopt", library = "/usr/lib/x86_64-linux-gnu/libcurl.so") - CURLCode easySetOpt(CurlInstance curl, CURLOption option, String value) throws NativeMemoryException; + CURLcode easySetOpt(CURL curl, CURLoption option, String value) throws NativeMemoryException; @NativeManualFunction(name = "curl_easy_setopt", library = "/usr/lib/x86_64-linux-gnu/libcurl.so") - CURLCode easySetOpt(CurlInstance curl, CURLOption option, @ByAddress long value) throws NativeMemoryException; + CURLcode easySetOpt(CURL curl, CURLoption option, @ByAddress long value) throws NativeMemoryException; @NativeManualFunction(name = "curl_easy_perform", library = "/usr/lib/x86_64-linux-gnu/libcurl.so") - CURLCode easyPerform(CurlInstance curl) throws NativeMemoryException; + CURLcode easyPerform(CURL curl) throws NativeMemoryException; } diff --git a/annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/libcurl/LibcurlTest.java b/annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/libcurl/LibcurlTest.java index e3cdb21..b6e35c8 100644 --- a/annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/libcurl/LibcurlTest.java +++ b/annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/libcurl/LibcurlTest.java @@ -1,27 +1,43 @@ package io.github.digitalsmile.gpio.libcurl; import io.github.digitalsmile.annotation.NativeMemoryException; -import io.github.digitalsmile.gpio.libcurl.enums.CURLCode; -import io.github.digitalsmile.gpio.libcurl.enums.CURLOption; +import io.github.digitalsmile.gpio.libcurl.enums.CURLcode; +import io.github.digitalsmile.gpio.libcurl.enums.CURLoption; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; public class LibcurlTest { +// @Test +// public void libcurl() throws NativeMemoryException { +// try (var libcurl = new LibcurlNative()) { +// var code = libcurl.globalInit(CurlConstants.CURL_GLOBAL_DEFAULT); +// assertEquals(code, CURLCode.CURLE_OK); +// var curl = libcurl.easyInit(); +// code = libcurl.easySetOpt(curl, CURLOption.CURLOPT_URL, "https://example.com"); +// assertEquals(code, CURLCode.CURLE_OK); +// code = libcurl.easySetOpt(curl, CURLOption.CURLOPT_FOLLOWLOCATION, 1L); +// assertEquals(code, CURLCode.CURLE_OK); +// +// code = libcurl.easyPerform(curl); +// assertEquals(code, CURLCode.CURLE_OK); +// } +// } + @Test public void libcurl() throws NativeMemoryException { try (var libcurl = new LibcurlNative()) { var code = libcurl.globalInit(CurlConstants.CURL_GLOBAL_DEFAULT); - assertEquals(code, CURLCode.CURLE_OK); + assertEquals(code, CURLcode.CURLE_OK); var curl = libcurl.easyInit(); - code = libcurl.easySetOpt(curl, CURLOption.CURLOPT_URL, "https://example.com"); - assertEquals(code, CURLCode.CURLE_OK); - code = libcurl.easySetOpt(curl, CURLOption.CURLOPT_FOLLOWLOCATION, 1L); - assertEquals(code, CURLCode.CURLE_OK); + code = libcurl.easySetOpt(curl, CURLoption.CURLOPT_URL, "https://example.com"); + assertEquals(code, CURLcode.CURLE_OK); + code = libcurl.easySetOpt(curl, CURLoption.CURLOPT_FOLLOWLOCATION, 1L); + assertEquals(code, CURLcode.CURLE_OK); code = libcurl.easyPerform(curl); - assertEquals(code, CURLCode.CURLE_OK); + assertEquals(code, CURLcode.CURLE_OK); } } } diff --git a/annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/shared/SharedTest.java b/annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/shared/SharedTest.java index 6cd3a39..37aefa5 100644 --- a/annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/shared/SharedTest.java +++ b/annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/shared/SharedTest.java @@ -1,7 +1,7 @@ package io.github.digitalsmile.gpio.shared; -import io.github.digitalsmile.gpio.shared.structs.Stat; +import io.github.digitalsmile.gpio.shared.system.Stat; import org.junit.jupiter.api.Test; import java.nio.file.Path; diff --git a/annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/shared/SharedTestTwo.java b/annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/shared/SharedTestTwo.java index 8dc512f..77be165 100644 --- a/annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/shared/SharedTestTwo.java +++ b/annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/shared/SharedTestTwo.java @@ -7,7 +7,7 @@ import io.github.digitalsmile.annotation.function.Returns; import io.github.digitalsmile.annotation.structure.Struct; import io.github.digitalsmile.annotation.structure.Structs; -import io.github.digitalsmile.gpio.shared.structs.Stat; +import io.github.digitalsmile.gpio.shared.system.Stat; @NativeMemory(headers = "/usr/include/x86_64-linux-gnu/sys/stat.h") @NativeMemoryOptions(systemHeader = true) diff --git a/annotation-processor/src/main/java/io/github/digitalsmile/NativeProcessor.java b/annotation-processor/src/main/java/io/github/digitalsmile/NativeProcessor.java index 153bdec..ec36f3b 100644 --- a/annotation-processor/src/main/java/io/github/digitalsmile/NativeProcessor.java +++ b/annotation-processor/src/main/java/io/github/digitalsmile/NativeProcessor.java @@ -106,7 +106,25 @@ public boolean process(Set annotations, RoundEnvironment } if (automaticFunctionElements != null) { - validator.validateAutomaticFunctions(parsed, automaticFunctionElements); + var functions = flatten(parsed).stream().filter(n -> n.getNodeType().isFunction()).toList(); + validator.validateAutomaticFunctions(functions, automaticFunctionElements); + + List autoFunctions = new ArrayList<>(); + for (NativeMemoryNode node : functions) { + List parameters = new ArrayList<>(); + for (NativeMemoryNode parameterNode : node.nodes()) { + parameters.add(new ParameterNode(parameterNode.getName(), parameterNode, false, false)); + } + + var type = ((FunctionOriginalType) node.getType()).returns(); + //processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, type.typeName() + " " + type.carrierClass()); + autoFunctions.add(new FunctionNode(node.getName(), null, + new NativeMemoryNode(type.typeName(), type, 0, Position.NO_POSITION), parameters, null)); + } + var autoFunctionComposer = new AutoFunctionComposer(processingEnv.getMessager()); + var name = rootElement.getSimpleName().toString(); + var output = autoFunctionComposer.compose(packageName, PrettyName.getObjectName(name), autoFunctions); + createGeneratedFile(packageName, PrettyName.getObjectName(name + "AutoFunctions"), output); } processFunctions(rootElement, manualFunctions, packageName, parsed, nativeOptions); @@ -214,7 +232,8 @@ private List processHeaderFiles(Element element, String[] head private void processOpaque(NativeMemoryNode node) { var opaqueComposer = new OpaqueComposer(processingEnv.getMessager()); var output = opaqueComposer.compose(PrettyName.getObjectName(node.getName()), node); - createGeneratedFile(PackageName.getPackageName(node.getName()), PrettyName.getObjectName(node.getName()), output); + var packageName = PackageName.getPackageName(node.getName()); + createGeneratedFile(packageName, PrettyName.getObjectName(node.getName()), output); } private void processStructs(NativeMemoryNode node) { @@ -223,7 +242,8 @@ private void processStructs(NativeMemoryNode node) { } var structComposer = new StructComposer(processingEnv.getMessager()); var output = structComposer.compose(PrettyName.getObjectName(node.getName()), node); - createGeneratedFile(PackageName.getPackageName(node.getName()), PrettyName.getObjectName(node.getName()), output); + var packageName = PackageName.getPackageName(node.getName()); + createGeneratedFile(packageName, PrettyName.getObjectName(node.getName()), output); } private void processEnums(NativeMemoryNode node, boolean rootConstants) { @@ -236,13 +256,15 @@ private void processEnums(NativeMemoryNode node, boolean rootConstants) { } var enumComposer = new EnumComposer(processingEnv.getMessager()); var output = enumComposer.compose(PrettyName.getObjectName(name), node); - createGeneratedFile(PackageName.getPackageName(name), PrettyName.getObjectName(name), output); + var packageName = PackageName.getPackageName(node.getName()); + createGeneratedFile(packageName, PrettyName.getObjectName(name), output); } private void processUnions(NativeMemoryNode node) { var structComposer = new StructComposer(processingEnv.getMessager(), true); var output = structComposer.compose(PrettyName.getObjectName(node.getName()), node); - createGeneratedFile(PackageName.getPackageName(node.getName()), PrettyName.getObjectName(node.getName()), output); + var packageName = PackageName.getPackageName(node.getName()); + createGeneratedFile(packageName, PrettyName.getObjectName(node.getName()), output); } private void processFunctions(Element rootElement, List functionElements, String packageName, List parsed, NativeMemoryOptions nativeOptions) { diff --git a/annotation-processor/src/main/java/io/github/digitalsmile/composers/AutoFunctionComposer.java b/annotation-processor/src/main/java/io/github/digitalsmile/composers/AutoFunctionComposer.java new file mode 100644 index 0000000..700fd3c --- /dev/null +++ b/annotation-processor/src/main/java/io/github/digitalsmile/composers/AutoFunctionComposer.java @@ -0,0 +1,135 @@ +package io.github.digitalsmile.composers; + +import com.squareup.javapoet.*; +import io.github.digitalsmile.PackageName; +import io.github.digitalsmile.PrettyName; +import io.github.digitalsmile.annotation.function.NativeCall; +import io.github.digitalsmile.functions.FunctionNode; +import io.github.digitalsmile.functions.ParameterNode; +import io.github.digitalsmile.headers.mapping.*; + +import javax.annotation.processing.Messager; +import javax.lang.model.element.Modifier; +import javax.tools.Diagnostic; +import java.lang.foreign.MemorySegment; +import java.util.List; +import java.util.Map; + +public class AutoFunctionComposer { + private final Messager messager; + + public AutoFunctionComposer(Messager messager) { + this.messager = messager; + } + + public String compose(String packageName, String originalName, List nodes) { + var classBuilder = TypeSpec.interfaceBuilder(originalName + "AutoFunctions") + //.addModifiers(Modifier.PUBLIC) + .addSuperinterface(ClassName.get(packageName, originalName)); + + for (FunctionNode node : nodes) { + var method = MethodSpec.methodBuilder(PrettyName.getVariableName(node.functionName())); + + var returnType = node.returnNode().getType(); + switch (returnType) { + case ArrayOriginalType arrayOriginalType -> { + method.returns(createType(arrayOriginalType)); +// if (arrayOriginalType.carrierClass().equals(String.class)) { +// method.returns(String.class); +// } else if (arrayOriginalType.carrierClass().equals(Object.class)) { +// method.returns(Object.class.arrayType()); +// } else { +// var typePackageName = PackageName.getPackageName(arrayOriginalType.typeName()); +// method.returns(ClassName.get(typePackageName, PrettyName.getObjectName(arrayOriginalType.typeName()))); +// } + } + case ObjectOriginalType objectOriginalType -> { + method.returns(createType(objectOriginalType)); + // messager.printMessage(Diagnostic.Kind.ERROR, objectOriginalType.typeName() + " " + objectOriginalType.carrierClass()); +// if (objectOriginalType.carrierClass().equals(void.class)) { +// method.returns(void.class); +// } else { +// var typePackageName = PackageName.getPackageName(objectOriginalType.typeName()); +// method.returns(ClassName.get(typePackageName, PrettyName.getObjectName(objectOriginalType.typeName()))); +// } + } + case PrimitiveOriginalType _ -> { + method.returns(returnType.carrierClass()); + } + default -> { + } + } + + + //messager.printMessage(Diagnostic.Kind.ERROR, "F: " + node.functionName()); + for (ParameterNode parameterNode : node.functionParameters()) { + //messager.printMessage(Diagnostic.Kind.ERROR, node.functionName() + " " + parameterNode.nativeMemoryNode().getName()); + var name = parameterNode.nativeMemoryNode().getName(); + if (name.isEmpty()) { + name = "arg" + node.functionParameters().indexOf(parameterNode); + } + var parameterType = parameterNode.nativeMemoryNode().getType(); + var parameterName = PrettyName.getVariableName(name); + switch (parameterType) { + case ArrayOriginalType arrayOriginalType -> { + method.addParameter(createType(arrayOriginalType), name); +// if (arrayOriginalType.isObjectType()) { +// if (arrayOriginalType.carrierClass().equals(String.class)) { +// method.addParameter(String.class, name); +// } else if (arrayOriginalType.carrierClass().equals(Object.class)) { +// method.addParameter(Object.class.arrayType(), name); +// } else { +// var typePackageName = PackageName.getPackageName(arrayOriginalType.typeName()); +// method.addParameter(ClassName.get(typePackageName, PrettyName.getObjectName(arrayOriginalType.typeName())), name); +// } +// } else { +// method.addParameter(arrayOriginalType.carrierClass().arrayType(), name); +// } + } + case ObjectOriginalType objectOriginalType -> { + method.addParameter(createType(objectOriginalType), name); +// if (objectOriginalType.carrierClass().equals(void.class)) { +// method.addParameter(MemorySegment.class, name); +// } else { +// var typePackageName = PackageName.getPackageName(objectOriginalType.typeName()); +// method.addParameter(ClassName.get(typePackageName, PrettyName.getObjectName(objectOriginalType.typeName())), parameterName); +// } + } + case PrimitiveOriginalType _ -> { + method.addParameter(parameterType.carrierClass(), parameterName); + } + default -> { + } + } + + } + + classBuilder.addMethod(method + .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT).build()); + } + + + var builder = JavaFile.builder(packageName, classBuilder.build()); + var outputFile = builder.indent("\t").skipJavaLangImports(true).build(); + return outputFile.toString(); + } + + + private TypeName createType(OriginalType type, boolean isArray) { + var typeName = type.typeName(); + var clazz = type.carrierClass(); + if (type.carrierClass().equals(Object.class)) { + var resolvedPackageName = PackageName.getPackageName(typeName); + if (typeName.equals(String.class.getSimpleName())) { + resolvedPackageName = ""; + } + return ClassName.get(resolvedPackageName, PrettyName.getObjectName(typeName) + (isArray ? "[]" : "")); + } else { + return TypeName.get(isArray ? clazz.arrayType() : clazz); + } + } + + private TypeName createType(OriginalType type) { + return createType(type, false); + } +} diff --git a/annotation-processor/src/main/java/io/github/digitalsmile/composers/StructComposer.java b/annotation-processor/src/main/java/io/github/digitalsmile/composers/StructComposer.java index 91cd225..d01ee25 100644 --- a/annotation-processor/src/main/java/io/github/digitalsmile/composers/StructComposer.java +++ b/annotation-processor/src/main/java/io/github/digitalsmile/composers/StructComposer.java @@ -6,6 +6,7 @@ import io.github.digitalsmile.annotation.types.interfaces.NativeMemoryLayout; import io.github.digitalsmile.headers.mapping.ArrayOriginalType; import io.github.digitalsmile.headers.mapping.ObjectOriginalType; +import io.github.digitalsmile.headers.mapping.OriginalType; import io.github.digitalsmile.headers.mapping.PrimitiveOriginalType; import io.github.digitalsmile.headers.model.NativeMemoryNode; import io.github.digitalsmile.headers.model.NodeType; @@ -76,7 +77,7 @@ var record = TypeSpec.recordBuilder(prettyName) .addModifiers(Modifier.PUBLIC) .addAnnotation(AnnotationSpec.builder(Override.class).build()) .addAnnotation(AnnotationSpec.builder(SuppressWarnings.class).addMember("value", "$S", "unchecked").build()) - .addParameter(TypeName.get(MemorySegment.class), "buffer") + .addParameter(TypeName.get(MemorySegment.class), "memoryBufferSegment") .addException(TypeName.get(Throwable.class)) .returns(ClassName.get(packageName, prettyName)) .addCode(CodeBlock.join(processFromBodyStatements(node.nodes(), node), "")) @@ -87,7 +88,7 @@ var record = TypeSpec.recordBuilder(prettyName) .addMethod(MethodSpec.methodBuilder("toBytes") .addModifiers(Modifier.PUBLIC) .addAnnotation(AnnotationSpec.builder(Override.class).build()) - .addParameter(TypeName.get(MemorySegment.class), "buffer") + .addParameter(TypeName.get(MemorySegment.class), "memoryBufferSegment") .addException(TypeName.get(Throwable.class)) .returns(TypeName.VOID) .addCode(CodeBlock.join(processToBodyStatements(node.nodes(), node), "")) @@ -106,16 +107,22 @@ var record = TypeSpec.recordBuilder(prettyName) return outputFile.toString(); } - private TypeName createType(String typeName, boolean isArray) { - var resolvedPackageName = PackageName.getPackageName(typeName); - if (typeName.equals(String.class.getSimpleName())) { - resolvedPackageName = ""; + private TypeName createType(OriginalType type, boolean isArray) { + var typeName = type.typeName(); + var clazz = type.carrierClass(); + if (type.carrierClass().equals(Object.class)) { + var resolvedPackageName = PackageName.getPackageName(typeName); + if (typeName.equals(String.class.getSimpleName())) { + resolvedPackageName = ""; + } + return ClassName.get(resolvedPackageName, PrettyName.getObjectName(typeName) + (isArray ? "[]" : "")); + } else { + return TypeName.get(isArray ? clazz.arrayType() : clazz); } - return ClassName.get(resolvedPackageName, PrettyName.getObjectName(typeName) + (isArray ? "[]" : "")); } - private TypeName createType(String typeName) { - return createType(typeName, false); + private TypeName createType(OriginalType type) { + return createType(type, false); } private List processConstructorParameters(List nodes) { @@ -126,7 +133,7 @@ private List processConstructorParameters(List node switch (type) { case ArrayOriginalType arrayType -> { if (arrayType.isObjectType()) { - fieldSpecs.add(FieldSpec.builder(createType(arrayType.typeName(), true), prettyName).build()); + fieldSpecs.add(FieldSpec.builder(createType(arrayType, true), prettyName).build()); } else { fieldSpecs.add(FieldSpec.builder(arrayType.carrierClass().arrayType(), prettyName).build()); } @@ -137,7 +144,7 @@ private List processConstructorParameters(List node if (node.getNodeType().isAnonymous()) { fieldSpecs.addAll(processConstructorParameters(node.nodes())); } else { - fieldSpecs.add(FieldSpec.builder(createType(objectType.typeName()), prettyName).build()); + fieldSpecs.add(FieldSpec.builder(createType(objectType), prettyName).build()); } } default -> messager.printMessage(Diagnostic.Kind.ERROR, "unsupported type " + type); @@ -193,7 +200,7 @@ private List processMemoryLayout(List nodes, Native if (objectType.carrierClass().equals(String.class) || node.getNodeType().equals(NodeType.POINTER)) { memoryLayouts.add(builder.add("$T.ADDRESS.withName($S)", ValueLayout.class, node.getName()).build()); } else { - memoryLayouts.add(builder.add("$T.LAYOUT.withName($S)", createType(objectType.typeName()), node.getName()).build()); + memoryLayouts.add(builder.add("$T.LAYOUT.withName($S)", createType(objectType), node.getName()).build()); } } } @@ -277,7 +284,7 @@ private List processEmptyConstructor(List nodes, Na } else if (objectType.typeName().equals(parentNode.getName())) { statements.add(builder.add("null").build()); } else { - statements.add(builder.add("$T.createEmpty()", createType(objectType.typeName())).build()); + statements.add(builder.add("$T.createEmpty()", createType(objectType)).build()); } } } @@ -298,7 +305,7 @@ private List processFromBodyStatements(List nodes, if (arrayType.isObjectType()) { var prettyObjectName = PrettyName.getObjectName(type.typeName()); statements.add(builder - .addStatement("var $LMemorySegment = invokeExact(MH_$L, buffer)", prettyName, node.getName().toUpperCase()) + .addStatement("var $LMemorySegment = invokeExact(MH_$L, memoryBufferSegment)", prettyName, node.getName().toUpperCase()) .addStatement("var $L = new $L[$L]", prettyName, prettyObjectName, arrayType.arraySize()) .beginControlFlow("for(int i = 0; i < $L; i++)", arrayType.arraySize()) .addStatement("var tmp = $L.createEmpty()", prettyObjectName) @@ -314,27 +321,28 @@ private List processFromBodyStatements(List nodes, if (node.getNodeType().isAnonymous()) { statements.add(builder .addStatement("var $LSize = LAYOUT.select($T.groupElement($S)).byteSize()", prettyName, MemoryLayout.PathElement.class, node.getName()) - .addStatement("var $LBuffer = buffer.asSlice(LAYOUT.byteSize() - $LSize, $LSize)", prettyName, prettyName, prettyName) + .addStatement("var $LBuffer = memoryBufferSegment.asSlice(LAYOUT.byteSize() - $LSize, $LSize)", prettyName, prettyName, prettyName) .build()); for (NativeMemoryNode innerNode : node.nodes()) { if (innerNode.getType() instanceof ObjectOriginalType) { var prettyInnerName = PrettyName.getVariableName(innerNode.getName()); + var typeName = createType(innerNode.getType()); statements.add(CodeBlock.builder() .addStatement("var $LMemorySegment = invokeExact(MH_$L, $LBuffer)", prettyInnerName, innerNode.getName().toUpperCase(), prettyName) - .addStatement("var $L = $L.createEmpty().fromBytes($LMemorySegment)", prettyInnerName, - PrettyName.getObjectName(innerNode.getType().typeName()), prettyInnerName) + .addStatement("var $L = $T.createEmpty().fromBytes($LMemorySegment)", prettyInnerName, + typeName, prettyInnerName) .build()); } } } else { if (objectType.carrierClass().equals(String.class)) { statements.add(builder - .addStatement("var $LMemorySegment = invokeExact(MH_$L, buffer)", prettyName, node.getName().toUpperCase()) + .addStatement("var $LMemorySegment = invokeExact(MH_$L, memoryBufferSegment)", prettyName, node.getName().toUpperCase()) .addStatement("var $L = $LMemorySegment.reinterpret(Integer.MAX_VALUE).getString(0)", prettyName, prettyName) .build()); } else { - builder.addStatement("var $LMemorySegment = invokeExact(MH_$L, buffer)", prettyName, node.getName().toUpperCase()); + builder.addStatement("var $LMemorySegment = invokeExact(MH_$L, memoryBufferSegment)", prettyName, node.getName().toUpperCase()); if (objectType.typeName().equals(parentNode.getName())) { builder.addStatement("$L $L = null", PrettyName.getObjectName(objectType.typeName()), prettyName); builder.beginControlFlow("if (!$LMemorySegment.get($T.ADDRESS, 0).equals($T.NULL))", prettyName, ValueLayout.class, MemorySegment.class); @@ -342,8 +350,9 @@ private List processFromBodyStatements(List nodes, .endControlFlow(); statements.add(builder.build()); } else { + var typeName = createType(objectType); statements.add(builder - .addStatement("var $L = $L.createEmpty().fromBytes($LMemorySegment)", prettyName, PrettyName.getObjectName(objectType.typeName()), prettyName) + .addStatement("var $L = $T.createEmpty().fromBytes($LMemorySegment)", prettyName, typeName, prettyName) .build()); } } @@ -361,7 +370,7 @@ private List processFromReturnStatements(List nodes var type = node.getType(); var bufferName = parentNode.getNodeType().isAnonymous() ? CodeBlock.builder().add("$LBuffer", PrettyName.getVariableName(parentNode.getName())).build() : - CodeBlock.builder().add("buffer").build(); + CodeBlock.builder().add("memoryBufferSegment").build(); var builder = CodeBlock.builder(); var prettyName = PrettyName.getVariableName(node.getName()); switch (type) { @@ -403,7 +412,7 @@ private List processToBodyStatements(List nodes, Na if (parentNodeType.isAnonymous()) { builder.add(CodeBlock.builder().beginControlFlow("if ($L.length > 0)", prettyVariableName).build()); } - builder.addStatement("var $LTmp = invokeExact(MH_$L, buffer)", prettyVariableName, node.getName().toUpperCase()) + builder.addStatement("var $LTmp = invokeExact(MH_$L, memoryBufferSegment)", prettyVariableName, node.getName().toUpperCase()) .beginControlFlow("for (int i = 0; i < $L.length; i++)", prettyVariableName) .addStatement("$L[i].toBytes($LTmp.asSlice($L.LAYOUT.byteSize() * i, $L.LAYOUT.byteSize()))", prettyVariableName, prettyVariableName, PrettyName.getObjectName(arrayType.typeName()), PrettyName.getObjectName(arrayType.typeName())) @@ -417,7 +426,7 @@ private List processToBodyStatements(List nodes, Na if (parentNodeType.isAnonymous()) { builder.add(CodeBlock.builder().beginControlFlow("if ($L$L)", prettyVariableName, arrayType.isNotArrayEmpty()).build()); } - builder.addStatement("var $LTmp = invokeExact(MH_$L, buffer)", prettyVariableName, node.getName().toUpperCase()) + builder.addStatement("var $LTmp = invokeExact(MH_$L, memoryBufferSegment)", prettyVariableName, node.getName().toUpperCase()) .beginControlFlow("for (int i = 0; i < $L.length; i++)", prettyVariableName) .addStatement("$LTmp.setAtIndex($T.$L, i, $L[i])", prettyVariableName, ValueLayout.class, arrayType.valueLayoutName(), prettyVariableName) @@ -435,7 +444,7 @@ private List processToBodyStatements(List nodes, Na } var bufferName = node.getNodeType().isAnonymous() ? CodeBlock.builder().add("$LBuffer", PrettyName.getVariableName(node.getName())).build() : - CodeBlock.builder().add("buffer").build(); + CodeBlock.builder().add("memoryBufferSegment").build(); builder.addStatement("VH_$L.set($L, 0L, $L)", node.getName().toUpperCase(), bufferName, prettyVariableName); if (parentNodeType.isAnonymous()) { builder.add(CodeBlock.builder().endControlFlow().build()); @@ -450,17 +459,17 @@ private List processToBodyStatements(List nodes, Na if (parentNodeType.isAnonymous()) { var builder = CodeBlock.builder(); builder.add(CodeBlock.builder().beginControlFlow("if (!$L.isEmpty())", prettyVariableName).build()); - builder.addStatement("var $LTmp = invokeExact(MH_$L, buffer)", prettyVariableName, node.getName().toUpperCase()) + builder.addStatement("var $LTmp = invokeExact(MH_$L, memoryBufferSegment)", prettyVariableName, node.getName().toUpperCase()) .addStatement("$L.toBytes($LTmp)", prettyVariableName, prettyVariableName); builder.add(CodeBlock.builder().endControlFlow().build()); statements.add(builder.build()); } else { var builder = CodeBlock.builder(); if (objectType.carrierClass().equals(String.class)) { - builder.addStatement("var $LTmp = invokeExact(MH_$L, buffer)", prettyVariableName, node.getName().toUpperCase()) + builder.addStatement("var $LTmp = invokeExact(MH_$L, memoryBufferSegment)", prettyVariableName, node.getName().toUpperCase()) .addStatement("$LTmp.setString(0, $L)", prettyVariableName, prettyVariableName); } else { - builder.addStatement("var $LTmp = invokeExact(MH_$L, buffer)", prettyVariableName, node.getName().toUpperCase()); + builder.addStatement("var $LTmp = invokeExact(MH_$L, memoryBufferSegment)", prettyVariableName, node.getName().toUpperCase()); if (type.typeName().equals(parentNode.getName())) { builder.beginControlFlow("if ($L != null)", prettyVariableName); builder.addStatement("$L.toBytes($LTmp.reinterpret(LAYOUT.byteSize()))", prettyVariableName, prettyVariableName); diff --git a/annotation-processor/src/main/java/io/github/digitalsmile/headers/DeclarationParser.java b/annotation-processor/src/main/java/io/github/digitalsmile/headers/DeclarationParser.java index 9ab7d17..f4f744a 100644 --- a/annotation-processor/src/main/java/io/github/digitalsmile/headers/DeclarationParser.java +++ b/annotation-processor/src/main/java/io/github/digitalsmile/headers/DeclarationParser.java @@ -9,6 +9,7 @@ import javax.annotation.processing.Messager; import javax.tools.Diagnostic; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -40,6 +41,10 @@ public DeclarationParser(Messager messager, List structs, List e this.enums = enums != null ? enums : Collections.emptyList(); } + private static final List builtinOpaques = List.of( + "FILE", "va_list", "__va_list_tag" + ); + private boolean notInScope(Declaration declaration) { return declaration.pos().isSystemHeader(); } @@ -71,26 +76,28 @@ private boolean skipParsing(String declarationName, Declaration.Scoped.Kind kind }; } - private String parseScoped(Declaration.Scoped declarationScoped, NodeType nodeType, String namePrefix) { + private String parseScoped(Declaration.Scoped declarationScoped, NodeType nodeType, String namePrefix, boolean isSystem) { var name = declarationScoped.name(); switch (declarationScoped.kind()) { case STRUCT -> { if (nodeType.isAnonymous()) { name = namePrefix + "_struct_" + structCount++; } - PackageName.addPackage(name, nodeType.equals(NodeType.OPAQUE) ? "opaque" : "structs"); + PackageName.addPackage(name, isSystem ? "system" + : (nodeType.equals(NodeType.OPAQUE) ? "opaque" : "structs") + ); } case ENUM -> { if (nodeType.isAnonymous()) { name = namePrefix + "_enum_" + enumCount++; } - PackageName.addPackage(name, "enums"); + PackageName.addPackage(name, isSystem ? "system" : "enums"); } case UNION -> { if (nodeType.isAnonymous()) { name = namePrefix + "_union_" + unionCount++; } - PackageName.addPackage(name, "unions"); + PackageName.addPackage(name, isSystem ? "system" : "unions"); } case BITFIELDS -> { messager.printMessage(Diagnostic.Kind.WARNING, "unsupported scoped kind " + declarationScoped.kind() + " " + declarationScoped.pos()); @@ -108,10 +115,16 @@ public void parseDeclaration(Declaration declaration, NativeMemoryNode parentNod } var nodeType = getNodeType(declarationScoped, declarationScoped.attributes()); var namePrefix = isTopLevel ? parentNode.getName() : "internal"; - var name = parseScoped(declarationScoped, nodeType, namePrefix); - var node = new NativeMemoryNode(name, nodeType, OriginalType.ofObject(name), parentNode.getLevel() + 1, declarationScoped.pos()); - parseRoot(declarationScoped, node); - parentNode.addNode(node); + var name = parseScoped(declarationScoped, nodeType, namePrefix, declaration.pos().isSystemHeader()); + if (builtinOpaques.contains(name)) { + nodeType = NodeType.OPAQUE; + var node = new NativeMemoryNode(name, nodeType, OriginalType.ofObject(name), parentNode.getLevel() + 1, declarationScoped.pos()); + parentNode.addNode(node); + } else { + var node = new NativeMemoryNode(name, nodeType, OriginalType.ofObject(name), parentNode.getLevel() + 1, declarationScoped.pos()); + parseRoot(declarationScoped, node); + parentNode.addNode(node); + } } case Declaration.Constant declarationConstant -> { var node = parseVariable(declarationConstant, declarationConstant.type(), parentNode.getLevel()); @@ -135,9 +148,9 @@ public void parseDeclaration(Declaration declaration, NativeMemoryNode parentNod messager.printMessage(Diagnostic.Kind.WARNING, "unsupported declaration type " + declarationBitfield.type()); case Declaration.Variable declarationVariable -> { switch (declarationVariable.kind()) { - case GLOBAL, BITFIELD, PARAMETER -> + case BITFIELD, PARAMETER -> messager.printMessage(Diagnostic.Kind.WARNING, "unsupported declaration kind " + declarationVariable.kind() + " " + declarationVariable.pos()); - case FIELD -> { + case GLOBAL, FIELD -> { var node = parseVariable(declarationVariable, declarationVariable.type(), parentNode.getLevel()); if (node != null) { parentNode.addNode(node); @@ -151,7 +164,20 @@ public void parseDeclaration(Declaration declaration, NativeMemoryNode parentNod parentNode.addNode(node); } } - case Declaration.Function _ -> { + case Declaration.Function declarationFunction -> { + List nodes = new ArrayList<>(); + var nextLevel = parentNode.getLevel() + 1; + for (Declaration.Variable declarationVariable : declarationFunction.parameters()) { + var parsedNode = parseVariable(declarationVariable, declarationVariable.type(), nextLevel); + if (parsedNode == null) { + return; + } + nodes.add(parsedNode); + } + var type = declarationFunction.type().withParameterNames(nodes.stream().map(NativeMemoryNode::getName).toList()); + var node = new NativeMemoryNode(declarationFunction.name(), NodeType.FUNCTION, OriginalType.of(type), nextLevel, declarationFunction.pos()); + node.addNodes(nodes); + parentNode.addNode(node); } default -> messager.printMessage(Diagnostic.Kind.WARNING, "unsupported declaration type " + declaration.name() + " " + declaration.pos()); @@ -173,14 +199,20 @@ private NativeMemoryNode parseVariable(Declaration declaration, Type type, int l printWarning(declaration, "type " + type + " is not valid C/C++ constructions and will be skipped."); return null; } - return new NativeMemoryNode(declaration.name(), OriginalType.of(typeArray), nextLevel, source); + var originalType = OriginalType.of(typeArray); + if (builtinOpaques.contains(originalType.typeName())) { + PackageName.addPackage(originalType.typeName(), "system"); + return new NativeMemoryNode(originalType.typeName(), NodeType.OPAQUE, OriginalType.of(typeArray), nextLevel, source); + } else { + return new NativeMemoryNode(declaration.name(), originalType, nextLevel, source); + } } case Type.Primitive typePrimitive -> { if (declaration instanceof Declaration.Constant declarationConstant) { return new NativeMemoryNode(declaration.name(), OriginalType.of(typePrimitive), nextLevel, source, declarationConstant.value()); } else { if (typePrimitive.kind().equals(Type.Primitive.Kind.Void)) { - PackageName.addPackage(declaration.name(), "opaque"); + PackageName.addPackage(declaration.name(), declaration.pos().isSystemHeader() ? "system" : "opaque"); return new NativeMemoryNode(declaration.name(), NodeType.OPAQUE, OriginalType.ofObject(declaration.name()), nextLevel, source); } else { return new NativeMemoryNode(declaration.name(), OriginalType.of(typePrimitive), nextLevel, source); @@ -197,10 +229,7 @@ private NativeMemoryNode parseVariable(Declaration declaration, Type type, int l } } case POINTER, TYPEDEF -> { - var originalType = OriginalType.of(typeDelegated.type()); - if (originalType.carrierClass().equals(byte.class)) { - originalType = OriginalType.ofObject(String.class.getSimpleName()); - } + var originalType = OriginalType.of(typeDelegated); if (declaration instanceof Declaration.Constant declarationConstant) { return new NativeMemoryNode(declaration.name(), originalType, nextLevel, source, declarationConstant.value()); } else { @@ -220,10 +249,16 @@ private NativeMemoryNode parseVariable(Declaration declaration, Type type, int l if (nodeType.isAnonymous()) { parseRoot(typeDeclared.tree(), node); return node; - } else if (notInScope(typeDeclared.tree())) { + } else if (notInScope(typeDeclared.tree()) && !builtinOpaques.contains(declaration.name())) { parseDeclarations(typeDeclared.tree(), node, false); return node; - } else if (level > 1) { + } else if (nextLevel > 1) { + return node; + } else if (builtinOpaques.contains(declaration.name())) { + PackageName.addPackage(declaration.name(), "system"); + return new NativeMemoryNode(declaration.name(), NodeType.OPAQUE, OriginalType.ofObject(typeName), nextLevel, source); + } else if (nodeType.isOpaque()) { + PackageName.addPackage(declaration.name(), "opaque"); return node; } else { return null; diff --git a/annotation-processor/src/main/java/io/github/digitalsmile/headers/Parser.java b/annotation-processor/src/main/java/io/github/digitalsmile/headers/Parser.java index 013cc0a..830087d 100644 --- a/annotation-processor/src/main/java/io/github/digitalsmile/headers/Parser.java +++ b/annotation-processor/src/main/java/io/github/digitalsmile/headers/Parser.java @@ -16,8 +16,10 @@ import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.stream.Stream; public class Parser { @@ -46,7 +48,13 @@ public List parse(List structs, List enums, } var newRoot = new NativeMemoryNode(rootName, NodeType.ROOT); - prepareStructure(newRoot, root); + List systemHeaders = Collections.emptyList(); + if (systemHeader) { + systemHeaders = flatten(root.nodes()).stream().filter(p -> p.getPosition().isSystemHeader()).toList(); + clearFromSystemHeaders(root, systemHeaders); + } + prepareStructure(newRoot, root, systemHeaders, systemHeader); + newRoot.addNodes(root.nodes()); if (debug) { @@ -58,25 +66,55 @@ public List parse(List structs, List enums, return nodes; } - private void prepareStructure(NativeMemoryNode rootNode, NativeMemoryNode parentNode) { + private List flatten(List nodes) { + return nodes.stream().flatMap(i -> Stream.concat(Stream.of(i), flatten(i.nodes()).stream())).toList(); + } + + private void clearFromSystemHeaders(NativeMemoryNode parentNode, List systemHeaderNodes) { var iterator = parentNode.nodes().listIterator(); while (iterator.hasNext()) { var node = iterator.next(); - var nodeType = node.getNodeType(); - var type = node.getType(); - var contains = rootNode.nodes().stream().anyMatch(p -> p.getName().equals(type.typeName())); - if (node.getLevel() > 1 && !nodeType.isVariable() && !nodeType.equals(NodeType.ANON_UNION) && !node.nodes().isEmpty() && !contains) { - var newNodeType = makeNotAnonymous(nodeType); - var newNode = new NativeMemoryNode(node.getName(), newNodeType, node.getType(), 1, node.getPosition(), node.getValue()); - iterator.set(newNode); - var typeName = type.typeName(); - PackageName.addPackage(typeName, "nested"); - var rebuildNode = new NativeMemoryNode(typeName, newNodeType, node.getType(), node.getLevel(), node.getPosition(), node.getValue()); - rebuildNode.addNodes(node.nodes()); - rootNode.addNode(rebuildNode); + if (systemHeaderNodes.stream().anyMatch(p -> p.getPosition().equals(node.getPosition()))) { + iterator.remove(); + continue; + } + clearFromSystemHeaders(node, systemHeaderNodes); + } + } + + private void prepareStructure(NativeMemoryNode rootNode, NativeMemoryNode parentNode, List systemHeaderNodes, boolean systemHeader) { + var iterator = parentNode.nodes().listIterator(); + + while (iterator.hasNext()) { + var node = iterator.next(); + if (node.getLevel() == 0) { + prepareStructure(rootNode, node, systemHeaderNodes, systemHeader); + } else { + var nodeType = node.getNodeType(); + var type = node.getType(); + + if (systemHeader) { + var foundReference = systemHeaderNodes.stream().filter(p -> p.getName().equals(type.typeName())).findFirst().orElse(null); + if (foundReference != null && !rootNode.nodes().contains(foundReference)) { + rootNode.addNode(foundReference); + prepareStructure(rootNode, foundReference, systemHeaderNodes, systemHeader); + } + } + + var contains = rootNode.nodes().stream().anyMatch(p -> p.getName().equals(type.typeName())); + if (node.getLevel() > 1 && !nodeType.isVariable() && !nodeType.equals(NodeType.ANON_UNION) && !node.nodes().isEmpty() && !contains) { + var newNodeType = makeNotAnonymous(nodeType); + var newNode = new NativeMemoryNode(node.getName(), newNodeType, node.getType(), 1, node.getPosition(), node.getValue()); + iterator.set(newNode); + var typeName = type.typeName(); + PackageName.addPackage(typeName, "nested"); + var rebuildNode = new NativeMemoryNode(typeName, newNodeType, node.getType(), node.getLevel(), node.getPosition(), node.getValue()); + rebuildNode.addNodes(node.nodes()); + rootNode.addNode(rebuildNode); + } + prepareStructure(rootNode, node, systemHeaderNodes, systemHeader); } - prepareStructure(rootNode, node); } } diff --git a/annotation-processor/src/main/java/io/github/digitalsmile/headers/mapping/FunctionOriginalType.java b/annotation-processor/src/main/java/io/github/digitalsmile/headers/mapping/FunctionOriginalType.java index 28123e4..42aa0c6 100644 --- a/annotation-processor/src/main/java/io/github/digitalsmile/headers/mapping/FunctionOriginalType.java +++ b/annotation-processor/src/main/java/io/github/digitalsmile/headers/mapping/FunctionOriginalType.java @@ -1,26 +1,27 @@ package io.github.digitalsmile.headers.mapping; import java.lang.foreign.ValueLayout; +import java.util.List; -public record FunctionOriginalType() implements OriginalType { +public record FunctionOriginalType(OriginalType returns, List parameterTypes, List parameterNames) implements OriginalType { @Override public String typeName() { - return "Unsupported"; + return returns.typeName(); } @Override public Class carrierClass() { - return void.class; + return returns.carrierClass(); } @Override public ValueLayout valueLayout() { - return ValueLayout.ADDRESS; + return returns.valueLayout(); } @Override public String toString() { - return "function type (unsupported)"; + return "(" + parameterTypes + ") (" + parameterNames + ") (returns: " + returns.typeName() + ")"; } } diff --git a/annotation-processor/src/main/java/io/github/digitalsmile/headers/mapping/ObjectOriginalType.java b/annotation-processor/src/main/java/io/github/digitalsmile/headers/mapping/ObjectOriginalType.java index c3b82d4..9556e91 100644 --- a/annotation-processor/src/main/java/io/github/digitalsmile/headers/mapping/ObjectOriginalType.java +++ b/annotation-processor/src/main/java/io/github/digitalsmile/headers/mapping/ObjectOriginalType.java @@ -1,5 +1,7 @@ package io.github.digitalsmile.headers.mapping; +import io.github.digitalsmile.annotation.types.RawPointer; + import java.lang.foreign.ValueLayout; public record ObjectOriginalType(String typeName, long alignment) implements OriginalType { diff --git a/annotation-processor/src/main/java/io/github/digitalsmile/headers/mapping/OriginalType.java b/annotation-processor/src/main/java/io/github/digitalsmile/headers/mapping/OriginalType.java index 2b74021..1a2056b 100644 --- a/annotation-processor/src/main/java/io/github/digitalsmile/headers/mapping/OriginalType.java +++ b/annotation-processor/src/main/java/io/github/digitalsmile/headers/mapping/OriginalType.java @@ -1,6 +1,7 @@ package io.github.digitalsmile.headers.mapping; import com.squareup.javapoet.CodeBlock; +import io.github.digitalsmile.annotation.types.RawPointer; import org.openjdk.jextract.Type; import javax.lang.model.type.ArrayType; @@ -8,6 +9,7 @@ import javax.lang.model.type.TypeMirror; import java.lang.foreign.AddressLayout; import java.lang.foreign.ValueLayout; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -62,8 +64,8 @@ default CodeBlock valueLayoutName() { List.of(Short), ValueLayout.JAVA_SHORT, List.of(Float), ValueLayout.JAVA_FLOAT, List.of(Double, LongDouble), ValueLayout.JAVA_DOUBLE, - List.of(Bool), ValueLayout.JAVA_BOOLEAN, - List.of(Void), ValueLayout.ADDRESS + List.of(Bool), ValueLayout.JAVA_BOOLEAN + //List.of(Void), ValueLayout.ADDRESS ); @@ -125,13 +127,36 @@ static OriginalType of(Type type) { return ofObject(typeDeclared.tree().name()); } case Type.Delegated typeDelegated -> { - return of(typeDelegated.type()); + if (typeDelegated.kind().equals(Type.Delegated.Kind.TYPEDEF)) { + var name = typeDelegated.name().orElse(""); + if (typeDelegated.type() instanceof Type.Declared) { + return ofObject(name); + } else if (typeDelegated.type() instanceof Type.Primitive typePrimitive && typePrimitive.kind().equals(Void)) { + return ofObject(name); + } else { + return of(typeDelegated.type()); + } + } else if (typeDelegated.kind().equals(Type.Delegated.Kind.POINTER) && typeDelegated.type() instanceof Type.Primitive primitiveType && primitiveType.kind().equals(Char)) { + return ofObject(String.class.getCanonicalName()); + } else if (typeDelegated.kind().equals(Type.Delegated.Kind.POINTER) && typeDelegated.type() instanceof Type.Primitive primitiveType && primitiveType.kind().equals(Void)) { + return ofObject(RawPointer.class.getCanonicalName()); + } else { + return of(typeDelegated.type()); + } } case Type.Primitive typePrimitive -> { - return new PrimitiveOriginalType(typePrimitive.kind().typeName(), find(typePrimitive.kind())); - } - case Type.Function _ -> { - return new FunctionOriginalType(); + if (typePrimitive.kind().equals(Type.Primitive.Kind.Void)) { + return ofObject(typePrimitive.kind().typeName()); + } else { + return new PrimitiveOriginalType(typePrimitive.kind().typeName(), find(typePrimitive.kind())); + } + } + case Type.Function typeFunction -> { + return new FunctionOriginalType( + of(typeFunction.returnType()), + typeFunction.argumentTypes().stream().map(OriginalType::of).toList(), + typeFunction.parameterNames().orElse(Collections.emptyList()) + ); } default -> { throw new IllegalArgumentException("Type " + type + " is not supported"); diff --git a/annotation-processor/src/main/java/io/github/digitalsmile/headers/model/NativeMemoryNode.java b/annotation-processor/src/main/java/io/github/digitalsmile/headers/model/NativeMemoryNode.java index 18989b3..551b7bf 100644 --- a/annotation-processor/src/main/java/io/github/digitalsmile/headers/model/NativeMemoryNode.java +++ b/annotation-processor/src/main/java/io/github/digitalsmile/headers/model/NativeMemoryNode.java @@ -87,8 +87,10 @@ public String toString() { public String getText() { var builder = new StringBuilder(); builder.append(name); - if (!nodeType.equals(NodeType.VARIABLE) && !nodeType.equals(NodeType.ROOT) && level <= 1) { - builder.append(" ").append(nodeType).append(" from ").append(position.path()); + if (nodeType.isFunction()) { + builder.append(" ").append(nodeType).append(": ").append(type).append(" ").append(position); + } else if (!nodeType.equals(NodeType.VARIABLE) && !nodeType.equals(NodeType.ROOT) && level <= 1) { + builder.append(" ").append(nodeType).append(" from ").append(position); } else if (!nodeType.equals(NodeType.ROOT)) { builder.append(" "); if (!nodeType.equals(NodeType.VARIABLE)) { diff --git a/annotation-processor/src/main/java/io/github/digitalsmile/headers/model/NodeType.java b/annotation-processor/src/main/java/io/github/digitalsmile/headers/model/NodeType.java index 4978eaa..d68da4a 100644 --- a/annotation-processor/src/main/java/io/github/digitalsmile/headers/model/NodeType.java +++ b/annotation-processor/src/main/java/io/github/digitalsmile/headers/model/NodeType.java @@ -4,7 +4,8 @@ public enum NodeType { ROOT, OPAQUE, STRUCT, ENUM, UNION, ANON_STRUCT, ANON_ENUM, ANON_UNION, POINTER, - VARIABLE; + VARIABLE, + FUNCTION; public boolean isAnonymous() { return this.equals(ANON_STRUCT) || this.equals(ANON_ENUM) || this.equals(ANON_UNION); @@ -25,4 +26,8 @@ public boolean isOpaque() { public boolean isEnum() { return this.equals(ENUM); } + + public boolean isFunction() { + return this.equals(FUNCTION); + } } diff --git a/annotation-processor/src/main/java/org/openjdk/jextract/JextractTool.java b/annotation-processor/src/main/java/org/openjdk/jextract/JextractTool.java index 9c8ea1f..2332231 100644 --- a/annotation-processor/src/main/java/org/openjdk/jextract/JextractTool.java +++ b/annotation-processor/src/main/java/org/openjdk/jextract/JextractTool.java @@ -44,6 +44,9 @@ public final class JextractTool { * @return a toplevel declaration. */ public static Declaration.Scoped parse(Path header, List options) { - return new Parser().parse(header, options); + var l = new ArrayList<>(options); + //l.add("--target=arm-none-eabi-gcc"); + //l.add("-std=c++17"); + return new Parser().parse(header, l); } } diff --git a/annotation-processor/src/main/java/org/openjdk/jextract/clang/Cursor.java b/annotation-processor/src/main/java/org/openjdk/jextract/clang/Cursor.java index cb9d6dc..a4e6811 100644 --- a/annotation-processor/src/main/java/org/openjdk/jextract/clang/Cursor.java +++ b/annotation-processor/src/main/java/org/openjdk/jextract/clang/Cursor.java @@ -122,6 +122,11 @@ public Type type() { return new Type(cursorType, owner); } + public Type typeOfTypeDef() { + var t = Index_h.clang_getTypedefDeclUnderlyingType(owner, segment); + return new Type(t, owner); + } + public Type getEnumDeclIntegerType() { var enumType = Index_h.clang_getEnumDeclIntegerType(owner, segment); return new Type(enumType, owner); diff --git a/annotation-processor/src/main/java/org/openjdk/jextract/impl/TreeMaker.java b/annotation-processor/src/main/java/org/openjdk/jextract/impl/TreeMaker.java index 027e063..bcbb075 100644 --- a/annotation-processor/src/main/java/org/openjdk/jextract/impl/TreeMaker.java +++ b/annotation-processor/src/main/java/org/openjdk/jextract/impl/TreeMaker.java @@ -105,7 +105,7 @@ public Declaration createTree(Cursor c) { private Declaration createTreeInternal(Cursor c) { Position pos = CursorPosition.of(c); - if (pos == Position.NO_POSITION) return null; // intrinsic, skip + if (c.isInvalid() && pos == Position.NO_POSITION) return null; // intrinsic, skip // dedup multiple declarations that point to the same source location Cursor.Key key = c.toKey(); Optional cachedDecl = lookup(key); @@ -482,7 +482,11 @@ private void collectNestedTypes(Cursor c, List nestedTypes, boolean } Type toType(Cursor c) { - return TypeMaker.makeType(c.type(), this); + if (c.kind().equals(CursorKind.TypedefDecl)) { + return TypeMaker.makeType(c.typeOfTypeDef(), this); + } else { + return TypeMaker.makeType(c.type(), this); + } } private void checkCursor(Cursor c, CursorKind k) { diff --git a/annotation/src/main/java/io/github/digitalsmile/annotation/types/RawPointer.java b/annotation/src/main/java/io/github/digitalsmile/annotation/types/RawPointer.java new file mode 100644 index 0000000..6fcb36b --- /dev/null +++ b/annotation/src/main/java/io/github/digitalsmile/annotation/types/RawPointer.java @@ -0,0 +1,40 @@ +package io.github.digitalsmile.annotation.types; + +import io.github.digitalsmile.annotation.types.interfaces.OpaqueMemoryLayout; + +import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.ValueLayout; + +public record RawPointer(MemorySegment memorySegment) implements OpaqueMemoryLayout { + public static final MemoryLayout LAYOUT = ValueLayout.ADDRESS; + + public static RawPointer create(MemorySegment memorySegment) { + return new RawPointer(memorySegment); + } + + public static RawPointer createEmpty() { + return new RawPointer(MemorySegment.NULL); + } + + @Override + public MemoryLayout getMemoryLayout() { + return LAYOUT; + } + + @Override + @SuppressWarnings("unchecked") + public RawPointer fromBytes(MemorySegment buffer) throws Throwable { + return new RawPointer(buffer); + } + + @Override + public void toBytes(MemorySegment buffer) throws Throwable { + memorySegment().copyFrom(buffer); + } + + @Override + public boolean isEmpty() { + return memorySegment.equals(MemorySegment.NULL); + } +}