1
0

refactor: finish refactor ExpFctsAnalyzer in BMapBinder

This commit is contained in:
2026-01-28 12:00:40 +08:00
parent 0202266ce5
commit f5645a06de
13 changed files with 340 additions and 746 deletions

View File

@@ -1,286 +0,0 @@
import java.io.OutputStreamWriter;
import java.util.Vector;
import java.util.stream.Collectors;
public class CSharpWriter {
/**
* The class represent the C# type corresponding to extracted variable type.
*/
private static class CsInteropType {
public CsInteropType() {
mMarshalAs = null;
mCsType = null;
}
/**
* The argument of MarshalAsAttribute constructor. In generation, this field
* should be used like this: "[MarshalAs(THIS)]" (for parameter) or "[return:
* MarshalAs(THIS)]" (for return value).
*/
public String mMarshalAs;
/**
* The C# type used in interop function declaration for corresponding parameter.
*/
public String mCsType;
}
/**
* C# specified function which get C# used interop MarshalAs constructor
* arguments and C# type used in interop function declaration.
*
* @param vt The instance of {@linkplain VariableType} for fetching interop
* type.
* @return The corresponding interop type of given variable type.
*/
private static CsInteropType getCsInteropType(ExpFctParamDecl paramdecl) {
// get essential variable type properties first
VariableType vt = paramdecl.mVarType;
String vt_base_type = vt.getBaseType();
int vt_pointer_level = vt.getPointerLevel();
// create return value
CsInteropType ret = new CsInteropType();
// use "switch" to check variable type
switch (vt_base_type) {
case "CKSTRING":
// decide direction cookies
String direction_cookie = "";
if (paramdecl.mIsInput) {
direction_cookie = "In";
} else {
direction_cookie = "Out";
}
// only allow 0 and 1 pointer level for string.
switch (vt_pointer_level) {
case 0:
ret.mMarshalAs = "UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringMarshaler), MarshalCookie = \"" + direction_cookie + "\"";
// ret.mMarshalAs = "UnmanagedType.LPUTF8Str";
ret.mCsType = "string";
break;
case 1:
ret.mMarshalAs = "UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(BMStringArrayMarshaler), MarshalCookie = \"" + direction_cookie + "\"";
ret.mCsType = "string[]";
break;
}
break;
case "CKDWORD":
if (vt_pointer_level == 0) {
ret.mMarshalAs = "UnmanagedType.U4";
ret.mCsType = "uint";
} else {
ret.mMarshalAs = "UnmanagedType.SysInt";
ret.mCsType = "IntPtr";
}
break;
case "CKWORD":
if (vt_pointer_level == 0) {
ret.mMarshalAs = "UnmanagedType.U2";
ret.mCsType = "ushort";
} else {
ret.mMarshalAs = "UnmanagedType.SysInt";
ret.mCsType = "IntPtr";
}
break;
case "CKINT":
if (vt_pointer_level == 0) {
ret.mMarshalAs = "UnmanagedType.I4";
ret.mCsType = "int";
} else {
ret.mMarshalAs = "UnmanagedType.SysInt";
ret.mCsType = "IntPtr";
}
break;
case "bool":
if (vt_pointer_level == 0) {
ret.mMarshalAs = "UnmanagedType.U1";
ret.mCsType = "bool";
} else {
ret.mMarshalAs = "UnmanagedType.SysInt";
ret.mCsType = "IntPtr";
}
break;
case "CKFLOAT":
if (vt_pointer_level == 0) {
ret.mMarshalAs = "UnmanagedType.R4";
ret.mCsType = "float";
} else {
ret.mMarshalAs = "UnmanagedType.SysInt";
ret.mCsType = "IntPtr";
}
break;
case "CKBYTE":
if (vt_pointer_level == 0) {
ret.mMarshalAs = "UnmanagedType.U1";
ret.mCsType = "byte";
} else {
ret.mMarshalAs = "UnmanagedType.SysInt";
ret.mCsType = "IntPtr";
}
break;
case "CK_ID":
if (vt_pointer_level == 0) {
ret.mMarshalAs = "UnmanagedType.U4";
ret.mCsType = "uint";
} else {
ret.mMarshalAs = "UnmanagedType.SysInt";
ret.mCsType = "IntPtr";
}
break;
case "NakedOutputCallback":
// callback actually is a function pointer
// so it only allow base type without any pointer level.
if (vt_pointer_level == 0) {
ret.mMarshalAs = "UnmanagedType.FunctionPtr";
ret.mCsType = "OutputCallback";
}
break;
case "BMFile":
// In any case, BMFile only should be raw pointer
if (vt_pointer_level != 0) {
ret.mMarshalAs = "UnmanagedType.SysInt";
ret.mCsType = "IntPtr";
}
break;
case "BMMeshTransition":
// In any case, BMMeshTransition only should be raw pointer
if (vt_pointer_level != 0) {
ret.mMarshalAs = "UnmanagedType.SysInt";
ret.mCsType = "IntPtr";
}
break;
case "VxVector3":
if (vt_pointer_level == 0) {
ret.mMarshalAs = "UnmanagedType.Struct";
ret.mCsType = "VxVector3";
} else {
ret.mMarshalAs = "UnmanagedType.SysInt";
ret.mCsType = "IntPtr";
}
break;
case "VxVector2":
if (vt_pointer_level == 0) {
ret.mMarshalAs = "UnmanagedType.Struct";
ret.mCsType = "VxVector2";
} else {
ret.mMarshalAs = "UnmanagedType.SysInt";
ret.mCsType = "IntPtr";
}
break;
case "VxColor":
if (vt_pointer_level == 0) {
ret.mMarshalAs = "UnmanagedType.Struct";
ret.mCsType = "VxColor";
} else {
ret.mMarshalAs = "UnmanagedType.SysInt";
ret.mCsType = "IntPtr";
}
break;
case "VxMatrix":
if (vt_pointer_level == 0) {
ret.mMarshalAs = "UnmanagedType.Struct";
ret.mCsType = "VxMatrix";
} else {
ret.mMarshalAs = "UnmanagedType.SysInt";
ret.mCsType = "IntPtr";
}
break;
case "CK_TEXTURE_SAVEOPTIONS":
case "VX_PIXELFORMAT":
case "VXLIGHT_TYPE":
case "VXTEXTURE_BLENDMODE":
case "VXTEXTURE_FILTERMODE":
case "VXTEXTURE_ADDRESSMODE":
case "VXBLEND_MODE":
case "VXFILL_MODE":
case "VXSHADE_MODE":
case "VXCMPFUNC":
case "VXMESH_LITMODE":
// all enum type use the same strategy
if (vt_pointer_level == 0) {
// all enum type should be marshaled as its underlying type
// but we can use its name in C# directly.
ret.mMarshalAs = "UnmanagedType.U4";
ret.mCsType = vt_base_type;
} else {
// for pointer type, use IntPtr instead.
ret.mMarshalAs = "UnmanagedType.SysInt";
ret.mCsType = "IntPtr";
}
break;
}
// check whether we successfully get result
if (ret.mMarshalAs == null || ret.mCsType == null) {
throw new IllegalArgumentException("Unexpected type: " + vt.toCType());
}
// return value
return ret;
}
public static void writeCSharpCode(Vector<ExpFctDecl> data) throws Exception {
OutputStreamWriter writer = CommonHelper.openWriter("dest/BMExports.cs");
IndentHelper helper = new IndentHelper(writer);
// write function decls
for (ExpFctDecl fctdecl : data) {
// write annotation
// summary (just plain function name)
helper.printf("/// <summary>%s</summary>", fctdecl.mFctName);
// parameter list
for (ExpFctParamDecl paramdecl : fctdecl.mFctParams) {
helper.printf("/// <param name=\"%s\">Type: %s. %s%s</param>", paramdecl.mVarName,
paramdecl.mVarType.toCType(), (paramdecl.mIsInput ? "" : "This is OUT parameter. "),
paramdecl.mVarDesc);
}
// return value
helper.puts("/// <returns>True if no error, otherwise False.</returns>");
// write real function declaration
// first, write DllImportAttribute
helper.printf(
"[DllImport(g_DllName, EntryPoint = \"%s\", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi, ExactSpelling = true)]",
fctdecl.mFctName);
// second, write return value MarshalAsAttribute
helper.printf("[return: MarshalAs(UnmanagedType.U1)]");
// then, before we write function body, we need origanize its parameter list
// first
Vector<String> cs_param_list = new Vector<String>();
for (ExpFctParamDecl paramdecl : fctdecl.mFctParams) {
// create string builder
StringBuilder sb = new StringBuilder();
// push in out symbol
if (paramdecl.mIsInput) {
sb.append("[In, ");
} else {
sb.append("[Out, ");
}
// get interop type now
CsInteropType interop_type = getCsInteropType(paramdecl);
// push MarshalAsAttribute
sb.append("MarshalAs(");
sb.append(interop_type.mMarshalAs);
sb.append(")] ");
// push out keyword if parameter is out parameter
if (!paramdecl.mIsInput) {
sb.append("out ");
}
// push parameter cs type
sb.append(interop_type.mCsType);
sb.append(" ");
// push parameter name
sb.append(paramdecl.mVarName);
// insert built string into list
cs_param_list.add(sb.toString());
}
// join built parameter list and output real function declaration
helper.printf("internal static extern bool %s(%s);", fctdecl.mFctName,
cs_param_list.stream().collect(Collectors.joining(", ")));
}
writer.close();
}
}

