package co.deepblue.java2cpp;
import co.deepblue.java2cpp.io.BufferedStringWriter;
import co.deepblue.java2cpp.processor.*;
import co.deepblue.java2cpp.symbol.SymbolTreeParser;
import co.deepblue.java2cpp.util.PathUtils;
import co.deepblue.java2cpp.type.TypeConverter;
import co.deepblue.java2cpp.util.FileUtils;
import co.deepblue.java2cpp.util.StringConstants;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
import com.github.javaparser.ast.body.EnumDeclaration;
import com.github.javaparser.ast.body.TypeDeclaration;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileFilter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
/**
* Created by levin on 17-5-6.
*/
public class Java2CppMemory {
String projNamespace;
String shortestPackage;
String javaDir;
String cppRootPath;
String cppProjectDirName;
Parser parser;
HashMap cuMap;
ArrayList cuList = new ArrayList<>();
ArrayList typeSizeList = new ArrayList<>();
BufferedWriter cmakeListWriter;
public Java2CppMemory(String shortestPackage, String srcDir, String dstDir, String namespace) {
this.shortestPackage = shortestPackage;
this.javaDir = srcDir;
this.cppRootPath = dstDir;
this.projNamespace = namespace;
parser = new Parser();
cuMap = new HashMap<>();
}
void cleanDstDir() {
try {
FileUtils.deleteDirectory(new File(cppRootPath));
} catch (Exception e) {
e.printStackTrace();
}
}
public void startParse() {
cleanDstDir();
parseDir(javaDir);
preprocessCompilationUnits();
SymbolTreeParser.createInstance("projectName", cuMap, cuList);
SymbolTreeParser.getInstance().scanSymbols();
//int total = symbolTreeParser.getTotalNumberOfSymbols();
try {
cppProjectDirName = Paths.get(cppRootPath).getFileName().toString();
cmakeListWriter = FileUtils.createWriter(Paths.get(cppRootPath).getParent(), "CMakeLists.txt");
cmakeListWriter.write("#\n");
cmakeListWriter.write("#autogenerated\n");
cmakeListWriter.write("#\n");
cmakeListWriter.write("cmake_minimum_required (VERSION 3.2.3)\n\n");
cmakeListWriter.write("project (projectName)\n\n");
cmakeListWriter.write("SET(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -Wall -std=c++11\")\n\n");
cmakeListWriter.write("set (WORLD_INCLUDE_DIRS src)\n");
cmakeListWriter.write("include_directories (${WORLD_INCLUDE_DIRS})\n\n");
cmakeListWriter.write("add_executable(projectName\n");
copyPredefinedCppFiles();
convertToCpp();
cmakeListWriter.write(")");
cmakeListWriter.close();
} catch (Exception e) {
e.printStackTrace();
}
}
String predefinedCppDir = "";
void copyPredefinedCppFiles() {
predefinedCppDir = Paths.get(shortestPackage.replace(".", File.separator), "cpptemplate").toString();
Path dst = Paths.get(cppRootPath, predefinedCppDir);
FileUtils.copyDirectory("/media/levin/842aef23-8664-4811-be6b-e3124f37cc64/levin/games/java_parser/cpp", dst.toString());
File f = dst.toFile();
File[] children = f.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.getName().endsWith(".h");
}
});
if (children != null) {
for (File child : children) {
String name = Paths.get(predefinedCppDir, child.getName()).toString();
name = name.substring(0, name.indexOf(".h"));
name = name.replace(File.separator, ".");
String typeName = child.getName().substring(0, child.getName().indexOf(".h"));
SymbolTreeParser.getInstance().registerPredefinedInclude(typeName, name);
}
}
}
public void parseDir(String dir) {
File srcFile = new File(dir);
if (srcFile.isDirectory()) {
File[] fileList = srcFile.listFiles();
if (fileList != null) {
for (File file : fileList) {
parseDir(file.getAbsolutePath());
}
}
} else if (srcFile.getName().endsWith(".java")){
try {
CompilationUnit cu = parser.parseToCompilationUnit(srcFile.getAbsolutePath());
String packageName = "";
String className = PathUtils.removeExtension(srcFile.getName(), ".java");
String key = "";
if (cu.getPackageDeclaration().isPresent()) {
packageName = cu.getPackageDeclaration().get().getNameAsString();
key = packageName + "." + className;
} else {
String path = srcFile.getAbsolutePath().replace(File.separator, ".");
packageName = path.substring(path.indexOf(shortestPackage));
packageName = PathUtils.removeExtension(packageName, ".java");
key = packageName.substring(0, packageName.lastIndexOf(".")) + "." + className;
}
cu.setData(AstNodeHelper.FilenameDatakey, key);
cuMap.put(key, cu);
if (cu.getTypes() != null)
typeSizeList.add(cu.getTypes().size());
else
typeSizeList.add(0);
cuList.add(cu);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void preprocessCompilationUnits() {
for (CompilationUnit cu : cuList) {
if (cu.getPackageDeclaration().isPresent()) {
String packageName = cu.getPackageDeclaration().get().getName().asString();
NodeList> types = cu.getTypes();
if (types.size() > 0) {
TypeDeclaration typeDeclaration = types.get(0);
if (typeDeclaration instanceof ClassOrInterfaceDeclaration) {
} else if (typeDeclaration instanceof EnumDeclaration) {
EnumDeclaration ed = (EnumDeclaration) typeDeclaration;
if (ed.getMembers().size() <= 0) {
TypeConverter.getInstance().addSimpleEnumType(ed.getNameAsString(), packageName);
}
}
}
}
}
}
public void convertToCpp() {
for (CompilationUnit cu : cuList) {
if (cu == SymbolTreeParser.getInstance().getMainCU()) {
writeMainEntrance(cu);
} else
processCompilationUnit(cu);
}
}
public void writeHeaderDeclaration(BufferedStringWriter writer) throws Exception {
writer.insertAtBegin("/*\nGenerate by Java2Cpp\n*/\n\n");
}
public void writeBasicIncludes(BufferedStringWriter writer) throws Exception {
writer.insert("\n", 0);
writer.insertAtBegin("#include \n");
writer.insertAtBegin("#include \n");
}
void writeIncludes(CompilationUnit unit, BufferedStringWriter writer) {
writer.insertAtBegin("\n");
String key = unit.getData(AstNodeHelper.FilenameDatakey);
Set includes = SymbolTreeParser.getInstance().getInclude(key);
if (includes != null) {
for (String include : includes) {
include = include.replace(".", File.separator);
if (!include.startsWith("<"))
include = "<" + include;
if (!include.endsWith(">"))
include = include + ".h>";
writer.insertAtBegin("#include " + include + "\n");
}
}
}
void writeUsingNamespace(CompilationUnit unit, BufferedStringWriter writer, boolean isMainUnit) {
writer.insertAtBegin("\n");
String key = unit.getData(AstNodeHelper.FilenameDatakey);
Set namespaceSet = SymbolTreeParser.getInstance().getNamespace(key);
if (namespaceSet != null) {
for (String ns : namespaceSet) {
writer.insertAtBegin("using namespace " + ns + ";\n");
}
}
if (isMainUnit)
writer.insertAtBegin("using namespace " + projNamespace + ";\n");
}
public void writeMainEntrance(CompilationUnit mainCU) {
String packageName = mainCU.getPackageDeclaration().get().getName().asString();
String pkgDir = PathUtils.packageName2Path(packageName);
Path fileDir = Paths.get(cppRootPath, pkgDir);
TypeDeclaration typeDeclaration = mainCU.getTypes().get(0);
String className = typeDeclaration.getNameAsString();
try {
cmakeListWriter.write(StringConstants.TAB + StringConstants.TAB + Paths.get(cppProjectDirName, pkgDir, className + ".cpp").toString() + "\n");
BufferedWriter implWriter = FileUtils.createWriter(fileDir, className + ".cpp");
BufferedStringWriter writer = new BufferedStringWriter();
MainClassProcessor.process((ClassOrInterfaceDeclaration) typeDeclaration, writer, "");
writeUsingNamespace(mainCU, writer, true);
writeIncludes(mainCU, writer);
implWriter.write(writer.getString());
implWriter.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void processCompilationUnit(CompilationUnit cu) {
if (cu.getPackageDeclaration().isPresent()) {
String packageName = cu.getPackageDeclaration().get().getName().asString();
String pkgDir = PathUtils.packageName2Path(packageName);
Path fileDir = Paths.get(cppRootPath, pkgDir);
NodeList> types = cu.getTypes();
if (types.size() > 0) {
boolean res = fileDir.toFile().mkdirs();
try {
TypeDeclaration typeDeclaration = types.get(0);
String className = typeDeclaration.getNameAsString();
BufferedWriter headerFileWriter = FileUtils.createWriter(fileDir, className + ".h");
BufferedStringWriter headerWriter = new BufferedStringWriter();
//writeIncludes(headerWriter, cu);
headerWriter.write("namespace " + projNamespace + "\n");
headerWriter.write("{\n\n");
boolean isSimpleEnum = false;
if (typeDeclaration instanceof EnumDeclaration) {
EnumDeclaration ed = (EnumDeclaration) typeDeclaration;
if (ed.getMembers().size() <= 0) {
SimpleEnumCreator.create(ed, headerWriter, "");
isSimpleEnum = true;
}
}
if (!isSimpleEnum) {
BufferedWriter implFileWriter = FileUtils.createWriter(fileDir, className + ".cpp");
BufferedStringWriter implWriter = new BufferedStringWriter();
implWriter.write("#include \"" + className + ".h\"\n\n");
implWriter.write("namespace " + projNamespace + "\n");
implWriter.write("{\n\n");
if (typeDeclaration instanceof ClassOrInterfaceDeclaration) {
ClassOrInterfaceProcessor.process((ClassOrInterfaceDeclaration) typeDeclaration, headerWriter, implWriter, "");
} else if (typeDeclaration instanceof EnumDeclaration) {
EnumDeclaration ed = (EnumDeclaration) typeDeclaration;
ComplexEnumProcessor.process(ed, headerWriter, implWriter, "");
}
implWriter.write("\n\n}");
implWriter.close();
writeIncludes(cu, implWriter);
implFileWriter.write(implWriter.getString());
implFileWriter.close();
cmakeListWriter.write(StringConstants.TAB + StringConstants.TAB + Paths.get(cppProjectDirName, pkgDir, className + ".cpp").toString() + "\n");
}
writeUsingNamespace(cu, headerWriter, false);
writeBasicIncludes(headerWriter);
writeIncludes(cu, headerWriter);
headerWriter.insert("#pragma once\n\n", 0);
writeHeaderDeclaration(headerWriter);
headerWriter.write("\n\n}");
headerWriter.close();
headerFileWriter.write(headerWriter.getString());
headerFileWriter.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
public ArrayList getCompilationUnitList() {
return cuList;
}
public int countNumberOfUnitTypesLargerThanOne() {
int counter = 0;
for (int i = 0; i < typeSizeList.size(); i++) {
if (typeSizeList.get(i) > 1)
counter++;
}
return counter;
}
public ArrayList getTypeSizeList() {
return typeSizeList;
}
public HashMap getCompilationUnitMap() {
return cuMap;
}
}