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 { isMappedTypeNode } = require('typescript'); 16const { InterfaceList, getArrayType, NumberIncrease, enumIndex, 17 isEnum, EnumValueType, getArrayTypeTwo, getMapType, EnumList, 18 jsType2CType, getUnionType, TypeList, isArrowFunc, getLogErrInfo } = require('../tools/common'); 19const { NapiLog } = require('../tools/NapiLog'); 20const { print } = require('../tools/tool'); 21 22const specialPrefixArr = ['p->', 'vio->out.']; 23 24/** 25 * Get the real value name by deleting prefix like "p->", "vio->out.", e.g. 26 * @param {*} valueName, example: p->xxx, vio->out.yyy 27 * @returns the real value without prefix, example: xxx, yyy 28 */ 29function delPrefix(valueName) { 30 return specialPrefixArr.reduce((result, prefix) => { 31 if (valueName.startsWith(prefix)) { 32 return valueName.substring(prefix.length); 33 } 34 return result; 35 }, valueName); 36} 37 38function cToJsForType(value, type, dest, deep) { 39 let lt = deep; 40 let result = ''; 41 let ifl = TypeList.getValue(type); 42 if (typeof (ifl) === 'object') { 43 for (let i in ifl) { 44 let name2 = ifl[i].name; 45 let type2 = ifl[i].type; 46 let optional2 = ifl[i].optional; 47 let isSubEnum = EnumList.getValue(type2) ? true : false; 48 let subDest = isSubEnum ? dest : 'tnv%d'.format(lt); 49 let typeType = null; 50 let ifOptional = ''; // 如果是可选参数则需要增加可选参数是否有值的判断 51 if (optional2) { 52 ifOptional = 'if (%s.%s.has_value())\n'.format(value, name2); 53 typeType = cToJs('%s.%s'.format(value, '%s.value()'.format(name2)), type2, subDest, deep + 1); 54 } else { 55 typeType = cToJs('%s.%s'.format(value, name2), type2, subDest, deep + 1); 56 } 57 if (isSubEnum) { 58 result += typeType; 59 } else { 60 result += '%s{\nnapi_value tnv%d = nullptr;\n'.format(ifOptional, lt) + 61 typeType + `\npxt->SetValueProperty(%s, "%s", tnv%d);\n}\n` 62 .format(dest, name2, lt); 63 } 64 } 65 } else { 66 result += cToJs(value, ifl, dest, deep); 67 } 68 return result; 69} 70 71function cToJsForInterface(value, type, dest, deep) { 72 let lt = deep; 73 let result = ''; 74 let ifl = InterfaceList.getValue(type); 75 for (let i in ifl) { 76 let name2 = ifl[i].name; 77 let type2 = ifl[i].type; 78 let optional2 = ifl[i].optional; 79 let isSubEnum = EnumList.getValue(type2) ? true : false; 80 let subDest = isSubEnum ? dest : 'tnv%d'.format(lt); 81 let interfaceType = null; 82 let ifOptional = ''; 83 if (optional2) { 84 ifOptional = 'if (%s.%s.has_value())\n'.format(value, name2); 85 interfaceType = cToJs('%s.%s'.format(value, '%s.value()'.format(name2)), type2, subDest, deep + 1); 86 } else { 87 interfaceType = cToJs('%s.%s'.format(value, name2), type2, subDest, deep + 1); 88 } 89 90 if (isSubEnum) { 91 // interface include enum properties 92 result += interfaceType; 93 } else { 94 result += '%s{\nnapi_value tnv%d = nullptr;\n'.format(ifOptional, lt) + 95 interfaceType + `\npxt->SetValueProperty(%s, "%s", tnv%d);\n}\n` 96 .format(dest, name2, lt); 97 } 98 } 99 return result; 100} 101 102function c2JsForEnum(deep, type, value, dest, propertyName) { 103 let lt = deep; 104 let result = ''; 105 let ifl = EnumList.getValue(type); 106 let type2 = ''; 107 if (ifl && ifl.length > 0) { 108 type2 = ifl[0].type; 109 } 110 let enumCtoJsStr = cToJs('enumC2Js%d'.format(lt), type2, dest, deep); 111 if (type2 === 'string') { 112 // string型枚举的getvalue函数 113 result += '{\nstd::string enumC2Js%d = %s;\n'.format(lt, value) + enumCtoJsStr + '}\n'; 114 } else { 115 // number型枚举的getvalue函数 116 result += ` 117 std::underlying_type<%s>::type enumType; 118 if (typeid(enumType) == typeid(uint32_t)) { 119 uint32_t enumC2Js%d = static_cast<uint32_t>(%s); 120 %s 121 } else if (typeid(enumType) == typeid(int32_t)) { 122 int32_t enumC2Js%d = static_cast<int32_t>(%s); 123 %s 124 } else if (typeid(enumType) == typeid(int64_t)) { 125 int64_t enumC2Js%d = static_cast<int64_t>(%s); 126 %s 127 } else if (typeid(enumType) == typeid(double_t)) { 128 double_t enumC2Js%d = static_cast<double_t>(%s); 129 %s 130 }`.format(type, lt, value, enumCtoJsStr, lt, value, enumCtoJsStr, lt, value, enumCtoJsStr, 131 lt, value, enumCtoJsStr,); 132 } 133 return result; 134} 135 136function cToJs(value, type, dest, deep = 1, optional, enumType = 0) { 137 let propertyName = delPrefix(value); 138 if (checkRetIsUndefined(type)) { 139 NapiLog.logError('type is invalid!'); 140 return undefined; 141 } 142 if (type.indexOf('|') >= 0) { 143 return unionTempleteFunc(value, type, dest, optional); 144 } else if (type === 'void') { 145 return '%s = pxt->UndefinedValue();\n'.format(dest); 146 } 147 else if (type === 'boolean') { 148 return '%s = pxt->SwapC2JsBool(%s);\n'.format(dest, value.replace('[replace]', deep - 2)); 149 } 150 else if (type === 'string') { 151 return `%s = pxt->SwapC2JsUtf8(%s.c_str());\n`.format(dest, value.replace('[replace]', deep - 2)); 152 } 153 else if (InterfaceList.getValue(type)) { 154 return cToJsForInterface(value, type, dest, deep); 155 } 156 else if (TypeList.getValue(type)) { 157 return cToJsForType(value, type, dest, deep); 158 } 159 else if (EnumList.getValue(type)) { 160 return c2JsForEnum(deep, type, value, dest, propertyName); 161 } 162 else if (checkRetIsArray(type)) { 163 let arrayType = checkArrayParamType(type); 164 return arrayTempleteFunc(arrayType, deep, dest, value); 165 } 166 else if (checkRetIsMap(type)) { 167 return mapTempleteFunc(type, deep, dest, value); 168 } 169 else if (type.substring(0, 12) === 'NUMBER_TYPE_') { 170 if (enumType) { 171 return c2JsForRetEnum(enumType, value, deep, dest); 172 } else { 173 return `%s = NUMBER_C_2_JS(pxt, %s);\n`.format(dest, value.replace('[replace]', deep - 2)); 174 } 175 } 176 else if (type === 'any') { 177 return anyTempleteFunc(value); 178 } 179 else if (checkRetIsObject(type)) { 180 return objectTempleteFuncReturn(value); 181 } 182 else { 183 NapiLog.logError(`\n---- This type do not generate cToJs %s,%s,%s ----\n. `.format(value, type, dest), getLogErrInfo()); 184 return undefined; 185 } 186} 187 188function checkRetIsUndefined(type) { 189 return type === null || type === undefined; 190} 191 192function checkRetIsObject(type) { 193 return type === 'Object' || type === 'object'; 194} 195 196function checkRetIsArray(type) { 197 return type.substring(0, 6) === 'Array<' || type.substring(type.length - 2) === '[]'; 198} 199 200function checkRetIsMap(type) { 201 return type.substring(0, 4) === 'Map<' || type.indexOf('{[key:') === 0; 202} 203 204function c2JsForRetEnum(enumType, value, deep, dest) { 205 let retEnum = `std::underlying_type<%s>::type enumType; 206 if (typeid(enumType) == typeid(uint32_t)) { 207 uint32_t uintValue = static_cast<uint32_t>(%s); 208 %s = NUMBER_C_2_JS(pxt, uintValue); 209 } else if (typeid(enumType) == typeid(int32_t)) { 210 int32_t intValue = static_cast<int32_t>(%s); 211 %s = NUMBER_C_2_JS(pxt, intValue); 212 } else if (typeid(enumType) == typeid(int64_t)) { 213 int64_t intValue = static_cast<int64_t>(%s); 214 %s = NUMBER_C_2_JS(pxt, intValue); 215 } else if (typeid(enumType) == typeid(double_t)) { 216 double_t doubleValue = static_cast<double_t>(%s); 217 %s = NUMBER_C_2_JS(pxt, doubleValue); 218 } else { 219 napi_throw_error(env, nullptr, "enum return value is wrong!"); 220 return nullptr; 221 }`.format(enumType, value.replace('[replace]', deep - 2), dest, value.replace('[replace]', deep - 2), dest, 222 value.replace('[replace]', deep - 2), dest, value.replace('[replace]', deep - 2), dest); 223 return retEnum; 224} 225 226function objectTempleteFuncReturn(value) { 227 let objectTemplete = `pxt->GetObjectValue(result, %s);` 228 .format(value); 229 return objectTemplete; 230} 231 232function unionTempleteFunc(value, type, dest, optional) { 233 let unionType = getUnionType(type); 234 let unionTypeString = ''; 235 let typeStr = 'type'; 236 let valueTmp = value + '.value()'; 237 if (optional) { 238 typeStr = 'type.value()'; 239 } 240 let value2 = optional ? valueTmp : value; 241 for (let i = 0; i < unionType.length; i++) { 242 if (unionType[i] === 'string') { 243 unionTypeString += `if (%s_%s == "string") { 244 %s 245 %s 246 }\n`.format(value, typeStr, 'std::string union_string = std::any_cast<std::string>(' + value2 + ');', 247 cToJs('union_string', unionType[i], dest)); 248 } else if (unionType[i].substring(0, 12) === 'NUMBER_TYPE_') { 249 unionTypeString += `if (%s_%s == "number") { 250 %s 251 %s 252 }\n`.format(value, typeStr, 'std::uint32_t union_number = std::any_cast<std::uint32_t>(' + value2 + ');', 253 cToJs('union_number', unionType[i], dest)); 254 } else if (unionType[i] === 'boolean') { 255 unionTypeString += `if (%s_%s == "boolean") { 256 %s 257 %s 258 }\n`.format(value, typeStr, 'bool union_boolean = std::any_cast<bool>(' + value2 + ');', 259 cToJs('union_boolean', unionType[i], dest)); 260 } 261 } 262 if (optional) { 263 let result = 264 `if (%s.has_value()) { 265 %s 266 }\n`.format(value, unionTypeString); 267 return result; 268 } else { 269 return unionTypeString; 270 } 271} 272 273function checkArrayParamType(type) { 274 let arrayType; 275 if (type.substring(type.length - 2) === '[]') { 276 arrayType = getArrayTypeTwo(type); 277 } 278 else { 279 arrayType = getArrayType(type); 280 } 281 return arrayType; 282} 283 284function arrayTempleteFunc(arrayType, deep, dest, value) { 285 let lt = deep; 286 let tnv = dest; 287 let tnvdef = `pxt->CreateArray(%s); 288 uint32_t outLen%d = %s.size(); 289 for (uint32_t i%d = 0; i%d < outLen%d; i%d++) { 290 napi_value tnv%d = nullptr; 291 [calc_out] 292 pxt->SetArrayElement(%s, i%d, tnv%d); 293 }`.format(tnv, lt, value.replace('[replace]', lt - 2), lt, lt, lt, lt, lt, tnv, lt, lt); 294 let ret = ''; 295 if (arrayType.substring(0, 12) === 'NUMBER_TYPE_') { 296 ret = tnvdef.replaceAll('[calc_out]', `tnv%d = NUMBER_C_2_JS(pxt, %s[i%d]);` 297 .format(lt, value.replace('[replace]', lt), lt)); 298 } 299 else if (arrayType === 'string') { 300 ret = tnvdef.replaceAll('[calc_out]', `tnv%d = pxt->SwapC2JsUtf8(%s[i%d].c_str());` 301 .format(lt, value.replace('[replace]', lt), lt)); 302 } 303 else if (arrayType === 'boolean') { 304 ret = tnvdef.replaceAll('[calc_out]', `tnv%d = pxt->SwapC2JsBool(%s[i%d]);` 305 .format(lt, value.replace('[replace]', lt), lt)); 306 } 307 else if (arrayType === 'any') { 308 return anyArrayTempleteFuncReturn(value.replace('[replace]', lt)); 309 } 310 else if (InterfaceList.getValue(arrayType)) { 311 ret = tnvdef.replaceAll('[calc_out]', cToJs(value + '[i[replace]]', arrayType, 'tnv' + lt, deep + 1)); 312 } 313 return ret; 314} 315 316function mapTempleteFunc(type, deep, dest, value) { 317 let mapType = getMapType(type); 318 let lt = deep; 319 let tnv = dest; 320 let tnvdef = `result = nullptr; 321 for (auto i = %s.begin(); i != %s.end(); i++) { 322 const char * tnv%d; 323 napi_value tnv%d = nullptr; 324 [calc_out] 325 pxt->SetMapElement(%s, tnv%d, tnv%d); 326 }`.format(value, value, lt, lt + 1, tnv, lt, lt + 1); 327 let ret = ''; 328 if (mapType[1] !== undefined && mapType[2] === undefined) { 329 ret = mapTempleteValue(mapType, tnvdef, lt, value, tnv); 330 } 331 else if (mapType[2] !== undefined) { 332 ret = mapTempleteMap(mapType, tnvdef, lt); 333 } 334 else if (mapType[3] !== undefined) { 335 ret = mapTempleteArray(mapType, tnvdef, lt); 336 } 337 return ret; 338} 339 340function anyTempleteFunc(value) { 341 let anyTemplete = `pxt->GetAnyValue(%s_type, result, %s);` 342 .format(value, value); 343 344 return anyTemplete; 345} 346 347function anyArrayTempleteFuncReturn(value) { 348 let anyTemplete = `pxt->GetAnyValue(%s_type, result, %s);` 349 .format(value, value); 350 351 return anyTemplete; 352} 353 354function mapInterface(value, lt, tnv, mapType) { 355 let ret; 356 let tnvdefInterface = `result = nullptr; 357 for (auto i = %s.begin(); i != %s.end(); i++) { 358 const char *tnv%d; 359 [calc_out] 360 }`.format(value, value, lt, lt + 1, tnv, lt, lt + 1); 361 let interfaceValue = InterfaceList.getValue(mapType[1]); 362 let interfaceVarName = ''; 363 let interfaceVar = ''; 364 let interfaceFun = ''; 365 for (let i = 0; i < interfaceValue.length; i++) { 366 if (interfaceValue[i].type === 'string') { 367 interfaceVarName += `const char *tnv_%s_name; 368 napi_value tnv_%s = nullptr;\n`.format(interfaceValue[i].name, interfaceValue[i].name); 369 interfaceVar += `tnv_%s_name = "%s"; 370 tnv_%s = pxt->SwapC2JsUtf8(i->second.%s.c_str());\n` 371 .format(interfaceValue[i].name, interfaceValue[i].name, interfaceValue[i].name, interfaceValue[i].name); 372 interfaceFun += `pxt->SetMapElement(result_obj, tnv_%s_name, tnv_%s);\n` 373 .format(interfaceValue[i].name, interfaceValue[i].name, interfaceValue[i].name); 374 } 375 else if (interfaceValue[i].type.substring(0, 12) === 'NUMBER_TYPE_') { 376 interfaceVarName += `const char *tnv_%s_name; 377 napi_value tnv_%s = nullptr;\n`.format(interfaceValue[i].name, interfaceValue[i].name); 378 interfaceVar += `tnv_%s_name = "%s"; 379 tnv_%s = NUMBER_C_2_JS(pxt, i->second.%s);\n` 380 .format(interfaceValue[i].name, interfaceValue[i].name, interfaceValue[i].name, interfaceValue[i].name); 381 interfaceFun += `pxt->SetMapElement(result_obj, tnv_%s_name, tnv_%s);\n` 382 .format(interfaceValue[i].name, interfaceValue[i].name, interfaceValue[i].name); 383 } 384 else if (interfaceValue[i].type === 'boolean') { 385 interfaceVarName += `const char *tnv_%s_name; 386 napi_value tnv_%s = nullptr;\n`.format(interfaceValue[i].name, interfaceValue[i].name); 387 interfaceVar += `tnv_%s_name = "%s"; 388 tnv_%s = pxt->SwapC2JsBool(i->second.%s);\n` 389 .format(interfaceValue[i].name, interfaceValue[i].name, interfaceValue[i].name, interfaceValue[i].name); 390 interfaceFun += `pxt->SetMapElement(result_obj, tnv_%s_name, tnv_%s);\n` 391 .format(interfaceValue[i].name, interfaceValue[i].name, interfaceValue[i].name); 392 } 393 } 394 ret = tnvdefInterface.replaceAll('[calc_out]', `tnv%d = (i -> first).c_str(); 395 napi_value result_obj = nullptr; 396 %s 397 %s 398 %s 399 pxt->SetMapElement(result, tnv%d, result_obj);` 400 .format(lt, interfaceVarName, interfaceVar, interfaceFun, lt)); 401 return ret; 402} 403 404function mapTempleteValue(mapType, tnvdef, lt, value, tnv) { 405 let ret; 406 if (mapType[1] === 'string') { 407 ret = tnvdef.replaceAll('[calc_out]', `tnv%d = (i -> first).c_str(); 408 tnv%d = pxt->SwapC2JsUtf8(i->second.c_str());`.format(lt, lt + 1)); 409 } else if (mapType[1] === 'boolean') { 410 ret = tnvdef.replaceAll('[calc_out]', `tnv%d = (i -> first).c_str(); 411 tnv%d = pxt->SwapC2JsBool(i->second);`.format(lt, lt + 1)); 412 } else if (mapType[1].substring(0, 12) === 'NUMBER_TYPE_') { 413 ret = tnvdef.replaceAll('[calc_out]', `tnv%d = (i -> first).c_str(); 414 tnv%d = NUMBER_C_2_JS(pxt, i->second);`.format(lt, lt + 1)); 415 } else if (mapType[1] === 'any') { 416 ret = tnvdef.replaceAll('[calc_out]', `tnv%d = (i -> first).c_str(); 417 pxt->GetAnyValue(%s_type, tnv%d, i->second);`.format(lt, value, lt + 1)); 418 } 419 else if (InterfaceList.getValue(mapType[1])) { 420 ret = mapInterface(value, lt, tnv, mapType); 421 } 422 else { 423 NapiLog.logError(`This type do not generate cToJs %s,%s,%s` 424 .format(value, type, dest), getLogErrInfo()); 425 } 426 return ret; 427} 428 429function mapTempleteMap(mapType, tnvdef, lt) { 430 let ret; 431 if (mapType[2] === 'string') { 432 ret = tnvdef.replaceAll('[calc_out]', `tnv%d = i->first.c_str(); 433 for (auto j = i->second.begin(); j != i->second.end(); j++) { 434 const char *tt%d; 435 napi_value tt%d; 436 tt%d = j->first.c_str(); 437 tt%d = pxt->SwapC2JsUtf8(j->second.c_str()); 438 pxt->SetMapElement(tnv%d, tt%d, tt%d); 439 }`.format(lt, lt + 2, lt + 3, lt + 2, lt + 3, lt + 1, lt + 2, lt + 3)); 440 } 441 else if (mapType[2] === 'boolean') { 442 ret = tnvdef.replaceAll('[calc_out]', `tnv%d = i->first.c_str(); 443 for (auto j = i->second.begin(); j != i->second.end(); j++) { 444 const char *tt%d; 445 napi_value tt%d; 446 tt%d = j->first.c_str(); 447 tt%d = pxt->SwapC2JsBool(j->second); 448 pxt->SetMapElement(tnv%d, tt%d, tt%d); 449 }`.format(lt, lt + 2, lt + 3, lt + 2, lt + 3, lt + 1, lt + 2, lt + 3)); 450 } 451 if (mapType[2].substring(0, 12) === 'NUMBER_TYPE_') { 452 ret = tnvdef.replaceAll('[calc_out]', `tnv%d = i->first.c_str(); 453 for (auto j = i->second.begin(); j != i->second.end(); j++) { 454 const char *tt%d; 455 napi_value tt%d; 456 tt%d = j->first.c_str(); 457 tt%d = NUMBER_C_2_JS(pxt, j->second); 458 pxt->SetMapElement(tnv%d, tt%d, tt%d); 459 }`.format(lt, lt + 2, lt + 3, lt + 2, lt + 3, lt + 1, lt + 2, lt + 3)); 460 } 461 return ret; 462} 463 464function mapTempleteArray(mapType, tnvdef, lt) { 465 let ret; 466 if (mapType[3] === 'string') { 467 ret = tnvdef.replaceAll('[calc_out]', `napi_value tnv%d = nullptr; 468 pxt->CreateArray(tnv%d); 469 tnv%d = (i -> first).c_str(); 470 uint32_t len%d = i->second.size(); 471 for (uint32_t j = 0; j < len%d; j++) { 472 tnv%d = pxt->SwapC2JsUtf8(i->second[j].c_str()); 473 pxt->SetArrayElement(tnv%d, j, tnv%d); 474 }`.format(lt + 2, lt + 2, lt, lt, lt, lt + 2, lt + 1, lt + 2)); 475 } else if (mapType[3] === 'boolean') { 476 ret = tnvdef.replaceAll('[calc_out]', `napi_value tnv%d = nullptr; 477 pxt->CreateArray(tnv%d); 478 tnv%d = (i -> first).c_str(); 479 uint32_t len%d = i->second.size(); 480 for (uint32_t j = 0; j < len%d; j++) { 481 tnv%d = pxt->SwapC2JsBool(i->second[j]); 482 pxt->SetArrayElement(tnv%d, j, tnv%d); 483 }`.format(lt + 2, lt + 2, lt, lt, lt, lt + 2, lt + 1, lt + 2)); 484 } else if (mapType[3].substring(0, 12) === 'NUMBER_TYPE_') { 485 ret = tnvdef.replaceAll('[calc_out]', `napi_value tnv%d = nullptr; 486 pxt->CreateArray(tnv%d); 487 tnv%d = (i -> first).c_str(); 488 uint32_t len%d = i->second.size(); 489 for (uint32_t j = 0; j < len%d; j++) { 490 tnv%d = NUMBER_C_2_JS(pxt, i->second[j]); 491 pxt->SetArrayElement(tnv%d, j, tnv%d); 492 }`.format(lt + 2, lt + 2, lt, lt, lt, lt + 2, lt + 1, lt + 2)); 493 } 494 return ret; 495} 496 497function returnGenerateMap(returnInfo, param) { 498 let type = returnInfo.type; 499 let mapType = getMapType(type); 500 let mapTypeString; 501 if (mapType[1] !== undefined && mapType[2] === undefined) { 502 if (mapType[1] === 'string') { mapTypeString = 'std::string' } 503 else if (mapType[1].substring(0, 12) === 'NUMBER_TYPE_') { mapTypeString = mapType[1] } 504 else if (mapType[1] === 'boolean') { mapTypeString = 'bool' } 505 else if (mapType[1] === 'any') { mapTypeString = 'std::any' } 506 else { mapTypeString = mapType[1] } 507 } 508 else if (mapType[2] !== undefined) { 509 if (mapType[2] === 'string') { mapTypeString = 'std::map<std::string, std::string>' } 510 else if (mapType[2].substring(0, 12) === 'NUMBER_TYPE_') { 'std::map<std::string, ' + mapType[2] + '>' } 511 else if (mapType[2] === 'boolean') { mapTypeString = 'std::map<std::string, bool>' } 512 } 513 else if (mapType[3] !== undefined) { 514 if (mapType[3] === 'string') { mapTypeString = 'std::vector<std::string>' } 515 else if (mapType[3].substring(0, 12) === 'NUMBER_TYPE_') { mapTypeString = 'std::vector<' + mapType[3] + '>' } 516 else if (mapType[3] === 'boolean') { mapTypeString = 'std::vector<bool>' } 517 } 518 let modifiers = returnInfo.optional ? '*' : '&'; 519 param.valueOut = returnInfo.optional ? 'std::map<std::string, %s>* out = nullptr;'.format(mapTypeString) 520 : 'std::map<std::string, %s> out;'.format(mapTypeString); 521 param.valueDefine += '%sstd::map<std::string, %s>%s out' 522 .format(param.valueDefine.length > 0 ? ', ' : '', mapTypeString, modifiers); 523} 524 525function returnGenerateUnion(param) { 526 param.valueOut = `std::any out; 527 std::string out_type;\n`; 528 param.valueDefine += '%sstd::any &out'.format(param.valueDefine.length > 0 ? ', ' : ''); 529} 530 531function returnGenerateObject(returnInfo, param, data) { 532 param.valueOut = `std::map<std::string, std::any> out;\n`; 533 param.valueDefine += '%sstd::map<std::string, std::any> &out'.format(param.valueDefine.length > 0 ? ', ' : ''); 534 535} 536 537/** 538 * 获取方法返回参数的填充代码 539 * @param returnInfo 方法的返回参数信息 540 * @param param 方法的所有参数信息 541 * @returns 返回参数的填充代码123 返回测试的值 542 */ 543function getReturnFill(returnInfo, param) { 544 let type = returnInfo.type; 545 let valueFillStr = ''; 546 if (isArrowFunc(type)) { 547 return valueFillStr; 548 } 549 550 if (param.callback) { // callback方法的返回参数处理 551 if (param.callback.isAsync) { 552 // 异步callback方法返回的是一个结构体,包含errcode和data两部分, 详见basic.d.ts中AsyncCallback的定义 553 valueFillStr = 'vio->outErrCode'; 554 param.valueDefine += '%suint32_t& outErrCode'.format(param.valueDefine.length > 0 ? ', ' : ''); 555 } 556 557 if (type !== 'void') { 558 // callback<xxx> 中的xxx不是void时,生成的cpp代码才需要用户填充out参数 559 if (param.callback.isArrowFuncFlag) { 560 valueFillStr += '%svio->%s'.format(valueFillStr.length > 0 ? ', ' : '', returnInfo.name); 561 } else { 562 valueFillStr += '%svio->out'.format(valueFillStr.length > 0 ? ', ' : ''); 563 } 564 } 565 } else { // 普通方法的返回参数处理 566 valueFillStr = 'vio->out'; 567 } 568 return valueFillStr; 569} 570 571function isObjectType(type) { 572 if (type === 'Object' || type === 'object') { 573 return true; 574 } 575 return false; 576} 577 578function generateOptionalAndUnion(returnInfo, param, data, outParam, c2JsresultName = 'result') { 579 let type = returnInfo.type; 580 if (type === undefined) { 581 NapiLog.logError('returnGenerate: type of returnInfo is undefined!'); 582 return; 583 } 584 585 if (returnInfo.optional) { 586 param.optionalParamDestory += 'C_DELETE(vio->out);\n '; 587 } 588 589 // 判断callback是否有效,若无效,则为普通函数 590 let paramCallbackFlag = param.callback !== undefined ? true : false; 591 let paramCallbackIsArrow; 592 if (paramCallbackFlag) { // 若callback有效, 判断是否是箭头函数 593 paramCallbackIsArrow = param.callback.isArrowFuncFlag; 594 } 595 // 普通函数 paramCallbackFlag === undefined 596 if (!isEnum(type, data) && !isArrowFunc(type) && !paramCallbackIsArrow) { 597 param.valuePackage = cToJs(outParam, type, c2JsresultName); 598 } else if (type.indexOf('|') >= 0) { 599 returnGenerateUnion(param); 600 } 601} 602 603function returnGenerateForArrowCbMultiPara(paramInfo, param, data, i) { 604 let type = paramInfo.type; 605 if (type === undefined) { 606 NapiLog.logError('returnGenerate: type of %s is undefined!'.format(paramInfo)); 607 return; 608 } 609 let valueFillStr = getReturnFill(paramInfo, param); 610 param.valueFill += ('%s' + valueFillStr).format(param.valueFill.length > 0 ? ', ' : ''); 611 let outParam = paramInfo.optional ? '(*vio->%s)' : 'vio->%s'.format(paramInfo.name, paramInfo.name); 612 613 // 回调为,参数个数为1,其转换结果保存在result中 614 // 回调给箭头函数,支持参数个数大于1,参数转换结果保存在args[i] 615 generateOptionalAndUnion(paramInfo, param, data, outParam); 616 param.valuePackage += cToJs(outParam, type, 'args[%s]'.format(i)); 617 618 let modifiers = paramInfo.optional ? '*' : '&'; 619 if (type === 'string') { 620 param.valueOut += paramInfo.optional ? 'std::string* %s = nullptr;' : 'std::string %s;\n' 621 .format(paramInfo.name, paramInfo.name); 622 param.valueDefine += '%sstd::string%s %s'.format(param.valueDefine.length > 0 ? ', ' : '', modifiers, 623 paramInfo.name); 624 } 625 else if (type === 'void') { 626 NapiLog.logInfo('The current void type don\'t need generate'); 627 } 628 else if (type === 'boolean') { 629 param.valueOut += paramInfo.optional ? 'bool* %s = nullptr;' : 'bool %s;\n' 630 .format(paramInfo.name, paramInfo.name); 631 param.valueDefine += '%sbool%s %s'.format(param.valueDefine.length > 0 ? ', ' : '', modifiers, paramInfo.name); 632 } 633 else if (type.substring(0, 12) === 'NUMBER_TYPE_') { 634 param.valueOut += type + (paramInfo.optional ? '* %s = nullptr;' : ' %s;\n') 635 .format(paramInfo.name, paramInfo.name); 636 param.valueDefine += '%s%s%s %s'.format(param.valueDefine.length > 0 ? ', ' : '', type, modifiers, 637 paramInfo.name); 638 } 639 else { 640 NapiLog.logError('Do not support returning the type [%s].' 641 .format(type), getLogErrInfo()); 642 } 643} 644 645function returnGenerateForOnOffMultiPara(paramInfo, param, data) { 646 let type = paramInfo.type; 647 if (type === undefined) { 648 NapiLog.logError('returnGenerate: type of %s is undefined!'.format(paramInfo)); 649 return; 650 } 651 let valueFillStr = getReturnFill(paramInfo, param); 652 param.valueFill += ('%s' + valueFillStr).format(param.valueFill.length > 0 ? ', ' : ''); 653 let outParam = paramInfo.optional ? '(*vio->%s)' : 'vio->%s'.format(paramInfo.name, paramInfo.name); 654 655 generateOptionalAndUnion(paramInfo, param, data, outParam); 656 657 param.useParams += '%s %s'.format(param.useParams.length > 0 ? ', ' : '', paramInfo.name); 658 param.resultDefine += 'napi_value %sNapi = nullptr;\n '.format(paramInfo.name); 659 param.cbParams += cToJs(paramInfo.name, paramInfo.type, paramInfo.name + 'Napi') + '\n'; 660 661 let modifiers = paramInfo.optional ? '*' : '&'; 662 if (type === 'string') { 663 param.valueOut += paramInfo.optional ? 'std::string* %s = nullptr;' : 'std::string %s;\n' 664 .format(paramInfo.name, paramInfo.name); 665 param.params += '%sstd::string%s %s'.format(param.params.length > 0 ? ', ' : '', modifiers, 666 paramInfo.name); 667 } 668 else if (type === 'void') { 669 NapiLog.logInfo('The current void type don\'t need generate'); 670 } 671 else if (type === 'boolean') { 672 param.valueOut += paramInfo.optional ? 'bool* %s = nullptr;' : 'bool %s;\n' 673 .format(paramInfo.name, paramInfo.name); 674 param.params += '%sbool%s %s'.format(param.params.length > 0 ? ', ' : '', modifiers, paramInfo.name); 675 } 676 else if (type.substring(0, 12) === 'NUMBER_TYPE_') { 677 param.valueOut += type + (paramInfo.optional ? '* %s = nullptr;' : ' %s;\n') 678 .format(paramInfo.name, paramInfo.name); 679 param.params += '%s%s%s %s'.format(param.params.length > 0 ? ', ' : '', type, modifiers, 680 paramInfo.name); 681 } 682 else if (generateType(type)) { 683 returnGenerate2(paramInfo, param, data); 684 param.params += '%s%s%s %s'.format(param.params.length > 0 ? ', ' : '', type, modifiers, paramInfo.name); 685 } 686 else { 687 NapiLog.logError('Do not support returning the type [%s].' 688 .format(type), getLogErrInfo()); 689 } 690} 691 692function returnGenerate(returnInfo, param, data, isOnFuncFlag = false) { 693 if (returnInfo === undefined) { 694 NapiLog.logError('returnGenerate: returnInfo is undefined!'); 695 return; 696 } 697 let type = returnInfo.type; 698 if (type === undefined) { 699 NapiLog.logError('returnGenerate: type of %s is undefined!'.format(returnInfo)); 700 return; 701 } 702 let valueFillStr = getReturnFill(returnInfo, param); 703 param.valueFill += ('%s' + valueFillStr).format(param.valueFill.length > 0 ? ', ' : ''); 704 let outParam = returnInfo.optional ? '(*vio->out)' : 'vio->out'; 705 let modifiers = returnInfo.optional ? '*' : '&'; 706 707 let result = onCallbackC2JsResName(isOnFuncFlag, type, outParam); 708 let c2JsresultName = result[0]; 709 outParam = result[1]; 710 generateOptionalAndUnion(returnInfo, param, data, outParam, c2JsresultName); 711 712 returnGenerateCheckType(type, param, returnInfo, modifiers, data); 713} 714 715function returnGenerateCheckType(type, param, returnInfo, modifiers, data) { 716 if (type === 'string') { 717 param.valueOut = returnInfo.optional ? 'std::string* out = nullptr;' : 'std::string out;\n'; 718 param.valueDefine += '%sstd::string%s out'.format(param.valueDefine.length > 0 ? ', ' : '', modifiers); 719 } else if (type === 'void') { 720 NapiLog.logInfo('The current void type do not need generate'); 721 } else if (type === 'boolean') { 722 param.valueOut = returnInfo.optional ? 'bool* out = nullptr;' : 'bool out;\n'; 723 param.valueDefine += '%sbool%s out'.format(param.valueDefine.length > 0 ? ', ' : '', modifiers); 724 } else if (isEnum(type, data)) { 725 returnGenerateEnum(data, returnInfo, param); 726 } else if (generateType(type)) { 727 returnGenerate2(returnInfo, param, data); 728 } else if (type.substring(0, 12) === 'NUMBER_TYPE_') { 729 param.valueOut = type + (returnInfo.optional ? '* out = nullptr;' : ' out;\n'); 730 param.valueDefine += '%s%s%s out'.format(param.valueDefine.length > 0 ? ', ' : '', type, modifiers); 731 } else if (isObjectType(type)) { 732 returnGenerateObject(returnInfo, param, data); 733 } else if (isArrowFunc(type)) { 734 genArrowFuncParam(param, returnInfo, data); 735 } else { 736 NapiLog.logError('Do not support returning the type [%s].' 737 .format(type), getLogErrInfo()); 738 } 739} 740 741function genArrowFuncParam(param, returnInfo, data) { 742 param.paramSize = returnInfo.arrowFuncParamList.length; 743 for (let i = 0; i < returnInfo.arrowFuncParamList.length; i++) { 744 let paramInfo = { 745 name: returnInfo.arrowFuncParamList[i].name, 746 type: returnInfo.arrowFuncParamList[i].type, 747 optional: returnInfo.optional, 748 }; 749 if (returnInfo.onFlag) { //on/off处理 750 returnGenerateForOnOffMultiPara(paramInfo, param, data); 751 param.valueSetArray += 'napi_set_element(pAsyncFuncs->env_, result, %d, %sNapi);\n ' 752 .format(i, paramInfo.name); 753 } else { 754 returnGenerateForArrowCbMultiPara(paramInfo, param, data, i); 755 } 756 } 757} 758 759function onCallbackC2JsResName(isOnFuncFlag, type, outParam) { 760 let c2JsresultName = 'result'; 761 if (isOnFuncFlag && !isArrowFunc(type) && type !== 'void') { // on事件普通回调方法的参数 762 outParam = 'valueIn'; 763 c2JsresultName = 'resultTmp'; 764 } 765 return [c2JsresultName, outParam]; 766} 767 768function generateType(type) { 769 if (InterfaceList.getValue(type)) { 770 return true; 771 } 772 else if (TypeList.getValue(type)) { 773 return true; 774 } 775 else if (type.substring(0, 6) === 'Array<') { 776 return true; 777 } 778 else if (type.substring(type.length - 2) === '[]') { 779 return true; 780 } 781 else if (type.substring(0, 4) === 'Map<' || type.indexOf('{[key:') === 0) { 782 return true; 783 } 784 else if (type === 'any' || type === 'Object' || type === 'object') { 785 return true; 786 } 787 else { 788 return false; 789 } 790} 791function isMapType(type) { 792 if (type.substring(0, 4) === 'Map<' || type.indexOf('{[key:') === 0) { 793 return true; 794 } 795 return false; 796} 797 798function returnGenerate2(returnInfo, param, data) { 799 let type = returnInfo.type; 800 let modifiers = returnInfo.optional ? '*' : '&'; 801 802 let flag = InterfaceList.getValue(type) || TypeList.getValue(type); 803 if (flag) { 804 param.valueOut = type + (returnInfo.optional ? '* out = nullptr;' : ' out;\n'); 805 param.valueDefine += '%s%s%s out'.format(param.valueDefine.length > 0 ? ', ' : '', type, modifiers); 806 } else if (type.substring(0, 6) === 'Array<') { 807 returnArrayGen(type, param, returnInfo, modifiers); 808 } else if (type.substring(type.length - 2) === '[]') { 809 let arrayType = getArrayTypeTwo(type); 810 arrayType = jsType2CType(arrayType); 811 if (arrayType === 'any') { 812 param.valueOut = `std::any out;\n 813 std::string out_type;`; 814 param.valueDefine += '%sstd::any &out'.format(param.valueDefine.length > 0 ? ', ' : ''); 815 } else { 816 param.valueOut = returnInfo.optional ? 'std::vector<%s>* out = nullptr;\n'.format(arrayType) 817 : 'std::vector<%s> out;'.format(arrayType); 818 param.valueDefine += '%sstd::vector<%s>%s out'.format( 819 param.valueDefine.length > 0 ? ', ' : '', arrayType, modifiers); 820 } 821 } else if (isMapType(type)) { 822 returnGenerateMap(returnInfo, param); 823 } else if (type === 'any') { 824 param.valueOut = `std::any out; 825 std::string out_type;`; 826 param.valueDefine += '%sstd::any &out'.format(param.valueDefine.length > 0 ? ', ' : ''); 827 } else if (isObjectType(type)) { 828 param.valueOut = `std::map<std::string, std::any> out;\n`; 829 param.valueDefine += '%sstd::map<std::string, std::any> &out'.format(param.valueDefine.length > 0 ? ', ' : ''); 830 } 831} 832 833function returnArrayGen(type, param, returnInfo, modifiers) { 834 let arrayType = getArrayType(type); 835 arrayType = jsType2CType(arrayType); 836 if (arrayType === 'any') { 837 param.valueOut = `std::any out; 838 std::string out_type;`; 839 param.valueDefine += '%sstd::any &out'.format(param.valueDefine.length > 0 ? ', ' : ''); 840 } else { 841 param.valueOut = returnInfo.optional ? 'std::vector<%s>* out = nullptr;'.format(arrayType) 842 : 'std::vector<%s> out;'.format(arrayType); 843 param.valueDefine += '%sstd::vector<%s>%s out'.format( 844 param.valueDefine.length > 0 ? ', ' : '', arrayType, modifiers); 845 } 846} 847 848function returnGenerateEnum(data, returnInfo, param) { 849 let type = returnInfo.type; 850 let enumType = returnInfo.type; 851 let index = enumIndex(type, data); 852 let modifiers = returnInfo.optional ? '*' : '&'; 853 if (data.enum[index].body.enumValueType === EnumValueType.ENUM_VALUE_TYPE_NUMBER) { 854 type = 'NUMBER_TYPE_' + NumberIncrease.getAndIncrease(); 855 } else if (data.enum[index].body.enumValueType === EnumValueType.ENUM_VALUE_TYPE_STRING) { 856 type = 'string'; 857 } else { 858 NapiLog.logError(`function returnGenerateEnum:this type is not support %s` 859 .format(type), getLogErrInfo()); 860 return; 861 } 862 param.valuePackage = cToJs('vio->out', type, 'result', 1, returnInfo.optional, enumType); 863 if (type === 'string') { 864 param.valueOut = returnInfo.optional ? 'std::string* out = nullptr;' : 'std::string out;\n'; 865 param.valueDefine += '%sstd::string%s out'.format(param.valueDefine.length > 0 ? ', ' : '', modifiers); 866 } 867 else if (type.substring(0, 12) === 'NUMBER_TYPE_') { 868 param.valueOut = enumType + ' out;\n'; 869 param.valueDefine += '%s%s%s out'.format(param.valueDefine.length > 0 ? ', ' : '', enumType, modifiers); 870 } 871} 872 873module.exports = { 874 cToJs, 875 cToJsForInterface, 876 returnGenerate, 877 returnGenerateEnum, 878 objectTempleteFuncReturn, 879 cToJsForType, 880}; 881