73 protected final String headerClassName;
74 protected final HeaderFile headerFile;
75 private final Map<String, JavaSourceBuilder> types;
76 private final List<String> libraryNames;
77 private final List<String> libraryPaths;
78 private final boolean noNativeLocations;
79 private final JavaSourceBuilder global_jsb;
80 protected final Path srcDir;
81 protected final Log log;
82
83 JavaSourceFactory(Context ctx, HeaderFile header) {
84 this.log = ctx.log;
85 log.print(Level.INFO, () -> "Instantiate JavaSourceFactory for " + header.path);
86 this.headerFile = header;
87 this.headerClassName = headerFile.pkgName + "." + headerFile.headerClsName;
88 this.types = new HashMap<>();
89 this.libraryNames = ctx.options.libraryNames;
90 this.libraryPaths = ctx.options.recordLibraryPath? ctx.options.libraryPaths : null;
91 this.noNativeLocations = ctx.options.noNativeLocations;
92 this.global_jsb = new JavaSourceBuilder();
93 this.srcDir = Paths.get(ctx.options.srcDumpDir)
94 .resolve(headerFile.pkgName.replace('.', File.separatorChar));
95 }
96
97 // main entry point that generates & saves .java files for the header file
98 public void generate(List<Tree> decls) {
99 global_jsb.addPackagePrefix(headerFile.pkgName);
100
101 Map<String, Object> header = new HashMap<>();
102 header.put("path", headerFile.path.toAbsolutePath().toString());
103 if (!libraryNames.isEmpty()) {
104 header.put("libraries", libraryNames.toArray(new String[0]));
105 if (libraryPaths != null && !libraryPaths.isEmpty()) {
106 header.put("libraryPaths", libraryPaths.toArray(new String[0]));
107 }
108 }
109
110 JType.ClassType[] classes = headerFile.dictionary().resolutionRoots()
111 .toArray(JType.ClassType[]::new);
112 if (classes.length != 0) {
113 header.put("resolutionContext", classes);
114 }
115
116 Set<Layout> global_layouts = new LinkedHashSet<>();
117 for (Tree tr : decls) {
118 if (tr instanceof VarTree) {
124 String[] globals = global_layouts.stream().map(Object::toString).toArray(String[]::new);
125 header.put("globals", globals);
126 }
127
128 global_jsb.addAnnotation(false, NATIVE_HEADER, header);
129 String clsName = headerFile.headerClsName;
130 global_jsb.interfaceBegin(clsName, false);
131
132 //generate all decls
133 decls.forEach(this::generateDecl);
134 //generate functional interfaces
135 headerFile.dictionary().functionalInterfaces()
136 .forEach(fi -> createFunctionalInterface((JType.FunctionalInterfaceType)fi));
137
138 for (JavaSourceBuilder jsb : types.values()) {
139 global_jsb.addNestedType(jsb);
140 }
141
142 global_jsb.interfaceEnd();
143 String src = global_jsb.build();
144 try {
145 Files.createDirectories(srcDir);
146 Path srcPath = srcDir.resolve(clsName + ".java");
147 Files.write(srcPath, List.of(src));
148 } catch (Exception ex) {
149 handleException(ex);
150 }
151 }
152
153 protected void handleException(Exception ex) {
154 log.printError("cannot.write.class.file", headerFile.pkgName + "." + headerFile.headerClsName, ex);
155 log.printStackTrace(ex);
156 }
157
158 private void addNativeLocation(JavaSourceBuilder jsb, Tree tree) {
159 addNativeLocation(jsb, tree.location());
160 }
161
162 private void addNativeLocation(JavaSourceBuilder jsb, SourceLocation src) {
163 addNativeLocation(true, jsb, src);
164 }
165
166 private void addNativeLocation(boolean align, JavaSourceBuilder jsb, SourceLocation src) {
167 if (! noNativeLocations) {
168 SourceLocation.Location loc = src.getFileLocation();
169 Path p = loc.path();
170 Map<String, Object> fields = new HashMap<>();
171 fields.put("file", p == null ? "<builtin>" : p.toAbsolutePath().toString());
172 fields.put("line", loc.line());
333 addClassIfNeeded(headerClassName + "." + intf, jsb);
334 }
335
336 @Override
337 public Boolean visitTypedef(TypedefTree typedefTree, JType jt) {
338 createAnnotationCls(typedefTree);
339 return true;
340 }
341
342 @Override
343 public Boolean visitTree(Tree tree, JType jt) {
344 log.print(Level.WARNING, () -> "Unsupported declaration tree:");
345 log.print(Level.WARNING, () -> tree.toString());
346 return true;
347 }
348
349 @Override
350 public Boolean visitFunction(FunctionTree funcTree, JType jt) {
351 assert (jt instanceof JType.Function);
352 JType.Function fn = (JType.Function)jt;
353 log.print(Level.FINE, () -> "Add method: " + fn.getSignature(false));
354
355 addNativeLocation(global_jsb, funcTree);
356 Type type = funcTree.type();
357 final String descStr = Utils.getFunction(type).toString();
358 global_jsb.addAnnotation(NATIVE_FUNCTION, Map.of("value", descStr));
359 global_jsb.addMethod(funcTree, fn);
360
361 return true;
362 }
363
364 private void generateDecl(Tree tree) {
365 try {
366 log.print(Level.FINE, () -> "Process tree " + tree.name());
367 tree.accept(this, tree.isPreprocessing() ? null : headerFile.dictionary().lookup(tree.type()));
368 } catch (Exception ex) {
369 handleException(ex);
370 log.print(Level.WARNING, () -> "Tree causing above exception is: " + tree.name());
371 log.print(Level.WARNING, () -> tree.toString());
372 }
373 }
|
73 protected final String headerClassName;
74 protected final HeaderFile headerFile;
75 private final Map<String, JavaSourceBuilder> types;
76 private final List<String> libraryNames;
77 private final List<String> libraryPaths;
78 private final boolean noNativeLocations;
79 private final JavaSourceBuilder global_jsb;
80 protected final Path srcDir;
81 protected final Log log;
82
83 JavaSourceFactory(Context ctx, HeaderFile header) {
84 this.log = ctx.log;
85 log.print(Level.INFO, () -> "Instantiate JavaSourceFactory for " + header.path);
86 this.headerFile = header;
87 this.headerClassName = headerFile.pkgName + "." + headerFile.headerClsName;
88 this.types = new HashMap<>();
89 this.libraryNames = ctx.options.libraryNames;
90 this.libraryPaths = ctx.options.recordLibraryPath? ctx.options.libraryPaths : null;
91 this.noNativeLocations = ctx.options.noNativeLocations;
92 this.global_jsb = new JavaSourceBuilder();
93 this.srcDir = ctx.options.srcDumpDir != null?
94 Paths.get(ctx.options.srcDumpDir).resolve(headerFile.pkgName.replace('.', File.separatorChar)) :
95 null;
96 }
97
98 // main entry point that generates & saves .java files for the header file
99 public Map<String, String> generate(List<Tree> decls) {
100 global_jsb.addPackagePrefix(headerFile.pkgName);
101
102 Map<String, Object> header = new HashMap<>();
103 header.put("path", headerFile.path.toAbsolutePath().toString());
104 if (!libraryNames.isEmpty()) {
105 header.put("libraries", libraryNames.toArray(new String[0]));
106 if (libraryPaths != null && !libraryPaths.isEmpty()) {
107 header.put("libraryPaths", libraryPaths.toArray(new String[0]));
108 }
109 }
110
111 JType.ClassType[] classes = headerFile.dictionary().resolutionRoots()
112 .toArray(JType.ClassType[]::new);
113 if (classes.length != 0) {
114 header.put("resolutionContext", classes);
115 }
116
117 Set<Layout> global_layouts = new LinkedHashSet<>();
118 for (Tree tr : decls) {
119 if (tr instanceof VarTree) {
125 String[] globals = global_layouts.stream().map(Object::toString).toArray(String[]::new);
126 header.put("globals", globals);
127 }
128
129 global_jsb.addAnnotation(false, NATIVE_HEADER, header);
130 String clsName = headerFile.headerClsName;
131 global_jsb.interfaceBegin(clsName, false);
132
133 //generate all decls
134 decls.forEach(this::generateDecl);
135 //generate functional interfaces
136 headerFile.dictionary().functionalInterfaces()
137 .forEach(fi -> createFunctionalInterface((JType.FunctionalInterfaceType)fi));
138
139 for (JavaSourceBuilder jsb : types.values()) {
140 global_jsb.addNestedType(jsb);
141 }
142
143 global_jsb.interfaceEnd();
144 String src = global_jsb.build();
145 if (srcDir != null) {
146 try {
147 Files.createDirectories(srcDir);
148 Path srcPath = srcDir.resolve(clsName + ".java");
149 Files.write(srcPath, List.of(src));
150 } catch (Exception ex) {
151 handleException(ex);
152 }
153 }
154
155 Map<String, String> srcMap = new HashMap<>();
156 srcMap.put(headerClassName, src);
157 return srcMap;
158 }
159
160 protected void handleException(Exception ex) {
161 log.printError("cannot.write.class.file", headerFile.pkgName + "." + headerFile.headerClsName, ex);
162 log.printStackTrace(ex);
163 }
164
165 private void addNativeLocation(JavaSourceBuilder jsb, Tree tree) {
166 addNativeLocation(jsb, tree.location());
167 }
168
169 private void addNativeLocation(JavaSourceBuilder jsb, SourceLocation src) {
170 addNativeLocation(true, jsb, src);
171 }
172
173 private void addNativeLocation(boolean align, JavaSourceBuilder jsb, SourceLocation src) {
174 if (! noNativeLocations) {
175 SourceLocation.Location loc = src.getFileLocation();
176 Path p = loc.path();
177 Map<String, Object> fields = new HashMap<>();
178 fields.put("file", p == null ? "<builtin>" : p.toAbsolutePath().toString());
179 fields.put("line", loc.line());
340 addClassIfNeeded(headerClassName + "." + intf, jsb);
341 }
342
343 @Override
344 public Boolean visitTypedef(TypedefTree typedefTree, JType jt) {
345 createAnnotationCls(typedefTree);
346 return true;
347 }
348
349 @Override
350 public Boolean visitTree(Tree tree, JType jt) {
351 log.print(Level.WARNING, () -> "Unsupported declaration tree:");
352 log.print(Level.WARNING, () -> tree.toString());
353 return true;
354 }
355
356 @Override
357 public Boolean visitFunction(FunctionTree funcTree, JType jt) {
358 assert (jt instanceof JType.Function);
359 JType.Function fn = (JType.Function)jt;
360 log.print(Level.FINE, () -> "Add method: " + fn.getSourceSignature(false));
361
362 addNativeLocation(global_jsb, funcTree);
363 Type type = funcTree.type();
364 final String descStr = Utils.getFunction(type).toString();
365 global_jsb.addAnnotation(NATIVE_FUNCTION, Map.of("value", descStr));
366 global_jsb.addMethod(funcTree, fn);
367
368 return true;
369 }
370
371 private void generateDecl(Tree tree) {
372 try {
373 log.print(Level.FINE, () -> "Process tree " + tree.name());
374 tree.accept(this, tree.isPreprocessing() ? null : headerFile.dictionary().lookup(tree.type()));
375 } catch (Exception ex) {
376 handleException(ex);
377 log.print(Level.WARNING, () -> "Tree causing above exception is: " + tree.name());
378 log.print(Level.WARNING, () -> tree.toString());
379 }
380 }
|