From 52c2d3f7e0f2372b4b9289efe2c390edfe1112cb Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Thu, 2 Nov 2023 22:02:39 +0800 Subject: [PATCH] add basic python writer for bmap binding --- CodeGen/BMapBindings/CSharpWriter.java | 12 ++++ CodeGen/BMapBindings/CommonHelper.java | 31 +++++++++ CodeGen/BMapBindings/ExpFctParamDecl.java | 2 + CodeGen/BMapBindings/ExpFctsWalker.java | 19 +++-- CodeGen/BMapBindings/IndentHelper.java | 42 +++++++++++ CodeGen/BMapBindings/MainRunner.java | 6 +- CodeGen/BMapBindings/PythonWriter.java | 85 +++++++++++++++++++++++ CodeGen/BMapBindings/VariableType.java | 6 +- CodeGen/BMapBindings/snippets/header.py | 63 +++++++++++++++++ 9 files changed, 260 insertions(+), 6 deletions(-) create mode 100644 CodeGen/BMapBindings/CSharpWriter.java create mode 100644 CodeGen/BMapBindings/CommonHelper.java create mode 100644 CodeGen/BMapBindings/IndentHelper.java create mode 100644 CodeGen/BMapBindings/PythonWriter.java create mode 100644 CodeGen/BMapBindings/snippets/header.py diff --git a/CodeGen/BMapBindings/CSharpWriter.java b/CodeGen/BMapBindings/CSharpWriter.java new file mode 100644 index 0000000..ee0480c --- /dev/null +++ b/CodeGen/BMapBindings/CSharpWriter.java @@ -0,0 +1,12 @@ +import java.io.OutputStreamWriter; +import java.util.Vector; + +public class CSharpWriter { + + public static void writeCSharpCode(Vector data) throws Exception { + OutputStreamWriter writer = CommonHelper.openWriter("dest/BMExports.cs"); + writer.write("// WIP"); + writer.close(); + } + +} diff --git a/CodeGen/BMapBindings/CommonHelper.java b/CodeGen/BMapBindings/CommonHelper.java new file mode 100644 index 0000000..f7360b1 --- /dev/null +++ b/CodeGen/BMapBindings/CommonHelper.java @@ -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"; + } + +} diff --git a/CodeGen/BMapBindings/ExpFctParamDecl.java b/CodeGen/BMapBindings/ExpFctParamDecl.java index d4b6368..6531530 100644 --- a/CodeGen/BMapBindings/ExpFctParamDecl.java +++ b/CodeGen/BMapBindings/ExpFctParamDecl.java @@ -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; } diff --git a/CodeGen/BMapBindings/ExpFctsWalker.java b/CodeGen/BMapBindings/ExpFctsWalker.java index 59b4127..f3b9974 100644 --- a/CodeGen/BMapBindings/ExpFctsWalker.java +++ b/CodeGen/BMapBindings/ExpFctsWalker.java @@ -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); @@ -80,7 +91,7 @@ public class ExpFctsWalker extends ExpFctsParserBaseListener { public void exitFctArgParamIn(ExpFctsParser.FctArgParamInContext ctx) { mCurrentParam.mVarName = ctx.EXPFCTS_IDENTIFIER().getText(); mCurrentParam.mIsInput = true; - + mCurrentFct.mFctParams.add(mCurrentParam); mCurrentParam = null; } @@ -95,8 +106,8 @@ public class ExpFctsWalker extends ExpFctsParserBaseListener { mCurrentParam.mVarName = ctx.EXPFCTS_IDENTIFIER().getText(); mCurrentParam.mIsInput = false; // set to its pointer type - //mCurrentParam.mVarType = mCurrentParam.mVarType.getPointerOfThis(); - + // mCurrentParam.mVarType = mCurrentParam.mVarType.getPointerOfThis(); + mCurrentFct.mFctParams.add(mCurrentParam); mCurrentParam = null; } @@ -110,7 +121,7 @@ public class ExpFctsWalker extends ExpFctsParserBaseListener { if (ctx.EXPFCTS_STAR() != null) { ctype += String.join("", Collections.nCopies(ctx.EXPFCTS_STAR().size(), "*")); } - + if (!mCurrentFct.mFctRetType.isValid()) { // fill function ret type first mCurrentFct.mFctRetType.fromCType(ctype); diff --git a/CodeGen/BMapBindings/IndentHelper.java b/CodeGen/BMapBindings/IndentHelper.java new file mode 100644 index 0000000..b4b4e63 --- /dev/null +++ b/CodeGen/BMapBindings/IndentHelper.java @@ -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(); + } + +} diff --git a/CodeGen/BMapBindings/MainRunner.java b/CodeGen/BMapBindings/MainRunner.java index d6207a6..077f661 100644 --- a/CodeGen/BMapBindings/MainRunner.java +++ b/CodeGen/BMapBindings/MainRunner.java @@ -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 result = worker.getResult(); + PythonWriter.writePythonCode(result); + CSharpWriter.writeCSharpCode(result); // print message. System.out.println("DONE!"); diff --git a/CodeGen/BMapBindings/PythonWriter.java b/CodeGen/BMapBindings/PythonWriter.java new file mode 100644 index 0000000..18a4b07 --- /dev/null +++ b/CodeGen/BMapBindings/PythonWriter.java @@ -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 g_CppTypeMap = cppTypeMapCreator(); + + private static Map cppTypeMapCreator() { + Map cache = new HashMap(); + 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 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(); + } + +} diff --git a/CodeGen/BMapBindings/VariableType.java b/CodeGen/BMapBindings/VariableType.java index ac61c84..4988c5c 100644 --- a/CodeGen/BMapBindings/VariableType.java +++ b/CodeGen/BMapBindings/VariableType.java @@ -20,7 +20,7 @@ public class VariableType { } private VariableType(Vector base_type, int pointer_level) { - mBaseType.addAll(base_type); + mBaseType = (Vector) base_type.clone(); mPointerLevel = pointer_level; } @@ -63,6 +63,10 @@ public class VariableType { public boolean isPointer() { return mPointerLevel != 0; } + + public int getPointerLevel() { + return mPointerLevel; + } public boolean isValid() { return mBaseType.size() != 0; diff --git a/CodeGen/BMapBindings/snippets/header.py b/CodeGen/BMapBindings/snippets/header.py new file mode 100644 index 0000000..1dd64a8 --- /dev/null +++ b/CodeGen/BMapBindings/snippets/header.py @@ -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