add basic python writer for bmap binding

This commit is contained in:
yyc12345 2023-11-02 22:02:39 +08:00
parent bcd58af132
commit 52c2d3f7e0
9 changed files with 260 additions and 6 deletions

View File

@ -0,0 +1,12 @@
import java.io.OutputStreamWriter;
import java.util.Vector;
public class CSharpWriter {
public static void writeCSharpCode(Vector<ExpFctDecl> data) throws Exception {
OutputStreamWriter writer = CommonHelper.openWriter("dest/BMExports.cs");
writer.write("// WIP");
writer.close();
}
}

View File

@ -0,0 +1,31 @@
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
public class CommonHelper {
public static InputStreamReader openReader(String filename) throws Exception {
FileInputStream fs = new FileInputStream(filename);
return new InputStreamReader(fs, StandardCharsets.UTF_8);
}
public static OutputStreamWriter openWriter(String filename) throws Exception {
FileOutputStream fs = new FileOutputStream(filename);
return new OutputStreamWriter(fs, StandardCharsets.UTF_8);
}
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";
}
}

View File

@ -4,10 +4,12 @@ public class ExpFctParamDecl {
public VariableType mVarType;
public String mVarName;
public boolean mIsInput;
public String mVarDesc;
public ExpFctParamDecl() {
mVarType = new VariableType();
mVarName = "";
mVarDesc = "";
mIsInput = true;
}

View File

@ -33,7 +33,14 @@ public class ExpFctsWalker extends ExpFctsParserBaseListener {
@Override
public void exitFctDecl(ExpFctsParser.FctDeclContext ctx) {
// set name
mCurrentFct.mFctName = ctx.EXPFCTS_IDENTIFIER().getText();
// check return type
if (!mCurrentFct.mFctRetType.isValid() || mCurrentFct.mFctRetType.isPointer()
|| !mCurrentFct.mFctRetType.getBaseType().equals("bool"))
throw new IllegalArgumentException("invalid interface function return type. must be bool.");
// add into list
mFctList.add(mCurrentFct);
mCurrentFct = null;
}
@ -42,6 +49,7 @@ public class ExpFctsWalker extends ExpFctsParserBaseListener {
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);
@ -51,6 +59,7 @@ public class ExpFctsWalker extends ExpFctsParserBaseListener {
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);
@ -60,12 +69,14 @@ public class ExpFctsWalker extends ExpFctsParserBaseListener {
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);
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);

View File

@ -0,0 +1,42 @@
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

@ -8,20 +8,24 @@ import org.antlr.v4.runtime.tree.*;
public class MainRunner {
public static void main(String[] args) throws Exception {
// get interface structture
// get interface structure
FileInputStream fs = new FileInputStream("dest/BMExports.hpp");
CharStream antlrfs = CharStreams.fromStream(fs, StandardCharsets.UTF_8);
ExpFctsLexer lexer = new ExpFctsLexer(antlrfs);
CommonTokenStream tokens = new CommonTokenStream(lexer);
ExpFctsParser parser = new ExpFctsParser(tokens);
// parsing data
ParseTree tree = parser.program();
ParseTreeWalker walker = new ParseTreeWalker();
ExpFctsWalker worker = new ExpFctsWalker();
walker.walk(worker, tree);
fs.close();
// get data and write them
Vector<ExpFctDecl> result = worker.getResult();
PythonWriter.writePythonCode(result);
CSharpWriter.writeCSharpCode(result);
// print message.
System.out.println("DONE!");

View File

@ -0,0 +1,85 @@
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("CKINT", "CKINT");
cache.put("bool", "bool");
cache.put("CKFLOAT", "CKFLOAT");
cache.put("CKBYTE", "CKBYTE");
cache.put("CK_ID", "CKID");
cache.put("BMFile", "void");
cache.put("BMMeshTransition", "void");
cache.put("VxVector3", "VxVector2");
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("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");
return Collections.unmodifiableMap(cache);
}
public static String pythonTypeGetter(ExpFctParamDecl paramdecl) {
VariableType vt = paramdecl.mVarType;
if (!paramdecl.mIsInput) {
vt = vt.getPointerOfThis();
}
StringBuilder sb = new StringBuilder();
sb.append("bm_");
sb.append(g_CppTypeMap.get(vt.getBaseType()));
if (vt.isPointer()) {
sb.append("_");
sb.append(String.join("", Collections.nCopies(vt.getPointerLevel(), "p")));
}
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 snippet
CommonHelper.writeSnippet(writer, "snippets/header.py");
// 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

@ -20,7 +20,7 @@ public class VariableType {
}
private VariableType(Vector<String> base_type, int pointer_level) {
mBaseType.addAll(base_type);
mBaseType = (Vector<String>) base_type.clone();
mPointerLevel = pointer_level;
}
@ -64,6 +64,10 @@ public class VariableType {
return mPointerLevel != 0;
}
public int getPointerLevel() {
return mPointerLevel;
}
public boolean isValid() {
return mBaseType.size() != 0;
}

View File

@ -0,0 +1,63 @@
import ctypes, os
#region Type Defines
bm_CKSTRING = ctypes.c_char_p
bm_CKSTRING_p = ctypes.POINTER(bm_CKSTRING)
bm_CKDWORD = ctypes.c_uint32
bm_CKDWORD_p = ctypes.POINTER(bm_CKDWORD)
bm_CKWORD = ctypes.c_uint16
bm_CKWORD_p = ctypes.POINTER(bm_CKWORD)
bm_CKID = ctypes.c_uint32
bm_CKID_p = ctypes.POINTER(bm_CKID)
bm_CKFLOAT = ctypes.c_float
bm_CKFLOAT_p = ctypes.POINTER(bm_CKFLOAT)
bm_CKINT = types.c_int32
bm_enum = bm_CKDWORD
bm_bool = ctypes.c_bool
bm_void_p = ctypes.c_void_p
class bm_VxVector2(ctypes.Structure):
_fields_ = [
('x', bm_CKFLOAT),
('y', bm_CKFLOAT),
]
bm_VxVector2_p = ctypes.POINTER(bm_VxVector2)
class bm_VxVector3(ctypes.Structure):
_fields_ = [
('x', bm_CKFLOAT),
('y', bm_CKFLOAT),
('z', bm_CKFLOAT),
]
bm_VxVector3_p = ctypes.POINTER(bm_VxVector3)
class bm_VxMatrix(ctypes.Structure):
_fields_ = list(
(f'i{idx}', bm_CKFLOAT) for idx in range(16)
)
#endregion
#region BMap Loader
_g_BMapModule: ctypes.CDLL = None
try:
_g_BMapModule = ctypes.cdll.LoadLibrary(
os.path.join(os.path.dirname(__file__), "BMap.dll")
)
except:
_g_BMapModule = None
def is_bmap_available() -> bool:
return _g_BMapModule is not None
def _create_bmap_func(fct_name: str, fct_params: list) -> None:
if _g_BMapModule is None: return None
cache = getattr(_g_BMapModule, fct_name)
cache.argtypes = fct_params
cache.restype = bm_bool
return cache
#endregion