View File

@@ -3,29 +3,32 @@ import java.io.FileOutputStream;
//import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
public class CommonHelper {
// public static InputStreamReader openReader(String filename) throws Exception {
// FileInputStream fs = new FileInputStream(filename);
// return new InputStreamReader(fs, StandardCharsets.UTF_8);
// }
// =========== File Operations ===========
public static OutputStreamWriter openWriter(String filename) throws Exception {
FileOutputStream fs = new FileOutputStream(filename);
return new OutputStreamWriter(fs, StandardCharsets.UTF_8);
private static Path getRootDirectoryPath() throws Exception {
String rootDir = System.getenv("BMAP_BINDER_ROOT");
if (rootDir == null) {
throw new RuntimeException("Can not find essential environment variable BMAP_BINDER_ROOT");
} else {
return Paths.get(rootDir);
}
}
// public static void writeSnippet(OutputStreamWriter writer, String snippet_path) throws Exception {
// // open snippet
// InputStreamReader reader = openReader(snippet_path);
// // write into writer
// reader.transferTo(writer);
// reader.close();
// }
public static String getDoxygenInOutStr(boolean isInput) {
return isInput ? "in" : "out";
public static String getInputFilePath(String filename) throws Exception {
Path rootDir = getRootDirectoryPath();
Path filePath = rootDir.resolve("Extracted").resolve(filename);
return filePath.toString();
}
public static String getOutputFilePath(String filename) throws Exception {
Path rootDir = getRootDirectoryPath();
Path filePath = rootDir.resolve("Analyzed").resolve(filename);
return filePath.toString();
}
}

View File

@@ -1,29 +0,0 @@
import java.util.Vector;
/**
* The class represent an export BMap function.
*/
public class ExpFctDecl {
/**
* The name of this function.
*/
public String mFctName;
/**
* The return value type of this function.
*/
public VariableType mFctRetType;
/**
* The parameters (arguments) list of this function. Each items are
* {@linkplain ExpFctParamDecl} and represent parameter one by one from left to
* right.
*/
public Vector<ExpFctParamDecl> mFctParams;
public ExpFctDecl() {
mFctName = "";
mFctRetType = new VariableType();
mFctParams = new Vector<ExpFctParamDecl>();
}
}

View File

@@ -1,48 +0,0 @@
/**
* The class represent a single parameter (argument) of function. This class
* usually is the member of {@linkplain ExpFctDecl}.
*/
public class ExpFctParamDecl {
/**
* The type of this parameter.
*/
public VariableType mVarType;
/**
* The name of this parameter.
*/
public String mVarName;
/**
* True if this paramter is marked as input parameter, otherwise false.
* <p>
* Input parameter and output paramter is commonly used in C/C++ code. By using
* this feature, each function can receive multiple arguments and return
* multiple arguments without defining a struct to hold it.
* <p>
* The type of input parameter is itself. However, the type of output parameter
* is the pointer of itself. So you may need get its pointer type when
* processing output paramter, especially for the scenario that the target
* language do not support explicit output parameter keyword.
*/
public boolean mIsInput;
/**
* The description of this parameter.
* <p>
* This description is generated by this program. It will indicate the
* underlying C++ type to tell end user how to treat this paramter because some
* target languages' native calling style can not represent these detail.
* <p>
* In this program, this field must be written as a annotation of corresponding
* function.
*/
public String mVarDesc;
public ExpFctParamDecl() {
mVarType = new VariableType();
mVarName = "";
mVarDesc = "";
mIsInput = true;
}
}

View File

@@ -0,0 +1,248 @@
import java.util.Collections;
import java.util.Vector;
import java.util.stream.Collectors;
public class ExpFctsHelper {
/**
* The class represent the type of each parameters and function return value.
*/
public static class VariableType {
/**
* The base type of this variable removing all ending stars (remove all pointer levels).
* Each item in this Vector is a part of namespace and the last one must be the type itself
* (without any namespace constraint).
* If no namespace constraint for this type, this Vector will only have one item.
* <p>
* For end user, it is enough that knowing the last item is type itself.
*/
private Vector<String> mBaseType;
/**
* The pointer level of this type. It is equal to the count of trailing star of
* this field in C style representation.
*/
private int mPointerLevel;
/**
* Construct an empty varible type. This is commonly used constructor.
*/
public VariableType() {
mBaseType = new Vector<String>();
mPointerLevel = 0;
}
/**
* The constructor used for cloning self. This constructor is only can be used
* by self.
*
* @param base_type The hierarchy of the variable type.
* @param pointer_level The pointer level of new created variable type.
*/
private VariableType(Vector<String> base_type, int pointer_level) {
mBaseType = (Vector<String>) base_type.clone();
mPointerLevel = pointer_level;
}
/**
* Set this variable type with a type string in C/C++ style. For example
* "NSTest::NSTest2::MyType**".
*
* @param ctype The type string in C/C++ style.
*/
public void fromCType(String ctype) {
if (ctype.isEmpty())
throw new IllegalArgumentException("empty string can not be parsed.");
// get pointer part and name part
int len = ctype.length();
int star_pos = ctype.indexOf('*');
String namepart;
if (star_pos == -1) {
// no star
namepart = ctype;
mPointerLevel = 0;
} else {
// has star
if (star_pos == 0)
throw new IllegalArgumentException("base type not found.");
namepart = ctype.substring(0, star_pos);
mPointerLevel = len - star_pos;
}
// resolve name part
mBaseType.clear();
for (String item : namepart.split("::")) {
mBaseType.add(item);
}
}
/**
* Build a type string represented by this variable type in C/C++ style.
*
* @return The type string in C/C++ style.
*/
public String toCType() {
return mBaseType.stream().collect(Collectors.joining("::"))
+ String.join("", Collections.nCopies(mPointerLevel, "*"));
}
/**
* Get the base type of this variable type without any namespace. It just simply
* get the last entry in type hierarchy.
*
* @return The base type string without namespace prefix.
*/
public String getBaseType() {
return mBaseType.lastElement();
}
/**
* Check whether this variable type is a pointer. This function just check
* whether the pointer level of this variavle type is zero.
*
* @return True if it is pointer, otherwise false.
*/
public boolean isPointer() {
return mPointerLevel != 0;
}
/**
* Return the pointer level of this variable type. You can simply assume the
* pointer level is equal to the count of trailing star.
*
* @return The pointer level integer. Zero means that this type is not a
* pointer.
*/
public int getPointerLevel() {
return mPointerLevel;
}
/**
* Return the clone of the type hierarchy of this variable type.
* <p>
* It is rarely used. This only should be used when you need the namespace
* hierarchy of this variable type.
*
* @return The clone of current variable type hierarchy.
*/
public Vector<String> getBaseTypeHierarchy() {
return (Vector<String>) mBaseType.clone();
}
/**
* Check whether this type is a valid one. It actually check whether type
* hierarchy include at least one entry.
*
* @return True if no problem of this type, otherwise false.
*/
public boolean isValid() {
return mBaseType.size() != 0;
}
/**
* Return a new created variable type which is the pointer of this variable
* type.
* <p>
* In internal implementation, it just create a clone of current variable type
* with the increase of pointer level by 1.
*
* @return The new created pointer type of this variable type.
*/
public VariableType getPointerOfThis() {
return new VariableType(mBaseType, mPointerLevel + 1);
}
}
/**
* The class represent a single parameter (argument) of function. This class
* usually is the member of {@linkplain ExpFct}.
*/
public static class ExpFctParam {
/**
* The type of this parameter.
*/
public VariableType mVarType;
/**
* The name of this parameter.
*/
public String mVarName;
/**
* True if this paramter is marked as input parameter, otherwise false.
* <p>
* Input parameter and output paramter is commonly used in C/C++ code. By using
* this feature, each function can receive multiple arguments and return
* multiple arguments without defining a struct to hold it.
* <p>
* The type of input parameter is itself. However, the type of output parameter
* is the pointer of itself. So you may need get its pointer type when
* processing output paramter, especially for the scenario that the target
* language do not support explicit output parameter keyword.
*/
public boolean mIsInput;
/**
* The description of this parameter.
* <p>
* This description is generated by this program. It will indicate the
* underlying C++ type to tell end user how to treat this paramter because some
* target languages' native calling style can not represent these detail.
* <p>
* In this program, this field must be written as a annotation of corresponding
* function.
*/
public String mVarDesc;
public ExpFctParam() {
mVarType = new VariableType();
mVarName = "";
mVarDesc = "";
mIsInput = true;
}
}
/**
* The class represent an export BMap function.
*/
public static class ExpFct {
/**
* The name of this function.
*/
public String mFctName;
/**
* The return value type of this function.
*/
public VariableType mFctRetType;
/**
* The parameters (arguments) list of this function. Each items are
* {@linkplain ExpFctParam} and represent parameter one by one from left to
* right.
*/
public Vector<ExpFctParam> mFctParams;
public ExpFct() {
mFctName = "";
mFctRetType = new VariableType();
mFctParams = new Vector<ExpFctParam>();
}
}
/**
* The class represent a collection of export BMap functions.
*/
public static class ExpFctCollection {
/**
* The collection of exported BMap functions.
*/
public Vector<ExpFct> mFcts;
public ExpFctCollection() {
mFcts = new Vector<ExpFct>();
}
}
}

View File

@@ -1,34 +1,30 @@
import java.util.Collections;
import java.util.Vector;
import java.util.stream.Collectors;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;
public class ExpFctsWalker extends ExpFctsParserBaseListener {
public ExpFctsWalker() {
mFctList = new Vector<ExpFctDecl>();
mFctCollection = null;
mCurrentFct = null;
mCurrentParam = null;
}
public Vector<ExpFctDecl> getResult() {
return mFctList;
public ExpFctsHelper.ExpFctCollection getResult() {
return mFctCollection;
}
private Vector<ExpFctDecl> mFctList;
private ExpFctDecl mCurrentFct;
private ExpFctParamDecl mCurrentParam;
private ExpFctsHelper.ExpFctCollection mFctCollection;
private ExpFctsHelper.ExpFct mCurrentFct;
private ExpFctsHelper.ExpFctParam mCurrentParam;
@Override
public void enterProgram(ExpFctsParser.ProgramContext ctx) {
mFctList.clear();
mFctCollection = new ExpFctsHelper.ExpFctCollection();
}
@Override
public void enterFctDecl(ExpFctsParser.FctDeclContext ctx) {
mCurrentFct = new ExpFctDecl();
mCurrentFct = new ExpFctsHelper.ExpFct();
}
@Override
@@ -41,50 +37,50 @@ public class ExpFctsWalker extends ExpFctsParserBaseListener {
throw new IllegalArgumentException("invalid interface function return type. must be bool.");
// add into list
mFctList.add(mCurrentFct);
mFctCollection.mFcts.add(mCurrentFct);
mCurrentFct = null;
}
@Override
public void exitFctArgFileDecl(ExpFctsParser.FctArgFileDeclContext ctx) {
ExpFctParamDecl decl = new ExpFctParamDecl();
decl.mVarName = ctx.EXPFCTS_IDENTIFIER().getText();
decl.mVarDesc = "The pointer to corresponding BMFile.";
decl.mIsInput = true;
decl.mVarType.fromCType("BMap::BMFile*");
mCurrentFct.mFctParams.add(decl);
ExpFctsHelper.ExpFctParam param = new ExpFctsHelper.ExpFctParam();
param.mVarName = ctx.EXPFCTS_IDENTIFIER().getText();
param.mVarDesc = "The pointer to corresponding BMFile.";
param.mIsInput = true;
param.mVarType.fromCType("BMap::BMFile*");
mCurrentFct.mFctParams.add(param);
}
@Override
public void exitFctArgMeshTransDecl(ExpFctsParser.FctArgMeshTransDeclContext ctx) {
ExpFctParamDecl decl = new ExpFctParamDecl();
decl.mVarName = ctx.EXPFCTS_IDENTIFIER().getText();
decl.mVarDesc = "The pointer to corresponding BMMeshTransition.";
decl.mIsInput = true;
decl.mVarType.fromCType("BMap::BMMeshTransition*");
mCurrentFct.mFctParams.add(decl);
ExpFctsHelper.ExpFctParam param = new ExpFctsHelper.ExpFctParam();
param.mVarName = ctx.EXPFCTS_IDENTIFIER().getText();
param.mVarDesc = "The pointer to corresponding BMMeshTransition.";
param.mIsInput = true;
param.mVarType.fromCType("BMap::BMMeshTransition*");
mCurrentFct.mFctParams.add(param);
}
@Override
public void exitFctArgObjDecl(ExpFctsParser.FctArgObjDeclContext ctx) {
ExpFctParamDecl first_decl = new ExpFctParamDecl();
first_decl.mVarName = ctx.EXPFCTS_IDENTIFIER(0).getText();
first_decl.mVarDesc = "The pointer to corresponding BMFile.";
first_decl.mIsInput = true;
first_decl.mVarType.fromCType("BMap::BMFile*");
mCurrentFct.mFctParams.add(first_decl);
ExpFctsHelper.ExpFctParam firstParam = new ExpFctsHelper.ExpFctParam();
firstParam.mVarName = ctx.EXPFCTS_IDENTIFIER(0).getText();
firstParam.mVarDesc = "The pointer to corresponding BMFile.";
firstParam.mIsInput = true;
firstParam.mVarType.fromCType("BMap::BMFile*");
mCurrentFct.mFctParams.add(firstParam);
ExpFctParamDecl second_decl = new ExpFctParamDecl();
second_decl.mVarName = ctx.EXPFCTS_IDENTIFIER(1).getText();
second_decl.mVarDesc = "The CKID of object you accessing.";
second_decl.mIsInput = true;
second_decl.mVarType.fromCType("LibCmo::CK2::CK_ID");
mCurrentFct.mFctParams.add(second_decl);
ExpFctsHelper.ExpFctParam secondParam = new ExpFctsHelper.ExpFctParam();
secondParam.mVarName = ctx.EXPFCTS_IDENTIFIER(1).getText();
secondParam.mVarDesc = "The CKID of object you accessing.";
secondParam.mIsInput = true;
secondParam.mVarType.fromCType("LibCmo::CK2::CK_ID");
mCurrentFct.mFctParams.add(secondParam);
}
@Override
public void enterFctArgParamIn(ExpFctsParser.FctArgParamInContext ctx) {
mCurrentParam = new ExpFctParamDecl();
mCurrentParam = new ExpFctsHelper.ExpFctParam();
}
@Override
@@ -98,7 +94,7 @@ public class ExpFctsWalker extends ExpFctsParserBaseListener {
@Override
public void enterFctArgParamOut(ExpFctsParser.FctArgParamOutContext ctx) {
mCurrentParam = new ExpFctParamDecl();
mCurrentParam = new ExpFctsHelper.ExpFctParam();
}
@Override

View File

@@ -1,42 +0,0 @@
import java.io.OutputStreamWriter;
public class IndentHelper {
public IndentHelper(OutputStreamWriter writer) {
mIndent = 0;
mWriter = writer;
}
private int mIndent;
private OutputStreamWriter mWriter;
public void inc() {
++mIndent;
}
public void dec() {
--mIndent;
}
private void indent() throws Exception {
for (int i = 0; i < mIndent; ++i) {
mWriter.write(" ");
}
}
private void lineBreak() throws Exception {
mWriter.write(System.lineSeparator());
}
public void puts(String data) throws Exception {
indent();
mWriter.write(data);
lineBreak();
}
public void printf(String fmt, Object... args) throws Exception {
indent();
mWriter.write(String.format(fmt, args));
lineBreak();
}
}

View File

@@ -1,5 +1,7 @@
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.Vector;
import java.nio.charset.StandardCharsets;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.Gson;
@@ -7,7 +9,7 @@ import com.google.gson.GsonBuilder;
public class JsonWriter {
private static JsonObject writeVariableType(VariableType vt) {
private static JsonObject writeVariableType(ExpFctsHelper.VariableType vt) {
JsonObject data = new JsonObject();
JsonArray hierarchy = new JsonArray();
@@ -20,41 +22,44 @@ public class JsonWriter {
return data;
}
private static JsonObject writeExpFctParamDecl(ExpFctParamDecl paramdecl) {
private static JsonObject writeExpFctParam(ExpFctsHelper.ExpFctParam param) {
JsonObject data = new JsonObject();
data.addProperty("name", paramdecl.mVarName);
data.addProperty("is_input", paramdecl.mIsInput);
data.addProperty("desc", paramdecl.mVarDesc);
data.add("type", writeVariableType(paramdecl.mVarType));
data.addProperty("name", param.mVarName);
data.addProperty("is_input", param.mIsInput);
data.addProperty("desc", param.mVarDesc);
data.add("type", writeVariableType(param.mVarType));
return data;
}
private static JsonObject writeExpFctDecl(ExpFctDecl fctdecl) {
private static JsonObject writeExpFct(ExpFctsHelper.ExpFct fct) {
JsonObject data = new JsonObject();
data.addProperty("name", fctdecl.mFctName);
data.add("return", writeVariableType(fctdecl.mFctRetType));
data.addProperty("name", fct.mFctName);
data.add("return", writeVariableType(fct.mFctRetType));
JsonArray paramlist = new JsonArray();
for (ExpFctParamDecl paramdecl : fctdecl.mFctParams) {
paramlist.add(writeExpFctParamDecl(paramdecl));
JsonArray paramList = new JsonArray();
for (ExpFctsHelper.ExpFctParam param : fct.mFctParams) {
paramList.add(writeExpFctParam(param));
}
data.add("params", paramlist);
data.add("params", paramList);
return data;
}
public static void writeJson(Vector<ExpFctDecl> data) throws Exception {
OutputStreamWriter writer = CommonHelper.openWriter("dest/BMExports.json");
//Gson gson_instance = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
Gson gson_instance = new GsonBuilder().disableHtmlEscaping().create();
JsonArray fcts = new JsonArray();
for (ExpFctDecl fctdecl : data) {
fcts.add(writeExpFctDecl(fctdecl));
private static JsonArray writeExpFctCollection(ExpFctsHelper.ExpFctCollection fctCollection) {
JsonArray data = new JsonArray();
for (ExpFctsHelper.ExpFct fct : fctCollection.mFcts) {
data.add(writeExpFct(fct));
}
writer.write(gson_instance.toJson(fcts));
return data;
}
public static void writeJson(ExpFctsHelper.ExpFctCollection data) throws Exception {
FileOutputStream fs = new FileOutputStream(CommonHelper.getOutputFilePath("BMExports.json"));
OutputStreamWriter writer = new OutputStreamWriter(fs, StandardCharsets.UTF_8);
//Gson gsonInstance = new GsonBuilder().serializeNulls().setPrettyPrinting().disableHtmlEscaping().create();
Gson gsonInstance = new GsonBuilder().serializeNulls().disableHtmlEscaping().create();
writer.write(gsonInstance.toJson(writeExpFctCollection(data)));
writer.close();
}
}

View File

@@ -9,9 +9,9 @@ public class MainRunner {
public static void main(String[] args) throws Exception {
// get interface structure
FileInputStream fs = new FileInputStream("dest/BMExports.hpp");
CharStream antlrfs = CharStreams.fromStream(fs, StandardCharsets.UTF_8);
ExpFctsLexer lexer = new ExpFctsLexer(antlrfs);
FileInputStream fs = new FileInputStream(CommonHelper.getInputFilePath("BMExports.hpp"));
CharStream antlrStream = CharStreams.fromStream(fs, StandardCharsets.UTF_8);
ExpFctsLexer lexer = new ExpFctsLexer(antlrStream);
CommonTokenStream tokens = new CommonTokenStream(lexer);
ExpFctsParser parser = new ExpFctsParser(tokens);
@@ -23,12 +23,10 @@ public class MainRunner {
fs.close();
// get data and write them
Vector<ExpFctDecl> result = worker.getResult();
PythonWriter.writePythonCode(result);
CSharpWriter.writeCSharpCode(result);
ExpFctsHelper.ExpFctCollection result = worker.getResult();
JsonWriter.writeJson(result);
// print message.
System.out.println("DONE!");
System.out.println("Done");
}
}

View File

@@ -1,96 +0,0 @@
import java.io.OutputStreamWriter;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import java.util.stream.Collectors;
public class PythonWriter {
private static final Map<String, String> g_CppTypeMap = cppTypeMapCreator();
private static Map<String, String> cppTypeMapCreator() {
Map<String, String> cache = new HashMap<String, String>();
cache.put("CKSTRING", "CKSTRING");
cache.put("CKDWORD", "CKDWORD");
cache.put("CKWORD", "CKWORD");
cache.put("CKINT", "CKINT");
cache.put("bool", "bool");
cache.put("CKFLOAT", "CKFLOAT");
cache.put("CKBYTE", "CKBYTE");
cache.put("CK_ID", "CKID");
cache.put("NakedOutputCallback", "callback");
cache.put("BMFile", "void");
cache.put("BMMeshTransition", "void");
cache.put("VxVector3", "VxVector3");
cache.put("VxVector2", "VxVector2");
cache.put("VxColor", "VxColor");
cache.put("VxMatrix", "VxMatrix");
cache.put("CK_TEXTURE_SAVEOPTIONS", "enum");
cache.put("VX_PIXELFORMAT", "enum");
cache.put("VXLIGHT_TYPE", "enum");
cache.put("VXTEXTURE_BLENDMODE", "enum");
cache.put("VXTEXTURE_FILTERMODE", "enum");
cache.put("VXTEXTURE_ADDRESSMODE", "enum");
cache.put("VXBLEND_MODE", "enum");
cache.put("VXFILL_MODE", "enum");
cache.put("VXSHADE_MODE", "enum");
cache.put("VXCMPFUNC", "enum");
cache.put("VXMESH_LITMODE", "enum");
return Collections.unmodifiableMap(cache);
}
private static String pythonTypeGetter(ExpFctParamDecl paramdecl) throws IllegalArgumentException {
VariableType vt = paramdecl.mVarType;
if (!paramdecl.mIsInput) {
vt = vt.getPointerOfThis();
}
// create string builder for build final type string
StringBuilder sb = new StringBuilder();
// add type prefix
sb.append("bm_");
// try getting cpp type from base type
String cpp_type = g_CppTypeMap.get(vt.getBaseType());
if (cpp_type == null) {
throw new IllegalArgumentException("Unexpected type: " + vt.toCType());
}
// assign cpp type
sb.append(cpp_type);
// add pointer suffix
if (vt.isPointer()) {
sb.append("_");
sb.append(String.join("", Collections.nCopies(vt.getPointerLevel(), "p")));
}
// return built type string.
return sb.toString();
}
public static void writePythonCode(Vector<ExpFctDecl> data) throws Exception {
OutputStreamWriter writer = CommonHelper.openWriter("dest/BMExports.py");
IndentHelper helper = new IndentHelper(writer);
// write function decls
for (ExpFctDecl fctdecl : data) {
// write annotation
// function name
helper.printf("## %s", fctdecl.mFctName);
// param
for (ExpFctParamDecl paramdecl : fctdecl.mFctParams) {
helper.printf("# @param %s[%s] Type: %s. %s%s", paramdecl.mVarName,
CommonHelper.getDoxygenInOutStr(paramdecl.mIsInput), paramdecl.mVarType.toCType(),
(paramdecl.mIsInput ? "" : "Use ctypes.byref(data) pass it. "), paramdecl.mVarDesc);
}
// return val
helper.puts("# @return True if no error, otherwise False.");
// write real declaration
// first, we need join all param
helper.printf("%s = _create_bmap_func('%s', [%s])", fctdecl.mFctName, fctdecl.mFctName, fctdecl.mFctParams
.stream().map(value -> pythonTypeGetter(value)).collect(Collectors.joining(", ")));
}
writer.close();
}
}

View File

@@ -1,153 +0,0 @@
import java.util.Collections;
import java.util.Vector;
import java.util.stream.Collectors;
/**
* The class represent the type of each parameters and function return value.
*/
public class VariableType {
/**
* The base type of this variable removing all ending stars (remove all pointer
* levels) Each item in this a part of namespace and the last one must be the
* type itself (without any namespace restriction). If no namespace restriction
* for this type, this Vector will only have one item.
* <p>
* For end user, it is enough that knowing the last item is type itself.
*/
private Vector<String> mBaseType;
/**
* The pointer level of this type. It is equal to the count of trailing star of
* this field in C style representation.
*/
private int mPointerLevel;
/**
* Construct an empty varible type. This is commonly used constructor.
*/
public VariableType() {
mBaseType = new Vector<String>();
mPointerLevel = 0;
}
/**
* The constructor used for cloning self. This constructor is only can be used
* by self.
*
* @param base_type The hierarchy of the variable type.
* @param pointer_level The pointer level of new created variable type.
*/
private VariableType(Vector<String> base_type, int pointer_level) {
mBaseType = (Vector<String>) base_type.clone();
mPointerLevel = pointer_level;
}
/**
* Set this variable type with a type string in C/C++ style. For example
* "NSTest::NSTest2::MyType**".
*
* @param ctype The type string in C/C++ style.
*/
public void fromCType(String ctype) {
if (ctype.isEmpty())
throw new IllegalArgumentException("empty string can not be parsed.");
// get pointer part and name part
int len = ctype.length();
int star_pos = ctype.indexOf('*');
String namepart;
if (star_pos == -1) {
// no star
namepart = ctype;
mPointerLevel = 0;
} else {
// has star
if (star_pos == 0)
throw new IllegalArgumentException("base type not found.");
namepart = ctype.substring(0, star_pos);
mPointerLevel = len - star_pos;
}
// resolve name part
mBaseType.clear();
for (String item : namepart.split("::")) {
mBaseType.add(item);
}
}
/**
* Build a type string represented by this variable type in C/C++ style.
*
* @return The type string in C/C++ style.
*/
public String toCType() {
return mBaseType.stream().collect(Collectors.joining("::"))
+ String.join("", Collections.nCopies(mPointerLevel, "*"));
}
/**
* Get the base type of this variable type without any namespace. It just simply
* get the last entry in type hierarchy.
*
* @return The base type string without namespace prefix.
*/
public String getBaseType() {
return mBaseType.lastElement();
}
/**
* Check whether this variable type is a pointer. This function just check
* whether the pointer level of this variavle type is zero.
*
* @return True if it is pointer, otherwise false.
*/
public boolean isPointer() {
return mPointerLevel != 0;
}
/**
* Return the pointer level of this variable type. You can simply assume the
* pointer level is equal to the count of trailing star.
*
* @return The pointer level integer. Zero means that this type is not a
* pointer.
*/
public int getPointerLevel() {
return mPointerLevel;
}
/**
* Return the clone of the type hierarchy of this variable type.
* <p>
* It is rarely used. This only should be used when you need the namespace
* hierarchy of this variable type.
*
* @return The clone of current variable type hierarchy.
*/
public Vector<String> getBaseTypeHierarchy() {
return (Vector<String>) mBaseType.clone();
}
/**
* Check whether this type is a valid one. It actually check whether type
* hierarchy include at least one entry.
*
* @return True if no problem of this type, otherwise false.
*/
public boolean isValid() {
return mBaseType.size() != 0;
}
/**
* Return a new created variable type which is the pointer of this variable
* type.
* <p>
* In internal implementation, it just create a clone of current variable type
* with the increase of pointer level by 1.
*
* @return The new created pointer type of this variable type.
*/
public VariableType getPointerOfThis() {
return new VariableType(mBaseType, mPointerLevel + 1);
}
}