Skip to content

Commit e9f524d

Browse files
committed
New parsing flow #7
Type refactoring #7 Add comments from native source #13 Add support of opaque types Add support of moving nested types to top level Add system include in options Add debug mode
1 parent b5de697 commit e9f524d

File tree

26 files changed

+945
-394
lines changed

26 files changed

+945
-394
lines changed

annotation-processor-test/src/test/java/io/github/digitalsmile/gpio/GPIOTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.github.digitalsmile.gpio;
22

33
import io.github.digitalsmile.gpio.types.all.*;
4+
import io.github.digitalsmile.gpio.types.all.structs.*;
5+
import io.github.digitalsmile.gpio.types.all.enums.*;
46
import org.junit.jupiter.api.Test;
57

68
import java.lang.foreign.Arena;
@@ -29,7 +31,7 @@ public void testGPIOV1AllTypes() {
2931

3032
assertEquals(GpioConstants.class.getFields().length, 40);
3133

32-
assertEquals(GpioEnum0.values().length, 3);
34+
//assertEquals(GpioConstants.values().length, 3);
3335

3436
var eventData = new GpioeventData(100, 5);
3537
memoryBuffer = arena.allocate(eventData.getMemoryLayout());
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package io.github.digitalsmile.gpio.libcurl;
2+
3+
import io.github.digitalsmile.annotation.NativeMemory;
4+
import io.github.digitalsmile.annotation.NativeMemoryOptions;
5+
import io.github.digitalsmile.annotation.structure.Enums;
6+
import io.github.digitalsmile.annotation.structure.Structs;
7+
import io.github.digitalsmile.annotation.structure.Unions;
8+
9+
@NativeMemory(headers = "/home/ds/curl/include/curl/curl.h")
10+
@NativeMemoryOptions(systemIncludes = {
11+
"/usr/lib/llvm-15/lib/clang/15.0.7/include/"
12+
})
13+
@Structs
14+
@Enums
15+
@Unions
16+
public interface Libcurl {
17+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.github.digitalsmile.gpio.libvlc;
2+
3+
import io.github.digitalsmile.annotation.NativeMemory;
4+
import io.github.digitalsmile.annotation.NativeMemoryOptions;
5+
import io.github.digitalsmile.annotation.structure.Enums;
6+
import io.github.digitalsmile.annotation.structure.Structs;
7+
import io.github.digitalsmile.annotation.structure.Unions;
8+
9+
@NativeMemory(headers = {
10+
"/home/ds/vlc/include/vlc/vlc.h",
11+
12+
})
13+
@NativeMemoryOptions(includes = {
14+
"/home/ds/vlc/include"
15+
16+
}, systemIncludes = "/usr/lib/llvm-15/lib/clang/15.0.7/include/", debugMode = true)
17+
@Structs
18+
@Enums
19+
@Unions
20+
public interface LibVLC {
21+
}

annotation-processor/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ dependencies {
1616

1717
annotationProcessor 'io.avaje:avaje-prisms:1.28'
1818
implementation 'io.avaje:avaje-prisms:1.28'
19+
implementation 'org.barfuin.texttree:text-tree:2.1.2'
1920

2021
testImplementation platform('org.junit:junit-bom:5.10.0')
2122
testImplementation 'org.junit.jupiter:junit-jupiter'

annotation-processor/src/main/java/io/github/digitalsmile/NativeProcessor.java

Lines changed: 63 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,17 @@
1414
import io.github.digitalsmile.annotation.structure.Unions;
1515
import io.github.digitalsmile.composers.EnumComposer;
1616
import io.github.digitalsmile.composers.FunctionComposer;
17+
import io.github.digitalsmile.composers.OpaqueComposer;
1718
import io.github.digitalsmile.composers.StructComposer;
1819
import io.github.digitalsmile.functions.FunctionNode;
1920
import io.github.digitalsmile.functions.Library;
2021
import io.github.digitalsmile.functions.ParameterNode;
2122
import io.github.digitalsmile.headers.Parser;
22-
import io.github.digitalsmile.headers.model.NativeMemoryModel;
23-
import io.github.digitalsmile.headers.model.NativeMemoryNode;
23+
import io.github.digitalsmile.headers.mapping.FunctionOriginalType;
2424
import io.github.digitalsmile.headers.mapping.ObjectOriginalType;
2525
import io.github.digitalsmile.headers.mapping.ObjectTypeMirror;
2626
import io.github.digitalsmile.headers.mapping.OriginalType;
27+
import io.github.digitalsmile.headers.model.NativeMemoryNode;
2728
import org.openjdk.jextract.Declaration;
2829
import org.openjdk.jextract.JextractTool;
2930
import org.openjdk.jextract.clang.Index;
@@ -44,9 +45,12 @@
4445
import javax.tools.StandardLocation;
4546
import java.io.File;
4647
import java.io.IOException;
48+
import java.io.PrintWriter;
49+
import java.io.StringWriter;
4750
import java.nio.file.Path;
4851
import java.util.*;
4952
import java.util.regex.Pattern;
53+
import java.util.stream.Stream;
5054

5155
@GeneratePrism(NativeFunction.class)
5256
@SupportedSourceVersion(SourceVersion.RELEASE_22)
@@ -72,6 +76,7 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
7276
if (nativeOptions != null && !nativeOptions.packageName().isEmpty()) {
7377
packageName = nativeOptions.packageName();
7478
}
79+
PackageName.setDefaultPackageName(packageName);
7580

7681
processHeaderFiles(rootElement, headerFiles, packageName, nativeOptions);
7782

@@ -80,6 +85,7 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
8085
processFunctions(rootElement, functionElements, packageName);
8186

8287
} catch (Throwable e) {
88+
e.printStackTrace();
8389
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage());
8490
}
8591
}
@@ -119,68 +125,84 @@ private void processHeaderFiles(Element element, String[] headerFiles, String pa
119125
}
120126

