• 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 { generateFunctionDirect } = require("./function_direct");
16const { generateFunctionSync } = require("./function_sync");
17const { generateFunctionAsync } = require("./function_async");
18const { FuncType, InterfaceList, getArrayType, getArrayTypeTwo, getMapType, EnumList, jsType2CType }
19    = require("../tools/common");
20const { jsToC } = require("./param_generate");
21const { cToJs } = require("./return_generate");
22const re = require("../tools/re");
23const { NapiLog } = require("../tools/NapiLog");
24const { addUniqFunc2List, addUniqObj2List, setOverrideFunc } = require("../tools/tool");
25
26let middleBodyTmplete = `
27class [className]_middle {
28public:
29    static napi_value constructor(napi_env env, napi_callback_info info)
30    {
31        XNapiTool *pxt = new XNapiTool(env, info);
32        [className] *p = new [className]();
33        napi_value thisvar = pxt->WrapInstance(reinterpret_cast<DataPtr>(p), release);
34        return thisvar;
35    }
36    static void release(DataPtr p)
37    {
38        void *dataPtr = p;
39        [className] *p2 = static_cast<[className] *>(dataPtr);
40        delete p2;
41    }
42    [static_funcs]
43};`
44
45function getHDefineOfVariable(name, type, variable) {
46    if (type.indexOf("|") >= 0) {
47        unionTypeString(name, type, variable)
48    } else if (type == "string") variable.hDefine += "\n    std::string %s;".format(name)
49    else if (InterfaceList.getValue(type)) variable.hDefine += "\n    %s %s;".format(type, name)
50    else if (EnumList.getValue(type)) variable.hDefine += "\n    %s %s;".format(type, name)
51    else if (type.indexOf("Array<") == 0) {
52        let arrayType = getArrayType(type)
53        if (arrayType == "any") {
54            variable.hDefine += "\n    std::string %s_type; \n    std::any %s;".format(name,name)
55        } else {
56            let cType = jsType2CType(arrayType)
57            variable.hDefine += "\n    std::vector<%s> %s;".format(cType, name)
58        }
59    } else if (type == "boolean") {
60        variable.hDefine += "\n    bool %s;".format(name)
61    } else if (type.substring(type.length - 2) == "[]") {
62        let arrayType = getArrayTypeTwo(type)
63        if (arrayType == "any") {
64            variable.hDefine += "\n    std::string %s_type;\n    std::any %s;".format(name,name)
65        } else {
66            let cType = jsType2CType(arrayType)
67            variable.hDefine += "\n    std::vector<%s> %s;".format(cType, name)
68        }
69    } else if (type.substring(0, 4) == "Map<" || type.indexOf("{[key:") == 0) {
70        variable.hDefine += mapTypeString(type, name)
71    } else if (type == "any") {
72        variable.hDefine += anyTypeString(type, name)
73    } else if (type.substring(0, 12) == "NUMBER_TYPE_") {
74        variable.hDefine += "\n    %s %s;".format(type, name)
75    } else if (type == "Object" || type == "object") {
76        variable.hDefine += "\n    std::map<std::string, std::any> %s;".format(name)
77    }
78    else {
79        NapiLog.logError(`
80        ---- generateVariable fail %s,%s ----
81        `.format(name, type));
82    }
83}
84
85function generateVariable(value, variable, className) {
86    let name = value.name
87    let type = value.type
88    if (!value.isParentMember) {
89        // 只有类/接口自己的成员属性需要在.h中定义, 父类/父接口不需要
90        getHDefineOfVariable(name, type, variable)
91    }
92
93    variable.middleValue += `
94    static napi_value getvalue_%s(napi_env env, napi_callback_info info)
95    {
96        XNapiTool *pxt = std::make_unique<XNapiTool>(env, info).release();
97        void *instPtr = pxt->UnWarpInstance();
98        %s *p = static_cast<%s *>(instPtr);
99        napi_value result = nullptr;
100        `.format(name, className, className) + cToJs("p->" + name, type, "result") + `
101        delete pxt;
102        return result;
103    }
104    static napi_value setvalue_%s(napi_env env, napi_callback_info info)
105    {
106        std::shared_ptr<XNapiTool> pxt = std::make_shared<XNapiTool>(env, info);
107        void *instPtr = pxt->UnWarpInstance();
108        %s *p = static_cast<%s *>(instPtr);
109        `.format(name, className, className) + jsToC("p->" + name, "pxt->GetArgv(XNapiTool::ZERO)", type) + `
110        return nullptr;
111    }`
112}
113
114function unionTypeString(name, type, variable) {
115    variable.hDefine += `std::string %s_type;\n
116    std::any %s;`.format(name, name)
117}
118
119function mapTypeString(type, name) {
120    let mapType = getMapType(type)
121    let mapTypeString
122    if (mapType[1] != undefined && mapType[2] == undefined) {
123        if (mapType[1] == "string") mapTypeString = "std::string, std::string"
124        else if (mapType[1] == "boolean") mapTypeString = "std::string, bool"
125        else if (mapType[1].substring(0, 12) == "NUMBER_TYPE_") {
126            mapTypeString = "std::string, %s".format(mapType[1])
127        }
128        else if (mapType[1].substring(0, 12) == "any") {
129            mapTypeString = `std::string, std::any`.format(mapType[1])
130            return `\n    std::map<%s> %s;
131            std::string %s_type;`.format(mapTypeString, name, name)
132        }
133        else if (InterfaceList.getValue(mapType[1])) mapTypeString = "std::string, %s".format(mapType[1])
134    }
135    if (mapType[2] != undefined) {
136        if (mapType[2] == "string") mapTypeString = "std::string, std::map<std::string, std::string>"
137        else if (mapType[2] == "boolean") mapTypeString = "std::string, std::map<std::string, bool>"
138        else if (mapType[2].substring(0, 12) == "NUMBER_TYPE_") {
139            mapTypeString = "std::string, std::map<std::string, %s>".format(mapType[2])
140        }
141    }
142    if (mapType[3] != undefined) {
143        if (mapType[3] == "string") mapTypeString = "std::string, std::vector<std::string>"
144        else if (mapType[3] == "boolean") mapTypeString = "std::string, std::vector<bool>"
145        else if (mapType[3].substring(0, 12) == "NUMBER_TYPE_") {
146            mapTypeString = "std::string, std::vector<%s>".format(mapType[3])
147        }
148    }
149    return "\n    std::map<%s> %s;".format(mapTypeString, name);
150}
151
152function anyTypeString (type, name) {
153    let anyType = `\n    std::string %s_type;
154    std::any %s;`
155
156    return anyType.format(name, name)
157}
158
159function generateInterface(name, data, inNamespace) {
160    let resultConnect = connectResult(data, inNamespace, name)
161    let middleFunc = resultConnect[0]
162    let implH = resultConnect[1]
163    let implCpp = resultConnect[2]
164    let middleInit = resultConnect[3]
165    let selfNs = ""
166    if (inNamespace.length > 0) {
167        let nsl = inNamespace.split("::")
168        nsl.pop()
169        if (nsl.length >= 2) {
170            selfNs = ", " + nsl[nsl.length - 1]
171        }
172    }
173    middleInit += `\n    pxt->DefineClass("%s", %s%s_middle::constructor,
174        valueList, funcList%s);\n}\n`
175        .format(name, inNamespace, name, selfNs)
176    let extendsStr = (data.parentNameList && data.parentNameList.length > 0) ?
177        " : public %s".format(data.parentNameList.join(", public ")) : ""
178    let result = {
179        implH: `
180class %s%s {
181public:%s
182};\n`.format(name, extendsStr, implH),
183        implCpp: implCpp,
184        middleBody: middleBodyTmplete.replaceAll("[className]", name).replaceAll("[static_funcs]", middleFunc),
185        middleInit: middleInit
186    }
187    return result
188}
189
190// 递归获取接口及接口父类的所有成员属性和方法
191function getAllPropties(interfaceBody, properties, isParentClass) {
192    for (let i in interfaceBody.value) {
193        interfaceBody.value[i].isParentMember = isParentClass
194        addUniqObj2List(interfaceBody.value[i], properties.values)
195    }
196    for (let i in interfaceBody.function) {
197        interfaceBody.function[i].isParentMember = isParentClass
198        if(!addUniqFunc2List(interfaceBody.function[i], properties.functions)) {
199            if (isParentClass) {
200                // 没添加到列表,说明子类方法properties.functions重写了父类方法interfaceBody.function[i]
201                // 找到该子类方法并将其设置为override (生成的重写函数如果没有override关键字会触发门禁告警)
202                setOverrideFunc(interfaceBody.function[i], properties.functions)
203            }
204        }
205    }
206    if (!isParentClass && interfaceBody.parentNameList && interfaceBody.parentNameList.length > 0) {
207        getAllPropties(interfaceBody.parentBody, properties, true)
208    }
209}
210
211function addVirtualKeywords(data, implH, name) {
212    if (data.childList && data.childList.length > 0) {
213        // 如果该类是其它类的父类,增加虚析构函数使其具备泛型特征 (基类必须有虚函数才能正确使用dynamic_cast和typeinfo等方法)
214        // 如果该类自己也有父类,虚析构函数需要加上override关键字(否则C++门禁会有告警)
215        let ovrrideStr = (data.parentList && data.parentList.length > 0) ? " override" : "";
216        // 如果虚析构函数已经有override关键字,就不需要再加virtual关键字了(否则C++门禁会有告警)
217        let virtualStr = (data.parentList && data.parentList.length > 0) ? "" : "virtual ";
218        implH += "\n    %s~%s()%s {};".format(virtualStr, name, ovrrideStr);
219    }
220    return implH;
221}
222
223function connectResult(data, inNamespace, name) {
224    let implH = ""
225    let implCpp = ""
226    let middleFunc = ""
227    let middleInit = ""
228    let variable = {
229        hDefine: "",
230        middleValue: "",
231    }
232    middleInit = `{\n    std::map<const char *, std::map<const char *, napi_callback>> valueList;`
233    data.allProperties = {values:[], functions:[]}
234    getAllPropties(data, data.allProperties, false)
235    for (let i in data.allProperties.values) {
236        let v = data.allProperties.values[i]
237        generateVariable(v, variable, name)
238        middleInit += `
239    valueList["%s"]["getvalue"] = %s%s_middle::getvalue_%s;
240    valueList["%s"]["setvalue"] = %s%s_middle::setvalue_%s;`
241            .format(v.name, inNamespace, name, v.name, v.name, inNamespace, name, v.name)
242    }
243    implH += variable.hDefine
244    middleFunc += variable.middleValue
245    middleInit += `\n    std::map<const char *, napi_callback> funcList;`
246    for (let i in data.allProperties.functions) {
247        let func = data.allProperties.functions[i]
248        let tmp;
249        switch (func.type) {
250            case FuncType.DIRECT:
251                tmp = generateFunctionDirect(func, data, name)
252                break;
253            case FuncType.SYNC:
254                tmp = generateFunctionSync(func, data, name)
255                break
256            case FuncType.ASYNC:
257            case FuncType.PROMISE:
258                tmp = generateFunctionAsync(func, data, name)
259                break
260            default:
261                return
262        }
263        middleFunc += tmp[0]
264        implH += tmp[1]
265        implCpp += tmp[2]
266        middleInit += `\n    funcList["%s"] = %s%s_middle::%s_middle;`.format(func.name, inNamespace, name, func.name)
267    }
268    implH = addVirtualKeywords(data, implH, name);
269    return [middleFunc, implH, implCpp, middleInit]
270}
271
272module.exports = {
273    generateInterface,
274    connectResult,
275    generateVariable,
276    mapTypeString
277}
278
279
280