diff --git a/Assets/CodeGen/BMapBinder/ExpFctsAnalyzer/ExpFctsHelper.java b/Assets/CodeGen/BMapBinder/ExpFctsAnalyzer/ExpFctsHelper.java
index 40b7c7c..bcbc787 100644
--- a/Assets/CodeGen/BMapBinder/ExpFctsAnalyzer/ExpFctsHelper.java
+++ b/Assets/CodeGen/BMapBinder/ExpFctsAnalyzer/ExpFctsHelper.java
@@ -1,184 +1,30 @@
-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.
- *
- * For end user, it is enough that knowing the last item is type itself.
- */
- private Vector 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();
- 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 base_type, int pointer_level) {
- mBaseType = (Vector) 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.
- *
- * 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 getBaseTypeHierarchy() {
- return (Vector) 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.
- *
- * 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}.
+ * The class represent a single parameter (argument) of function.
*/
public static class ExpFctParam {
/**
* The type of this parameter.
*/
- public VariableType mVarType;
+ public String mVarType;
/**
* The name of this parameter.
*/
public String mVarName;
/**
- * True if this paramter is marked as input parameter, otherwise false.
+ * True if this parameter is marked as input parameter, otherwise false.
*
- * Input parameter and output paramter is commonly used in C/C++ code. By using
+ * Input parameter and output parameter 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.
*
* 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
+ * processing output parameter, especially for the scenario that the target
* language do not support explicit output parameter keyword.
*/
public boolean mIsInput;
@@ -186,7 +32,7 @@ public class ExpFctsHelper {
* The description of this parameter.
*
* 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
+ * underlying C++ type to tell end user how to treat this parameter because some
* target languages' native calling style can not represent these detail.
*
* In this program, this field must be written as a annotation of corresponding
@@ -195,7 +41,7 @@ public class ExpFctsHelper {
public String mVarDesc;
public ExpFctParam() {
- mVarType = new VariableType();
+ mVarType = "";
mVarName = "";
mVarDesc = "";
mIsInput = true;
@@ -215,9 +61,9 @@ public class ExpFctsHelper {
/**
* The return value type of this function.
*/
- public VariableType mFctRetType;
+ public String mFctRvType;
/**
- * The parameters (arguments) list of this function. Each items are
+ * The parameters (arguments) list of this function. Each item are
* {@linkplain ExpFctParam} and represent parameter one by one from left to
* right.
*/
@@ -225,7 +71,7 @@ public class ExpFctsHelper {
public ExpFct() {
mFctName = "";
- mFctRetType = new VariableType();
+ mFctRvType = "";
mFctParams = new Vector();
}
diff --git a/Assets/CodeGen/BMapBinder/ExpFctsAnalyzer/ExpFctsWalker.java b/Assets/CodeGen/BMapBinder/ExpFctsAnalyzer/ExpFctsWalker.java
index bbfc09d..48d5c6f 100644
--- a/Assets/CodeGen/BMapBinder/ExpFctsAnalyzer/ExpFctsWalker.java
+++ b/Assets/CodeGen/BMapBinder/ExpFctsAnalyzer/ExpFctsWalker.java
@@ -1,4 +1,5 @@
import java.util.Collections;
+import java.util.Objects;
import java.util.stream.Collectors;
public class ExpFctsWalker extends ExpFctsParserBaseListener {
@@ -32,8 +33,7 @@ public class ExpFctsWalker extends ExpFctsParserBaseListener {
// set name
mCurrentFct.mFctName = ctx.EXPFCTS_IDENTIFIER().getText();
// check return type
- if (!mCurrentFct.mFctRetType.isValid() || mCurrentFct.mFctRetType.isPointer()
- || !mCurrentFct.mFctRetType.getBaseType().equals("bool"))
+ if (!Objects.equals(mCurrentFct.mFctRvType, "bool"))
throw new IllegalArgumentException("invalid interface function return type. must be bool.");
// add into list
@@ -47,7 +47,7 @@ public class ExpFctsWalker extends ExpFctsParserBaseListener {
param.mVarName = ctx.EXPFCTS_IDENTIFIER().getText();
param.mVarDesc = "The pointer to corresponding BMFile.";
param.mIsInput = true;
- param.mVarType.fromCType("BMap::BMFile*");
+ param.mVarType = "BMap::BMFile*";
mCurrentFct.mFctParams.add(param);
}
@@ -57,7 +57,7 @@ public class ExpFctsWalker extends ExpFctsParserBaseListener {
param.mVarName = ctx.EXPFCTS_IDENTIFIER().getText();
param.mVarDesc = "The pointer to corresponding BMMeshTransition.";
param.mIsInput = true;
- param.mVarType.fromCType("BMap::BMMeshTransition*");
+ param.mVarType = "BMap::BMMeshTransition*";
mCurrentFct.mFctParams.add(param);
}
@@ -67,14 +67,14 @@ public class ExpFctsWalker extends ExpFctsParserBaseListener {
firstParam.mVarName = ctx.EXPFCTS_IDENTIFIER(0).getText();
firstParam.mVarDesc = "The pointer to corresponding BMFile.";
firstParam.mIsInput = true;
- firstParam.mVarType.fromCType("BMap::BMFile*");
+ firstParam.mVarType = "BMap::BMFile*";
mCurrentFct.mFctParams.add(firstParam);
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");
+ secondParam.mVarType = "LibCmo::CK2::CK_ID";
mCurrentFct.mFctParams.add(secondParam);
}
@@ -118,12 +118,15 @@ public class ExpFctsWalker extends ExpFctsParserBaseListener {
ctype += String.join("", Collections.nCopies(ctx.EXPFCTS_STAR().size(), "*"));
}
- if (!mCurrentFct.mFctRetType.isValid()) {
+ // if there is function return value is not filled,
+ // we fill it first because return value type is the first captured type in function statement.
+ // otherwise we fill parameter type.
+ if (mCurrentFct.mFctRvType.isEmpty()) {
// fill function ret type first
- mCurrentFct.mFctRetType.fromCType(ctype);
+ mCurrentFct.mFctRvType = ctype;
} else {
// otherwise, fill param data
- mCurrentParam.mVarType.fromCType(ctype);
+ mCurrentParam.mVarType = ctype;
}
}
diff --git a/Assets/CodeGen/BMapBinder/ExpFctsAnalyzer/JsonWriter.java b/Assets/CodeGen/BMapBinder/ExpFctsAnalyzer/JsonWriter.java
index d5a87b7..578761a 100644
--- a/Assets/CodeGen/BMapBinder/ExpFctsAnalyzer/JsonWriter.java
+++ b/Assets/CodeGen/BMapBinder/ExpFctsAnalyzer/JsonWriter.java
@@ -8,26 +8,13 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class JsonWriter {
-
- private static JsonObject writeVariableType(ExpFctsHelper.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 writeExpFctParam(ExpFctsHelper.ExpFctParam param) {
JsonObject data = new JsonObject();
+ data.addProperty("type", param.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;
}
@@ -35,7 +22,7 @@ public class JsonWriter {
private static JsonObject writeExpFct(ExpFctsHelper.ExpFct fct) {
JsonObject data = new JsonObject();
data.addProperty("name", fct.mFctName);
- data.add("return", writeVariableType(fct.mFctRetType));
+ data.addProperty("return", fct.mFctRvType);
JsonArray paramList = new JsonArray();
for (ExpFctsHelper.ExpFctParam param : fct.mFctParams) {
diff --git a/Assets/CodeGen/BMapBinder/ExpFctsRender/json_loader.py b/Assets/CodeGen/BMapBinder/ExpFctsRender/json_loader.py
new file mode 100644
index 0000000..2b318b9
--- /dev/null
+++ b/Assets/CodeGen/BMapBinder/ExpFctsRender/json_loader.py
@@ -0,0 +1,225 @@
+import json
+import typing
+import utils
+from dataclasses import dataclass
+
+
+class VariableType:
+ """The class represent the type of each parameters and function return value."""
+
+ __base_type_hierarchy: list[str]
+ """
+ The base type of this variable removing all ending stars (remove all pointer levels).
+ Each item in this list 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 list will only have one item.
+
+ For end user, it is enough that knowing the last item is type itself.
+ """
+ __pointer_level: int
+ """
+ The pointer level of this type.
+ It is equal to the count of trailing star of this field in C style representation.
+ """
+
+ def __init__(
+ self, base_type_hierarchy: list[str] = [], pointer_level: int = 0
+ ) -> None:
+ """Construct a new varible type."""
+ self.__base_type_hierarchy = base_type_hierarchy
+ self.__pointer_level = pointer_level
+
+ def clone(self) -> "VariableType":
+ """CLone self into a new instance."""
+ return VariableType(list(self.__base_type_hierarchy), self.__pointer_level)
+
+ @staticmethod
+ def from_c_type(ctype: str) -> "VariableType":
+ """
+ Set this variable type with a type string in C/C++ style.
+
+ For example, "NSTest::NSTest2::MyType**" will produce 2 pointer level
+ with ('NSTest', 'NSTest2', 'MyType') as its base type hierarchy.
+
+ :param ctype: The type string in C/C++ style.
+ :return: The parsed VariableType instance.
+ """
+ if len(ctype) == 0:
+ raise RuntimeError("empty string can not be parsed")
+
+ # get pointer part and name part
+ length = len(ctype)
+ star_index = ctype.find("*")
+ name_part: str
+ pointer_level: int
+ if star_index == -1:
+ # No star, no pointer level
+ name_part = ctype
+ pointer_level = 0
+ else:
+ # Has star
+ if star_index == 0:
+ raise RuntimeError("base type not found")
+ name_part = ctype[0:star_index]
+ pointer_level = length - star_index
+
+ # resolve name part
+ base_type_hierarchy = list(name_part.split("::"))
+
+ # return value
+ return VariableType(base_type_hierarchy, pointer_level)
+
+ def to_c_type(self) -> str:
+ """
+ Build a type string represented by this variable type in C/C++ style.
+
+ :return: The type string in C/C++ style.
+ """
+ return "::".join(self.__base_type_hierarchy) + ("*" * self.__pointer_level)
+
+ def get_base_type(self) -> str:
+ """
+ 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.
+ """
+ return self.__base_type_hierarchy[-1]
+
+ def is_pointer(self) -> bool:
+ """
+ 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.
+ """
+ return self.__pointer_level != 0
+
+ def get_pointer_level(self) -> int:
+ """
+ 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.
+ """
+ return self.__pointer_level
+
+ def iter_base_type_hierarchy(self) -> typing.Iterator[str]:
+ """
+ Return the clone of the type hierarchy of this variable type.
+
+ 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.
+ """
+ return iter(self.__base_type_hierarchy)
+
+ # def is_valid(self) -> bool:
+ # """
+ # 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.
+ # """
+ # return len(self.__base_type_hierarchy) != 0
+
+ def get_pointer_of_this(self) -> "VariableType":
+ """
+ Return a new created variable type which is the pointer of this variable type.
+
+ 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.
+ """
+ return VariableType(list(self.__base_type_hierarchy), self.__pointer_level + 1)
+
+ @staticmethod
+ def from_json(data: str) -> "VariableType":
+ return VariableType.from_c_type(data)
+
+
+@dataclass(frozen=True)
+class ExpFctParam:
+ """The class represent a single parameter (argument) of function."""
+
+ var_type: VariableType
+ """The type of this parameter."""
+ var_name: str
+ """The name of this parameter."""
+ is_input: bool
+ """
+ True if this parameter is marked as input parameter, otherwise false.
+
+ Input parameter and output parameter 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.
+
+ 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 parameter,
+ especially for the scenario that the target language do not support explicit output parameter keyword.
+ """
+ var_desc: str
+ """
+ The description of this parameter.
+
+ This description is generated by this program.
+ It will indicate the underlying C++ type to tell end user how to treat this parameter
+ because some target languages' native calling style can not represent these detail.
+
+ In this program, this field must be written as a docstring of corresponding function.
+ """
+
+ @staticmethod
+ def from_json(data: dict[str, typing.Any]) -> "ExpFctParam":
+ return ExpFctParam(
+ VariableType.from_c_type(data["type"]),
+ data["name"],
+ data["is_input"],
+ data["desc"],
+ )
+
+
+@dataclass(frozen=True)
+class ExpFct:
+ """The class represent an export BMap function."""
+
+ fct_name: str
+ """The name of this function."""
+ fct_rv_type: VariableType
+ """The return value type of this function."""
+ fct_params: list[ExpFctParam]
+ """
+ The parameters (arguments) list of this function.
+ Each item represent parameter accepted by this function one by one from left to right.
+ """
+
+ @staticmethod
+ def from_json(data: dict[str, typing.Any]) -> "ExpFct":
+ return ExpFct(
+ data["name"],
+ VariableType.from_json(data["return"]),
+ list(map(lambda i: ExpFctParam.from_json(i), data["params"])),
+ )
+
+
+@dataclass(frozen=True)
+class ExpFctCollection:
+ """The class represent a collection of export BMap functions."""
+
+ fcts: list[ExpFct]
+ """The collection of exported BMap functions."""
+
+ @staticmethod
+ def from_json(data: list[typing.Any]) -> "ExpFctCollection":
+ return ExpFctCollection(list(map(lambda i: ExpFct.from_json(i), data)))
+
+
+def load_fcts(filename: str) -> ExpFctCollection:
+ with open(utils.get_input_file_path(filename), "r", encoding="utf-8") as f:
+ return ExpFctCollection.from_json(json.load(f))
diff --git a/Assets/CodeGen/BMapBinder/ExpFctsRender/main.py b/Assets/CodeGen/BMapBinder/ExpFctsRender/main.py
index 4cd3820..a3c4580 100644
--- a/Assets/CodeGen/BMapBinder/ExpFctsRender/main.py
+++ b/Assets/CodeGen/BMapBinder/ExpFctsRender/main.py
@@ -1,5 +1,10 @@
+import json_loader
+import utils
+
def main():
- print("Hello from exp-fcts-render!")
+ fcts = json_loader.load_fcts("BMExports.json")
+
+ print("Done")
if __name__ == "__main__":
diff --git a/Assets/CodeGen/BMapBinder/ExpFctsRender/utils.py b/Assets/CodeGen/BMapBinder/ExpFctsRender/utils.py
new file mode 100644
index 0000000..d1e1ba8
--- /dev/null
+++ b/Assets/CodeGen/BMapBinder/ExpFctsRender/utils.py
@@ -0,0 +1,22 @@
+import os
+from pathlib import Path
+
+
+def _get_root_directory() -> Path:
+ bmap_binder_root = os.environ.get("BMAP_BINDER_ROOT", None)
+ if bmap_binder_root is None:
+ return Path(__file__).resolve().parent.parent
+ else:
+ return Path(bmap_binder_root).resolve()
+
+
+def get_input_file_path(filename: str) -> Path:
+ return _get_root_directory() / "Analyzed" / filename
+
+
+def get_output_file_path(filename: str) -> Path:
+ return _get_root_directory() / "Output" / filename
+
+
+def get_template_directory() -> Path:
+ return Path(__file__).resolve().parent / "templates"