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