1
0

refactor: change repo layout

This commit is contained in:
2026-01-24 19:46:23 +08:00
parent 34de35dd31
commit c2dafab217
82 changed files with 0 additions and 170 deletions

182
Assets/CodeGen/BMapBindings/.gitignore vendored Normal file
View File

@@ -0,0 +1,182 @@
# ===== Result =====
dest/*
!dest/*.gitkeep
# ===== Antlr =====
*.interp
*.tokens
ExpFctsLexer*.java
ExpFctsParser*.java
# ===== Python =====
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# ===== Eclipse =====
# Eclipse projects
.classpath
.project
.settings/
.metadata
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*

View File

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

@@ -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

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

@@ -0,0 +1,48 @@
/**
* 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,23 @@
lexer grammar ExpFctsLexer;
// keywords
EXPFCTS_EXPORT: 'BMAP_EXPORT' ;
EXPFCTS_FILE_DECL: 'BMPARAM_FILE_DECL' ;
EXPFCTS_MESHTRANS_DECL: 'BMPARAM_MESHTRANS_DECL' ;
EXPFCTS_OBJECT_DECL: 'BMPARAM_OBJECT_DECL' ;
EXPFCTS_PARAM_IN: 'BMPARAM_IN' ;
EXPFCTS_PARAM_OUT: 'BMPARAM_OUT' ;
// symbols
EXPFCTS_LPARENTHESES: '(' ;
EXPFCTS_RPARENTHESES: ')' ;
EXPFCTS_COMMA: ',' ;
EXPFCTS_SEMICOLON: ';' ;
EXPFCTS_STAR: '*' ;
EXPFCTS_DOUBLE_COLON: '::' ;
// identifider
EXPFCTS_IDENTIFIER: [_a-zA-Z][_a-zA-Z0-9]* ;
// remove whitespace and line break
EXPFCTS_WS: [ \t\n\r\f]+ -> skip ;

View File

@@ -0,0 +1,21 @@
parser grammar ExpFctsParser;
options { tokenVocab = ExpFctsLexer; }
program: fctDecl* ;
fctDecl
: EXPFCTS_EXPORT varType EXPFCTS_IDENTIFIER '(' (fctArg (',' fctArg)*)? ')' ';'
;
fctArg
: EXPFCTS_FILE_DECL '(' EXPFCTS_IDENTIFIER ')' # fctArgFileDecl
| EXPFCTS_MESHTRANS_DECL '(' EXPFCTS_IDENTIFIER ')' #fctArgMeshTransDecl
| EXPFCTS_OBJECT_DECL '(' EXPFCTS_IDENTIFIER ',' EXPFCTS_IDENTIFIER ')' # fctArgObjDecl
| EXPFCTS_PARAM_IN '(' varType ',' EXPFCTS_IDENTIFIER ')' # fctArgParamIn
| EXPFCTS_PARAM_OUT '(' varType ',' EXPFCTS_IDENTIFIER ')' # fctArgParamOut
;
varType
: EXPFCTS_IDENTIFIER ('::' EXPFCTS_IDENTIFIER)* '*'*
;

View File

@@ -0,0 +1,134 @@
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>();
mCurrentFct = null;
mCurrentParam = null;
}
public Vector<ExpFctDecl> getResult() {
return mFctList;
}
private Vector<ExpFctDecl> mFctList;
private ExpFctDecl mCurrentFct;
private ExpFctParamDecl mCurrentParam;
@Override
public void enterProgram(ExpFctsParser.ProgramContext ctx) {
mFctList.clear();
}
@Override
public void enterFctDecl(ExpFctsParser.FctDeclContext ctx) {
mCurrentFct = new ExpFctDecl();
}
@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;
}
@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);
}
@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);
}
@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);
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);
}
@Override
public void enterFctArgParamIn(ExpFctsParser.FctArgParamInContext ctx) {
mCurrentParam = new ExpFctParamDecl();
}
@Override
public void exitFctArgParamIn(ExpFctsParser.FctArgParamInContext ctx) {
mCurrentParam.mVarName = ctx.EXPFCTS_IDENTIFIER().getText();
mCurrentParam.mIsInput = true;
mCurrentFct.mFctParams.add(mCurrentParam);
mCurrentParam = null;
}
@Override
public void enterFctArgParamOut(ExpFctsParser.FctArgParamOutContext ctx) {
mCurrentParam = new ExpFctParamDecl();
}
@Override
public void exitFctArgParamOut(ExpFctsParser.FctArgParamOutContext ctx) {
mCurrentParam.mVarName = ctx.EXPFCTS_IDENTIFIER().getText();
mCurrentParam.mIsInput = false;
// set to its pointer type
// mCurrentParam.mVarType = mCurrentParam.mVarType.getPointerOfThis();
mCurrentFct.mFctParams.add(mCurrentParam);
mCurrentParam = null;
}
@Override
public void exitVarType(ExpFctsParser.VarTypeContext ctx) {
// get namespace parts and join them
String ctype = ctx.EXPFCTS_IDENTIFIER().stream().map(value -> value.getText())
.collect(Collectors.joining("::"));
// add star if necessary
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);
} else {
// otherwise, fill param data
mCurrentParam.mVarType.fromCType(ctype);
}
}
}

View File

@@ -0,0 +1,19 @@
import os, re
self_path: str = os.path.dirname(__file__)
src_file: str = os.path.join(self_path, '../../BMap/BMExports.hpp')
dst_file: str = os.path.join(self_path, 'dest/BMExports.hpp')
with open(src_file, 'r', encoding='utf-8') as fsrc:
# read full text
fulltext: str = fsrc.read()
# do findall and write into file
with open(dst_file, 'w', encoding='utf-8') as fdst:
# We should not only match BMAP_EXPORT,
# because it may match the defination of BMAP_EXPORT.
# So we add a bool at head because all BMap functions return bool.
for item in re.findall('^BMAP_EXPORT[ \\t]+bool[ \\t]+[^;]+;', fulltext, re.MULTILINE):
fdst.write(item)
fdst.write('\n')
print('DONE')

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

@@ -0,0 +1,60 @@
import java.io.OutputStreamWriter;
import java.util.Vector;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class JsonWriter {
private static JsonObject writeVariableType(VariableType vt) {
JsonObject data = new JsonObject();
JsonArray hierarchy = new JsonArray();
for (String item : vt.getBaseTypeHierarchy()) {
hierarchy.add(item);
}
data.add("hierarchy", hierarchy);
data.addProperty("pointer_level", vt.getPointerLevel());
return data;
}
private static JsonObject writeExpFctParamDecl(ExpFctParamDecl paramdecl) {
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));
return data;
}
private static JsonObject writeExpFctDecl(ExpFctDecl fctdecl) {
JsonObject data = new JsonObject();
data.addProperty("name", fctdecl.mFctName);
data.add("return", writeVariableType(fctdecl.mFctRetType));
JsonArray paramlist = new JsonArray();
for (ExpFctParamDecl paramdecl : fctdecl.mFctParams) {
paramlist.add(writeExpFctParamDecl(paramdecl));
}
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));
}
writer.write(gson_instance.toJson(fcts));
writer.close();
}
}

View File

@@ -0,0 +1,34 @@
import java.io.FileInputStream;
import java.nio.charset.StandardCharsets;
import java.util.Vector;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;
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);
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);
JsonWriter.writeJson(result);
// print message.
System.out.println("DONE!");
}
}

View File

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

@@ -0,0 +1,17 @@
# BMap Bindings Generation
A helper program to generate BMap binding in Python and CSharp
This program is consisted by 2 parts, first is Python part which extract BMap interface function declarations from source file, thus following Antlr step can focus on syntax analyze.
Next part is Antlr part. It analyse extracted function declarations and output corresponding Python binding and CSharp binding.
```
python ExtractBMapFctDecl.py
antlr4 ExpFctsLexer.g4
antlr4 ExpFctsParser.g4
javac *.java
java MainRunner
```

View File

@@ -0,0 +1,153 @@
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);
}
}