• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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