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()); | 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()); |