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, CallFunctionList, isOnOffRegisterFunc, isCreateThreadsafeFunc } = 22require('../tools/common'); 23const { generateEnum } = require('./enum'); 24const { generateFunctionOnOff } = require('./function_onoff'); 25const { generateThreadsafeFunc } = require('./function_threadsafe'); 26 27const { NapiLog } = require('../tools/NapiLog'); 28const { addUniqFunc2List, addUniqObj2List } = require('../tools/tool'); 29 30function findParentByName(parentName, data) { 31 for (let i in data.interface) { 32 if (parentName === data.interface[i].name) { 33 return data.interface[i]; 34 } 35 } 36 37 for (let i in data.class) { 38 if (parentName === data.class[i].name) { 39 return data.class[i]; 40 } 41 } 42 return null; 43} 44 45/** 46 * 生成父类的成员变量和方法 47 * @param currentObj 当前类 48 * @param data 全局数据上下文 49 * @param parentBody 输出参数,保存父类的成员变量和方法 50 * @returns void 51 */ 52function genParentPropties(currentObj, data, parentBody) { 53 for (let i in currentObj.body.parentNameList) { 54 let parentName = currentObj.body.parentNameList[i]; 55 let parentObj = findParentByName(parentName, data); 56 if (!parentObj) { 57 NapiLog.logError("Failed to find %s's parent by name [%s]".format(currentObj.body.name, parentName)); 58 return; 59 } 60 61 // 为父类添加子类的对象信息 62 addUniqObj2List(currentObj, parentObj.body.childList); 63 64 // 为当前类添加父类对象信息 65 addUniqObj2List(parentObj, currentObj.body.parentList); 66 67 for (let i in parentObj.body.value) { 68 // 添加父类的所有成员属性到parentBody 69 addUniqObj2List(parentObj.body.value[i], parentBody.value); 70 } 71 for (let i in parentObj.body.function) { 72 // 添加父类的所有成员方法到parentBody 73 addUniqFunc2List(parentObj.body.function[i], parentBody.function); 74 } 75 if (parentObj.body.parentNameList.length > 0) { 76 // 递归查找父类的父类 77 genParentPropties(parentObj, data, parentBody); 78 } 79 } 80} 81 82// 为有继承关系的interface和class类型建立父子类关系信息 83function genExtendsRelation(data) { 84 for (let i in data.interface) { 85 let ifObj = data.interface[i]; 86 if (ifObj && ifObj.body.parentNameList && ifObj.body.parentNameList.length > 0) { 87 ifObj.body.parentBody = {value:[], function:[]}; 88 genParentPropties(ifObj, data, ifObj.body.parentBody); 89 } 90 } 91 92 for (let i in data.class) { 93 let classObj = data.class[i]; 94 if (classObj.body.parentName) { 95 classObj.body.parentBody = {value:[], function:[]}; 96 genParentPropties(classObj, data, classObj.body.parentBody); 97 } 98 } 99} 100 101//生成module_middle.cpp、module.h、module.cpp 102function generateNamespace(name, data, inNamespace = '') { 103 let namespaceResult = { implH: '', implCpp: '', middleFunc: '', middleInit: '', declarationH: '', middleH: '', middleInitEnumDef: '' }; 104 namespaceResult.middleInit += formatMiddleInit(inNamespace, name); 105 genExtendsRelation(data); 106 InterfaceList.push(data.interface); 107 TypeList.push(data.type); 108 EnumList.push(data.enum); 109 CallFunctionList.push(data.callFunction); 110 let toolNamespace = getToolNamespaceFunc(inNamespace, name); 111 enumNamespaceFunction(data, namespaceResult, inNamespace, name, toolNamespace); 112 for (let i in data.type) { 113 let ii = data.type[i]; 114 let result = generateType(ii.name, ii.body, inNamespace + name + '::', inNamespace, name, toolNamespace); 115 namespaceResult = getNamespaceResult(result, namespaceResult); 116 } 117 for (let i in data.interface) { 118 let ii = data.interface[i]; 119 let result = generateInterface(ii.name, ii.body, inNamespace + name + '::'); 120 namespaceResult = getNamespaceResult(result, namespaceResult); 121 } 122 for (let i in data.class) { 123 let ii = data.class[i]; 124 let result = generateClass(ii.name, ii.body, inNamespace + name + '::', ii.functiontType); 125 namespaceResult = getNamespaceResult(result, namespaceResult); 126 } 127 namespaceResult.implH = namespaceResult.declarationH + namespaceResult.implH; 128 for (let i in data.function) { 129 genNamespaceFunc(data, i, namespaceResult, inNamespace, name); 130 } 131 let flag = true; 132 if (data.namespace.length !== 0) { 133 flag = false; 134 } 135 for (let i in data.namespace) { 136 let ns = data.namespace[i]; 137 let result = generateNamespace(ns.name, ns.body, inNamespace + name + '::'); 138 namespaceResult = getNamespaceResult(result, namespaceResult); 139 } 140 InterfaceList.pop(); 141 TypeList.pop(); 142 EnumList.pop(); 143 CallFunctionList.pop(); 144 if (inNamespace.length > 0) { 145 namespaceResult.middleInit += '}'; 146 flag = true; 147 } 148 return generateResult(name, namespaceResult.implH, namespaceResult.implCpp, namespaceResult.middleFunc, 149 namespaceResult.middleInit, namespaceResult.middleH, namespaceResult.middleInitEnumDef, flag); 150} 151 152function genNamespaceFunc(data, i, namespaceResult, inNamespace, name) { 153 let func = data.function[i]; 154 let tmp = generateFunction(func, data, namespaceResult.implH); 155 namespaceResult.middleFunc += tmp[0]; 156 namespaceResult.implH += tmp[1]; 157 namespaceResult.implCpp += tmp[2]; 158 namespaceResult.middleH += tmp[3]; 159 let toolNamespace = getToolNamespaceFunc(inNamespace, name); 160 let middleTmp = ' pxt->DefineFunction("%s", %s%s::%s%s_middle%s);\n' 161 .format(func.name, inNamespace, name, toolNamespace, func.name, inNamespace.length > 0 ? ', ' + name : ''); 162 if (namespaceResult.middleInit.indexOf(middleTmp) < 0) { // on方法不需要重复定义 163 namespaceResult.middleInit += middleTmp; 164 } 165} 166 167function getToolNamespaceFunc(inNamespace, name) { 168 let toolNamespace; 169 if (inNamespace !== '') { 170 let index = inNamespace.lastIndexOf('::'); 171 let bodyTmp = inNamespace.substring(0, index); 172 let index2 = bodyTmp.lastIndexOf('::'); 173 if (index2 > 0 && index2 < index) { 174 toolNamespace = inNamespace.substring(index2 + 2, index) + '_interface::'; 175 } else { 176 toolNamespace = name + '_interface::'; 177 } 178 } else { 179 toolNamespace = name + '_interface::'; 180 } 181 return toolNamespace; 182} 183 184function enumNamespaceFunction(data, namespaceResult, inNamespace, nameSpaceName, toolNamespace) { 185 let result = generateEnumResult(data, inNamespace, nameSpaceName, toolNamespace); 186 namespaceResult.implH += result.implH; 187 namespaceResult.implCpp += result.implCpp; 188 namespaceResult.middleInit += result.middleInit; 189 namespaceResult.middleInitEnumDef += result.midInitEnumDefine; 190} 191 192function getNamespaceResult(subResult, returnResult) { 193 returnResult.middleFunc += subResult.middleBody; 194 returnResult.implH += subResult.implH; 195 returnResult.implCpp += subResult.implCpp; 196 returnResult.middleInit += subResult.middleInit; 197 returnResult.declarationH += subResult.declarationH; 198 returnResult.middleH += subResult.middleH; 199 200 if (subResult.midInitEnumDefine !== undefined) { 201 returnResult.middleInitEnumDef += subResult.midInitEnumDefine; 202 } 203 204 return returnResult; 205} 206 207 function generateEnumResult(data, inNamespace, nameSpaceName, toolNamespace) { 208 let resultEnum = { 209 implH: '', 210 implCpp: '', 211 middleInit: '', 212 midInitEnumDefine: '' 213 }; 214 215 for (let i in data.enum) { 216 let enumm = data.enum[i]; 217 let result = generateEnum(enumm.name, enumm.body, inNamespace, nameSpaceName, toolNamespace); 218 resultEnum.implH += result.implH; 219 resultEnum.implCpp += result.implCpp; 220 resultEnum.middleInit += result.midInitEnum; 221 resultEnum.midInitEnumDefine += result.midInitEnumDefine; 222 } 223 return resultEnum; 224} 225 226function generateResult(name, implH, implCpp, middleFunc, middleInit, middleH, middleInitEnumDef, flag) { 227 let result; 228 let middleEnumDefine = middleInitEnumDef.indexOf('undefined') >= 0 ? '' : middleInitEnumDef; 229 if (flag) { 230 result = { 231 implH: `\nnamespace %s {\nnamespace %s_interface {%s\n}\n}`.format(name, name, implH), 232 implCpp: `\nnamespace %s {\nnamespace %s_interface {%s\n}\n}`.format(name, name, implCpp), 233 middleBody: `\nnamespace %s {\nnamespace %s_interface {\n%s%s\n}\n}`.format(name, name, middleEnumDefine, middleFunc), 234 middleInit: middleInit, 235 middleH: `\nnamespace %s {\nnamespace %s_interface {%s\n}\n}`.format(name, name, middleH) 236 }; 237 } else { 238 result = { 239 implH: `\nnamespace %s {%s\n}`.format(name, implH), 240 implCpp: `\nnamespace %s {%s}`.format(name, implCpp), 241 middleBody: `\nnamespace %s {\n%s%s}`.format(name, middleEnumDefine, middleFunc), 242 middleInit: middleInit, 243 middleH: `\nnamespace %s {%s\n}`.format(name, middleH) 244 }; 245 } 246 return result; 247} 248 249function generateFunction(func, data, implH = null) { 250 let tmp; 251 let className; 252 if (isOnOffRegisterFunc(func.name)) { 253 return generateFunctionOnOff(func, data); 254 } else if (isCreateThreadsafeFunc(func.name)) { 255 return generateThreadsafeFunc(func, data); 256 } 257 switch (func.type) { 258 case FuncType.DIRECT: 259 tmp = generateFunctionDirect(func, data); 260 break; 261 case FuncType.SYNC: 262 tmp = generateFunctionSync(func, data); 263 break; 264 case FuncType.ASYNC: 265 case FuncType.PROMISE: 266 tmp = generateFunctionAsync(func, data, className, implH); 267 break; 268 default: 269 break; 270 } 271 return tmp; 272} 273 274function formatMiddleInit(inNamespace, name) { 275 let middleInit = ''; 276 if (inNamespace.length > 0) { 277 let nsl = inNamespace.split('::'); 278 nsl.pop(); 279 let parentNs = nsl[nsl.length - 1]; 280 middleInit = `{\nnapi_value %s = pxt->CreateSubObject(%s, "%s");\n` 281 .format(name, nsl.length === 1 ? 'exports' : parentNs, name); 282 } 283 return middleInit; 284} 285 286module.exports = { 287 generateNamespace, 288 getNamespaceResult, 289 generateEnumResult, 290 generateResult, 291 generateFunction, 292 formatMiddleInit 293}; 294