diff --git a/README.md b/README.md index 87e8f6492594d2feba2e40becb7ed9bf93253550..5a80e741805035e0c75e477ba59ba8d78d5e25db 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,31 @@ 通过src/main/java/com/example/codegen/CodeGen*.java运行,可以将输入的class文件和输入的MOP程序文件生成对对应的宿主语言程序。 -CodegenJava.java可以生成Java程序, CodegenCSharp.java可以生成C#程序。 +CodeGenJava.java可以生成Java程序, CodeGenCSharp.java可以生成C#程序,CodeGenCJ.java用于生成仓颉程序。 在程序运行前,需要在程序的Line11-Line14中设置输入的class文件和输入的MOP程序文件的路径, 以及设置输出的宿主语言程序的路径。 目前转换后结果存放在同一个文件中。 -执行前,请先使用src/main/resources/run.sh脚本生成主函数, run.sh脚本参数为MOP程序文件夹路径。 +执行前,**请先使用src/main/resources/run.sh脚本生成主函数**, run.sh脚本参数为MOP程序文件夹路径,脚本将对路径下的dslProgram.txt做出修改 ```shell cd src/main/resources bash run.sh guava -mkdir java ``` -以当前项目中存在的guava MOP程序为例(请保证路径文件夹存在) +以当前项目中存在的guava MOP程序为例(**请保证路径文件夹存在**,若路径中文件夹不存在,请手动添加) + +Java语言执行方式: + +在CodeGenJava.java中配置路径 ```java -String kLassPath = "src/main/resources/guava/MainClasses.txt"; -String dSLProgramPath = "src/main/resources/guava/dslProgram.txt"; -String dslInitPath = "src/main/resources/guava/"; -String outputJavaDir = "src/main/resources/java/"; -String outputMainPath = outputJavaDir + "Main.java"; + String name = "guava";// 项目名称(仅作为路径判断,名称不影响程序执行) + String kLassPath = "src/main/resources/"+name+"/MainClasses.txt"; //类文件 + String dSLProgramPath = "src/main/resources/"+name+"/dslProgram.txt"; //MOP程序 + String dslInitPath = "src/main/resources/"+name+"/"; //全局变量初始化文件路径,文件命名格式为MainX.txt, X为数字 + String outputJavaDir = "src/main/resources/"+name+"/java/"; //输出文件路径 + String outputMainPath = outputJavaDir + "Main.java"; // 输出的主类文件 ``` -运行对应程序后,会在outputJavaDir中生成Main.java文件,即为转换后的Java程序。之后可以直接运行 +运行程序后,会在outputJavaDir中生成Main.java文件以及全局变量初始化文件MainX.java,即为转换后的Java程序。之后可以直接运行 ```shell cd src/main/resources/java @@ -32,11 +36,12 @@ java Main C#语言执行类似 ```java -String kLassPath = "src/main/resources/guava/MainClasses.txt"; -String dSLProgramPath = "src/main/resources/guava/dslProgram.txt"; -String dslInitPath = "src/main/resources/guava/"; -String outputJavaDir = "src/main/resources/csharp/"; -String outputMainPath = outputJavaDir + "Program.cs"; + String name = "guava"; + String kLassPath = "src/main/resources/"+name+"/MainClasses.txt"; + String dSLProgramPath = "src/main/resources/"+name+"/dslProgram.txt"; + String dslInitPath = "src/main/resources/"+name+"/"; + String outputJavaDir = "src/main/resources/"+name+"/CS/"; + String outputMainPath = outputJavaDir + "Program.cs"; ``` 运行后,会在outputJavaDir中生成cs文件, 之后建立dotnet项目,将所有cs文件加入项目中,之后可以直接运行 @@ -51,4 +56,29 @@ dotnet run example.csproj > log.out 2>&1 ```shell dotnet run example.csproj > log.out 2>&1 -``` \ No newline at end of file +``` + +仓颉语言执行方式 + +路径配置同上,其中CJUtils.isVariableNameNormalized是记录变量名是否符合变量命名规格化class_n形式,用于方便转化人工编写的MOP程序,对于自动转化出来的MOP程序请设置为true,对于人工编写且父子类无同名字段的MOP程序可以设置为false + +```java + CJUtils.isVariableNameNormalized = true;//true 表示变量命名规格化,为class_n,无特殊情况请默认为ture + String name = "guava"; + String kLassPath = "src/main/resources/"+name+"/MainClasses.txt"; + String dSLProgramPath = "src/main/resources/"+name+"/dslProgram.txt"; + String dslInitPath = "src/main/resources/"+name+"/"; + String outputJavaDir = "src/main/resources/"+name+"/cj/"; + String outputMainPath = outputJavaDir + "main.cj"; +``` + +获取到资源文件后,需要建立仓颉项目,将所有资源放于src文件夹路径下,然后编译执行(如果需要屏蔽编译过程中关于未使用变量的提醒,可以在配置文件cjpm.toml的compiler-option选项中添加-Woff unused) + +```shell +cd CJProm +cjpm init +mv /path/*.cj ./src +cjpm build +cjpm run +``` + diff --git a/src/main/java/com/example/codegen/AssignStatement.java b/src/main/java/com/example/codegen/AssignStatement.java index 9631383ac8194f635c96701cf197c8074a9e521a..5cc2a7db4d565f36fa1c9e693c32a57dd27eddf0 100644 --- a/src/main/java/com/example/codegen/AssignStatement.java +++ b/src/main/java/com/example/codegen/AssignStatement.java @@ -1,10 +1,12 @@ package com.example.codegen; +import com.example.utils.CJUtils; + import java.util.Optional; public class AssignStatement implements Statement { public DeclareExpression declareVariable; - // please wrap both type and left expression in a bracket if you want to force cast like (int)(a.b) + // please wrap the type and left expression in a bracket if you want to force cast like (int)(a.b) public Optional castType; public Expression leftExpression; @@ -31,4 +33,27 @@ public class AssignStatement implements Statement { public String toCSharp() { return declareVariable.toCSharp() + " = " + (castType.isPresent() ? "(" + castType.get().toCSharp() + ")" : "") + (castType.isPresent() ? "(" : "") + leftExpression.toCSharp() + (castType.isPresent() ? ")" : "") + ";"; } + + @Override + public String toCJ() { + if(CJUtils.isVariableNameNormalized) { + boolean typeChange = true; + if (castType.isPresent()) { + String typeName = castType.get().toCJ(); + if (typeName.startsWith("?Array<")) { + typeChange = false; + } + } + String left = leftExpression.toCJ(); + if (left.equals("None") || (leftExpression instanceof NewArrayExpression) || (leftExpression instanceof NewInstanceExpression)) + typeChange = false; + if (typeChange) + left = "turnClass(" + leftExpression.toCJ() + ")"; + return declareVariable.toCJ() + " = " + left; + } else { + if(castType.isPresent()) + return declareVariable.toCJ() + " = " +"turnClass(" + leftExpression.toCJ() + ")"; + return declareVariable.toCJ() + " = " + leftExpression.toCJ() ; + } + } } diff --git a/src/main/java/com/example/codegen/AstNode.java b/src/main/java/com/example/codegen/AstNode.java index 17653ea1ea5b0105d5d59c3603e13bb525047db3..9b09c7aa755df088e4756416ca833a5923809d7e 100644 --- a/src/main/java/com/example/codegen/AstNode.java +++ b/src/main/java/com/example/codegen/AstNode.java @@ -8,4 +8,6 @@ public interface AstNode { String toJs(); String toCSharp(); + + String toCJ(); } diff --git a/src/main/java/com/example/codegen/CallExpression.java b/src/main/java/com/example/codegen/CallExpression.java index 5bdebe1ad1b4b5059a5f115b0516beeafb3b3c8a..2e379f38862a653476562c5d73f3f5dd34cddc96 100644 --- a/src/main/java/com/example/codegen/CallExpression.java +++ b/src/main/java/com/example/codegen/CallExpression.java @@ -34,4 +34,9 @@ public class CallExpression implements Expression { public String toCSharp() { return (className.map(s -> s + ".").orElse("")) + methodName + "(" + String.join(", ", args.stream().map(Variables::toCSharp).toArray(String[]::new)) + ")"; } + + @Override + public String toCJ() { + return (className.map(s -> s + ".").orElse("")) + methodName + "(" + String.join(", ", args.stream().map(Variables::toCJ).toArray(String[]::new)) + ")"; + } } diff --git a/src/main/java/com/example/codegen/CallStatement.java b/src/main/java/com/example/codegen/CallStatement.java index 685e1de77312b31b27ad8a0844c183611a42f3a2..4de3e1e4e234b2d3c8e86bb13309af3ce5a79c56 100644 --- a/src/main/java/com/example/codegen/CallStatement.java +++ b/src/main/java/com/example/codegen/CallStatement.java @@ -24,4 +24,8 @@ public class CallStatement implements Statement { public String toCSharp() { return callExpression.toCSharp() + ";"; } + + public String toCJ() { + return callExpression.toCJ(); + } } diff --git a/src/main/java/com/example/codegen/CodeGenCJ.java b/src/main/java/com/example/codegen/CodeGenCJ.java new file mode 100644 index 0000000000000000000000000000000000000000..e4a08e06a9cdcfbeda95fd5ad8816b958ff1d5a2 --- /dev/null +++ b/src/main/java/com/example/codegen/CodeGenCJ.java @@ -0,0 +1,93 @@ +package com.example.codegen; + +import com.example.utils.CJUtils; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.FileReader; +import java.io.FileWriter; +import java.util.Optional; + +public class CodeGenCJ { + public static void main(String[] args) { + CJUtils.isVariableNameNormalized = true;//true 表示变量命名规格化,为class_n + String name = "guava"; + String kLassPath = "src/main/resources/"+name+"/MainClasses.txt"; + String dSLProgramPath = "src/main/resources/"+name+"/dslProgram.txt"; + String dslInitPath = "src/main/resources/"+name+"/"; + String outputJavaDir = "src/main/resources/"+name+"/cj/"; + String outputMainPath = outputJavaDir + "main.cj"; +// String name = "BD"; +// String kLassPath = "src/main/resources/"+name+"/"+name+"Class.txt"; +// String dSLProgramPath = "src/main/resources/"+name+"/"+name+"Func.txt"; +// String dslInitPath = "src/main/resources/"+name+"/"; +// String outputJavaDir = "src/main/resources/"+name+"/"; +// String outputMainPath = outputJavaDir + "Program.cj"; + try { + + Type.disableInterface = false; + CJUtils.inClass = true; + BufferedWriter writer = new BufferedWriter(new FileWriter(outputMainPath)); + BufferedReader klassReader = new BufferedReader(new FileReader(kLassPath)); + BufferedReader dSLProgramReader = new BufferedReader(new FileReader(dSLProgramPath)); + writer.write("from std import collection.*\n\n"); + // test is klassReader is empty without readline + Optional klass = Optional.empty(); + do { + klass = Parser.parserKlass(klassReader); + if (klass.isPresent()) { + Klass k = klass.get(); + writer.write(k.toCJ().replace('$', '_')); + writer.newLine(); + } + } while (klass.isPresent()); + writer.write("func turnClass(a: ?T1) :?T2 {\n" + + " match (a) {\n" + + " case Some(v) => v as T2\n" + + " case None => Option.None\n" + + " }\n" + + "}\n"); + writer.newLine(); + Type.disableInterface = true; + + // find all Main*.txt files expect MainClasses.txt in dslInitPath + // for each file, generate a Main*.cs file under outputJavaDir using parserKlass + Optional klassInit = Optional.empty(); + for (String file : new java.io.File(dslInitPath).list()) { + if (file.startsWith("Main") && file.endsWith(".txt") && !file.equals("MainClasses.txt")) { + BufferedReader klassInitReader = new BufferedReader(new FileReader(dslInitPath + file)); + String outputInitPath = outputJavaDir + file.replace(".txt", ".cj"); + BufferedWriter writer1 = new BufferedWriter(new FileWriter(outputInitPath)); + do { + klassInit = Parser.parserKlass(klassInitReader); + if (klassInit.isPresent()) { + Klass k = klassInit.get(); + writer1.write(k.toCJ().replace('$', '_')); + writer1.newLine(); + } + } while (klassInit.isPresent()); + writer1.close(); + klassInitReader.close(); + } + } + CJUtils.inClass = false; + writer.newLine(); + Optional program = Optional.empty(); + do { + program = Parser.parserMethod("", dSLProgramReader); + if (program.isPresent()) { + Method m = program.get(); + writer.write(m.toCJ().replace('$', '_')); + writer.newLine(); + } + } while (program.isPresent()); + writer.newLine(); + writer.close(); + klassReader.close(); + dSLProgramReader.close(); + + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/example/codegen/CodeGenCSharp.java b/src/main/java/com/example/codegen/CodeGenCSharp.java index 224d5ce7a2a742140dd1ed9be3a035bd04e3e461..fb55a44813bffed676a6c1ece45922150a3de0cd 100644 --- a/src/main/java/com/example/codegen/CodeGenCSharp.java +++ b/src/main/java/com/example/codegen/CodeGenCSharp.java @@ -9,11 +9,17 @@ import java.util.Optional; public class CodeGenCSharp { public static void main(String[] args) { - String kLassPath = "src/main/resources/guava/MainClasses.txt"; - String dSLProgramPath = "src/main/resources/guava/dslProgram.txt"; - String dslInitPath = "src/main/resources/guava/"; - String outputJavaDir = "src/main/resources/csharp/"; + String name = "gcbench1"; + String kLassPath = "src/main/resources/"+name+"/MainClasses.txt"; + String dSLProgramPath = "src/main/resources/"+name+"/dslProgram.txt"; + String dslInitPath = "src/main/resources/"+name+"/"; + String outputJavaDir = "src/main/resources/"+name+"/CS/"; String outputMainPath = outputJavaDir + "Program.cs"; + // String kLassPath = "src/main/resources/guava/MainClasses.txt"; + // String dSLProgramPath = "src/main/resources/guava/dslProgram.txt"; + // String dslInitPath = "src/main/resources/guava/"; + // String outputJavaDir = "src/main/resources/csharp/"; + // String outputMainPath = outputJavaDir + "Program.cs"; try { Type.disableInterface = false; BufferedWriter writer = new BufferedWriter(new FileWriter(outputMainPath)); @@ -33,7 +39,6 @@ public class CodeGenCSharp { } } while (klass.isPresent()); writer.newLine(); - // collect all classes first, all type not in classSet will be treated as Interface and be replaced by Object Type.disableInterface = true; writer.write("class Example {"); diff --git a/src/main/java/com/example/codegen/CodeGenGo.java b/src/main/java/com/example/codegen/CodeGenGo.java index f7f43a09599827b1bfcd19d10eacd70c16504630..b42e8fa828bdcbecb309a42212bf1c7984139a61 100644 --- a/src/main/java/com/example/codegen/CodeGenGo.java +++ b/src/main/java/com/example/codegen/CodeGenGo.java @@ -8,6 +8,7 @@ import java.util.Optional; public class CodeGenGo { public static void main(String[] args) { + String kLassPath = "src/main/resources/classDB.txt"; String dSLProgramPath = "src/main/resources/programDB.txt"; String outputJavaDir = "src/main/resources/"; diff --git a/src/main/java/com/example/codegen/CodeGenJava.java b/src/main/java/com/example/codegen/CodeGenJava.java index 9b6ace5b571a39204f32a256e13e70e467dbf81a..82474d4bd6798898e4de08916ebd2ab2cabf83ce 100644 --- a/src/main/java/com/example/codegen/CodeGenJava.java +++ b/src/main/java/com/example/codegen/CodeGenJava.java @@ -8,10 +8,11 @@ import java.util.Optional; public class CodeGenJava { public static void main(String[] args) { - String kLassPath = "src/main/resources/guava/MainClasses.txt"; - String dSLProgramPath = "src/main/resources/guava/dslProgram.txt"; - String dslInitPath = "src/main/resources/guava/"; - String outputJavaDir = "src/main/resources/java/"; + String name = "gcbench1"; + String kLassPath = "src/main/resources/"+name+"/MainClasses.txt"; + String dSLProgramPath = "src/main/resources/"+name+"/dslProgram.txt"; + String dslInitPath = "src/main/resources/"+name+"/"; + String outputJavaDir = "src/main/resources/"+name+"/java/"; String outputMainPath = outputJavaDir + "Main.java"; try { Type.disableInterface = false; @@ -31,7 +32,6 @@ public class CodeGenJava { } } while (klass.isPresent()); writer.newLine(); - // collect all classes first, all type not in classSet will be treated as Interface and be replaced by Object Type.disableInterface = true; writer.write("public class Main {"); diff --git a/src/main/java/com/example/codegen/Constant.java b/src/main/java/com/example/codegen/Constant.java index e2b31823c613a3a84322c9baebadc7aa67bec56e..c0a940b02b744df0d6ff2ee7eb4a487aa390c04e 100644 --- a/src/main/java/com/example/codegen/Constant.java +++ b/src/main/java/com/example/codegen/Constant.java @@ -25,4 +25,8 @@ public class Constant implements Expression { public String toCSharp() { return value; } + + public String toCJ() { + return value; + } } diff --git a/src/main/java/com/example/codegen/DeclareExpression.java b/src/main/java/com/example/codegen/DeclareExpression.java index 67fe1c5e20078b597def9bf37d40d03940a2c821..d6db198f72e23b9e2fc44747251150c2fda6fa15 100644 --- a/src/main/java/com/example/codegen/DeclareExpression.java +++ b/src/main/java/com/example/codegen/DeclareExpression.java @@ -1,5 +1,7 @@ package com.example.codegen; +import com.example.utils.CJUtils; + import java.util.Optional; public class DeclareExpression implements Expression { @@ -32,4 +34,17 @@ public class DeclareExpression implements Expression { public String toCSharp() { return (variableType.map(type -> type.toCSharp() + " ").orElse("")) + variable.toCSharp(); } + + @Override + public String toCJ() { + String name = variable.toCJ(); + if(variableType.isPresent()){ + if(CJUtils.spawnParamSet.contains(name)) + return "let " + name + ": " + variableType.get().toCJ(); + else + return "var " + name + ": " + variableType.get().toCJ(); + }else { + return name; + } + } } diff --git a/src/main/java/com/example/codegen/Field.java b/src/main/java/com/example/codegen/Field.java index 35a69fcd3d3d63de93892ee057e975a0fed7f05b..58ae540fad051141530514a211c7662493882e0a 100644 --- a/src/main/java/com/example/codegen/Field.java +++ b/src/main/java/com/example/codegen/Field.java @@ -1,14 +1,19 @@ package com.example.codegen; +import com.example.utils.CJUtils; +import com.example.utils.classNode; + public class Field implements AstNode { public boolean isStatic; public Type fieldType; public Variable fieldName; + public String className; - public Field(boolean isStatic, Type type, Variable s) { + public Field(boolean isStatic, Type type, Variable s, String className) { this.isStatic = isStatic; this.fieldType = type; this.fieldName = s; + this.className = className; } public String toJava() { @@ -32,4 +37,8 @@ public class Field implements AstNode { public String toCSharp() { return "public " + (isStatic ? "static " : "") + fieldType.toCSharp() + " " + fieldName.toCSharp() + ";"; } + + public String toCJ() { + return "public " + (isStatic ? "static " : "") + "var "+(CJUtils.isVariableNameNormalized ? className+ "_" + fieldName.toCJ() : fieldName.toCJ())+ " : " + fieldType.toCJ() + " = " + CJUtils.getDefaultValue(fieldType.toCJ()); + } } diff --git a/src/main/java/com/example/codegen/Identifier.java b/src/main/java/com/example/codegen/Identifier.java index b4051482a9ca5944b55a5194de721b6fcb1a67a7..0fb9bf0be735ad1d3736f4c008140d5260fc9c0a 100644 --- a/src/main/java/com/example/codegen/Identifier.java +++ b/src/main/java/com/example/codegen/Identifier.java @@ -26,4 +26,8 @@ public class Identifier implements AstNode { public String toCSharp() { return name; } + + public String toCJ() { + return name; + } } diff --git a/src/main/java/com/example/codegen/Klass.java b/src/main/java/com/example/codegen/Klass.java index 399f40c2b2cbda2679375a95acf1b49d90fd430a..0427b72314665900ea0ec37ae3a5c58cd2f95c58 100644 --- a/src/main/java/com/example/codegen/Klass.java +++ b/src/main/java/com/example/codegen/Klass.java @@ -1,8 +1,12 @@ package com.example.codegen; +import com.example.utils.CJUtils; +import com.example.utils.classNode; + import java.util.ArrayList; import java.util.Arrays; import java.util.Optional; +import java.util.Set; public class Klass implements AstNode { public String className; @@ -88,4 +92,26 @@ public class Klass implements AstNode { } }}) + "\n}"; } + + public String toCJ(){ + if(Super.isPresent()){ + Field s = Super.get(); + String parentName = s.fieldType.toCJ().charAt(0)=='?' ? s.fieldType.toCJ().substring(1) : s.fieldType.toCJ(); + CJUtils.classNodes.put(className.toLowerCase(), new classNode(className, parentName)); + } else { + CJUtils.classNodes.put(className.toLowerCase(), new classNode(className, null)); + } + Set fieldName = CJUtils.classNodes.get(className.toLowerCase()).fields; + for(Field field: fields){ + fieldName.add(field); + } + return "public open class " + className.replace('$', '_') + Super.map(s -> " <: " + (s.fieldType.toCJ().charAt(0)=='?' ? s.fieldType.toCJ().substring(1) : s.fieldType.toCJ()).replace('$', '_')).orElse("") + " {\n" + String.join("\n", new ArrayList() {{ + for (Field field : fields) { + add(field.toCJ()); + } + for (Method method : methods) { + add(method.toCJ()); + } + }}) + "\n}\n"; + } } diff --git a/src/main/java/com/example/codegen/LoopStatement.java b/src/main/java/com/example/codegen/LoopStatement.java index 3e0852e9afb8af2f62d195c3a50a83a321661bae..93eea768fcec4e0ce88a9219f9e8d6478366d1de 100644 --- a/src/main/java/com/example/codegen/LoopStatement.java +++ b/src/main/java/com/example/codegen/LoopStatement.java @@ -43,4 +43,9 @@ public class LoopStatement implements Statement { return String.format("for(int %s = %s; %s < %s; %s += %s)", indexVar.toCSharp(), startVal.toCSharp(), indexVar.toCSharp(), endVal.toCSharp(), indexVar.toCSharp(), stepVal.toCSharp()) + "{\n" + String.join("\n", statements.stream().map(Statement::toCSharp).toArray(String[]::new)) + "\n}"; } + + public String toCJ() { + return String.format("for (%s in %s..%s:%s)", indexVar.toCJ(), startVal.toCJ(), endVal.toCJ(), stepVal.toCJ()) + + "{\n\t" + String.join("\n\t\t", statements.stream().map(Statement::toCJ).toArray(String[]::new)) + "\n\t}"; + } } diff --git a/src/main/java/com/example/codegen/Method.java b/src/main/java/com/example/codegen/Method.java index 070e959522b837c4a5793803ffe374f18d818022..2645a671ee7068dc6ee944c9030434e1445a2a88 100644 --- a/src/main/java/com/example/codegen/Method.java +++ b/src/main/java/com/example/codegen/Method.java @@ -1,5 +1,7 @@ package com.example.codegen; +import com.example.utils.CJUtils; + import java.util.Arrays; import java.util.Optional; @@ -52,4 +54,40 @@ public class Method implements AstNode { String post_spawn = useSpawn ? String.format("\n%s.ForEach(thread => {\n" + "thread.Join();\n" + "});\n", SpawnStatement.threadsPool) : ""; return "public static " + returnType.toCSharp() + " " + className.map(s -> s + ".").orElse("") + (funcName.equals("main") ? "Main" : funcName) + "(" + String.join(", ", Arrays.stream(parameters).map(Parameter::toCSharp).toArray(String[]::new)) + ")" + "{" + pre_spawn + "\n" + String.join("\n", Arrays.stream(stmts).map(Statement::toCSharp).toArray(String[]::new)) + post_spawn + "\n}"; } + + public String toCJ(){ + String paramList = ""; + for(Parameter par : parameters){ + paramList += par.toCJ() + ", "; + } + if(!paramList.equals("")) + paramList = paramList.substring(0, paramList.length()-2); + String stmtList = ""; + String returnStmt = ""; + if(stmts.length > 0){ + for (int i = 0; i < stmts.length-1; i++) { + stmtList += "\t" + stmts[i].toCJ() + "\n"; + } + if(stmts[stmts.length-1] instanceof ReturnStatement ) + returnStmt = "\t" + stmts[stmts.length-1].toCJ() + "\n"; + else + stmtList += "\t" + stmts[stmts.length-1].toCJ() + "\n"; + } + + CJUtils.spawnParamSet.clear(); + + String classStr = ""; + if(className.isPresent()) + classStr = className.get()+"."; + String preSpawn = ""; + String postSpawn = ""; + if(useSpawn){ + preSpawn = "\tvar futureList = ArrayList>()\n"; + postSpawn = "\tfor (fut in futureList) { fut.get() }\n"; + } + if(funcName.equals("main")) + return funcName+ "(" + paramList+"): " + returnType.toCJ() + " {\n" + preSpawn + stmtList + postSpawn + returnStmt + "}\n"; + else + return (CJUtils.inClass ?"public static func " : "func ")+ classStr + funcName+ "(" + paramList+"): " + returnType.toCJ() + " {\n" + preSpawn + stmtList + postSpawn + returnStmt + "}\n"; + } } diff --git a/src/main/java/com/example/codegen/NewArrayExpression.java b/src/main/java/com/example/codegen/NewArrayExpression.java index 774083856e733336a6dd098ebc10aaca9e1b4231..fb0bb25a4258ce517991f98474de5c4b021066a7 100644 --- a/src/main/java/com/example/codegen/NewArrayExpression.java +++ b/src/main/java/com/example/codegen/NewArrayExpression.java @@ -1,5 +1,7 @@ package com.example.codegen; +import com.example.utils.CJUtils; + public class NewArrayExpression implements Expression { public Type type; public long dimensions; @@ -32,4 +34,18 @@ public class NewArrayExpression implements Expression { public String toCSharp() { return "new " + type.toCSharp() + "[" + length.toCSharp() + "]" + "[]".repeat((int) (dimensions - 1)); } + + public String toCJ(){ + assert dimensions > 0; + String innerType = type.toCJ(); + if(innerType.startsWith("Option<")) + innerType = innerType.substring(7, innerType.length()-1); + for (int i = 0; i < dimensions - 1; i++) { + innerType = "?Array<" + innerType + ">"; + } + + String initVal = CJUtils.getDefaultValue(innerType); + + return "Array<" + innerType + ">("+ length.toCJ() + ", item: "+ initVal + ")"; + } } diff --git a/src/main/java/com/example/codegen/NewInstanceExpression.java b/src/main/java/com/example/codegen/NewInstanceExpression.java index 6fe8783616a3aeb825f2ab1f29113de890594f2c..c4ef783ee5b36e34f7ab2439dac898f82b5fae0a 100644 --- a/src/main/java/com/example/codegen/NewInstanceExpression.java +++ b/src/main/java/com/example/codegen/NewInstanceExpression.java @@ -26,4 +26,9 @@ public class NewInstanceExpression implements Expression { public String toCSharp() { return "new " + className.toCSharp() + "()"; } + + @Override + public String toCJ() { + return className.toCJ() + "()"; + } } diff --git a/src/main/java/com/example/codegen/NewStatement.java b/src/main/java/com/example/codegen/NewStatement.java index 3ad55197f94b752341ff0e7ea779af5b641847ad..bab80eebd90ae97bb2ec083680b10d2dab20cd3e 100644 --- a/src/main/java/com/example/codegen/NewStatement.java +++ b/src/main/java/com/example/codegen/NewStatement.java @@ -24,4 +24,9 @@ public class NewStatement implements Statement { public String toCSharp() { return newExpr.toCSharp() + ";"; } + + @Override + public String toCJ() { + return newExpr.toCJ(); + } } diff --git a/src/main/java/com/example/codegen/Parameter.java b/src/main/java/com/example/codegen/Parameter.java index 9bf5443594e2cd8a340389cd64a3029a495956c5..b43c7bc1c9e773432e69efc393ad657361fc8793 100644 --- a/src/main/java/com/example/codegen/Parameter.java +++ b/src/main/java/com/example/codegen/Parameter.java @@ -26,4 +26,9 @@ public class Parameter implements AstNode { public String toCSharp() { return parameterType.toCSharp() + " " + parameterName; } + + @Override + public String toCJ() { + return parameterName + ": " + parameterType.toCJ(); + } } diff --git a/src/main/java/com/example/codegen/Parser.java b/src/main/java/com/example/codegen/Parser.java index 918bab6e6cf1fda27dfe3d495601f6c1ba548ebf..288a7d61fa8fd8496909aef213b6f401b68ec235 100644 --- a/src/main/java/com/example/codegen/Parser.java +++ b/src/main/java/com/example/codegen/Parser.java @@ -131,7 +131,7 @@ public class Parser { // // 实例变量类型, 如 static String str // field = ["static "], type, " ", identifier; - public static Optional parserField(String line) { + public static Optional parserField(String line, String className) { String[] strs = line.strip().split("[;\\s]+"); if (strs.length != 3 && strs.length != 2) { return Optional.empty(); @@ -155,7 +155,7 @@ public class Parser { if (variable.isEmpty()) { return Optional.empty(); } - return Optional.of(new Field(isStatic, type.get(), variable.get())); + return Optional.of(new Field(isStatic, type.get(), variable.get(), className)); } @@ -570,7 +570,7 @@ public class Parser { if (line.strip().isEmpty()) { continue; } - Optional field = parserField(line); + Optional field = parserField(line, className); if (field.isPresent()) { fields.add(field.get()); continue; diff --git a/src/main/java/com/example/codegen/ReturnStatement.java b/src/main/java/com/example/codegen/ReturnStatement.java index 09cdb0d584015da47b4744f46c3e3a4cb79a3f27..9c57e30119a206306e4db166388a117b00029282 100644 --- a/src/main/java/com/example/codegen/ReturnStatement.java +++ b/src/main/java/com/example/codegen/ReturnStatement.java @@ -24,4 +24,9 @@ public class ReturnStatement implements Statement { public String toCSharp() { return "return" + " " + variables.toCSharp() + ";"; } + + @Override + public String toCJ() { + return "return " + variables.toCJ(); + } } diff --git a/src/main/java/com/example/codegen/SpawnExpression.java b/src/main/java/com/example/codegen/SpawnExpression.java index 59bc17e6e00d7f81dd2f0187977256d4a51d7ccb..1be3dc74bc35491c5fb2dd4b28aae850f4d627f0 100644 --- a/src/main/java/com/example/codegen/SpawnExpression.java +++ b/src/main/java/com/example/codegen/SpawnExpression.java @@ -1,10 +1,16 @@ package com.example.codegen; +import com.example.utils.CJUtils; + public class SpawnExpression implements Expression { public CallExpression callExpression; public SpawnExpression(CallExpression callExpression) { this.callExpression = callExpression; + // for CJ let + for(Variables arg : callExpression.args){ + CJUtils.spawnParamSet.add(arg.toCJ()); + } } @Override @@ -26,4 +32,9 @@ public class SpawnExpression implements Expression { public String toCSharp() { return "new Thread(() => " + callExpression.toCSharp() + ")"; } + + @Override + public String toCJ() { + return "spawn { => "+ callExpression.toCJ() +" }"; + } } diff --git a/src/main/java/com/example/codegen/SpawnStatement.java b/src/main/java/com/example/codegen/SpawnStatement.java index ad67c791f4ecfac35b34626bdbfd87e74406014c..b9874c085b485cecc16b8f3956b0e109f31eadf0 100644 --- a/src/main/java/com/example/codegen/SpawnStatement.java +++ b/src/main/java/com/example/codegen/SpawnStatement.java @@ -30,4 +30,9 @@ public class SpawnStatement implements Statement { public String toCSharp() { return threadsPool + ".Add(" + spawnExpression.toCSharp() + ");\n" + threadsPool + ".Last().Start();"; } + + @Override + public String toCJ() { + return "futureList.append(" + spawnExpression.toCJ() + ")"; + } } diff --git a/src/main/java/com/example/codegen/Type.java b/src/main/java/com/example/codegen/Type.java index 63bc224fc07292f32a8d0f3b3a6f3d48b34dd8a8..cd0ff2668a034bb1cadc35b9dd33cdec0ee14cce 100644 --- a/src/main/java/com/example/codegen/Type.java +++ b/src/main/java/com/example/codegen/Type.java @@ -1,6 +1,10 @@ package com.example.codegen; +import com.example.utils.CJUtils; + +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; public class Type implements AstNode { public String type; @@ -146,4 +150,36 @@ public class Type implements AstNode { public String toCSharp() { return toCSharpType(type) + "[]".repeat(dimension); } + + public static String toCJType(String type){ + Map map = new HashMap<>(); + map.put("byte", "Byte"); + map.put("char", "Char"); + map.put("boolean", "Bool"); + map.put("short", "Int8"); + map.put("int", "Int64"); + map.put("float", "Float32"); + map.put("double", "Float64"); + map.put("long", "Int64"); + map.put("void", "Unit"); + map.put("null", "None"); + map.put("", ""); + String res = type; + if(map.containsKey(res)) + res = map.get(res); + if(CJUtils.defaultValue.containsKey(res)) + return res; + return "?" + res; + } + + public String toCJ(){ + String typeTem = type; + if(type.equals("java_lang_Object")) + typeTem = "Object"; + String res = toCJType(typeTem); + for (int i = 0; i < dimension; i++) { + res = "?Array<" + res + ">"; + } + return res; + } } diff --git a/src/main/java/com/example/codegen/Variable.java b/src/main/java/com/example/codegen/Variable.java index 15f6a80acc53c468289ee5f5c1762cfa9edd65d7..e00da878a31a038b7ca36effd5aa1ce6933fea5f 100644 --- a/src/main/java/com/example/codegen/Variable.java +++ b/src/main/java/com/example/codegen/Variable.java @@ -1,7 +1,9 @@ package com.example.codegen; import java.util.Arrays; +import java.util.HashSet; import java.util.Optional; +import java.util.Set; public class Variable implements Expression { // please handle null for each language in the toXXX method @@ -14,7 +16,23 @@ public class Variable implements Expression { // filter the empty string this.indexes = indexes.map(indexes1 -> Arrays.stream(indexes1).filter(index -> !index.isEmpty()).toArray(String[]::new)); } + public static Set keywords = new HashSet<>(); + static { + String[] words = { + "as", "abstract", "break", "Bool", "case", "catch", "class", "const", "continue", + "Char", "do", "else", "enum", "extend", "for", "from", "func", "false", "finally", + "foreign", "Float16", "Float32", "Float64", "if", "in", "is", "init", "import", + "interface", "Int8", "Int16", "Int32", "Int64", "IntNative", "let", "mut", "main", + "macro", "match", "Nothing", "open", "operator", "override", "prop", "public", + "package", "private", "protected", "quote", "redef", "return", "spawn", "super", + "static", "struct", "synchronized", "try", "this", "true", "type", "throw", "This", + "unsafe", "Unit", "UInt8", "UInt16", "UInt32", "UInt64", "UIntNative", "var", "where", "while" + }; + for (String word : words) { + keywords.add(word); + } + } public boolean containUpper() { for (char c : identifier.toCharArray()) { if (Character.isUpperCase(c)) { @@ -51,4 +69,19 @@ public class Variable implements Expression { // the null is keyword in C# return (IsCSharpKeywordExpectNULL(identifier) ? "@" + identifier : identifier) + (indexes.map(index -> "[" + String.join("][", index) + "]").orElse("")); } + + @Override + public String toCJ() { + String str = ""; + if(indexes.isPresent()){ + for(String s : indexes.get()) + str += ".getOrThrow()["+ s +"]"; + } + if(keywords.contains(identifier)) + return identifier+"HadTurn" + str; + else if(identifier.equals("null")) + return "None" + str; + else + return identifier + str; + } } diff --git a/src/main/java/com/example/codegen/Variables.java b/src/main/java/com/example/codegen/Variables.java index 6a8e87c945110e2777ab68734bf795538a23bc6f..f15b54245b7a5139eff222e86dcb50d1afa41387 100644 --- a/src/main/java/com/example/codegen/Variables.java +++ b/src/main/java/com/example/codegen/Variables.java @@ -1,11 +1,14 @@ package com.example.codegen; +import com.example.utils.CJUtils; +import com.example.utils.classNode; + import java.util.ArrayList; import java.util.Optional; public class Variables implements Expression { // resvered for force cast - // please wrap both type and variables in a bracket if you want to force cast like (int)(a.b) + // please wrap the type and variables in a bracket if you want to force cast like (int)(a.b) public Optional type; public ArrayList variables; @@ -46,4 +49,81 @@ public class Variables implements Expression { public String toCSharp() { return (type.isPresent() ? "(" + type.get().toJava() + ")" : "") + (type.isPresent() ? "(" : "") + String.join(".", variables.stream().map(Expression::toCSharp).toArray(String[]::new)) + (type.isPresent() ? ")" : ""); } + + public static String getFromWhichClass(String classNow, String field){ + classNode tmp = CJUtils.classNodes.get(classNow.toLowerCase()); + if(tmp != null){ + for(Field field1 : tmp.fields){ + if(field1.fieldName.toCJ().replaceFirst("HadTurn$","").equals(field)){ + return classNow; + } + } + // no found + if(tmp.parent != null){ + return getFromWhichClass(tmp.parent, field); + } + } + return ""; + } + public static String getClassNameOfField(String fieldName, String className){ + classNode nowNode = CJUtils.classNodes.get(className.toLowerCase()); + if(nowNode == null) return ""; + for(Field field: nowNode.fields){ + if(field.fieldName.toCJ().equals(fieldName)){ + return field.fieldType.toCJ().replace("?", ""); + } + } + return ""; + } + @Override + public String toCJ() { + String res = ""; + if(CJUtils.isVariableNameNormalized) { + int size = variables.size(); + if (size < 1) + return null; + else if (size == 1) + res = variables.get(0).toCJ(); + else { + String firstVar = variables.get(0).toCJ(); + String classOfFirst = firstVar.replaceFirst("(_\\d+)$", ""); + + if (CJUtils.classNodes.containsKey(classOfFirst)) + classOfFirst = CJUtils.classNodes.get(classOfFirst).className; + else if (CJUtils.classNodes.containsKey(classOfFirst.replaceFirst("(_array_\\d+_\\d+)$", ""))) + classOfFirst = CJUtils.classNodes.get(classOfFirst.replaceFirst("(_array_\\d+_\\d+)$", "")).className; + + for (int i = 1; i < variables.size(); i++) { + String tmp = variables.get(i).toCJ(); + String tmpClass = getFromWhichClass(classOfFirst, variables.get(i).identifier); + String frontClass = tmpClass.equals("") ? "" : tmpClass + "_"; + if (!firstVar.equals(classOfFirst)) + res += firstVar + ".getOrThrow()." + frontClass; + else + res += firstVar + "." + frontClass; + firstVar = tmp; + classOfFirst = getClassNameOfField(variables.get(i).identifier, tmpClass); + } + res += firstVar; + } + } else { + for (int i = 0; i < variables.size()-1; i++) { + String tmp = variables.get(i).toCJ(); + if(Type.classSet.contains(tmp)){ + res += tmp + "."; + } else { + res += tmp + ".getOrThrow()."; + } + } + res += variables.get(variables.size()-1).toCJ(); + } + if(type.isPresent()){ + String typeName = type.get().toCJ(); + if(typeName.startsWith("?Array<")) + return res; + if(typeName.charAt(0) == '?') + return "turnClass(" + res + ")"; + } + return res; + } } diff --git a/src/main/java/com/example/utils/CJUtils.java b/src/main/java/com/example/utils/CJUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..7fc873339ceb6ceb9b25d95c790553568e6290f7 --- /dev/null +++ b/src/main/java/com/example/utils/CJUtils.java @@ -0,0 +1,33 @@ +package com.example.utils; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class CJUtils { + // 变量名是否规格化 + public static boolean isVariableNameNormalized = true; + public static boolean inClass = false; + public static Set spawnParamSet = new HashSet<>(); + public static Map classNodes = new HashMap<>(); + public static Map defaultValue = new HashMap<>(); + static { + defaultValue.put("Byte", "0"); + defaultValue.put("Char", "' '"); + defaultValue.put("Bool", "false"); + defaultValue.put("Int8", "0"); + defaultValue.put("Int32", "0"); + defaultValue.put("Float32", "0.0"); + defaultValue.put("Float64", "0.0"); + defaultValue.put("Int64", "0"); + defaultValue.put("Unit", "()"); + defaultValue.put("String", "\"\""); + } + public static String getDefaultValue(String rawType){ + if(defaultValue.containsKey(rawType)){ + return defaultValue.get(rawType); + } + return "None"; + } +} diff --git a/src/main/java/com/example/utils/classNode.java b/src/main/java/com/example/utils/classNode.java new file mode 100644 index 0000000000000000000000000000000000000000..2bc1c66fddcd202f0f505b57a5597c28de2d4b12 --- /dev/null +++ b/src/main/java/com/example/utils/classNode.java @@ -0,0 +1,16 @@ +package com.example.utils; + +import com.example.codegen.Field; + +import java.util.HashSet; +import java.util.Set; + +public class classNode { + public String className; + public String parent; + public Set fields = new HashSet<>(); + public classNode(String className, String parent){ + this.className = className; + this.parent = parent; + } +}