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, setOverrideFunc } = 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 [className] *p = new [className](); 33 napi_value thisvar = pxt->WrapInstance(reinterpret_cast<DataPtr>(p), release); 34 return thisvar; 35 } 36 static void release(DataPtr p) 37 { 38 void *dataPtr = p; 39 [className] *p2 = static_cast<[className] *>(dataPtr); 40 delete p2; 41 } 42 [static_funcs] 43};` 44 45function getHDefineOfVariable(name, type, variable) { 46 if (type.indexOf("|") >= 0) { 47 unionTypeString(name, type, variable) 48 } else if (type == "string") variable.hDefine += "\n std::string %s;".format(name) 49 else if (InterfaceList.getValue(type)) variable.hDefine += "\n %s %s;".format(type, name) 50 else if (EnumList.getValue(type)) variable.hDefine += "\n %s %s;".format(type, name) 51 else if (type.indexOf("Array<") == 0) { 52 let arrayType = getArrayType(type) 53 if (arrayType == "any") { 54 variable.hDefine += "\n std::string %s_type; \n std::any %s;".format(name,name) 55 } else { 56 let cType = jsType2CType(arrayType) 57 variable.hDefine += "\n std::vector<%s> %s;".format(cType, name) 58 } 59 } else if (type == "boolean") { 60 variable.hDefine += "\n bool %s;".format(name) 61 } else if (type.substring(type.length - 2) == "[]") { 62 let arrayType = getArrayTypeTwo(type) 63 if (arrayType == "any") { 64 variable.hDefine += "\n std::string %s_type;\n std::any %s;".format(name,name) 65 } else { 66 let cType = jsType2CType(arrayType) 67 variable.hDefine += "\n std::vector<%s> %s;".format(cType, name) 68 } 69 } else if (type.substring(0, 4) == "Map<" || type.indexOf("{[key:") == 0) { 70 variable.hDefine += mapTypeString(type, name) 71 } else if (type == "any") { 72 variable.hDefine += anyTypeString(type, name) 73 } else if (type.substring(0, 12) == "NUMBER_TYPE_") { 74 variable.hDefine += "\n %s %s;".format(type, name) 75 } else if (type == "Object" || type == "object") { 76 variable.hDefine += "\n std::map<std::string, std::any> %s;".format(name) 77 } 78 else { 79 NapiLog.logError(` 80 ---- generateVariable fail %s,%s ---- 81 `.format(name, type)); 82 } 83} 84 85function generateVariable(value, variable, className) { 86 let name = value.name 87 let type = value.type 88 if (!value.isParentMember) { 89 // 只有类/接口自己的成员属性需要在.h中定义, 父类/父接口不需要 90 getHDefineOfVariable(name, type, variable) 91 } 92 93 variable.middleValue += ` 94 static napi_value getvalue_%s(napi_env env, napi_callback_info info) 95 { 96 XNapiTool *pxt = std::make_unique<XNapiTool>(env, info).release(); 97 void *instPtr = pxt->UnWarpInstance(); 98 %s *p = static_cast<%s *>(instPtr); 99 napi_value result = nullptr; 100 `.format(name, className, className) + cToJs("p->" + name, type, "result") + ` 101 delete pxt; 102 return result; 103 } 104 static napi_value setvalue_%s(napi_env env, napi_callback_info info) 105 { 106 std::shared_ptr<XNapiTool> pxt = std::make_shared<XNapiTool>(env, info); 107 void *instPtr = pxt->UnWarpInstance(); 108 %s *p = static_cast<%s *>(instPtr); 109 `.format(name, className, className) + jsToC("p->" + name, "pxt->GetArgv(XNapiTool::ZERO)", type) + ` 110 return nullptr; 111 }` 112} 113 114function unionTypeString(name, type, variable) { 115 variable.hDefine += `std::string %s_type;\n 116 std::any %s;`.format(name, name) 117} 118 119function mapTypeString(type, name) { 120 let mapType = getMapType(type) 121 let mapTypeString 122 if (mapType[1] != undefined && mapType[2] == undefined) { 123 if (mapType[1] == "string") mapTypeString = "std::string, std::string" 124 else if (mapType[1] == "boolean") mapTypeString = "std::string, bool" 125 else if (mapType[1].substring(0, 12) == "NUMBER_TYPE_") { 126 mapTypeString = "std::string, %s".format(mapType[1]) 127 } 128 else if (mapType[1].substring(0, 12) == "any") { 129 mapTypeString = `std::string, std::any`.format(mapType[1]) 130 return `\n std::map<%s> %s; 131 std::string %s_type;`.format(mapTypeString, name, name) 132 } 133 else if (InterfaceList.getValue(mapType[1])) mapTypeString = "std::string, %s".format(mapType[1]) 134 } 135 if (mapType[2] != undefined) { 136 if (mapType[2] == "string") mapTypeString = "std::string, std::map<std::string, std::string>" 137 else if (mapType[2] == "boolean") mapTypeString = "std::string, std::map<std::string, bool>" 138 else if (mapType[2].substring(0, 12) == "NUMBER_TYPE_") { 139 mapTypeString = "std::string, std::map<std::string, %s>".format(mapType[2]) 140 } 141 } 142 if (mapType[3] != undefined) { 143 if (mapType[3] == "string") mapTypeString = "std::string, std::vector<std::string>" 144 else if (mapType[3] == "boolean") mapTypeString = "std::string, std::vector<bool>" 145 else if (mapType[3].substring(0, 12) == "NUMBER_TYPE_") { 146 mapTypeString = "std::string, std::vector<%s>".format(mapType[3]) 147 } 148 } 149 return "\n std::map<%s> %s;".format(mapTypeString, name); 150} 151 152function anyTypeString (type, name) { 153 let anyType = `\n std::string %s_type; 154 std::any %s;` 155 156 return anyType.format(name, name) 157} 158 159function generateInterface(name, data, inNamespace) { 160 let resultConnect = connectResult(data, inNamespace, name) 161 let middleFunc = resultConnect[0] 162 let implH = resultConnect[1] 163 let implCpp = resultConnect[2] 164 let middleInit = resultConnect[3] 165 let selfNs = "" 166 if (inNamespace.length > 0) { 167 let nsl = inNamespace.split("::") 168 nsl.pop() 169 if (nsl.length >= 2) { 170 selfNs = ", " + nsl[nsl.length - 1] 171 } 172 } 173 middleInit += `\n pxt->DefineClass("%s", %s%s_middle::constructor, 174 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 if(!addUniqFunc2List(interfaceBody.function[i], properties.functions)) { 199 if (isParentClass) { 200 // 没添加到列表,说明子类方法properties.functions重写了父类方法interfaceBody.function[i] 201 // 找到该子类方法并将其设置为override (生成的重写函数如果没有override关键字会触发门禁告警) 202 setOverrideFunc(interfaceBody.function[i], properties.functions) 203 } 204 } 205 } 206 if (!isParentClass && interfaceBody.parentNameList && interfaceBody.parentNameList.length > 0) { 207 getAllPropties(interfaceBody.parentBody, properties, true) 208 } 209} 210 211function addVirtualKeywords(data, implH, name) { 212 if (data.childList && data.childList.length > 0) { 213 // 如果该类是其它类的父类,增加虚析构函数使其具备泛型特征 (基类必须有虚函数才能正确使用dynamic_cast和typeinfo等方法) 214 // 如果该类自己也有父类,虚析构函数需要加上override关键字(否则C++门禁会有告警) 215 let ovrrideStr = (data.parentList && data.parentList.length > 0) ? " override" : ""; 216 // 如果虚析构函数已经有override关键字,就不需要再加virtual关键字了(否则C++门禁会有告警) 217 let virtualStr = (data.parentList && data.parentList.length > 0) ? "" : "virtual "; 218 implH += "\n %s~%s()%s {};".format(virtualStr, name, ovrrideStr); 219 } 220 return implH; 221} 222 223function connectResult(data, inNamespace, name) { 224 let implH = "" 225 let implCpp = "" 226 let middleFunc = "" 227 let middleInit = "" 228 let variable = { 229 hDefine: "", 230 middleValue: "", 231 } 232 middleInit = `{\n std::map<const char *, std::map<const char *, napi_callback>> valueList;` 233 data.allProperties = {values:[], functions:[]} 234 getAllPropties(data, data.allProperties, false) 235 for (let i in data.allProperties.values) { 236 let v = data.allProperties.values[i] 237 generateVariable(v, variable, name) 238 middleInit += ` 239 valueList["%s"]["getvalue"] = %s%s_middle::getvalue_%s; 240 valueList["%s"]["setvalue"] = %s%s_middle::setvalue_%s;` 241 .format(v.name, inNamespace, name, v.name, v.name, inNamespace, name, v.name) 242 } 243 implH += variable.hDefine 244 middleFunc += variable.middleValue 245 middleInit += `\n std::map<const char *, napi_callback> funcList;` 246 for (let i in data.allProperties.functions) { 247 let func = data.allProperties.functions[i] 248 let tmp; 249 switch (func.type) { 250 case FuncType.DIRECT: 251 tmp = generateFunctionDirect(func, data, name) 252 break; 253 case FuncType.SYNC: 254 tmp = generateFunctionSync(func, data, name) 255 break 256 case FuncType.ASYNC: 257 case FuncType.PROMISE: 258 tmp = generateFunctionAsync(func, data, name) 259 break 260 default: 261 return 262 } 263 middleFunc += tmp[0] 264 implH += tmp[1] 265 implCpp += tmp[2] 266 middleInit += `\n funcList["%s"] = %s%s_middle::%s_middle;`.format(func.name, inNamespace, name, func.name) 267 } 268 implH = addVirtualKeywords(data, implH, name); 269 return [middleFunc, implH, implCpp, middleInit] 270} 271 272module.exports = { 273 generateInterface, 274 connectResult, 275 generateVariable, 276 mapTypeString 277} 278 279 280