• 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 { generateInterface } = require("./interface");
19const { generateClass } = require("./class");
20const { FuncType, InterfaceList, EnumList } = require("../tools/common");
21const { generateEnum } = require("./enum");
22const { generateFunctionOnOff } = require("./function_onoff");
23const { NapiLog } = require("../tools/NapiLog");
24const { addUniqFunc2List, addUniqObj2List } = require("../tools/tool");
25
26function findParentByName(parentName, data) {
27    for (let i in data.interface) {
28        if (parentName == data.interface[i].name) {
29            return data.interface[i]
30        }
31    }
32
33    for (let i in data.class) {
34        if (parentName == data.class[i].name) {
35            return data.class[i]
36        }
37    }
38    return null
39}
40
41/**
42 * 生成父类的成员变量和方法
43 * @param currentObj 当前类
44 * @param data 全局数据上下文
45 * @param parentBody 输出参数,保存父类的成员变量和方法
46 * @returns void
47 */
48function genParentPropties(currentObj, data, parentBody) {
49    for (let i in currentObj.body.parentNameList) {
50        let parentName = currentObj.body.parentNameList[i]
51        let parentObj = findParentByName(parentName, data)
52        if (!parentObj) {
53            NapiLog.logError("Failed to find %s's parent by name [%s]".format(currentObj.body.name, parentName))
54            return
55        }
56
57        // 为父类添加子类的对象信息
58        addUniqObj2List(currentObj, parentObj.body.childList)
59
60        // 为当前类添加父类对象信息
61        addUniqObj2List(parentObj, currentObj.body.parentList)
62
63        for (let i in parentObj.body.value) {
64            // 添加父类的所有成员属性到parentBody
65            addUniqObj2List(parentObj.body.value[i], parentBody.value)
66        }
67        for (let i in parentObj.body.function) {
68            // 添加父类的所有成员方法到parentBody
69            addUniqFunc2List(parentObj.body.function[i], parentBody.function)
70        }
71        if (parentObj.body.parentNameList.length > 0) {
72            // 递归查找父类的父类
73            genParentPropties(parentObj, data, parentBody)
74        }
75    }
76}
77
78// 为有继承关系的interface和class类型建立父子类关系信息
79function genExtendsRelation(data) {
80    for (let i in data.interface) {
81        let ifObj = data.interface[i]
82        if (ifObj && ifObj.body.parentNameList && ifObj.body.parentNameList.length > 0) {
83            ifObj.body.parentBody = {value:[], function:[]}
84            genParentPropties(ifObj, data, ifObj.body.parentBody)
85        }
86    }
87
88    for (let i in data.class) {
89        let classObj = data.class[i]
90        if (classObj.body.parentName) {
91            classObj.body.parentBody = {value:[], function:[]}
92            genParentPropties(classObj, data, classObj.body.parentBody)
93        }
94    }
95}
96
97//生成module_middle.cpp、module.h、module.cpp
98function generateNamespace(name, data, inNamespace = "") {
99    let namespaceResult = {
100        implH: "",
101        implCpp: "",
102        middleFunc: "",
103        middleInit: ""
104    }
105
106    namespaceResult.middleInit += formatMiddleInit(inNamespace, name)
107    genExtendsRelation(data)
108    InterfaceList.push(data.interface)
109    EnumList.push(data.enum)
110    let result = generateEnumResult(data);
111    namespaceResult.implH += result.implH
112    namespaceResult.implCpp += result.implCpp
113    namespaceResult.middleInit += result.middleInit
114    for (let i in data.interface) {
115        let ii = data.interface[i]
116        let result = generateInterface(ii.name, ii.body, inNamespace + name + "::")
117        namespaceResult = getNamespaceResult(result, namespaceResult)
118    }
119
120    for (let i in data.class) {
121        let ii = data.class[i]
122        let result = generateClass(ii.name, ii.body, inNamespace + name + "::", ii.functiontType)
123        namespaceResult = getNamespaceResult(result, namespaceResult)
124    }
125    for (let i in data.function) {
126        let func = data.function[i]
127        let tmp = generateFunction(func, data)
128        namespaceResult.middleFunc += tmp[0]
129        namespaceResult.implH += tmp[1]
130        namespaceResult.implCpp += tmp[2]
131        namespaceResult.middleInit += '    pxt->DefineFunction("%s", %s%s::%s_middle%s);\n'
132            .format(func.name, inNamespace, name, func.name, inNamespace.length > 0 ? ", " + name : "")
133    }
134    for (let i in data.namespace) {
135        let ns = data.namespace[i]
136        let result = generateNamespace(ns.name, ns.body, inNamespace + name + "::")
137        namespaceResult = getNamespaceResult(result, namespaceResult)
138    }
139    InterfaceList.pop();
140    EnumList.pop();
141    if (inNamespace.length > 0) {
142        namespaceResult.middleInit += "}"
143    }
144    return generateResult(name, namespaceResult.implH, namespaceResult.implCpp, namespaceResult.middleFunc,
145        namespaceResult.middleInit)
146}
147
148function getNamespaceResult(subResult, returnResult) {
149    returnResult.middleFunc += subResult.middleBody
150    returnResult.implH += subResult.implH
151    returnResult.implCpp += subResult.implCpp
152    returnResult.middleInit += subResult.middleInit
153    return returnResult
154}
155
156function generateEnumResult(data) {
157    let resultEnum = {
158        implH: "",
159        implCpp: "",
160        middleInit: ""
161    }
162
163    for (let i in data.enum) {
164        let enumm = data.enum[i]
165        let result = generateEnum(enumm.name, enumm.body)
166        resultEnum.implH += result.implH
167        resultEnum.implCpp += result.implCpp
168        resultEnum.middleInit += result.midInitEnum
169    }
170    return resultEnum
171}
172
173function generateResult(name, implH, implCpp, middleFunc, middleInit) {
174    let result = {
175        implH: `namespace %s {%s\n}`.format(name, implH),
176        implCpp: `namespace %s {%s}`.format(name, implCpp),
177        middleBody: `namespace %s {%s}`.format(name, middleFunc),
178        middleInit: middleInit
179    }
180    return result;
181}
182
183function generateFunction(func, data) {
184    let tmp;
185    if (func.name == 'on' || func.name == 'off' ) {
186        return generateFunctionOnOff(func, data)
187    }
188    switch (func.type) {
189        case FuncType.DIRECT:
190            tmp = generateFunctionDirect(func, data)
191            break;
192        case FuncType.SYNC:
193            tmp = generateFunctionSync(func, data)
194            break
195        case FuncType.ASYNC:
196        case FuncType.PROMISE:
197            tmp = generateFunctionAsync(func, data)
198            break
199        default:
200            return
201    }
202    return tmp
203}
204
205function formatMiddleInit(inNamespace, name) {
206    let middleInit = ""
207    if (inNamespace.length > 0) {
208        let nsl = inNamespace.split("::")
209        nsl.pop()
210        let parentNs = nsl[nsl.length - 1]
211        middleInit = `{\nnapi_value %s=pxt->CreateSubObject(%s,"%s");\n`
212            .format(name, nsl.length == 1 ? "exports" : parentNs, name)
213    }
214    return middleInit
215}
216
217module.exports = {
218    generateNamespace,
219    getNamespaceResult,
220    generateEnumResult,
221    generateResult,
222    generateFunction,
223    formatMiddleInit
224}