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