1/* 2* Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development Co., Ltd. 3* Licensed under the Apache License, Version 2.0 (the "License"); 4* you may not use this file except in compliance with the License. 5* You may obtain a copy of the License at 6* 7* http://www.apache.org/licenses/LICENSE-2.0 8* 9* Unless required by applicable law or agreed to in writing, software 10* distributed under the License is distributed on an "AS IS" BASIS, 11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12* See the License for the specific language governing permissions and 13* limitations under the License. 14*/ 15const { generateFunctionDirect } = require("./function_direct"); 16const { generateFunctionSync } = require("./function_sync"); 17const { generateFunctionAsync } = require("./function_async"); 18const { FuncType, InterfaceList, getArrayType, getArrayTypeTwo, getMapType, EnumList, jsType2CType } 19 = require("../tools/common"); 20const { jsToC } = require("./param_generate"); 21const { cToJs } = require("./return_generate"); 22const re = require("../tools/re"); 23const { NapiLog } = require("../tools/NapiLog"); 24const { addUniqFunc2List, addUniqObj2List } = require("../tools/tool"); 25 26let middleBodyTmplete = ` 27class [className]_middle { 28public: 29 static napi_value constructor(napi_env env, napi_callback_info info) 30 { 31 XNapiTool *pxt = new XNapiTool(env, info); 32 33 [className] *p = new [className](); 34 35 napi_value thisvar = pxt->WrapInstance(p, release); 36 37 return thisvar; 38 } 39 static void release(void *p) 40 { 41 [className] *p2 = ([className] *)p; 42 delete p2; 43 } 44 [static_funcs] 45};` 46 47function getHDefineOfVariable(name, type, variable) { 48 if (type.indexOf("|") >= 0) { 49 unionTypeString(name, type, variable) 50 } else if (type == "string") variable.hDefine += "\n std::string %s;".format(name) 51 else if (InterfaceList.getValue(type)) variable.hDefine += "\n %s %s;".format(type, name) 52 else if (EnumList.getValue(type)) variable.hDefine += "\n %s %s;".format(type, name) 53 else if (type.indexOf("Array<") == 0) { 54 let arrayType = getArrayType(type) 55 if (arrayType == "any") { 56 variable.hDefine += "\n std::string %s_type; \n std::any %s;".format(name,name) 57 } else { 58 let cType = jsType2CType(arrayType) 59 variable.hDefine += "\n std::vector<%s> %s;".format(cType, name) 60 } 61 } else if (type == "boolean") { 62 variable.hDefine += "\n bool %s;".format(name) 63 } else if (type.substring(type.length - 2) == "[]") { 64 let arrayType = getArrayTypeTwo(type) 65 if (arrayType == "any") { 66 variable.hDefine += "\n std::string %s_type; \n std::any %s;".format(name,name) 67 } else { 68 let cType = jsType2CType(arrayType) 69 variable.hDefine += "\n std::vector<%s> %s;".format(cType, name) 70 } 71 } else if (type.substring(0, 4) == "Map<" || type.indexOf("{[key:") == 0) { 72 variable.hDefine += mapTypeString(type, name) 73 } else if (type == "any") { 74 variable.hDefine += anyTypeString(type, name) 75 } else if (type.substring(0, 12) == "NUMBER_TYPE_") { 76 variable.hDefine += "\n %s %s;".format(type, name) 77 } else if (type == "Object" || type == "object") { 78 variable.hDefine += "\n std::map<std::string, std::any> %s;".format(name) 79 } 80 else { 81 NapiLog.logError(` 82 ---- generateVariable fail %s,%s ---- 83 `.format(name, type)); 84 } 85} 86 87function generateVariable(value, variable, className) { 88 let name = value.name 89 let type = value.type 90 if (!value.isParentMember) { 91 // 只有类/接口自己的成员属性需要在.h中定义, 父类/父接口不需要 92 getHDefineOfVariable(name, type, variable) 93 } 94 95 variable.middleValue += ` 96 static napi_value getvalue_%s(napi_env env, napi_callback_info info) 97 { 98 XNapiTool *pxt = std::make_unique<XNapiTool>(env, info).release(); 99 %s *p = (%s *)pxt->UnWarpInstance(); 100 napi_value result = nullptr; 101 `.format(name, className, className) + cToJs("p->" + name, type, "result") + ` 102 delete pxt; 103 return result; 104 } 105 static napi_value setvalue_%s(napi_env env, napi_callback_info info) 106 { 107 std::shared_ptr<XNapiTool> pxt = std::make_shared<XNapiTool>(env, info); 108 %s *p = (%s *)pxt->UnWarpInstance(); 109 `.format(name, className, className) + jsToC("p->" + name, "pxt->GetArgv(0)", type) + ` 110 return nullptr; 111 } 112` 113} 114 115function unionTypeString(name, type, variable) { 116 variable.hDefine += `std::string %s_type;\n 117 std::any %s;`.format(name, name) 118} 119 120function mapTypeString(type, name) { 121 let mapType = getMapType(type) 122 let mapTypeString 123 if (mapType[1] != undefined && mapType[2] == undefined) { 124 if (mapType[1] == "string") mapTypeString = "std::string,std::string" 125 else if (mapType[1] == "boolean") mapTypeString = "std::string,bool" 126 else if (mapType[1].substring(0, 12) == "NUMBER_TYPE_") { 127 mapTypeString = "std::string,%s".format(mapType[1]) 128 } 129 else if (mapType[1].substring(0, 12) == "any") { 130 mapTypeString = `std::string,std::any`.format(mapType[1]) 131 return `\n std::map<%s> %s; 132 std::string %s_type;`.format(mapTypeString, name, name) 133 } 134 else if (InterfaceList.getValue(mapType[1])) mapTypeString = "std::string,%s".format(mapType[1]) 135 } 136 if (mapType[2] != undefined) { 137 if (mapType[2] == "string") mapTypeString = "std::string,std::map<std::string,std::string>" 138 else if (mapType[2] == "boolean") mapTypeString = "std::string,std::map<std::string,bool>" 139 else if (mapType[2].substring(0, 12) == "NUMBER_TYPE_") { 140 mapTypeString = "std::string,std::map<std::string,%s>".format(mapType[2]) 141 } 142 } 143 if (mapType[3] != undefined) { 144 if (mapType[3] == "string") mapTypeString = "std::string,std::vector<std::string>" 145 else if (mapType[3] == "boolean") mapTypeString = "std::string,std::vector<bool>" 146 else if (mapType[3].substring(0, 12) == "NUMBER_TYPE_") { 147 mapTypeString = "std::string,std::vector<%s>".format(mapType[3]) 148 } 149 } 150 return "\n std::map<%s> %s;".format(mapTypeString, name); 151} 152 153function anyTypeString (type, name) { 154 let anyType = `\n std::string %s_type; 155 std::any %s;` 156 157 return anyType.format(name, name) 158} 159 160function generateInterface(name, data, inNamespace) { 161 let resultConnect = connectResult(data, inNamespace, name) 162 let middleFunc = resultConnect[0] 163 let implH = resultConnect[1] 164 let implCpp = resultConnect[2] 165 let middleInit = resultConnect[3] 166 let selfNs = "" 167 if (inNamespace.length > 0) { 168 let nsl = inNamespace.split("::") 169 nsl.pop() 170 if (nsl.length >= 2) { 171 selfNs = ", " + nsl[nsl.length - 1] 172 } 173 } 174 middleInit += `\n pxt->DefineClass("%s", %s%s_middle::constructor, valueList ,funcList%s);\n}\n` 175 .format(name, inNamespace, name, selfNs) 176 let extendsStr = (data.parentNameList && data.parentNameList.length > 0) ? 177 " : public %s".format(data.parentNameList.join(", public ")) : "" 178 let result = { 179 implH: ` 180class %s%s { 181public:%s 182};\n`.format(name, extendsStr, implH), 183 implCpp: implCpp, 184 middleBody: middleBodyTmplete.replaceAll("[className]", name).replaceAll("[static_funcs]", middleFunc), 185 middleInit: middleInit 186 } 187 return result 188} 189 190// 递归获取接口及接口父类的所有成员属性和方法 191function getAllPropties(interfaceBody, properties, isParentClass) { 192 for (let i in interfaceBody.value) { 193 interfaceBody.value[i].isParentMember = isParentClass 194 addUniqObj2List(interfaceBody.value[i], properties.values) 195 } 196 for (let i in interfaceBody.function) { 197 interfaceBody.function[i].isParentMember = isParentClass 198 addUniqFunc2List(interfaceBody.function[i], properties.functions) 199 } 200 if (!isParentClass && interfaceBody.parentNameList && interfaceBody.parentNameList.length > 0) { 201 getAllPropties(interfaceBody.parentBody, properties, true) 202 } 203} 204 205function connectResult(data, inNamespace, name) { 206 let implH = "" 207 let implCpp = "" 208 let middleFunc = "" 209 let middleInit = "" 210 let variable = { 211 hDefine: "", 212 middleValue: "", 213 } 214 middleInit = `{\n std::map<const char *,std::map<const char *,napi_callback>> valueList;` 215 data.allProperties = {values:[], functions:[]} 216 getAllPropties(data, data.allProperties, false) 217 for (let i in data.allProperties.values) { 218 let v = data.allProperties.values[i] 219 generateVariable(v, variable, name) 220 middleInit += ` 221 valueList["%s"]["getvalue"]=%s%s_middle::getvalue_%s; 222 valueList["%s"]["setvalue"]=%s%s_middle::setvalue_%s;` 223 .format(v.name, inNamespace, name, v.name, v.name, inNamespace, name, v.name) 224 } 225 implH += variable.hDefine 226 middleFunc += variable.middleValue 227 middleInit += `\n std::map<const char *, napi_callback> funcList;` 228 for (let i in data.allProperties.functions) { 229 let func = data.allProperties.functions[i] 230 let tmp; 231 switch (func.type) { 232 case FuncType.DIRECT: 233 tmp = generateFunctionDirect(func, data, name) 234 break; 235 case FuncType.SYNC: 236 tmp = generateFunctionSync(func, data, name) 237 break 238 case FuncType.ASYNC: 239 case FuncType.PROMISE: 240 tmp = generateFunctionAsync(func, data, name) 241 break 242 default: 243 return 244 } 245 middleFunc += tmp[0] 246 implH += tmp[1] 247 implCpp += tmp[2] 248 middleInit += `\n funcList["%s"] = %s%s_middle::%s_middle;`.format(func.name, inNamespace, name, func.name) 249 } 250 if (data.childList && data.childList.length > 0) { 251 // 如果是父类,增加虚析构函数使其具备泛型特征 (基类必须有虚函数才能正确使用dynamic_cast和typeinfo等方法) 252 implH += "\n virtual ~%s(){};".format(name) 253 } 254 return [middleFunc, implH, implCpp, middleInit] 255} 256 257module.exports = { 258 generateInterface, 259 connectResult, 260 generateVariable, 261 mapTypeString 262}