121127
boolean rootConstants = false;
128+
boolean debug = false;
122129
List<String> includes = Collections.emptyList();
130+
List<String> systemIncludes = Collections.emptyList();
123131
if (options != null) {
124132
rootConstants = options.processRootConstants();
125133
includes = Arrays.stream(options.includes()).map(p -> "-I" + p).toList();
134+
systemIncludes = Arrays.stream(options.systemIncludes()).map(p -> "-isystem" + p).toList();
135+
debug = options.debugMode();
126136
}
127137

128138
Map<Path, Declaration.Scoped> allParsedHeaders = new HashMap<>();
129139

130140
for (Path header : headerPaths) {
131141
try {
132-
var parsed = JextractTool.parse(Path.of(header.toFile().getAbsolutePath()), includes);
142+
var parsed = JextractTool.parse(Path.of(header.toFile().getAbsolutePath()), Stream.concat(includes.stream(), systemIncludes.stream()).toList());
133143
allParsedHeaders.put(header, parsed);
134144
} catch (ExceptionInInitializerError | ClangException | TypeLayoutError | Index.ParsingFailedException e) {
145+
if (debug) {
146+
printStackTrace(e);
147+
}
135148
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getCause().getMessage());
136149
return;
137150
}
138151
}
139-
var parser = new Parser(processingEnv.getMessager());
152+
var parser = new Parser(packageName, processingEnv.getMessager(), processingEnv.getFiler());
140153
try {
141-
var parsed = parser.parse(structs, enums, unions, allParsedHeaders);
142-
for (NativeMemoryModel model : parsed) {
143-
for (Map.Entry<Declaration.Scoped.Kind, List<NativeMemoryNode>> entry : model.nodes().entrySet()) {
144-
var kind = entry.getKey();
145-
switch (kind) {
146-
case STRUCT -> processStructs(packageName, entry.getValue());
147-
case ENUM -> processEnums(packageName, entry.getValue(), rootConstants);
148-
case UNION -> processUnions(packageName, entry.getValue());
154+
var parsed = parser.parse(structs, enums, unions, allParsedHeaders, debug);
155+
for (NativeMemoryNode rootNode : parsed) {
156+
for (NativeMemoryNode node : rootNode.nodes()) {
157+
switch (node.getNodeType()) {
158+
case STRUCT -> processStructs(node);
159+
case ENUM -> processEnums(node, rootConstants);
160+
case UNION -> processUnions(node);
161+
case OPAQUE -> processOpaque(node);
149162
}
150163
}
151164
}
152165
} catch (Throwable e) {
166+
if (debug) {
167+
printStackTrace(e);
168+
}
153169
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage());
154170
}
155171
}
156172

157-
private void processStructs(String packageName, List<NativeMemoryNode> nodes) {
158-
for (NativeMemoryNode node : nodes) {
159-
var structComposer = new StructComposer(processingEnv.getMessager());
160-
var output = structComposer.compose(packageName, PrettyName.getObjectName(node.getName()), node);
161-
createGeneratedFile(packageName, PrettyName.getObjectName(node.getName()), output);
173+
private void processOpaque(NativeMemoryNode node) {
174+
var opaqueComposer = new OpaqueComposer(processingEnv.getMessager());
175+
var output = opaqueComposer.compose(PrettyName.getObjectName(node.getName()), node);
176+
createGeneratedFile(PackageName.getPackageName(node.getName()), PrettyName.getObjectName(node.getName()), output);
177+
}
178+
179+
private void processStructs(NativeMemoryNode node) {
180+
if (node.nodes().stream().anyMatch(n -> n.getType() instanceof FunctionOriginalType)) {
181+
return;
162182
}
183+
var structComposer = new StructComposer(processingEnv.getMessager());
184+
var output = structComposer.compose(PrettyName.getObjectName(node.getName()), node);
185+
createGeneratedFile(PackageName.getPackageName(node.getName()), PrettyName.getObjectName(node.getName()), output);
163186
}
164187

165-
private void processEnums(String packageName, List<NativeMemoryNode> nodes, boolean rootConstants) {
166-
for (NativeMemoryNode node : nodes) {
167-
if (node.getName().contains("Constants")) {
168-
if (!rootConstants) {
169-
continue;
170-
}
188+
private void processEnums(NativeMemoryNode node, boolean rootConstants) {
189+
if (node.getName().contains("Constants")) {
190+
if (!rootConstants) {
191+
return;
171192
}
172-
var enumComposer = new EnumComposer(processingEnv.getMessager());
173-
var output = enumComposer.compose(packageName, PrettyName.getObjectName(node.getName()), node);
174-
createGeneratedFile(packageName, PrettyName.getObjectName(node.getName()), output);
175193
}
194+
if (node.nodes().isEmpty()) {
195+
return;
196+
}
197+
var enumComposer = new EnumComposer(processingEnv.getMessager());
198+
var output = enumComposer.compose(PrettyName.getObjectName(node.getName()), node);
199+
createGeneratedFile(PackageName.getPackageName(node.getName()), PrettyName.getObjectName(node.getName()), output);
176200
}
177201

178-
private void processUnions(String packageName, List<NativeMemoryNode> nodes) {
179-
for (NativeMemoryNode node : nodes) {
180-
var structComposer = new StructComposer(processingEnv.getMessager());
181-
var output = structComposer.compose(packageName, PrettyName.getObjectName(node.getName()), node);
182-
createGeneratedFile(packageName, PrettyName.getObjectName(node.getName()), output);
183-
}
202+
private void processUnions(NativeMemoryNode node) {
203+
var structComposer = new StructComposer(processingEnv.getMessager(), true);
204+
var output = structComposer.compose(PrettyName.getObjectName(node.getName()), node);
205+
createGeneratedFile(PackageName.getPackageName(node.getName()), PrettyName.getObjectName(node.getName()), output);
184206
}
185207

186208
private void processFunctions(Element rootElement, List<Element> functionElements, String packageName) {
@@ -314,4 +336,13 @@ private void createGeneratedFile(String packageName, String fileName, String con
314336
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "Exception occurred while processing file '" + fileName + "': " + e.getMessage());
315337
}
316338
}
339+
340+
private void printStackTrace(Throwable exception) {
341+
var writer = new StringWriter();
342+
var printWriter = new PrintWriter(writer);
343+
exception.printStackTrace(printWriter);
344+
printWriter.flush();
345+
346+
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, writer.toString());
347+
}
317348
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package io.github.digitalsmile;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
public class PackageName {
7+
8+
private static String DEFAULT_PACKAGE_NAME = "";
9+
private static final Map<String, String> packageNamesMap = new HashMap<>();
10+
11+
public static void addPackage(String typeName, String packageName) {
12+
packageNamesMap.put(typeName, DEFAULT_PACKAGE_NAME + "." + packageName);
13+
}
14+
15+
public static void addPackage(String typeName) {
16+
packageNamesMap.put(typeName, DEFAULT_PACKAGE_NAME);
17+
}
18+
19+
public static String getPackageName(String typeName) {
20+
return packageNamesMap.getOrDefault(typeName, DEFAULT_PACKAGE_NAME);
21+
}
22+
23+
public static void setDefaultPackageName(String packageName) {
24+
DEFAULT_PACKAGE_NAME = packageName;
25+
}
26+
}

0 commit comments

Comments
 (0)