• 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 { InterfaceList, getArrayType, getArrayTypeTwo, NumberIncrease,
16    enumIndex, isEnum, EnumValueType, getMapType, getLogErrInfo,
17    EnumList, getUnionType, TypeList, CallFunctionList, isFuncType, isArrowFunc } = require('../tools/common');
18const re = require('../tools/re');
19const { NapiLog } = require('../tools/NapiLog');
20const { getConstNum } = require('../tools/tool');
21
22class LenIncrease { }
23LenIncrease.LEN_TO = 1;
24LenIncrease.Reset = function () {
25    LenIncrease.LEN_TO = 1;
26};
27LenIncrease.getAndIncrease = function () {
28    return LenIncrease.LEN_TO++;
29};
30
31function getValueProperty(napiVn, name) {
32    return 'pxt->GetValueProperty(%s, "%s")'.format(napiVn, name);
33}
34
35function getCType(type) {
36    if (type === 'boolean') {
37        return 'bool';
38    } else if (type === 'string') {
39        return 'std::string';
40    } else if (type.substring(0, 6) === 'Array<' || type.substring(type.length - 2) === '[]') {
41       return 'std::vector<%s>'.format(getArrayTypeTemplete(type));
42    } else if (type.substring(0, 4) === 'Map<' || type.indexOf('{[key:') === 0) {
43        return getMapCType(type);
44    } else {
45        return type;
46    }
47}
48
49function getMapCType(type) {
50    let mapType = getMapType(type);
51    let mapTypeString = '';
52
53    if (mapType[1] !== undefined && mapType[2] === undefined) {
54        if (mapType[1] === 'string') { mapTypeString = 'std::string' }
55        else if (mapType[1].substring(0, 12) === 'NUMBER_TYPE_') { mapTypeString = mapType[1] }
56        else if (mapType[1] === 'boolean') { mapTypeString = 'bool' }
57        else if (mapType[1] === 'any') { mapTypeString = 'std::any' }
58        else if (mapType[1] !== null) { mapTypeString = mapType[1] }
59    } else if (mapType[2] !== undefined) {
60        if (mapType[2] === 'string') {
61            mapTypeString = 'std::map<std::string, std::string>';
62        }
63        else if (mapType[2].substring(0, 12) === 'NUMBER_TYPE_') {
64            mapTypeString = 'std::map<std::string, %s>'.format(mapType[2]);
65        }
66        else if (mapType[2] === 'boolean') { mapTypeString = 'std::map<std::string, bool>' }
67    } else if (mapType[3] !== undefined) {
68        if (mapType[3] === 'string') { mapTypeString = 'std::vector<std::string>' }
69        else if (mapType[3].substring(0, 12) === 'NUMBER_TYPE_') {
70            mapTypeString = 'std::vector<%s>'.format(mapType[3]);
71        }
72        else if (mapType[3] === 'boolean') { mapTypeString = 'std::vector<bool>' }
73    }
74    return 'std::map<std::string, %s>'.format(mapTypeString);
75}
76
77function jsToC(dest, napiVn, type, enumType = 0, optional) {
78    if (type.indexOf('|') >= 0) {
79        return unionTempleteFunc(dest, napiVn, type, optional);
80    } else if (type === 'string') {
81      let verifyEnumValue = getVeriyEnumValue(enumType, dest);
82
83      if (napiVn.indexOf('GetValueProperty') >= 0) {
84        let lt = LenIncrease.getAndIncrease();
85        return `napi_value tnv%d = %s;\n    if (tnv%d !=  nullptr) {pxt->SwapJs2CUtf8(tnv%d, %s);}\n`
86            .format(lt, napiVn, lt, lt, dest);
87      } else {
88        return 'pxt->SwapJs2CUtf8(%s, %s);'.format(napiVn, dest) + verifyEnumValue;
89      }
90    } else if (type.substring(type.length - 2) === '[]') {
91        return arrTemplete(dest, napiVn, type);
92    } else if (type.substring(0, 12) === 'NUMBER_TYPE_') {
93        return numTempleteFunc(enumType, napiVn, type, dest);
94    } else if (InterfaceList.getValue(type)) {
95        return interfaceTempleteFunc(type, napiVn, dest);
96    } else if (TypeList.getValue(type)) {
97        return typeTempleteFunc(type, dest, napiVn);
98    } else if (EnumList.getValue(type)) {
99        return jsToCEnum(type, dest, napiVn);
100    } else if (type.indexOf('Array<') === 0) {
101        return arrTemplete(dest, napiVn, type);
102    } else if (type === 'boolean') {
103        return `BOOLEAN_JS_2_C(%s, %s, %s);\n`.format(napiVn, 'bool', dest);
104    } else if (type.substring(0, 4) === 'Map<' || type.substring(0, 6) === '{[key:') {
105        return mapTempleteFunc(dest, napiVn, type);
106    } else if (type === 'any') {
107        return anyTempleteFunc(dest, napiVn, type);
108    } else if (type === 'Object' || type === 'object') {
109        return objectTempleteFunc(dest, napiVn);
110    } else {
111        NapiLog.logError(`do not support to generate jsToC %s,%s,%s`
112            .format(dest, napiVn, type), getLogErrInfo());
113        return null;
114    }
115}
116
117function getVeriyEnumValue(enumType, dest) {
118  let verifyEnumValue = '';
119  let strlt = LenIncrease.getAndIncrease();
120  if (enumType) {
121    // 对枚举是string的值做校验
122    verifyEnumValue = `
123    bool isStrValueInMap%s = false;
124    for (const auto& pair : enumMap%s) {
125      const char* charPtr = std::any_cast<const char*>(pair.second);
126      std::string value = charPtr;
127      if (value == %s) {
128        isStrValueInMap%s = true;
129        break;
130      }
131    }
132    if (!isStrValueInMap%s) {
133      napi_throw_error(env, nullptr, "enum value is wrong!");
134      return nullptr;
135    }`.format(strlt, enumType, dest, strlt, strlt);
136  }
137  return verifyEnumValue;
138}
139
140function interfaceTempleteFunc(type, napiVn, dest) {
141    let tt = '';
142    let ifl = InterfaceList.getValue(type);
143    for (let i in ifl) {
144        let name2 = ifl[i].name;
145        let type2 = ifl[i].type;
146        let optional2 = ifl[i].optional;
147        if (name2 === undefined || type2 === undefined) {
148            NapiLog.logError(`interfaceTempleteFunc: name2 or type2 is undefined!`);
149            return tt;
150        } else if (optional2 && type2.indexOf('|') < 0) {
151            let optType2 = getCType(type2);
152            tt += `    if (pxt->GetProperty(%s, "%s")) {\n `.format(napiVn, name2);
153            tt += `        %s %s_tmp;\n`.format(optType2, name2);
154            tt += jsToC('%s'.format('%s_tmp'.format(name2)), getValueProperty(napiVn, name2), type2);
155            tt += `        %s.%s.emplace(%s_tmp);\n`.format(dest, name2, name2);
156            tt += `    }\n`;
157        } else if (optional2 && type2.indexOf('|') >= 0) {
158            tt += `    if (pxt->GetProperty(%s, "%s")) {\n `.format(napiVn, name2);
159            tt += jsToC('%s.%s'.format(dest, name2), getValueProperty(napiVn, name2), type2, 0, optional2);
160            tt += `    }\n`;
161        } else {
162            tt += jsToC('%s.%s'.format(dest, name2), getValueProperty(napiVn, name2), type2);
163        }
164    }
165    return tt;
166}
167
168function typeTempleteFunc(type, dest, napiVn) {
169  let tt = '';
170  let ifl = TypeList.getValue(type);
171  if (typeof (ifl) === 'object') {
172    for (let i in ifl) {
173      let name2 = ifl[i].name;
174      let type2 = ifl[i].type;
175      let optional2 = ifl[i].optional;
176      if (optional2 && type2.indexOf('|') < 0) {
177          let optType2 = getCType(type2);
178          tt += `    if (pxt->GetProperty(%s, "%s")) {\n `.format(napiVn, name2);
179          tt += `        %s %s_tmp;\n`.format(optType2, name2);
180          tt += jsToC('%s'.format('%s_tmp'.format(name2)), getValueProperty(napiVn, name2), type2);
181          tt += `        %s.%s.emplace(%s_tmp);\n`.format(dest, name2, name2);
182          tt += `    }\n`;
183      } else if (optional2 && type2.indexOf('|') >= 0) {
184          tt += `    if (pxt->GetProperty(%s, "%s")) {\n `.format(napiVn, name2);
185          tt += jsToC('%s.%s'.format(dest, name2), getValueProperty(napiVn, name2), type2, 0, optional2);
186          tt += `    }\n`;
187      } else {
188          tt += jsToC('%s.%s'.format(dest, name2), getValueProperty(napiVn, name2), type2);
189      }
190    }
191  } else {
192    tt += jsToC(dest, napiVn, ifl);
193  }
194  return tt;
195}
196
197function unionTempleteFunc(dest, napiVn, type, optional) {
198    let unionType = getUnionType(type);
199    let unionTypeString = '';
200    let typeStr = 'type';
201    if (optional) {
202        typeStr = 'type.value()';
203        unionTypeString += '%s_type.emplace(pxt->GetUnionType(%s));\n'.format(dest, napiVn);
204    } else {
205        unionTypeString += '%s_type = pxt->GetUnionType(%s);\n'.format(dest, napiVn);
206    }
207    for (let i = 0; i < unionType.length; i++) {
208        if (unionType[i] === 'string') {
209            unionTypeString += `if (%s_%s == "string") {
210                std::string union_string;
211                %s
212                %s
213            }\n`.format(dest, typeStr, jsToC('union_string', napiVn, unionType[i]),
214            optional ? dest + '.emplace(union_string);' : dest + ' = union_string;');
215        } else if (unionType[i].substring(0, 12) === 'NUMBER_TYPE_') {
216            unionTypeString += `if (%s_%s == "number") {
217                std::uint32_t union_number;
218                %s
219                %s
220            }\n`.format(dest, typeStr, jsToC('union_number', napiVn, unionType[i]),
221            optional ? dest + '.emplace(union_number);' : dest + ' = union_number;');
222        } else if (unionType[i] === 'boolean') {
223            unionTypeString += `if (%s_%s == "boolean") {
224                bool union_boolean;
225                %s
226                %s
227            }\n`.format(dest, typeStr, jsToC('union_boolean', napiVn, unionType[i]),
228            optional ? dest + '.emplace(union_boolean);' : dest + ' = union_boolean;');
229        }
230    }
231    return unionTypeString;
232}
233
234function jsToCEnum(type, dest, napiVn) {
235    let tt = '';
236    let ifl = EnumList.getValue(type);
237    let type2 = '';
238    if (ifl && ifl.length > 0) {
239      type2 = ifl[0].type;
240    } else {
241      return null;
242    }
243    tt += jsToC('%s'.format(dest), napiVn, type2, type);
244    return tt;
245}
246
247function getArrayTypeTemplete(type) {
248    let arrayType;
249    if (type.substring(type.length - 2) === '[]') {
250        arrayType = getArrayTypeTwo(type);
251    } else {
252        arrayType = getArrayType(type);
253    }
254    if (arrayType === 'string') {
255        arrayType = 'std::string';
256    } else if (arrayType === 'boolean') {
257        arrayType = 'bool';
258    } else if (arrayType === 'any') {
259        arrayType = 'any';
260    } else if (arrayType === '[key:string]:string' || arrayType === 'Map<string,string>') {
261        arrayType = 'std::map<std::string, std::string>';
262    } else if (arrayType.substring(0, arrayType.lastIndexOf('_') + 1) === '[key:string]:NUMBER_TYPE_' ||
263        arrayType.substring(0, arrayType.lastIndexOf('_') + 1) === 'Map<string,NUMBER_TYPE_>') {
264        let len = arrayType.length;
265        let num = arrayType.substring(arrayType.lastIndexOf('_') + 1, len);
266        arrayType = 'std::map<std::string, NUMBER_TYPE_%s>'.format(num);
267    } else if (arrayType === '[key:string]:boolean' || arrayType === 'Map<string,boolean>') {
268        arrayType = 'std::map<std::string, bool>';
269    } else if (arrayType.substring(0, 14) === '[key:string]:') {
270        let valueType = arrayType.substring(14, arrayType.length);
271        arrayType = 'std::map<std::string, %s>'.format(valueType);
272    } else if (arrayType.substring(0, 11) === 'Map<string,') {
273        let valueType = arrayType.substring(11, arrayType.length - 1);
274        arrayType = 'std::map<std::string, %s>'.format(valueType);
275    }
276    return arrayType;
277}
278
279function arrTemplete(dest, napiVn, type) {
280    let lt = LenIncrease.getAndIncrease();
281    let arrayType = getArrayTypeTemplete(type);
282    if (arrayType === 'any') {
283        return anyArrayTempleteFunc(dest, napiVn);
284    }
285    let arrTemplete = `\
286    uint32_t len[replace_lt] = pxt->GetArrayLength(%s);
287    for (uint32_t i[replace_lt] = 0; i[replace_lt] < len[replace_lt]; i[replace_lt]++) {
288        %s tt[replace_lt];
289        [replace_swap]
290        %s.push_back(tt[replace_lt]);
291    }\n`.format(napiVn, arrayType === 'boolean' ? 'bool' : arrayType, dest);
292
293    let arrMapTemplete = `\
294    uint32_t len[replace_lt] = pxt->GetArrayLength(%s);
295    for (uint32_t i[replace_lt] = 0; i[replace_lt] < len[replace_lt]; i[replace_lt]++) {
296        %s tt[replace_lt];
297        napi_value mapPara = pxt->GetArrayElement(pxt->GetArgv(XNapiTool::ZERO), i[replace_lt]);
298        uint32_t len2 = pxt->GetMapLength(mapPara);
299        for (uint32_t i2 = 0; i2 < len2; i2++) {
300            std::string ttName;
301            pxt->SwapJs2CUtf8(pxt->GetMapElementName(mapPara, i2), ttName);
302            napi_value mapValue = pxt->GetMapElementValue(mapPara, ttName.c_str());
303            [code_gen]
304            tt[replace_lt].insert(std::make_pair(ttName, ttValue));
305        }
306        %s.push_back(tt[replace_lt]);
307    }\n`.format(napiVn, arrayType, dest);
308    arrTemplete = arrTemplete.replaceAll('[replace_lt]', lt);
309
310    let str = 'std::map<std::string,';
311    let strLen = str.length;
312    if (arrayType.substring(0, strLen) === 'std::map<std::string,') {
313        let codegen = getMapValueCode(arrayType);
314        if (codegen === null) {
315            return arrMapTemplete;
316        }
317        arrMapTemplete = arrMapTemplete.replaceAll('[replace_lt]', lt);
318        arrMapTemplete = arrMapTemplete.replaceAll('[code_gen]', codegen);
319        return arrMapTemplete;
320    } else {
321        arrTemplete = getArrTempletereplaceSwap(arrTemplete, arrayType, napiVn, lt);
322    }
323    return arrTemplete;
324}
325
326function numTempleteFunc(enumType, napiVn, type, dest) {
327    if (enumType) {
328      let strlt = LenIncrease.getAndIncrease();
329        // 对传入的枚举值做校验
330        let verifyEnumValue = `
331    bool isValueInMap%s = false;
332    for (const auto& pair : enumMap%s) {
333      int value = std::any_cast<int>(pair.second);
334      if (value == (int)%s) {
335        isValueInMap%s = true;
336        break;
337      }
338    }
339    if (!isValueInMap%s) {
340      napi_throw_error(env, nullptr, "enum value is wrong!");
341      return nullptr;
342    }`.format(strlt, enumType, dest, strlt, strlt);
343        if (napiVn.indexOf('GetValueProperty') >= 0) {
344            let lt = LenIncrease.getAndIncrease();
345            return `napi_value tnv%d = %s;\n    if (tnv%d !=  nullptr) {NUMBER_JS_2_C_ENUM(tnv%d, %s, %s, %s);}\n`
346            .format(lt, napiVn, lt, lt, type, dest, enumType) + verifyEnumValue;
347        } else {
348            return `NUMBER_JS_2_C_ENUM(%s, %s, %s, %s);`.format(napiVn, type, dest, enumType) + verifyEnumValue;
349        }
350
351    } else {
352        if (napiVn.indexOf('GetValueProperty') >= 0) {
353            let lt = LenIncrease.getAndIncrease();
354            return `napi_value tnv%d = %s;\n    if (tnv%d !=  nullptr) {NUMBER_JS_2_C(tnv%d, %s, %s);}\n`
355            .format(lt, napiVn, lt, lt, type, dest);
356        } else {
357            return `NUMBER_JS_2_C(%s, %s, %s);`.format(napiVn, type, dest);
358        }
359   }
360}
361
362function getMapValueCode(arrayType) {
363    let valueTypeOut = arrayType.substring(22, arrayType.length - 1);
364    let strTypeOut = '%s'.format(valueTypeOut);
365    let codegen;
366    if (strTypeOut === 'std::string') {
367        codegen = '\
368        std::string ttValue;\n\
369        pxt->SwapJs2CUtf8(mapValue, ttValue);';
370    } else if (strTypeOut === 'bool') {
371        codegen = '\
372        bool ttValue;\n\
373        ttValue = pxt->SwapJs2CBool(mapValue);';
374    } else if (strTypeOut.substr(0, 12) === 'NUMBER_TYPE_') {
375        codegen = '\
376        %s ttValue;\n\
377        NUMBER_JS_2_C(mapValue, %s, ttValue);'.format(strTypeOut, strTypeOut);
378    }
379    return codegen;
380}
381
382function getArrTempletereplaceSwap(arrTemplete, arrayType, napiVn, lt) {
383    if (arrayType.substring(0, 12) === 'NUMBER_TYPE_') {
384        arrTemplete = arrTemplete.replaceAll('[replace_swap]',
385            'NUMBER_JS_2_C(pxt->GetArrayElement(%s, i%d), %s, tt%d);'.format(napiVn, lt, arrayType, lt));
386    } else if (arrayType === 'std::string') {
387        arrTemplete = arrTemplete.replaceAll('[replace_swap]',
388            'pxt->SwapJs2CUtf8(pxt->GetArrayElement(%s, i%d), tt%d);'.format(napiVn, lt, lt));
389    } else if (InterfaceList.getValue(arrayType)) {
390        arrTemplete = arrTemplete.replaceAll('[replace_swap]',
391            jsToC('tt' + lt, 'pxt->GetArrayElement(%s, i%d)'.format(napiVn, lt), arrayType));
392    } else if (arrayType === 'bool') {
393        arrTemplete = arrTemplete.replaceAll('[replace_swap]',
394            'tt%d = pxt->SwapJs2CBool(pxt->GetArrayElement(%s, i%d));'.format(lt, napiVn, lt));
395    }
396    return arrTemplete;
397}
398function getMapValueType(strLen, keyType, arrayType) {
399    let valueTypeIn;
400    if (keyType === '[key:string]:') {
401        valueTypeIn = arrayType.substring(strLen, arrayType.length);
402    } else if (keyType === 'Map<string,') {
403        valueTypeIn = arrayType.substring(strLen, arrayType.length - 1);
404    }
405
406    let mapValueType;
407    if (valueTypeIn === 'string') {
408        mapValueType = 'std::string';
409    } else if (valueTypeIn === 'boolean') {
410        mapValueType = 'bool';
411    } else {
412        mapValueType = valueTypeIn;
413    }
414    return mapValueType;
415}
416
417function getMapKeyLen(arrayType) {
418    let strLen;
419    if (arrayType.substring(0, 13) === '[key:string]:') {
420        strLen = '[key:string]:'.length;
421    } else if (arrayType.substring(0, 10) === 'Map<string') {
422        strLen = 'Map<string,'.length;
423    }
424    return strLen;
425}
426
427function paramGenerateArray(p, funcValue, param) {
428    let type = funcValue.type;
429    let name = funcValue.name;
430    let inParamName = funcValue.optional ? '(*vio->in' + p + ')' : 'vio->in' + p;
431    let modifiers = funcValue.optional ? '* ' : '&';
432    if (type.substring(type.length - 2) === '[]') {
433        let arrayType = getArrayTypeTwo(type);
434        if (arrayType === 'string') {
435            arrayType = 'std::string';
436        }
437        if (arrayType === 'boolean') {
438            arrayType = 'bool';
439        }
440        if (arrayType === 'any') {
441            paramGenerateAnyArray(p, name, type, param);
442            return;
443        }
444        param.valueIn += funcValue.optional ? '\n    std::vector<%s>* in%d = nullptr;'.format(arrayType, p)
445                                            : '\n    std::vector<%s> in%d;'.format(arrayType, p);
446        param.valueCheckout += jsToC(inParamName, 'pxt->GetArgv(%d)'.format(getConstNum(p)), type);
447        param.valueFill += '%svio->in%d'.format(param.valueFill.length > 0 ? ', ' : '', p);
448        param.valueDefine += '%sstd::vector<%s>%s%s'.format(param.valueDefine.length > 0 ? ', '
449                            : '', arrayType, modifiers, name);
450    } else if (type.substring(0, 6) === 'Array<') {
451        let arrayType = getArrayType(type);
452        let strLen = getMapKeyLen(arrayType);
453        let keyType = arrayType.substring(0, strLen);
454        if (arrayType === 'string') {
455            arrayType = 'std::string';
456        } else if (arrayType === 'boolean') {
457            arrayType = 'bool';
458        } else if (arrayType === 'any') {
459            paramGenerateAnyArray(p, name, type, param);
460            return;
461        }
462        else if (checkIsMap(keyType)) {
463            let mapValueType = getMapValueType(strLen, keyType, arrayType);
464            arrayType = 'std::map<std::string, %s>'.format(mapValueType);
465        }
466        paramGenArray(param, funcValue, arrayType, p, inParamName, type, modifiers, name);
467    } else {
468        NapiLog.logError('The current version do not support to this param to generate :', name,
469            'type :', type, getLogErrInfo());
470        return;
471    }
472}
473
474function paramGenArray(param, funcValue, arrayType, p, inParamName, type, modifiers, name) {
475  param.valueIn += funcValue.optional ? '\n    std::vector<%s>* in%d = nullptr;'.format(arrayType, p)
476    : '\n    std::vector<%s> in%d;'.format(arrayType, p);
477  let arrValueCheckout = jsToC(inParamName, 'pxt->GetArgv(%d)'.format(getConstNum(p)), type);
478  arrValueCheckout = getFuncOptionalValue(funcValue, arrValueCheckout, p, arrayType, param);
479  param.valueCheckout += arrValueCheckout;
480  param.valueFill += '%svio->in%d'.format(param.valueFill.length > 0 ? ', ' : '', p);
481  param.valueDefine += '%sstd::vector<%s>%s%s'.format(param.valueDefine.length > 0 ? ', '
482    : '', arrayType, modifiers, name);
483}
484
485function checkIsMap(keyType) {
486  return keyType === '[key:string]:' || keyType === 'Map<string,';
487}
488
489function getFuncOptionalValue(funcValue, arrValueCheckout, p, arrayType, param) {
490  if (funcValue.optional) {
491    arrValueCheckout = 'if (pxt->GetArgc() > %s) {\n        vio->in%d = new std::vector<%s>;\n'
492      .format(getConstNum(p), p, arrayType) + arrValueCheckout + '    }\n';
493    param.optionalParamDestory += 'C_DELETE(vio->in%d);\n    '.format(p);
494  }
495  return arrValueCheckout;
496}
497
498function paramGenerateAny(p, name, type, param) {
499    param.valueIn += `\n    std::any in%d;
500        std::string in%d_type;`.format(p, p);
501    param.valueCheckout += jsToC('vio->in' + p, 'pxt->GetArgv(%d)'.format(getConstNum(p)), type);
502    param.valueFill += '%svio->in%d'.format(param.valueFill.length > 0 ? ', ' : '', p);
503    param.valueDefine += '%sstd::any &%s'.format(param.valueDefine.length > 0 ? ', ' : '', name);
504}
505
506function paramGenerateAnyArray(p, name, type, param) {
507    param.valueIn += `\n    std::any in%d;
508        std::string in%d_type;`.format(p, p);
509    param.valueCheckout += jsToC('vio->in' + p, 'pxt->GetArgv(%d)'.format(getConstNum(p)), type);
510    param.valueFill += '%svio->in%d'.format(param.valueFill.length > 0 ? ', ' : '', p);
511    param.valueDefine += '%sstd::any &%s'.format(param.valueDefine.length > 0 ? ', ' : '', name);
512}
513
514function paramGenerateEnum(data, funcValue, param, p) {
515    let index = enumIndex(funcValue.type, data);
516    if (data.enum[index].body.enumValueType === EnumValueType.ENUM_VALUE_TYPE_NUMBER) {
517        funcValue.type = 'NUMBER_TYPE_' + NumberIncrease.getAndIncrease();
518    } else if (data.enum[index].body.enumValueType === EnumValueType.ENUM_VALUE_TYPE_STRING) {
519        funcValue.type = 'string';
520    } else {
521        NapiLog.logError(`paramGenerate is not support`, getLogErrInfo());
522        return;
523    }
524    paramGenerate(p, funcValue, param, data);
525}
526
527function paramGenerateMap(funcValue, param, p) {
528    let type = funcValue.type;
529    let name = funcValue.name;
530    let mapType = getMapType(type);
531    let mapTypeString;
532    if (mapType[1] !== undefined && mapType[2] === undefined) {
533        if (mapType[1] === 'string') { mapTypeString = 'std::string' }
534        else if (mapType[1].substring(0, 12) === 'NUMBER_TYPE_') { mapTypeString = mapType[1] }
535        else if (mapType[1] === 'boolean') { mapTypeString = 'bool' }
536        else if (mapType[1] === 'any') { mapTypeString = 'std::any' }
537        else { mapTypeString = mapType[1] }
538    }
539    else if (mapType[2] !== undefined) {
540        if (mapType[2] === 'string') { mapTypeString = 'std::map<std::string, std::string>' }
541        else if (mapType[2].substring(0, 12) === 'NUMBER_TYPE_') { 'std::map<std::string, ' + mapType[2] + '>' }
542        else if (mapType[2] === 'boolean') { mapTypeString = 'std::map<std::string, bool>' }
543    }
544    else if (mapType[3] !== undefined) {
545        if (mapType[3] === 'string') { mapTypeString = 'std::vector<std::string>' }
546        else if (mapType[3].substring(0, 12) === 'NUMBER_TYPE_') { mapTypeString = 'std::vector<' + mapType[3] + '>' }
547        else if (mapType[3] === 'boolean') { mapTypeString = 'std::vector<bool>' }
548    }
549    paramGenerateMap2(funcValue, param, p, mapType, mapTypeString, name);
550}
551
552function paramGenerateMap2(funcValue, param, p, mapType, mapTypeString, name) {
553    let inParamName = funcValue.optional ? '(*vio->in' + p + ')' : 'vio->in' + p;
554    let modifiers = funcValue.optional ? '*' : '&';
555    if (mapType[1] === 'any') {
556        param.valueIn += funcValue.optional ? `\n    std::map<std::string, %s>* in%d = nullptr;
557                                                std::string in%d_type;`.format(mapTypeString, p, p)
558                                            : `\n    std::map<std::string, %s> in%d;
559                                                std::string in%d_type;`.format(mapTypeString, p, p);
560    } else {
561        param.valueIn += funcValue.optional ? '\n    std::map<std::string, %s>* in%d = nullptr;'
562                                            .format(mapTypeString, p)
563                                        : '\n    std::map<std::string, %s> in%d;'.format(mapTypeString, p);
564    }
565    param.valueCheckout += getValueCheckout(funcValue, param, inParamName, p,
566        'std::map<std::string, %s>'.format(mapTypeString));
567    param.valueFill += '%svio->in%d'.format(param.valueFill.length > 0 ? ', ' : '', p);
568    param.valueDefine += '%sstd::map<std::string, %s>%s %s'
569            .format(param.valueDefine.length > 0 ? ', ' : '', mapTypeString, modifiers, name);
570}
571
572function mapTempleteFunc(dest, napiVn, type) {
573    let mapType = getMapType(type);
574    let lt = LenIncrease.getAndIncrease();
575    let mapTemplete = '';
576    if (mapType[1] !== undefined && mapType[2] === undefined) {
577        mapTemplete = mapValue(mapType, napiVn, dest, lt);
578    }
579    else if (mapType[2] !== undefined) {
580        mapTemplete = mapMap(mapType, napiVn, dest, lt);
581    }
582    else if (mapType[3] !== undefined) {
583        mapTemplete = mapArray(mapType, napiVn, dest, lt);
584    }
585    return mapTemplete;
586}
587
588function anyTempleteFunc(dest) {
589    let anyTemplete = `%s_type = pxt->GetAnyType(pxt->GetArgv(XNapiTool::ZERO));
590    pxt->SetAnyValue(%s_type, pxt->GetArgv(XNapiTool::ZERO), %s);\n`
591    .format(dest, dest, dest);
592
593    return anyTemplete;
594}
595
596function anyArrayTempleteFunc(dest, napiVn) {
597    let anyArrayTemplete = `%s_type = pxt->GetAnyArrayType(%s);
598    pxt->SetAnyValue(%s_type, %s, %s);\n`
599    .format(dest, napiVn, dest, napiVn, dest);
600
601    return anyArrayTemplete;
602}
603
604let mapValueTemplete = `\
605uint32_t len[replace_lt] = pxt->GetMapLength(%s);
606for (uint32_t i[replace_lt] = 0; i[replace_lt] < len[replace_lt]; i[replace_lt]++) {
607    std::string tt[replace_lt];
608    %s tt[replace_lt+1];
609    [replace_swap]
610    %s.insert(std::make_pair(tt[replace_lt], tt[replace_lt+1]));
611}`;
612
613function mapInterface(mapTypeString, mapTemplete, napiVn, lt) {
614    let interfaceValue = InterfaceList.getValue(mapTypeString);
615    let interfaceVarName = '';
616    let interfaceFun = '';
617    for (let i = 0; i < interfaceValue.length; i++) {
618        if (interfaceValue[i].type === 'string') {
619            interfaceVarName += `std::string %dName = "%d";\n`.format(interfaceValue[i].name, interfaceValue[i].name);
620            interfaceFun +=
621                `pxt->%s(pxt->%s(pxt->GetMapElementValue(pxt->GetArgv(XNapiTool::ZERO),
622            tt%d.c_str()), %sName.c_str()), tt%d.%s);\n`
623                    .format('SwapJs2CUtf8', 'GetMapElementValue',
624                        lt, interfaceValue[i].name, lt + 1, interfaceValue[i].name);
625        }
626        else if (interfaceValue[i].type.substring(0, 12) === 'NUMBER_TYPE_') {
627            interfaceVarName += `std::string %dName = "%d";\n`.format(interfaceValue[i].name, interfaceValue[i].name);
628            interfaceFun +=
629                `%s(pxt->%s(pxt->GetMapElementValue(pxt->GetArgv(XNapiTool::ZERO),
630            tt%d.c_str()), %sName.c_str()), %s, tt%d.%s);\n`
631                    .format('NUMBER_JS_2_C', 'GetMapElementValue', lt, interfaceValue[i].name,
632                        interfaceValue[i].type, lt + 1, interfaceValue[i].name);
633        }
634        else if (interfaceValue[i].type === 'boolean') {
635            interfaceVarName += `std::string %dName = "%d";\n`.format(interfaceValue[i].name, interfaceValue[i].name);
636            interfaceFun +=
637                `tt%d.%s = pxt->%s(pxt->%s(pxt->GetMapElementValue(pxt->GetArgv(XNapiTool::ZERO),
638            tt%d.c_str()), %sName.c_str()));\n`
639                    .format(lt + 1, interfaceValue[i].name, 'SwapJs2CBool', 'GetMapElementValue',
640                        lt, interfaceValue[i].name);
641        }
642    }
643    mapTemplete = mapTemplete.replaceAll('[replace_swap]',
644        `pxt->SwapJs2CUtf8(pxt->GetMapElementName(%s, i%d), tt%d);
645        %d
646        %d`.format(napiVn, lt, lt, interfaceVarName, interfaceFun));
647    return mapTemplete;
648}
649
650function mapValue(mapType, napiVn, dest, lt) {
651    let mapTypeString;
652    if (mapType[1] === 'string') { mapTypeString = 'std::string' }
653    else if (mapType[1].substring(0, 12) === 'NUMBER_TYPE_') { mapTypeString = mapType[1] }
654    else if (mapType[1] === 'boolean') { mapTypeString = 'bool' }
655    else if (mapType[1] === 'any') { mapTypeString = 'std::any' }
656    else if (mapType[1] !== null) { mapTypeString = mapType[1] }
657    let mapTemplete = mapValueTemplete.format(napiVn, mapTypeString, dest);
658    mapTemplete = mapTemplete.replaceAll('[replace_lt]', lt);
659    mapTemplete = mapTemplete.replaceAll('[replace_lt+1]', lt + 1);
660    if (mapTypeString === 'std::string') {
661        mapTemplete = mapTemplete.replaceAll('[replace_swap]',
662            `pxt->SwapJs2CUtf8(pxt->GetMapElementName(%s, i%d), tt%d);
663        pxt->SwapJs2CUtf8(pxt->GetMapElementValue(%s, tt%d.c_str()), tt%d);\n`
664                .format(napiVn, lt, lt, napiVn, lt, lt + 1));
665    }
666    else if (mapTypeString.substring(0, 12) === 'NUMBER_TYPE_') {
667        mapTemplete = mapTemplete.replaceAll('[replace_swap]',
668            `pxt->SwapJs2CUtf8(pxt->GetMapElementName(%s, i%d), tt%d);
669        NUMBER_JS_2_C(pxt->GetMapElementValue(%s, tt%d.c_str()), %s, tt%d);\n`
670                .format(napiVn, lt, lt, napiVn, lt, mapTypeString, lt + 1));
671    }
672    else if (mapTypeString === 'bool') {
673        mapTemplete = mapTemplete.replaceAll('[replace_swap]',
674            `pxt->SwapJs2CUtf8(pxt->GetMapElementName(%s, i%d), tt%d);
675        tt%d = pxt->SwapJs2CBool(pxt->GetMapElementValue(%s, tt%d.c_str()));\n`
676                .format(napiVn, lt, lt, lt + 1, napiVn, lt));
677    }
678    if (mapTypeString === 'std::any') {
679        mapTemplete = mapTemplete.replaceAll('[replace_swap]',
680            `pxt->SwapJs2CUtf8(pxt->GetMapElementName(%s, i%d), tt%d);
681            if (i%d == 0) {
682                %s_type = pxt->GetAnyType(pxt->GetMapElementValue(%s, tt%d.c_str()));
683            }
684            pxt->SetAnyValue(%s_type, pxt->GetMapElementValue(%s, tt%d.c_str()), tt%d);\n`
685                .format(napiVn, lt, lt, lt, dest, napiVn, lt, dest, napiVn, lt, lt + 1));
686    }
687    else if (InterfaceList.getValue(mapTypeString)) {
688        mapTemplete = mapInterface(mapTypeString, mapTemplete, napiVn, lt);
689    }
690    return mapTemplete;
691}
692
693let mapMapTemplete = `\
694uint32_t len[replace_lt] = pxt->GetMapLength(%s);
695for (uint32_t i[replace_lt] = 0; i[replace_lt] < len[replace_lt]; i[replace_lt]++) {
696    std::string tt[replace_lt];
697    std::map<std::string, %s> tt[replace_lt+1];
698    [replace_swap]
699    %s.insert(std::make_pair(tt[replace_lt], tt[replace_lt+1]));
700}`;
701
702function mapMapString(mapTemplete, napiVn, lt) {
703    return mapTemplete.replaceAll('[replace_swap]',
704    `pxt->SwapJs2CUtf8(pxt->GetMapElementName(%s, i%d), tt%d);
705    uint32_t len%d = pxt->GetMapLength(pxt->GetMapElementValue(%s, tt%d.c_str()));
706    for (uint32_t i%d = 0; i%d < len%d; i%d++) {
707        std::string tt%d;
708        std::string tt%d;
709        pxt->SwapJs2CUtf8(pxt->GetMapElementName(pxt->GetMapElementValue(%s,
710            tt%d.c_str()), i%d), tt%d);
711        pxt->SwapJs2CUtf8(pxt->GetMapElementValue(pxt->GetMapElementValue(%s,
712            tt%d.c_str()), tt%d.c_str()), tt%d);
713        tt%d.insert(std::make_pair(tt%d, tt%d));
714    }`.format(napiVn, lt, lt, lt + 1, napiVn, lt, lt + 1, lt + 1, lt + 1, lt + 1,
715        lt + 2, lt + 3, napiVn, lt, lt + 1, lt + 2, napiVn, lt, lt + 2, lt + 3, lt + 1, lt + 2, lt + 3));
716}
717
718function mapMapBoolean(mapTemplete, napiVn, lt) {
719    return mapTemplete.replaceAll('[replace_swap]',
720    `pxt->SwapJs2CUtf8(pxt->GetMapElementName(%s, i%d), tt%d);
721    uint32_t len%d = pxt->GetMapLength(pxt->GetMapElementValue(%s, tt%d.c_str()));
722    for (uint32_t i%d = 0; i%d < len%d; i%d++) {
723        std::string tt%d;
724        bool tt%d;
725        pxt->SwapJs2CUtf8(pxt->GetMapElementName(pxt->GetMapElementValue(%s,
726            tt%d.c_str()), i%d), tt%d);
727        tt%d = pxt->%s(pxt->GetMapElementValue(pxt->GetMapElementValue(%s,
728            tt%d.c_str()), tt%d.c_str()));
729        tt%d.insert(std::make_pair(tt%d, tt%d));
730    }\n`.format(napiVn, lt, lt, lt + 1, napiVn, lt, lt + 1, lt + 1, lt + 1, lt + 1,
731        lt + 2, lt + 3, napiVn, lt, lt + 1, lt + 2, lt + 3, 'SwapJs2CBool'
732        , napiVn, lt, lt + 2, lt + 1, lt + 2, lt + 3));
733}
734
735function mapMapNumber(mapTemplete, napiVn, lt, mapTypeString) {
736    return mapTemplete.replaceAll('[replace_swap]',
737    `pxt->SwapJs2CUtf8(pxt->GetMapElementName(%s, i%d), tt%d);
738    uint32_t len%d = pxt->GetMapLength(pxt->GetMapElementValue(%s, tt%d.c_str()));
739    for (uint32_t i%d = 0; i%d < len%d; i%d++) {
740        std::string tt%d;
741        %s tt%d;
742        pxt->SwapJs2CUtf8(pxt->GetMapElementName(pxt->GetMapElementValue(%s,
743            tt%d.c_str()), i%d), tt%d);
744        NUMBER_JS_2_C(pxt->GetMapElementValue(pxt->GetMapElementValue(%s,
745            tt%d.c_str()), tt%d.c_str()), %s, tt%d);
746        tt%d.insert(std::make_pair(tt%d, tt%d));
747    }`.format(napiVn, lt, lt, lt + 1, napiVn, lt, lt + 1, lt + 1, lt + 1, lt + 1,
748        lt + 2, mapTypeString, lt + 3, napiVn, lt, lt + 1, lt + 2, napiVn, lt, lt + 2,
749        mapTypeString, lt + 3, lt + 1, lt + 2, lt + 3));
750}
751
752function mapMap(mapType, napiVn, dest, lt) {
753    let mapTypeString;
754    if (mapType[2] === 'string') { mapTypeString = 'std::string' }
755    else if (mapType[2].substring(0, 12) === 'NUMBER_TYPE_') { mapTypeString = mapType[2] }
756    else if (mapType[2] === 'boolean') { mapTypeString = 'bool' }
757    let mapTemplete = mapMapTemplete.format(napiVn, mapTypeString, dest);
758    mapTemplete = mapTemplete.replaceAll('[replace_lt]', lt);
759    mapTemplete = mapTemplete.replaceAll('[replace_lt+1]', lt + 1);
760    if (mapType[2] === 'string') {
761        mapTemplete = mapMapString(mapTemplete, napiVn, lt);
762    }
763    else if (mapType[2] === 'boolean') {
764        mapTemplete = mapMapBoolean(mapTemplete, napiVn, lt);
765    }
766    else if (mapType[2].substring(0, 12) === 'NUMBER_TYPE_') {
767        mapTemplete = mapMapNumber(mapTemplete, napiVn, lt, mapTypeString);
768    }
769    return mapTemplete;
770}
771
772let mapArrayTemplete = `\
773uint32_t len[replace_lt] = pxt->GetMapLength(%s);
774for (uint32_t i[replace_lt] = 0; i[replace_lt] < len[replace_lt]; i[replace_lt]++) {
775    std::string tt[replace_lt];
776    std::vector<%s> tt[replace_lt+1];
777    [replace_swap]
778    %s.insert(std::make_pair(tt[replace_lt], tt[replace_lt+1]));
779}`;
780
781function mapArray(mapType, napiVn, dest, lt) {
782    let mapTypeString;
783    if (mapType[3] === 'string') { mapTypeString = 'std::string' }
784    else if (mapType[3].substring(0, 12) === 'NUMBER_TYPE_') { mapTypeString = mapType[3] }
785    else if (mapType[3] === 'boolean') { mapTypeString = 'bool' }
786    let mapTemplete = mapArrayTemplete.format(napiVn, mapTypeString, dest);
787    mapTemplete = mapTemplete.replaceAll('[replace_lt]', lt);
788    mapTemplete = mapTemplete.replaceAll('[replace_lt+1]', lt + 1);
789    if (mapType[3] === 'string') {
790        mapTemplete = mapTemplete.replaceAll('[replace_swap]',
791            `pxt->SwapJs2CUtf8(pxt->GetMapElementName(%s, i%s), tt%d);
792            uint32_t len%s = pxt->GetArrayLength(pxt->GetMapElementValue(%s, tt%d.c_str()));
793            for (uint32_t i%d = 0; i%d < len%d; i%d++) {
794                std::string tt%d;
795                pxt->SwapJs2CUtf8(pxt->GetArrayElement(pxt->GetMapElementValue(%s,
796                    tt%d.c_str()), i%d), tt%d);
797                tt%d.push_back(tt%d);
798            }`.format(napiVn, lt, lt, lt + 1, napiVn, lt, lt + 1, lt + 1, lt + 1,
799                lt + 1, lt + 2, napiVn, lt, lt + 1, lt + 2, lt + 1, lt + 2));
800    }
801    else if (mapType[3] === 'boolean') {
802        mapTemplete = mapTemplete.replaceAll('[replace_swap]',
803            `pxt->SwapJs2CUtf8(pxt->GetMapElementName(%s, i%s), tt%d);
804            uint32_t len%s = pxt->GetArrayLength(pxt->GetMapElementValue(%s, tt%d.c_str()));
805            for (uint32_t i%d = 0; i%d < len%d; i%d++) {
806                bool tt%d;
807                tt%d = pxt->SwapJs2CBool(pxt->GetArrayElement(pxt->GetMapElementValue(%s,
808                    tt%d.c_str()), i%d));
809                tt%d.push_back(tt%d);
810            }`.format(napiVn, lt, lt, lt + 1, napiVn, lt, lt + 1, lt + 1, lt + 1,
811                lt + 1, lt + 2, lt + 2, napiVn, lt, lt, lt + 1, lt + 2));
812    }
813    else if (mapType[3].substring(0, 12) === 'NUMBER_TYPE_') {
814        mapTemplete = mapTemplete.replaceAll('[replace_swap]',
815            `pxt->SwapJs2CUtf8(pxt->GetMapElementName(%s, i%s), tt%d);
816            uint32_t len%s = pxt->GetArrayLength(pxt->GetMapElementValue(%s, tt%d.c_str()));
817            for (uint32_t i%d = 0; i%d < len%d; i%d++) {
818                %s tt%d;
819                NUMBER_JS_2_C(pxt->GetArrayElement(pxt->GetMapElementValue(%s,
820                    tt%d.c_str()), i%d), %s, tt%d);
821                tt%d.push_back(tt%d);
822            }`.format(napiVn, lt, lt, lt + 1, napiVn, lt, lt + 1, lt + 1, lt + 1,
823                lt + 1, mapTypeString, lt + 2, napiVn, lt, lt + 1, mapTypeString, lt + 2, lt + 1, lt + 2));
824    }
825    return mapTemplete;
826}
827
828function getCBparaTypeForArrow(type) {
829    let cbParamType;
830    const typeSplits = type.split('=>', 2);
831    let callbackParams = typeSplits[0];
832    let returnType = typeSplits[1];
833    callbackParams = callbackParams.substring(1, callbackParams.length - 1); // 去掉参数列表两侧的小括号
834    if (callbackParams.length <= 0) { //无参
835        cbParamType = 'void';
836    }
837
838    if (callbackParams.indexOf(',') >= 0) { // 多个参数,进行分割
839        callbackParams = callbackParams.split(',');
840        for (let i = 0; i < callbackParams.length; i++) {
841            NapiLog.logInfo('muilti paramets');
842        }
843    } else { // 一个参数
844        let params = callbackParams.split(':', 2);
845        cbParamType = params[1];
846    }
847    return [cbParamType, returnType];
848}
849
850function matchCBParamType(cbParamType, type) {
851    let arrayType = re.match('(Async)*Callback<(Array<([a-zA-Z_0-9]+)>)>', type);
852    if (arrayType) {
853        cbParamType = re.getReg(type, arrayType.regs[2]);
854    }
855
856    let arrayType2 = re.match('(Async)*Callback<(([a-zA-Z_0-9]+)\\[\\])>', type);
857    if (arrayType2) {
858        cbParamType = re.getReg(type, arrayType2.regs[2]);
859    }
860
861    let tt = re.match('(Async)*Callback<([a-zA-Z_0-9]+)>', type);
862    if (tt) {
863        cbParamType = re.getReg(type, tt.regs[2]);
864    }
865    return cbParamType;
866}
867
868function paramGenerateCallBack(data, funcValue, param, p) {
869    let cbParamType;
870    let returnType = 'void';
871
872    let type = funcValue.type;
873
874    if (isFuncType(type)) {
875        cbParamType = 'void';
876    }
877    cbParamType = matchCBParamType(cbParamType, type);
878
879    if (isEnum(cbParamType, data)) {
880        let index = enumIndex(cbParamType, data);
881        if (data.enum[index].body.enumValueType === EnumValueType.ENUM_VALUE_TYPE_NUMBER) {
882            cbParamType = 'NUMBER_TYPE_' + NumberIncrease.getAndIncrease();
883        } else if (data.enum[index].body.enumValueType === EnumValueType.ENUM_VALUE_TYPE_STRING) {
884            cbParamType = 'string';
885        } else {
886            NapiLog.logError(`paramGenerate is not support`, getLogErrInfo());
887            return;
888        }
889    }
890
891    param.callback = {
892        // function类型参数,按照空参数、空返回值回调处理 () => void {}
893        type: cbParamType,
894        offset: p,
895        returnType: returnType,
896        optional: funcValue.optional,
897        isAsync: type.indexOf('AsyncCallback') >= 0
898    };
899}
900
901function paramGenerateArrowCallBack(funcValue, param, p, onFlag = false) {
902    let cbParamType;
903    let returnType = 'void';
904
905    let type = funcValue.type;
906    let cbParamList = [];
907
908    if (CallFunctionList.getValue(type)) {
909        // callFunction => 函数参数处理
910        let funcBody = CallFunctionList.getValue(type)[0]; // 取出回调方法参数
911        returnType = CallFunctionList.getValue(type)[1];
912        cbParamType = type;
913        for (let i in funcBody) {
914            let cbParam = {
915                name: funcBody[i].name,
916                type: funcBody[i].type
917            };
918            cbParamList[i] = cbParam;
919        }
920    }
921
922    param.callback = {
923        // function类型参数,按照空参数、空返回值回调处理 () => void {}
924        type: cbParamType,
925        offset: p,
926        returnType: returnType,
927        optional: funcValue.optional,
928        isArrowFuncFlag: true,
929        arrowFuncParamList:cbParamList,
930        onFlag: onFlag,
931        isAsync: type.indexOf('AsyncCallback') >= 0
932    };
933}
934
935function isArrayType(type) {
936    if (type.substring(type.length - 2) === '[]' || type.substring(0, 6) === 'Array<') {
937        return true;
938    }
939    return false;
940}
941
942function getValueCheckout(funcValue, param, inParamName, p, cType) {
943    let enumType = 0;
944    if (funcValue.type !== funcValue.realType) {
945      enumType = funcValue.realType;
946    }
947    let valueCheckout = jsToC(inParamName, 'pxt->GetArgv(%d)'.format(getConstNum(p)), funcValue.type, enumType) + '\n    ';
948    if (funcValue.optional) {
949        valueCheckout = 'if (pxt->GetArgc() > %d) {\n        vio->in%d = new %s;\n        '
950            .format(getConstNum(p), p, cType) + valueCheckout + '}\n    ';
951        param.optionalParamDestory += 'C_DELETE(vio->in%d);\n    '.format(p);
952    }
953    return valueCheckout;
954}
955
956function paramGenerateUnion(type, param, p, name) {
957    param.valueIn += `\n    std::any in%d;
958        std::string in%d_type;`.format(p, p);
959    param.valueCheckout += jsToC('vio->in' + p, 'pxt->GetArgv(%d)'.format(getConstNum(p)), type);
960    param.valueFill += '%svio->in%d'.format(param.valueFill.length > 0 ? ', ' : '', p);
961    param.valueDefine += '%sstd::any &%s'.format(param.valueDefine.length > 0 ? ', ' : '', name);
962}
963
964function isEnumTypeFunc(cType, funcValue) {
965    if (cType !== funcValue.realType && funcValue.type !== funcValue.realType && funcValue.type !== 'string') {
966      return true;
967    } else {
968      return false;
969    }
970}
971
972
973function paramGenerateCommon(p, cType, funcValue, param, modifiers, inParamName) {
974    // string类型和number类型枚举处理时才走该分支
975    if (isEnumTypeFunc(cType, funcValue)) {
976      cType = funcValue.realType;
977    }
978
979    param.valueIn += funcValue.optional ? '\n    %s* in%d = nullptr;'.format(cType, p)
980                                            : '\n    %s in%d;'.format(cType, p);
981    if (TypeList.getValue(cType)) {
982      let realType = TypeList.getValue(cType);
983      if (realType.indexOf('|') > 0) {
984        param.valueIn += `\n    std::string in%d_type;`.format(p, p);
985      }
986    }
987    param.valueCheckout += getValueCheckout(funcValue, param, inParamName, p, cType);
988    param.valueFill += '%svio->in%d'.format(param.valueFill.length > 0 ? ', ' : '', p);
989    param.valueDefine += '%s%s%s %s'.format(
990        param.valueDefine.length > 0 ? ', ' : '', cType, modifiers, funcValue.name);
991}
992
993let objectTemplete = `\
994    uint32_t len[replace_lt] = pxt->GetMapLength(%s);
995    for (uint32_t i[replace_lt] = 0; i[replace_lt] < len[replace_lt]; i[replace_lt]++) {
996        std::string tt[replace_lt];
997        std::any tt[replace_lt+1];
998        pxt->SwapJs2CUtf8(pxt->GetMapElementName(%s, i[replace_lt]), tt[replace_lt]);
999        napi_value valueObj = pxt->GetMapElementValue(%s, tt[replace_lt].c_str());
1000        std::string valueObjType = pxt->GetAnyType(valueObj);
1001        [replace_swap]
1002        %s.insert(std::make_pair(tt[replace_lt], tt[replace_lt+1]));
1003    }\n`;
1004
1005// To avoid function that exceed 50 lines
1006let objectTempleteArrnum = `\
1007            uint32_t len[replace_lt+1] = pxt->GetArrayLength(valueObj);
1008            std::vector<NUMBER_TYPE_%d> arr;
1009            for(uint32_t i[replace_lt+1] = 0; i[replace_lt+1] < len[replace_lt+1]; i[replace_lt+1]++) {
1010                napi_value arr_value_result;
1011                NUMBER_TYPE_%d tt[replace_lt+2];
1012                napi_get_element(env, valueObj, i[replace_lt+1], &arr_value_result);
1013                NUMBER_JS_2_C(arr_value_result, NUMBER_TYPE_%d, tt[replace_lt+2]);
1014                arr.push_back(tt[replace_lt+2]);
1015            }
1016            tt[replace_lt+1] = arr;
1017`;
1018
1019let objectTempleteMap = `\
1020            napi_value obj_name_value;
1021            napi_value obj_name_result;
1022            napi_valuetype obj_name_type;
1023            napi_get_property_names (env, valueObj, &obj_name_value);
1024            uint32_t ret;
1025            napi_get_array_length(env, obj_name_value, &ret);
1026            std::vector<std::any> anyValue;
1027            for(uint32_t i[replace_lt+1] = 0; i[replace_lt+1] < ret; i[replace_lt+1]++) {
1028                napi_get_element (env, obj_name_value, i[replace_lt+1], &obj_name_result);
1029                napi_typeof(env, obj_name_result, &obj_name_type);
1030                if (obj_name_type == napi_string) {
1031                    napi_value obj_value;
1032                    napi_valuetype obj_value_type;
1033                    std::string obj_name_string;
1034                    pxt->SwapJs2CUtf8(obj_name_result, obj_name_string);
1035                    napi_get_named_property (env, valueObj, obj_name_string.c_str(), &obj_value);
1036                    napi_typeof(env, obj_value, &obj_value_type);
1037                    std::map<std::string, std::any> anyValueMap;
1038                    if (obj_value_type == napi_string) {
1039                        std::string tt[replace_lt+2];
1040                        pxt->SwapJs2CUtf8(obj_value, tt[replace_lt+2]);
1041                        anyValueMap.insert(std::make_pair(obj_name_string, tt[replace_lt+2]));
1042                        anyValue.push_back(anyValueMap);
1043                    } else if (obj_value_type == napi_number) {
1044                        NUMBER_TYPE_%d tt[replace_lt+2];
1045                        NUMBER_JS_2_C(obj_value, NUMBER_TYPE_%d, tt[replace_lt+2] );
1046                        anyValueMap.insert(std::make_pair(obj_name_string, tt[replace_lt+2]));
1047                        anyValue.push_back(anyValueMap);
1048                    } else if (obj_value_type == napi_boolean) {
1049                        bool tt[replace_lt+2];
1050                        tt[replace_lt+2] = pxt->SwapJs2CBool(obj_value);
1051                        anyValueMap.insert(std::make_pair(obj_name_string, tt[replace_lt+2]));
1052                        anyValue.push_back(anyValueMap);
1053                    }
1054                }
1055            }
1056            tt[replace_lt+1] = anyValue;
1057`;
1058
1059function objectTempleteFunc(dest, napiVn) {
1060    let lt = LenIncrease.getAndIncrease();
1061    let objTemplete = objectTemplete.format(napiVn, napiVn, napiVn, dest);
1062
1063    objTemplete = objTemplete.replaceAll('[replace_swap]',
1064        `if (valueObjType == "string") {
1065            std::string tt[replace_lt+2];
1066            pxt->SwapJs2CUtf8(valueObj, tt[replace_lt+2]);
1067            tt[replace_lt+1] = tt[replace_lt+2];
1068        } else if (valueObjType == "boolean") {
1069            bool tt[replace_lt+2];
1070            tt[replace_lt+2] = pxt->SwapJs2CBool(valueObj);
1071            tt[replace_lt+1] = tt[replace_lt+2];
1072        } else if (valueObjType == "number") {
1073            NUMBER_JS_2_C(valueObj, NUMBER_TYPE_%d, tt[replace_lt+1]);
1074        } else if (valueObjType == "arr_string") {
1075            uint32_t len[replace_lt+1] = pxt->GetArrayLength(valueObj);
1076            std::vector<std::string> arr;
1077            for(uint32_t i[replace_lt+1] = 0; i[replace_lt+1] < len[replace_lt+1]; i[replace_lt+1]++) {
1078                napi_value arr_value_result;
1079                napi_get_element(env, valueObj, i[replace_lt+1], &arr_value_result);
1080                std::string tt[replace_lt+2];
1081                pxt->SwapJs2CUtf8(arr_value_result, tt[replace_lt+2]);
1082                arr.push_back(tt[replace_lt+2]);
1083            }
1084            tt[replace_lt+1] = arr;
1085        } else if (valueObjType == "arr_boolean") {
1086            uint32_t len[replace_lt+1] = pxt->GetArrayLength(valueObj);
1087            std::vector<bool> arr;
1088            for(uint32_t i[replace_lt+1] = 0; i[replace_lt+1] < len[replace_lt+1]; i[replace_lt+1]++) {
1089                napi_value arr_value_result;
1090                napi_get_element(env, valueObj, i[replace_lt+1], &arr_value_result);
1091                bool tt[replace_lt+2];
1092                tt[replace_lt+2] = pxt->SwapJs2CBool(arr_value_result);
1093                arr.push_back(tt[replace_lt+2]);
1094            }
1095            tt[replace_lt+1] = arr;
1096        } else if (valueObjType == "arr_number") {
1097            [replace_objectTemplete_arrnum]
1098        } else if (valueObjType == "map_string" || valueObjType == "map_number" || valueObjType == "map_boolean") {
1099            [replace_objectTemplete_map]
1100        }
1101        `).format(lt);
1102    objTemplete = objTemplete.replaceAll('[replace_objectTemplete_arrnum]', objectTempleteArrnum.format(lt, lt, lt));
1103    objTemplete = objTemplete.replaceAll('[replace_objectTemplete_map]', objectTempleteMap.format(lt, lt));
1104    objTemplete = objTemplete.replaceAll('[replace_lt]', lt);
1105    objTemplete = objTemplete.replaceAll('[replace_lt+1]', lt + 1);
1106    objTemplete = objTemplete.replaceAll('[replace_lt+2]', lt + 2);
1107    return objTemplete;
1108}
1109
1110function paramGenerateObject(p, funcValue, param) {
1111    let type = funcValue.type;
1112    let name = funcValue.name;
1113    let inParamName = funcValue.optional ? '(*vio->in' + p + ')' : 'vio->in' + p;
1114    let modifiers = funcValue.optional ? '* ' : '&';
1115
1116        let arrayType = 'std::map<std::string, std::any>';
1117        param.valueIn += funcValue.optional ? '\n    %s* in%d = nullptr;'.format(arrayType, p)
1118                                            : '\n    %s in%d;'.format(arrayType, p);
1119
1120        let arrValueCheckout = jsToC(inParamName, 'pxt->GetArgv(%d)'.format(getConstNum(p)), type);
1121        param.valueCheckout += arrValueCheckout;
1122        param.valueFill += '%svio->in%d'.format(param.valueFill.length > 0 ? ', ' : '', p);
1123        param.valueDefine += '%s%s %s%s'.format(param.valueDefine.length > 0 ? ', '
1124            : '', arrayType, modifiers, name);
1125}
1126
1127function isCallbackFunc(type) {
1128    let callbackFunc = false;
1129    if (type.substring(0, 9) === 'Callback<' ||
1130    type.substring(0, 14) === 'AsyncCallback<' ||
1131    isFuncType(type)) {
1132        callbackFunc = true;
1133    }
1134    return callbackFunc;
1135}
1136
1137// 函数的参数处理
1138function paramGenerate(p, funcValue, param, data) {
1139    let type = funcValue.type;
1140    let name = funcValue.name;
1141    let inParamName = funcValue.optional ? '(*vio->in' + p + ')' : 'vio->in' + p;
1142    let modifiers = funcValue.optional ? '*' : '&';
1143    if (type.indexOf('|') >= 0) {
1144        paramGenerateUnion(type, param, p, name);
1145        return;
1146    } else if (type === 'string') {
1147        paramGenerateCommon(p, 'std::string', funcValue, param, modifiers, inParamName);
1148    } else if (type.substring(0, 12) === 'NUMBER_TYPE_' && type.indexOf('[]') < 0) {
1149        paramGenerateCommon(p, funcValue.type, funcValue, param, modifiers, inParamName);
1150    } else if (InterfaceList.getValue(type)) {
1151        paramGenerateCommon(p, funcValue.type, funcValue, param, modifiers, inParamName);
1152    } else if (TypeList.getValue(type)) {
1153        paramGenerateCommon(p, funcValue.type, funcValue, param, modifiers, inParamName);
1154    } else if (isCallbackFunc(type)) {
1155        paramGenerateCallBack(data, funcValue, param, p);
1156    } else if (CallFunctionList.getValue(type)) {
1157        paramGenerateArrowCallBack(funcValue, param, p);
1158    } else if (type === 'boolean') {
1159        paramGenerateCommon(p, 'bool', funcValue, param, modifiers, inParamName);
1160    } else if (isEnum(type, data)) {
1161        paramGenerateEnum(data, funcValue, param, p);
1162    } else if (type.substring(0, 4) === 'Map<' || type.substring(0, 6) === '{[key:') {
1163        paramGenerateMap(funcValue, param, p);
1164    } else if (isArrayType(type)) {
1165        paramGenerateArray(p, funcValue, param);
1166    } else if (type === 'any') {
1167        paramGenerateAny(p, name, type, param);
1168    } else if (type === 'object' || type === 'Object') {
1169        paramGenerateObject(p, funcValue, param);
1170    } else {
1171        NapiLog.logError('The current version does not support generating parameter [%s] with type [%s].'
1172            .format(name, type), getLogErrInfo());
1173    }
1174}
1175
1176// on/off 接口的参数处理
1177function eventParamGenerate(p, funcValue, param, data) {
1178    let type = funcValue.type;
1179    if (type === undefined) {
1180        NapiLog.logError('eventParamGenerate param error: funcValue.type is null');
1181        return;
1182    }
1183    if (type.indexOf("'") >= 0) {
1184        type = type.replaceAll('\'', '');
1185    }
1186    let regName = re.match('([a-zA-Z_0-9]+)', type);
1187    if (isFuncType(type)) {
1188        paramGenerateCallBack(data, funcValue, param, p);
1189    } else if (type.substring(0, 9) === 'Callback<' || type.substring(0, 14) === 'AsyncCallback<') {
1190        paramGenerateCallBack(data, funcValue, param, p); // callback参数处理
1191    } else if (CallFunctionList.getValue(type)) { // 判断条件
1192        let onFlag = true; // callFunction => 函数参数处理
1193        paramGenerateArrowCallBack(funcValue, param, p, onFlag);
1194    } else if (InterfaceList.getValue(type)) {
1195        let aaOnFlag = true;
1196    } else if (regName) { // event type参数处理
1197        param.eventName = re.getReg(type, regName.regs[1]); // string类型如何处理?
1198        if (param.eventName === 'string') {
1199            param.eventNameIsStr = true;
1200            param.eventName = 'string%d'.format(NumberIncrease.getAndIncrease());
1201        }
1202        param.valueDefine += '%sstd::string &%s'.format(param.valueDefine.length > 0 ? ', ' : '', funcValue.name);
1203    } else {
1204        NapiLog.logError('function eventParamGenerate:The current version do not support to this param to generate :',
1205        funcValue.name, 'type :', type, getLogErrInfo());
1206    }
1207}
1208
1209module.exports = {
1210    jsToC,
1211    getCType,
1212    jsToCEnum,
1213    arrTemplete,
1214    paramGenerate,
1215    paramGenerateArray,
1216    paramGenerateMap,
1217    paramGenerateCommon,
1218    paramGenerateUnion,
1219    paramGenerateCallBack,
1220    paramGenerateAny,
1221    paramGenerateObject,
1222    mapTempleteFunc,
1223    eventParamGenerate,
1224    anyTempleteFunc,
1225    objectTempleteFunc,
1226    unionTempleteFunc
1227};
1228