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 re = require('../tools/re');
16const { checkOutBody, print } = require('../tools/tool');
17const { FuncType, NumberIncrease, isFuncType, isArrowFunc, isRegisterFunc } = require('../tools/common');
18const { NapiLog } = require('../tools/NapiLog');
19
20function isSyncFuncType(type, funcType) {
21    let isSync = false;
22    if (funcType === FuncType.DIRECT && type.indexOf('Callback') >= 0 && type.indexOf('AsyncCallback') < 0 ||
23        isFuncType(type) || isArrowFunc(type)) {
24        isSync = true;
25    }
26    return isSync;
27}
28
29/**
30 * on方法中回调方法的解析
31 * @param {*} valueType 回调方法体
32 * @param {*} valueName 参数名
33 * @param {*} rsltCallFunction 解析结果
34 */
35function analyzeCallbackFunction(valueType, valueName, rsltCallFunction) {
36
37    if (valueType.indexOf('=>') > 0) {
38        valueType = re.replaceAll(valueType, ' ', '');
39    }
40    let matchs = re.match('\\(([a-zA-Z_0-9:,]+)*\\)=>([a-zA-Z_0-9]+)', valueType);
41
42    if (matchs) {
43        let number = NumberIncrease.getAndIncrease();
44        let functionTypeName = 'AUTO_CALLFUNCTION_%s_%s'.format(valueName, number);
45
46        let functionRet = re.getReg(valueType, matchs.regs[2]);
47        let functionBody = re.getReg(valueType, matchs.regs[1]);
48
49        let tmp = analyzeParams(functionTypeName, functionBody);
50        let bodyRes = tmp[0];
51        for (let i in bodyRes) {
52            let hasProperty = Object.prototype.hasOwnProperty.call(bodyRes[i], 'type');
53            if (hasProperty && bodyRes[i].type === 'number') {
54                bodyRes[i].type = 'NUMBER_TYPE_' + NumberIncrease.getAndIncrease();
55            }
56        }
57
58        rsltCallFunction.push({
59            'name': functionTypeName,
60            'body': bodyRes,
61            'ret': functionRet,
62        });
63        valueType = functionTypeName;
64    }
65    return valueType;
66}
67
68/**函数参数解析 */
69function analyzeParams(funcName, values) {
70    let result = [];
71    let rsltCallFunction = [];
72    let funcType = FuncType.DIRECT;
73    let optionalParamCount = 0; // 可选参数的个数
74    while (values.length > 0) {
75        let v = checkOutBody(values, 0, ['', ',']);
76        if (v === null) {
77            v = values;
78        }
79
80        values = values.substring(v.length, values.length);
81        let matchs = re.match('([a-zA-Z_0-9\\.]+)(\\?*): *([a-zA-Z<,>|_0-9\\[\\]\\(\\):=\'{}]+)', v);
82        if (matchs === null && (funcName === 'on' || funcName === 'off')) {
83            // on和off的第一个参数的类型可以是一串字符
84            matchs = re.match('([a-zA-Z_0-9\\.]+)(\\?*): *\"([a-zA-Z|_0-9\\[\\]\\(\\):=\'{}]+)\"', v);
85        }
86        if (matchs !== null) {
87            let type = re.getReg(v, matchs.regs[3]);
88            if (type.indexOf('Map') < 0 && !isArrowFunc(type)) {
89                type = type.replace(/,/g, '');
90            }
91
92            let valueName = re.getReg(v, matchs.regs[1]);
93            type = analyzeCallbackFunction(type, valueName, rsltCallFunction);
94
95            let optionalFlag = re.getReg(v, matchs.regs[2]) === '?' ? true : false;
96            let checkParamOk = true;
97            let retVal = analyzaParamsFunc(optionalFlag, optionalParamCount, v, funcName, checkParamOk,
98                result, matchs, type, funcType);
99            result = retVal[0];
100            funcType = retVal[1];
101        }
102        else {
103            NapiLog.logError('Failed to analyse parameter [%s] of function [%s].'.format(v, funcName));
104        }
105    }
106    return [result, funcType, rsltCallFunction];
107}
108
109function analyzaParamsFunc(optionalFlag, optionalParamCount, v, funcName, checkParamOk,
110    result, matchs, type, funcType) {
111    if (optionalFlag) {
112        optionalParamCount++;
113    } else if (optionalParamCount > 0) {
114        // 可选参数之后不能再有必选参数,须是可选参数。
115        NapiLog.logError('Invalid parameter [%s] of function [%s],'.format(v, funcName) +
116            ' the required parameter cannot follow an optional parameter.');
117        checkParamOk = false;
118    }
119    if (checkParamOk) {
120        result.push({ 'name': re.getReg(v, matchs.regs[1]), 'type': type, 'optional': optionalFlag, 'realType': type });
121        if (type.indexOf('AsyncCallback') >= 0) {
122            funcType = FuncType.ASYNC;
123        }
124
125        if (isSyncFuncType(type, funcType)) {
126            funcType = FuncType.SYNC;
127        }
128    }
129    return [result, funcType];
130}
131
132module.exports = {
133    analyzeParams,
134};
135