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 { replaceAll, getPrefix, getConstNum } = require('../tools/tool'); 16const { paramGenerate } = require('./param_generate'); 17const { returnGenerate } = require('./return_generate'); 18const { NapiLog } = require('../tools/NapiLog'); 19const { NumberIncrease, jsonCfgList, getLogErrInfo } = require('../tools/common'); 20 21/** 22 * 结果通过同步回调(CallBack)返回 23 */ 24let funcSyncMiddleHTemplete = ` 25struct [funcName]_value_struct {[valueIn][valueOut] 26}; 27 28[static_define]napi_value [funcName]_middle(napi_env env, napi_callback_info info); 29`; 30 31let funcSyncTemplete = ` 32napi_value [middleClassName][funcName]_middle(napi_env env, napi_callback_info info) 33{ 34 XNapiTool *pxt = std::make_unique<XNapiTool>(env, info).release(); 35 if (pxt->IsFailed()) { 36 napi_value err = pxt->GetError(); 37 delete pxt; 38 return err; 39 } 40 [unwarp_instance] 41 struct [funcName]_value_struct *vio = new [funcName]_value_struct(); 42 [valueCheckout][optionalCallbackInit] 43 [callFunc] 44 napi_value result = nullptr; 45 napi_value retVal = nullptr; 46 if (pxt->GetArgc() > [callback_param_offset]) { 47 static const int ARGS_SIZE = [agrs_size]; 48 napi_value args[ARGS_SIZE]; 49 [valuePackage] 50 { 51 // 回调为Callback<XX>,参数个数为1,其转换结果保存在result中 52 // 回调为箭头函数,支持参数个数大于1,参数转换结果保存在args[i] 53 if (ARGS_SIZE == XNapiTool::ONE && result != nullptr) { 54 args[0] = result; 55 } 56 retVal = pxt->SyncCallBack(pxt->GetArgv([callback_param_offset]), ARGS_SIZE, args); 57 } 58 } 59 60 if (retVal != nullptr) { 61 [cbRetValJs2C] 62 [funcRetC2Js] 63 } 64 65 [optionalParamDestory] 66 delete vio; 67 delete pxt; // release 68 return result; 69}`; 70 71let cppTemplate = ` 72bool %s%s(%s) 73{ 74 %s 75 return true; 76} 77`; 78let cppFuncReturnTemplate = ` 79bool %s%sReturn(%s) 80{ 81 return true; 82} 83`; 84 85function removeEndlineEnter(value) { 86 for (let i = value.length; i > 0; i--) { 87 let len = value.length; 88 if (value.substring(len - 1, len) === '\n' || value.substring(len - 1, len) === ' ') { 89 value = value.substring(0, len - 1); 90 } else { 91 value = ' ' + value + '\n'; 92 break; 93 } 94 } 95 return value; 96} 97 98function getOptionalCallbackInit(param) { 99 if (!param.callback.optional) { 100 return ''; 101 } 102 let cType = param.valueOut.substr(0, param.valueOut.indexOf('*')); 103 return 'if (pxt->GetArgc() > %s) {\n vio->out = new %s;\n }' 104 .format(getConstNum(param.callback.offset), cType); 105} 106 107function callBackReturnValJs2C(className, funcName, callbackRetType, funcRetType) { 108 let cbRetJs2CTrans = ''; 109 let retOutFill = ''; 110 if (funcRetType !== 'void') { 111 retOutFill = ', vio->retOut'; 112 } 113 114 if (callbackRetType === 'void') { 115 cbRetJs2CTrans = ''; 116 } else if (callbackRetType === 'string') { 117 cbRetJs2CTrans = 'pxt->SwapJs2CUtf8(retVal, vio->cbOut);\n' + 118 '%s%sReturn(vio->cbOut%s);\n'.format((className === null || className === undefined) ? 119 '' : 'pInstance->', funcName, retOutFill); 120 } else if (callbackRetType === 'boolean') { 121 cbRetJs2CTrans = 'vio->cbOut = pxt->SwapJs2CBool(retVal);\n' + 122 '%s%sReturn(vio->cbOut%s);\n'.format((className === null || className === undefined) ? 123 '' : 'pInstance->', funcName, retOutFill); 124 } else if (callbackRetType.substring(0, 12) === 'NUMBER_TYPE_') { 125 let lt = NumberIncrease.getAndIncrease(); 126 cbRetJs2CTrans = 'NUMBER_JS_2_C(retVal, NUMBER_TYPE_%d, vio->cbOut);\n'.format(lt) + 127 '%s%sReturn(vio->cbOut%s);\n'.format((className === null || className === undefined) ? 128 '' : 'pInstance->', funcName, retOutFill); 129 } else if (callbackRetType === 'number') { 130 cbRetJs2CTrans = 'NUMBER_JS_2_C(retVal, NUMBER_TYPE_1, vio->cbOut);\n' + 131 '%s%sReturn(vio->cbOut%s);\n'.format((className === null || className === undefined) ? 132 '' : 'pInstance->', funcName, retOutFill); 133 } else { 134 NapiLog.logError('callBackReturnValJs2C not surpport callbackRetType:%s.' 135 .format(callbackRetType), getLogErrInfo()); 136 } 137 return cbRetJs2CTrans; 138} 139 140function returnProcRetC2Js(funRetType) { 141 let retC2JsCode = ''; 142 if (funRetType === 'void') { 143 NapiLog.logInfo('returnProcRetC2Js void type do nothing!'); 144 } else if (funRetType === 'string') { 145 retC2JsCode = 'result = pxt->SwapC2JsUtf8(vio->retOut.c_str());'; 146 } else if (funRetType === 'boolean') { 147 retC2JsCode = 'result = pxt->SwapC2JsBool(vio->retOut);'; 148 } else if (funRetType.substring(0, 12) === 'NUMBER_TYPE_') { 149 retC2JsCode = 'result = NUMBER_C_2_JS(pxt, vio->retOut);'; 150 } else { 151 NapiLog.logError('returnProcRetC2Js not surpport funRetType:%s'.format(funRetType)); 152 } 153 return retC2JsCode; 154} 155 156function fillCbRetValueStruct(type, param, outName) { 157 if (type === null || param === null || param.valueOut === null || param.valueDefine === null) { 158 NapiLog.logError('[fillCbRetValueStruct] param in is null!'); 159 return; 160 } 161 162 if (type === 'void') { 163 NapiLog.logInfo("The current void type don't need generate"); 164 } else if (type === 'string') { 165 param.cbRetvalueDefine += '%sstd::string& %s'.format(param.cbRetvalueDefine.length > 0 ? ', ' : '', outName); 166 } else if (type === 'boolean') { 167 param.cbRetvalueDefine += '%sbool& %s'.format(param.cbRetvalueDefine.length > 0 ? ', ' : '', outName); 168 } else if (type.substring(0, 12) === 'NUMBER_TYPE_') { 169 param.cbRetvalueDefine += '%s%s& %s'.format(param.cbRetvalueDefine.length > 0 ? ', ' : '', type, outName); 170 } else if (type === 'number') { 171 param.cbRetvalueDefine += '%sNUMBER_TYPE_1& %s'.format(param.cbRetvalueDefine.length > 0 ? ', ' : '', 172 type, outName); 173 } 174 else { 175 NapiLog.logError("[fillCbRetValueStruct] The current type:%s don't support." 176 .format(type), getLogErrInfo()); 177 } 178} 179 180function fillValueStruct(type, param, outName) { 181 if (type === null || param === null || param.valueOut === null || param.valueDefine === null) { 182 NapiLog.logError('[fillValueStruct] Param in is null!'); 183 return; 184 } 185 186 if (type === 'void') { 187 NapiLog.logInfo("The current void type don't need generate"); 188 } else if (type === 'string') { 189 param.valueOut += 'std::string %s;\n'.format(outName); 190 if (param.callback.returnType === 'void') { 191 param.valueDefine += '%sstd::string& %s'.format(param.valueDefine.length > 0 ? ', ' : '', outName); 192 } 193 } else if (type === 'boolean') { 194 param.valueOut += 'bool %s;\n'.format(outName); 195 if (param.callback.returnType === 'void') { 196 param.valueDefine += '%sbool& %s'.format(param.valueDefine.length > 0 ? ', ' : '', outName); 197 } 198 } else if (type.substring(0, 12) === 'NUMBER_TYPE_') { 199 param.valueOut += '%s %s;\n'.format(type, outName); 200 if (param.callback.returnType === 'void') { 201 param.valueDefine += '%s%s& %s'.format(param.valueDefine.length > 0 ? ', ' : '', type, outName); 202 } 203 } else if (type === 'number') { 204 param.valueOut += 'NUMBER_TYPE_1 %s;\n'.format(outName); 205 if (param.callback.returnType === 'void') { 206 param.valueDefine += '%sNUMBER_TYPE_1& %s'.format(param.valueDefine.length > 0 ? ', ' : '', outName); 207 } 208 } 209 else { 210 NapiLog.logError("[fillValueStruct] The current type:%s don't support." 211 .format(type), getLogErrInfo()); 212 } 213} 214 215function callbackReturnProc(param, func) { 216 fillValueStruct(param.callback.returnType, param, 'cbOut'); 217 fillValueStruct(func.ret, param, 'retOut'); 218 219 // 回调返回值非空,业务代码分两部分,一部分填写JS回调需要的参数(对应funcname函数),一部分根据回调返回值进行后续业务处理(对应funcnameReturn函数), 220 // 回调返回值为空,则业务代码处理是一个整体,对应funcname函数,统一处理填写参数、函数返回值赋值处理。 221 if (param.callback.returnType === 'void') { 222 if (func.ret === 'string' || func.ret === 'boolean' || func.ret.substring(0, 12) === 'NUMBER_TYPE_') { 223 param.valueFill += param.valueFill.length > 0 ? ', vio->retOut' : 'vio->retOut'; 224 } else if (func.ret === 'void') { 225 NapiLog.logInfo("The current void type don't need generate"); 226 } else { 227 NapiLog.logError('not support returnType:%s!'.format(param.callback.returnType), 228 getLogErrInfo()); 229 } 230 } else { 231 // param.cbRetvalueDefine赋值,传递给funcnameReturn函数 232 fillCbRetValueStruct(param.callback.returnType, param, 'in'); 233 fillCbRetValueStruct(func.ret, param, 'out'); 234 } 235} 236 237function replaceValueOut(param, middleH) { 238 if (param.valueOut === '') { 239 middleH = replaceAll(middleH, '[valueOut]', param.valueOut); // # 输出参数定义 240 } else { 241 middleH = replaceAll(middleH, '[valueOut]', '\n ' + param.valueOut); // # 输出参数定义 242 } 243 return middleH; 244} 245 246function replaceValueCheckout(param, middleFunc) { 247 if (param.valueCheckout === '') { 248 middleFunc = replaceAll(middleFunc, '[valueCheckout]', param.valueCheckout); // # 输入参数解析 249 } else { 250 param.valueCheckout = removeEndlineEnter(param.valueCheckout); 251 middleFunc = replaceAll(middleFunc, '[valueCheckout]', param.valueCheckout); // # 输入参数解析 252 } 253 return middleFunc; 254} 255 256function generateFunctionSync(func, data, className) { 257 let middleFunc = replaceAll(funcSyncTemplete, '[funcName]', func.name); 258 let middleH = ''; 259 if (func.name !== 'constructor') { 260 middleH = replaceAll(funcSyncMiddleHTemplete, '[funcName]', func.name); 261 } 262 let isClassresult = isClassFunc(className, middleH, middleFunc); 263 middleH = isClassresult[0]; 264 middleFunc = isClassresult[1]; 265 266 // 定义输入,定义输出,解析,填充到函数内,输出参数打包,impl参数定义,可选参数内存释放 267 let param = { 268 valueIn: '', valueOut: '', valueCheckout: '', valueFill: '', 269 valuePackage: '', valueDefine: '', optionalParamDestory: '', cbRetvalueDefine: '', paramSize: 1 270 }; 271 272 for (let i in func.value) { 273 paramGenerate(i, func.value[i], param, data); 274 } 275 returnGenerate(param.callback, param); 276 callbackReturnProc(param, func); 277 278 middleH = replaceAll(middleH, '[valueIn]', param.valueIn); // # 输入参数定义 279 middleH = replaceValueOut(param, middleH); 280 middleFunc = replaceValueCheckout(param, middleFunc); 281 282 let callFunc = '%s%s(%s);'.format((className === null || className === undefined) ? 283 '' : 'pInstance->', func.name, param.valueFill); 284 middleFunc = getMiddleFunc(middleFunc, callFunc, param); // 呼叫回调 285 286 // callback返回值处理,回调成功后根据js返回值,业务进行后续处理 287 let callBackReturnProc = callBackReturnValJs2C(className, func.name, param.callback.returnType, func.ret); 288 middleFunc = middleFunc.replaceAll('[cbRetValJs2C]', callBackReturnProc); 289 290 // 同步函数返回值处理 291 let retTrans = returnProcRetC2Js(func.ret); 292 middleFunc = middleFunc.replaceAll('[funcRetC2Js]', retTrans); 293 294 let prefixArr = getPrefix(data, func); 295 let implH = ''; 296 let implCpp = ''; 297 298 if (!func.isParentMember) { 299 // 只有类/接口自己的成员方法需要在.h.cpp中生成,父类/父接口不需要 300 implH = '\n%s%s%sbool %s(%s)%s;'.format( 301 prefixArr[0], prefixArr[1], prefixArr[2], func.name, param.valueDefine, prefixArr[3]); 302 let callStatement = jsonCfgList.getValue((className === null || className === undefined) ? '' : className, 303 func.name); 304 implCpp = cppTemplate.format((className === null || className === undefined) ? '' : className + 305 '::', func.name, param.valueDefine, 306 (callStatement === null || callStatement === undefined) ? '' : callStatement); 307 308 if (param.callback.returnType !== 'void' && param.callback.returnType !== undefined) { 309 implH += '\n%s%s%sbool %sReturn(%s)%s;'.format( 310 prefixArr[0], prefixArr[1], prefixArr[2], func.name, param.cbRetvalueDefine, prefixArr[3]); 311 implCpp += cppFuncReturnTemplate.format((className === null || className === undefined) ? 312 '' : className + '::', 313 func.name, param.cbRetvalueDefine); 314 } 315 } 316 return [middleFunc, implH, implCpp, middleH]; 317} 318 319function getMiddleFunc(middleFunc, callFunc, param) { 320 middleFunc = replaceAll(middleFunc, '[callFunc]', callFunc); // 执行 321 let optionalCallback = getOptionalCallbackInit(param); 322 middleFunc = replaceAll(middleFunc, '[optionalCallbackInit]', optionalCallback); // 可选callback参数初始化 323 middleFunc = replaceAll(middleFunc, '[valuePackage]', param.valuePackage); // 输出参数打包 324 middleFunc = replaceAll(middleFunc, '[optionalParamDestory]', param.optionalParamDestory); // 可选参数内存释放 325 middleFunc = replaceAll(middleFunc, '[agrs_size]', param.paramSize); 326 327 middleFunc = middleFunc.replaceAll('[callback_param_offset]', param.callback.offset); // 呼叫回调 328 return middleFunc; 329} 330 331function isClassFunc(className, middleH, middleFunc) { 332 if (className === null || className === undefined) { 333 middleH = middleH.replaceAll('[static_define]', ''); 334 middleFunc = middleFunc.replaceAll('[unwarp_instance]', ''); 335 middleFunc = middleFunc.replaceAll('[middleClassName]', ''); 336 } 337 else { 338 middleH = middleH.replaceAll('[static_define]', 'static '); 339 middleFunc = middleFunc.replaceAll('[unwarp_instance]', 340 `void *instPtr = pxt->UnWarpInstance(); 341 %s *pInstance = static_cast<%s *>(instPtr);`.format(className, className)); 342 middleFunc = middleFunc.replaceAll('[middleClassName]', className + '_middle' + '::'); 343 } 344 return [middleH, middleFunc]; 345} 346 347module.exports = { 348 generateFunctionSync 349};