• 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 } = 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
33        [className] *p = new [className]();
34
35        napi_value thisvar = pxt->WrapInstance(p, release);
36
37        return thisvar;
38    }
39    static void release(void *p)
40    {
41        [className] *p2 = ([className] *)p;
42        delete p2;
43    }
44    [static_funcs]
45};`
46
47function getHDefineOfVariable(name, type, variable) {
48    if (type.indexOf("|") >= 0) {
49        unionTypeString(name, type, variable)
50    } else if (type == "string") variable.hDefine += "\n    std::string %s;".format(name)
51    else if (InterfaceList.getValue(type)) variable.hDefine += "\n    %s %s;".format(type, name)
52    else if (EnumList.getValue(type)) variable.hDefine += "\n    %s %s;".format(type, name)
53    else if (type.indexOf("Array<") == 0) {
54        let arrayType = getArrayType(type)
55        if (arrayType == "any") {
56            variable.hDefine += "\n    std::string %s_type; \n    std::any %s;".format(name,name)
57        } else {
58            let cType = jsType2CType(arrayType)
59            variable.hDefine += "\n    std::vector<%s> %s;".format(cType, name)
60        }
61    } else if (type == "boolean") {
62        variable.hDefine += "\n    bool %s;".format(name)
63    } else if (type.substring(type.length - 2) == "[]") {
64        let arrayType = getArrayTypeTwo(type)
65        if (arrayType == "any") {
66            variable.hDefine += "\n    std::string %s_type; \n    std::any %s;".format(name,name)
67        } else {
68            let cType = jsType2CType(arrayType)
69            variable.hDefine += "\n    std::vector<%s> %s;".format(cType, name)
70        }
71    } else if (type.substring(0, 4) == "Map<" || type.indexOf("{[key:") == 0) {
72        variable.hDefine += mapTypeString(type, name)
73    } else if (type == "any") {
74        variable.hDefine += anyTypeString(type, name)
75    } else if (type.substring(0, 12) == "NUMBER_TYPE_") {
76        variable.hDefine += "\n    %s %s;".format(type, name)
77    } else if (type == "Object" || type == "object") {
78        variable.hDefine += "\n    std::map<std::string, std::any> %s;".format(name)
79    }
80    else {
81        NapiLog.logError(`
82        ---- generateVariable fail %s,%s ----
83        `.format(name, type));
84    }
85}
86
87function generateVariable(value, variable, className) {
88    let name = value.name
89    let type = value.type
90    if (!value.isParentMember) {
91        // 只有类/接口自己的成员属性需要在.h中定义, 父类/父接口不需要
92        getHDefineOfVariable(name, type, variable)
93    }
94
95    variable.middleValue += `
96    static napi_value getvalue_%s(napi_env env, napi_callback_info info)
97    {
98        XNapiTool *pxt = std::make_unique<XNapiTool>(env, info).release();
99        %s *p = (%s *)pxt->UnWarpInstance();
100        napi_value result = nullptr;
101        `.format(name, className, className) + cToJs("p->" + name, type, "result") + `
102        delete pxt;
103        return result;
104    }
105    static napi_value setvalue_%s(napi_env env, napi_callback_info info)
106    {
107        std::shared_ptr<XNapiTool> pxt = std::make_shared<XNapiTool>(env, info);
108        %s *p = (%s *)pxt->UnWarpInstance();
109        `.format(name, className, className) + jsToC("p->" + name, "pxt->GetArgv(0)", type) + `
110        return nullptr;
111    }
112`
113}
114
115function unionTypeString(name, type, variable) {
116    variable.hDefine += `std::string %s_type;\n
117    std::any %s;`.format(name, name)
118}
119
120function mapTypeString(type, name) {
121    let mapType = getMapType(type)
122    let mapTypeString
123    if (mapType[1] != undefined && mapType[2] == undefined) {
124        if (mapType[1] == "string") mapTypeString = "std::string,std::string"
125        else if (mapType[1] == "boolean") mapTypeString = "std::string,bool"
126        else if (mapType[1].substring(0, 12) == "NUMBER_TYPE_") {
127            mapTypeString = "std::string,%s".format(mapType[1])
128        }
129        else if (mapType[1].substring(0, 12) == "any") {
130            mapTypeString = `std::string,std::any`.format(mapType[1])
131            return `\n    std::map<%s> %s;
132            std::string %s_type;`.format(mapTypeString, name, name)
133        }
134        else if (InterfaceList.getValue(mapType[1])) mapTypeString = "std::string,%s".format(mapType[1])
135    }
136    if (mapType[2] != undefined) {
137        if (mapType[2] == "string") mapTypeString = "std::string,std::map<std::string,std::string>"
138        else if (mapType[2] == "boolean") mapTypeString = "std::string,std::map<std::string,bool>"
139        else if (mapType[2].substring(0, 12) == "NUMBER_TYPE_") {
140            mapTypeString = "std::string,std::map<std::string,%s>".format(mapType[2])
141        }
142    }
143    if (mapType[3] != undefined) {
144        if (mapType[3] == "string") mapTypeString = "std::string,std::vector<std::string>"
145        else if (mapType[3] == "boolean") mapTypeString = "std::string,std::vector<bool>"
146        else if (mapType[3].substring(0, 12) == "NUMBER_TYPE_") {
147            mapTypeString = "std::string,std::vector<%s>".format(mapType[3])
148        }
149    }
150    return "\n    std::map<%s> %s;".format(mapTypeString, name);
151}
152
153function anyTypeString (type, name) {
154    let anyType = `\n    std::string %s_type;
155    std::any %s;`
156
157    return anyType.format(name, name)
158}
159
160function generateInterface(name, data, inNamespace) {
161    let resultConnect = connectResult(data, inNamespace, name)
162    let middleFunc = resultConnect[0]
163    let implH = resultConnect[1]
164    let implCpp = resultConnect[2]
165    let middleInit = resultConnect[3]
166    let selfNs = ""
167    if (inNamespace.length > 0) {
168        let nsl = inNamespace.split("::")
169        nsl.pop()
170        if (nsl.length >= 2) {
171            selfNs = ", " + nsl[nsl.length - 1]
172        }
173    }
174    middleInit += `\n    pxt->DefineClass("%s", %s%s_middle::constructor, 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        addUniqFunc2List(interfaceBody.function[i], properties.functions)
199    }
200    if (!isParentClass && interfaceBody.parentNameList && interfaceBody.parentNameList.length > 0) {
201        getAllPropties(interfaceBody.parentBody, properties, true)
202    }
203}
204
205function connectResult(data, inNamespace, name) {
206    let implH = ""
207    let implCpp = ""
208    let middleFunc = ""
209    let middleInit = ""
210    let variable = {
211        hDefine: "",
212        middleValue: "",
213    }
214    middleInit = `{\n    std::map<const char *,std::map<const char *,napi_callback>> valueList;`
215    data.allProperties = {values:[], functions:[]}
216    getAllPropties(data, data.allProperties, false)
217    for (let i in data.allProperties.values) {
218        let v = data.allProperties.values[i]
219        generateVariable(v, variable, name)
220        middleInit += `
221    valueList["%s"]["getvalue"]=%s%s_middle::getvalue_%s;
222    valueList["%s"]["setvalue"]=%s%s_middle::setvalue_%s;`
223            .format(v.name, inNamespace, name, v.name, v.name, inNamespace, name, v.name)
224    }
225    implH += variable.hDefine
226    middleFunc += variable.middleValue
227    middleInit += `\n    std::map<const char *, napi_callback> funcList;`
228    for (let i in data.allProperties.functions) {
229        let func = data.allProperties.functions[i]
230        let tmp;
231        switch (func.type) {
232            case FuncType.DIRECT:
233                tmp = generateFunctionDirect(func, data, name)
234                break;
235            case FuncType.SYNC:
236                tmp = generateFunctionSync(func, data, name)
237                break
238            case FuncType.ASYNC:
239            case FuncType.PROMISE:
240                tmp = generateFunctionAsync(func, data, name)
241                break
242            default:
243                return
244        }
245        middleFunc += tmp[0]
246        implH += tmp[1]
247        implCpp += tmp[2]
248        middleInit += `\n    funcList["%s"] = %s%s_middle::%s_middle;`.format(func.name, inNamespace, name, func.name)
249    }
250    if (data.childList && data.childList.length > 0) {
251        // 如果是父类,增加虚析构函数使其具备泛型特征 (基类必须有虚函数才能正确使用dynamic_cast和typeinfo等方法)
252        implH += "\n    virtual ~%s(){};".format(name)
253    }
254    return [middleFunc, implH, implCpp, middleInit]
255}
256
257module.exports = {
258    generateInterface,
259    connectResult,
260    generateVariable,
261    mapTypeString
262}