From 46eaad0be133910ab478265573ca6c57e7303a6b Mon Sep 17 00:00:00 2001 From: wqzhappy Date: Tue, 16 Aug 2022 20:56:41 +0800 Subject: [PATCH] support extends and implements Signed-off-by: wqzhappy --- src/gen/analyze/class.js | 19 +-- src/gen/analyze/function.js | 8 +- src/gen/analyze/interface.js | 7 +- src/gen/analyze/namespace.js | 110 +++++++++++--- src/gen/generate/class.js | 26 ++-- src/gen/generate/function_async.js | 41 ++--- src/gen/generate/function_direct.js | 32 ++-- src/gen/generate/function_sync.js | 32 ++-- src/gen/generate/interface.js | 77 +++++++--- src/gen/generate/namespace.js | 74 +++++++++ src/gen/generate/return_generate.js | 2 +- src/gen/tools/common.js | 2 +- src/gen/tools/tool.js | 81 +++++++++- test/storytest/test_extends/@ohos.test.d.ts | 87 +++++++++++ test/storytest/test_extends/test.js | 157 ++++++++++++++++++++ test/unittest/analyze.test.js | 8 +- 16 files changed, 636 insertions(+), 127 deletions(-) create mode 100644 test/storytest/test_extends/@ohos.test.d.ts create mode 100644 test/storytest/test_extends/test.js diff --git a/src/gen/analyze/class.js b/src/gen/analyze/class.js index a570e92e..c358219f 100644 --- a/src/gen/analyze/class.js +++ b/src/gen/analyze/class.js @@ -37,10 +37,10 @@ function analyzeClass(data) { } // 如果t为空直接返回 if (classBody == "") break - let matchNameAndType = re.match(" *([a-zA-Z0-9_]+) *: *([a-zA-Z_0-9<>]+)", classBody) - if (matchNameAndType) { - let valueName = re.getReg(classBody, matchNameAndType.regs[1]) - let valueType = re.getReg(classBody, matchNameAndType.regs[2]) + let matcher = re.match(" *([a-zA-Z0-9_]+) *: *([a-zA-Z_0-9<>]+)", classBody) + if (matcher) { + let valueName = re.getReg(classBody, matcher.regs[1]) + let valueType = re.getReg(classBody, matcher.regs[2]) if (valueType.indexOf("number") >= 0) { valueType = valueType.replace("number", "NUMBER_TYPE_" + NumberIncrease.getAndIncrease()) } @@ -49,11 +49,12 @@ function analyzeClass(data) { type: valueType }) } - let rules = "(static)? *([A-Za-z0-9_]+)\\(([\n a-zA-Z:;=,_0-9?<>{}|]*)\\) *: *([A-Za-z0-9_<>{}:, .]+)"; - matchNameAndType = re.match(rules, classBody) - if (matchNameAndType) { - let funcDetail = analyzeFunction(data, re.getReg(classBody, matchNameAndType.regs[2]), - re.getReg(classBody, matchNameAndType.regs[3]), re.getReg(classBody, matchNameAndType.regs[4])) + let rules = "(static )? *([A-Za-z0-9_]+)\\(([\n a-zA-Z:;=,_0-9?<>{}|]*)\\) *: *([A-Za-z0-9_<>{}:, .]+)"; + matcher = re.match(rules, classBody) + if (matcher) { + let funcDetail = analyzeFunction(data, + re.getReg(classBody, matcher.regs[1]) != '', re.getReg(classBody, matcher.regs[2]), + re.getReg(classBody, matcher.regs[3]), re.getReg(classBody, matcher.regs[4])) if (funcDetail != null) result.function.push(funcDetail) } diff --git a/src/gen/analyze/function.js b/src/gen/analyze/function.js index d24e3664..9aa0af0e 100644 --- a/src/gen/analyze/function.js +++ b/src/gen/analyze/function.js @@ -24,7 +24,10 @@ function analyzeSubInterface(data) { let body = re.replaceAll(data, "\n", "").split(";")// # replace(" ", ""). let result = { value: [], - function: [] + function: [], + parentNameList: [], + childList: [], + parentList: [] } for (let i in body) { let t = body[i] @@ -83,7 +86,7 @@ function getFuncParaType(v, interfaceName, data) { } /**函数解析 */ -function analyzeFunction(data, name, values, ret) { +function analyzeFunction(data, isStatic, name, values, ret) { values = re.replaceAll(re.replaceAll(values, " ", ""), "\n", "") let matchs = re.match("([a-zA-Z_0-9]*)\\?*:{([A-Za-z0-9_]+:[A-Za-z0-9_,]+)([A-Za-z0-9_]+:[A-Za-z0-9_]+)}$", values) let interfaceName = '' @@ -126,6 +129,7 @@ function analyzeFunction(data, name, values, ret) { type: funcType, value: values, ret: ret, + isStatic: isStatic } return result } diff --git a/src/gen/analyze/interface.js b/src/gen/analyze/interface.js index dd9e5b10..0de3be7e 100644 --- a/src/gen/analyze/interface.js +++ b/src/gen/analyze/interface.js @@ -46,10 +46,11 @@ function analyzeInterface(data) {//same as class type: valueType }) } - tt = re.match(" *([A-Za-z0-9_]+)\\(([\n 'a-zA-Z:;=,_0-9?<>{}|[\\]]*)\\) *: *([A-Za-z0-9_<>{}:, .[\\]]+)", t) + tt = re.match( + "(static )* *([A-Za-z0-9_]+)\\(([\n 'a-zA-Z:;=,_0-9?<>{}|[\\]]*)\\) *: *([A-Za-z0-9_<>{}:, .[\\]]+)", t) if (tt) {//函数 - let funcDetail = analyzeFunction(data, re.getReg(t, tt.regs[1]), - re.getReg(t, tt.regs[2]), re.getReg(t, tt.regs[3])) + let funcDetail = analyzeFunction(data, re.getReg(t, tt.regs[1]) != '', re.getReg(t, tt.regs[2]), + re.getReg(t, tt.regs[3]), re.getReg(t, tt.regs[4])) if (funcDetail != null) result.function.push(funcDetail) } diff --git a/src/gen/analyze/namespace.js b/src/gen/analyze/namespace.js index 0a49ddb6..5d63a513 100644 --- a/src/gen/analyze/namespace.js +++ b/src/gen/analyze/namespace.js @@ -90,19 +90,12 @@ function parseNamespace(matchs, data, result) { } function parseClass(matchs, data, result) { - matchs = re.match("(export )*class ([a-zA-Z]+) (extends [a-zA-Z]+ )*(implements [a-zA-Z]+ )*({)", data) + matchs = re.match( + "(export )*class ([A-Za-z_0-9]+)()* *(extends [a-zA-Z_0-9, ]+)* *(implements [a-zA-Z_0-9, ]+)* *({)" + , data) if (matchs) { - let className = re.getReg(data, matchs.regs[2]) - let classBody = checkOutBody(data, matchs.regs[5][0], null, true) - result.class.push({ - name: className, - body: analyzeClass(classBody.substring(1, classBody.length - 1)), - functiontType: classBody.indexOf('static') > 0 ? 'static' : '' - }) - data = data.substring(matchs.regs[5][0] + classBody.length + 2, data.length) - if (matchs.regs[1][0] != -1) { - result.exports.push(className) - } + // class类型也解析成interface结构,该结构在后面生成C++代码时会按napi_define_class处理成C++的class + return createInterfaceData(matchs, data, result) } return data } @@ -190,7 +183,8 @@ function parseFunction(matchs, data, result) { else { funcRet = "void" } - let funcDetail = analyzeFunction(result, funcName, funcValue.substring(1, funcValue.length - 1), funcRet) + let funcDetail = analyzeFunction( + result, false, funcName, funcValue.substring(1, funcValue.length - 1), funcRet) if (funcDetail != null) result.function.push(funcDetail) if (matchs.regs[1][0] != -1) { @@ -200,19 +194,87 @@ function parseFunction(matchs, data, result) { return data } +/** + * 提取当前类继承或实现的父类名称列表 + * @param firstKey 继承/实现关键字 (extends或implements) + * @param secondKey 继承/实现关键字 (extends或implements) + * @param parentStr 正则匹配到的继承语句 (如 extends xx1, xx2 implements yy1, yy2) + * @returns 继承的名称列表 ([xx1, xx2, yy1, yy2]) + */ +function getParentNameList(firstKey, secondKey, parentStr) { + if (parentStr == '') { + return [] + } + + let firstParents = '' + let secondParents = '' + if (parentStr.indexOf(secondKey) > 0) { + // 同时出现extends和implements关键字的情况 (如 extends xx1, xx2 implements yy1, yy2) + firstParents = parentStr.split(secondKey)[0].split(firstKey)[1] + secondParents = parentStr.split(secondKey)[1].trim() + } else { + // 只有extends或implements一种关键字的情况 (如 extends xx1, xx2 或者 implements yy1, yy2) + firstParents = parentStr.split(firstKey)[1] + } + + let nameList = firstParents.split(",") + if (secondParents != '') { + let secondList = secondParents.split(",") + nameList.push(...secondList) + } + + return nameList +} + +/** + * 创建interface数据结构 + * @param matchs 正则匹配对象 + * @param data 原始ts文件内容 + * @param result 解析后的ts数据结构 + * @returns data 原始ts文件内容中剩余未解析的部分 + */ +function createInterfaceData (matchs, data, result) { + let interfaceName = re.getReg(data, matchs.regs[2]) + let interfaceBody = checkOutBody(data, matchs.regs[6][0], null, null) + let bodyObj = analyzeInterface(interfaceBody.substring(1, interfaceBody.length - 1)) + let extendsParent = re.getReg(data, matchs.regs[4]) + let implementParent = re.getReg(data, matchs.regs[5]) + bodyObj.parentNameList = [] + if(extendsParent != '') { + bodyObj.parentNameList = getParentNameList("extends", "implements", extendsParent) + } + if(implementParent != '') { + bodyObj.parentNameList = getParentNameList("implements", "extends", implementParent) + } + for (let i in bodyObj.parentNameList) { + bodyObj.parentNameList[i] = bodyObj.parentNameList[i].trim() + if (bodyObj.parentNameList[i] == interfaceName) { + // 接口不能自己继承自己 + NapiLog.logError("The interface [%s] can not extends with itself.".format(interfaceName)) + return data + } + } + + bodyObj.parentList = [] //该接口继承的父类型列表 + bodyObj.childList = [] //继承自该接口的子类型列表 + + result.interface.push({ + name: interfaceName, + body: bodyObj + }) + data = data.substring(matchs.regs[6][0] + interfaceBody.length, data.length) + if (matchs.regs[1][0] != -1) { + result.exports.push(interfaceName) + } + return data +} + function parseInterface(matchs, data, result) { - matchs = re.match("(export )*interface ([A-Za-z_0-9]+)()* (extends [a-zA-Z]+ )*({)", data) + matchs = re.match( + "(export )*interface ([A-Za-z_0-9]+)()* *(extends [a-zA-Z_0-9, ]+)* *(implements [a-zA-Z_0-9, ]+)* *({)" + , data) if (matchs) { - let interfaceName = re.getReg(data, matchs.regs[2]) - let interfaceBody = checkOutBody(data, matchs.regs[5][0], null, null) - result.interface.push({ - name: interfaceName, - body: analyzeInterface(interfaceBody.substring(1, interfaceBody.length - 1)) - }) - data = data.substring(matchs.regs[5][0] + interfaceBody.length, data.length) - if (matchs.regs[1][0] != -1) { - result.exports.push(interfaceName) - } + return createInterfaceData (matchs, data, result) } return data } diff --git a/src/gen/generate/class.js b/src/gen/generate/class.js index 56e000d8..38de99ae 100644 --- a/src/gen/generate/class.js +++ b/src/gen/generate/class.js @@ -24,22 +24,22 @@ const { NapiLog } = require("../tools/NapiLog"); let middleBodyTmplete = ` class [className]_middle { public: -static napi_value constructor(napi_env env, napi_callback_info info) -{ - XNapiTool *pxt = new XNapiTool(env, info); + static napi_value constructor(napi_env env, napi_callback_info info) + { + XNapiTool *pxt = new XNapiTool(env, info); - [className] *p = new [className](); + [className] *p = new [className](); - napi_value thisvar = pxt->WrapInstance(p, release); + napi_value thisvar = pxt->WrapInstance(p, release); - return thisvar; -} -static void release(void *p) -{ - [className] *p2 = ([className] *)p; - delete p2; -} -[static_funcs] + return thisvar; + } + static void release(void *p) + { + [className] *p2 = ([className] *)p; + delete p2; + } + [static_funcs] };` function generateVariable(name, type, variable, className) { diff --git a/src/gen/generate/function_async.js b/src/gen/generate/function_async.js index 4e9718fc..d325f0bc 100644 --- a/src/gen/generate/function_async.js +++ b/src/gen/generate/function_async.js @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -const { replaceAll } = require("../tools/tool"); +const { replaceAll, getPrefix } = require("../tools/tool"); const { paramGenerate } = require("./param_generate"); const { returnGenerate } = require("./return_generate"); @@ -78,6 +78,13 @@ struct [funcName]_value_struct {[valueIn] return result; }` +let cppTemplate = ` +bool %s%s(%s) +{ + return true; +} +` + function getOptionalCallbackInit(param) { if (!param.callback.optional) { return "" @@ -86,8 +93,7 @@ function getOptionalCallbackInit(param) { return "vio->out = new %s;".format(cType) } -function generateFunctionAsync(func, data, className) { - let middleFunc = replaceAll(funcAsyncTemplete, "[funcName]", func.name) +function replaceBasicInfo(middleFunc, className) { if (className == null) { middleFunc = middleFunc.replaceAll("[static_define]", "") middleFunc = middleFunc.replaceAll("[unwarp_instance]", "") @@ -100,6 +106,12 @@ function generateFunctionAsync(func, data, className) { middleFunc = middleFunc.replaceAll("[checkout_async_instance]", "%s *pInstance = (%s *)pxt->GetAsyncInstance();".format(className, className)) } + return middleFunc +} +function generateFunctionAsync(func, data, className) { + let middleFunc = replaceAll(funcAsyncTemplete, "[funcName]", func.name) + middleFunc = replaceBasicInfo(middleFunc, className) + let param = { valueIn: "",//定义输入 valueOut: "",//定义输出 @@ -113,36 +125,31 @@ function generateFunctionAsync(func, data, className) { for (let i in func.value) { paramGenerate(i, func.value[i], param, data) } - returnGenerate(param.callback, param, data) middleFunc = replaceAll(middleFunc, "[valueIn]", param.valueIn)// # 输入参数定义 middleFunc = replaceAll(middleFunc, "[valueOut]", param.valueOut)// # 输出参数定义 - middleFunc = replaceAll(middleFunc, "[valueCheckout]", param.valueCheckout)// # 输入参数解析 - let optionalCallback = getOptionalCallbackInit(param) middleFunc = replaceAll(middleFunc, "[optionalCallbackInit]", optionalCallback)//可选callback参数初始化 - middleFunc = replaceAll(middleFunc, "[start_async]", ` napi_value result = \ pxt->StartAsync(%s_execute, vio, %s_complete, pxt->GetArgc() == %s ? pxt->GetArgv(%d) : nullptr);`.format(func.name, func.name, parseInt(param.callback.offset) + 1, param.callback.offset))// 注册异步调用 - let callFunc = "%s%s(%s);".format(className == null ? "" : "pInstance->", func.name, param.valueFill) middleFunc = replaceAll(middleFunc, "[callFunc]", callFunc)//执行 - middleFunc = replaceAll(middleFunc, "[valuePackage]", param.valuePackage)//输出参数打包 middleFunc = replaceAll(middleFunc, "[optionalParamDestory]", param.optionalParamDestory)//可选参数内存释放 - let implH = "\nbool %s(%s);".format(func.name, param.valueDefine) - let implCpp = ` -bool %s%s(%s) -{ - return true; -} -`.format(className == null ? "" : className + "::", func.name, param.valueDefine) - + let prefixArr = getPrefix(data, func.isStatic) + let implH = "" + let implCpp = "" + if (!func.isParentMember) { + // 只有类/接口自己的成员方法需要在.h.cpp中生成,父类/父接口不需要 + implH = "\n%s%s%sbool %s(%s);".format( + prefixArr[0], prefixArr[1], prefixArr[2], func.name, param.valueDefine) + implCpp = cppTemplate.format(className == null ? "" : className + "::", func.name, param.valueDefine) + } return [middleFunc, implH, implCpp] } diff --git a/src/gen/generate/function_direct.js b/src/gen/generate/function_direct.js index f98c3330..ab17ffe4 100644 --- a/src/gen/generate/function_direct.js +++ b/src/gen/generate/function_direct.js @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -const { replaceAll } = require("../tools/tool"); +const { replaceAll, getPrefix } = require("../tools/tool"); const { paramGenerate } = require("./param_generate"); const { returnGenerate } = require("./return_generate"); @@ -55,6 +55,13 @@ struct [funcName]_value_struct {[valueIn] return result; }` +let cppTemplate = ` +bool %s%s(%s) +{ + return true; +} +` + function generateFunctionDirect(func, data, className) { let middleFunc = replaceAll(funcDirectTemplete, "[funcName]", func.name) if (className == null) { @@ -79,33 +86,28 @@ function generateFunctionDirect(func, data, className) { for (let i in func.value) { paramGenerate(i, func.value[i], param, data) } - let returnInfo = {type: func.ret, optional: false} if (func.ret == 'void') { param.valuePackage = "result = pxt->UndefinedValue();"; } else { returnGenerate(returnInfo, param, data) } - middleFunc = replaceAll(middleFunc, "[valueIn]", param.valueIn)// # 输入参数定义 middleFunc = replaceAll(middleFunc, "[valueOut]", param.valueOut)// # 输出参数定义 - middleFunc = replaceAll(middleFunc, "[valueCheckout]", param.valueCheckout)// # 输入参数解析 - let callFunc = "%s%s(%s);".format(className == null ? "" : "pInstance->", func.name, param.valueFill) middleFunc = replaceAll(middleFunc, "[callFunc]", callFunc)//执行 - middleFunc = replaceAll(middleFunc, "[valuePackage]", param.valuePackage)//输出参数打包 middleFunc = replaceAll(middleFunc, "[optionalParamDestory]", param.optionalParamDestory)//可选参数内存释放 - - let implH = "\nbool %s(%s);".format(func.name, param.valueDefine) - let implCpp = ` -bool %s%s(%s) -{ - return true; -} -`.format(className == null ? "" : className + "::", func.name, param.valueDefine) - + let prefixArr = getPrefix(data, func.isStatic) + let implH = "" + let implCpp = "" + if (!func.isParentMember) { + // 只有类/接口自己的成员方法需要在.h.cpp中生成,父类/父接口不需要 + implH = "\n%s%s%sbool %s(%s);".format( + prefixArr[0], prefixArr[1], prefixArr[2], func.name, param.valueDefine) + implCpp = cppTemplate.format(className == null ? "" : className + "::", func.name, param.valueDefine) + } return [middleFunc, implH, implCpp] } diff --git a/src/gen/generate/function_sync.js b/src/gen/generate/function_sync.js index 10fc8c99..7761ec03 100644 --- a/src/gen/generate/function_sync.js +++ b/src/gen/generate/function_sync.js @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -const { replaceAll } = require("../tools/tool"); +const { replaceAll, getPrefix } = require("../tools/tool"); const { paramGenerate } = require("./param_generate"); const { returnGenerate } = require("./return_generate"); @@ -62,6 +62,13 @@ struct [funcName]_value_struct {[valueIn] return result; }` +let cppTemplate = ` +bool %s%s(%s) +{ + return true; +} +` + function getOptionalCallbackInit(param) { if (!param.callback.optional) { return "" @@ -94,33 +101,28 @@ function generateFunctionSync(func, data, className) { for (let i in func.value) { paramGenerate(i, func.value[i], param, data) } - returnGenerate(param.callback, param) middleFunc = replaceAll(middleFunc, "[valueIn]", param.valueIn)// # 输入参数定义 middleFunc = replaceAll(middleFunc, "[valueOut]", param.valueOut)// # 输出参数定义 - middleFunc = replaceAll(middleFunc, "[valueCheckout]", param.valueCheckout)// # 输入参数解析 - let callFunc = "%s%s(%s);".format(className == null ? "" : "pInstance->", func.name, param.valueFill) middleFunc = replaceAll(middleFunc, "[callFunc]", callFunc)//执行 - let optionalCallback = getOptionalCallbackInit(param) middleFunc = replaceAll(middleFunc, "[optionalCallbackInit]", optionalCallback)//可选callback参数初始化 - middleFunc = replaceAll(middleFunc, "[valuePackage]", param.valuePackage)//输出参数打包 middleFunc = replaceAll(middleFunc, "[optionalParamDestory]", param.optionalParamDestory)//可选参数内存释放 - middleFunc = middleFunc.replaceAll("[callback_param_offset]", param.callback.offset);//呼叫回调 - let implH = "\nbool %s(%s);".format(func.name, param.valueDefine) - let implCpp = ` -bool %s%s(%s) -{ - return true; -} -`.format(className == null ? "" : className + "::", func.name, param.valueDefine) - + let prefixArr = getPrefix(data, func.isStatic) + let implH = "" + let implCpp = "" + if (!func.isParentMember) { + // 只有类/接口自己的成员方法需要在.h.cpp中生成,父类/父接口不需要 + implH = "\n%s%s%sbool %s(%s);".format( + prefixArr[0], prefixArr[1], prefixArr[2], func.name, param.valueDefine) + implCpp = cppTemplate.format(className == null ? "" : className + "::", func.name, param.valueDefine) + } return [middleFunc, implH, implCpp] } diff --git a/src/gen/generate/interface.js b/src/gen/generate/interface.js index 3f7c2e43..ea3a205c 100644 --- a/src/gen/generate/interface.js +++ b/src/gen/generate/interface.js @@ -20,30 +20,30 @@ const { jsToC } = require("./param_generate"); const { cToJs } = require("./return_generate"); const re = require("../tools/re"); const { NapiLog } = require("../tools/NapiLog"); -const { print } = require("../tools/tool"); +const { addUniqFunc2List, addUniqObj2List } = require("../tools/tool"); let middleBodyTmplete = ` class [className]_middle { public: -static napi_value constructor(napi_env env, napi_callback_info info) -{ - XNapiTool *pxt = new XNapiTool(env, info); + static napi_value constructor(napi_env env, napi_callback_info info) + { + XNapiTool *pxt = new XNapiTool(env, info); - [className] *p = new [className](); + [className] *p = new [className](); - napi_value thisvar = pxt->WrapInstance(p, release); + napi_value thisvar = pxt->WrapInstance(p, release); - return thisvar; -} -static void release(void *p) -{ - [className] *p2 = ([className] *)p; - delete p2; -} -[static_funcs] + return thisvar; + } + static void release(void *p) + { + [className] *p2 = ([className] *)p; + delete p2; + } + [static_funcs] };` -function generateVariable(name, type, variable, className) { +function getHDefineOfVariable(name, type, variable) { if (type == "string") variable.hDefine += "\n std::string %s;".format(name) else if (type.substring(0, 12) == "NUMBER_TYPE_") variable.hDefine += "\n %s %s;".format(type, name) else if (InterfaceList.getValue(type)) variable.hDefine += "\n %s %s;".format(type, name) @@ -65,6 +65,16 @@ function generateVariable(name, type, variable, className) { ---- generateVariable fail %s,%s ---- `.format(name, type)); } +} + +function generateVariable(value, variable, className) { + let name = value.name + let type = value.type + if (!value.isParentMember) { + // 只有类/接口自己的成员属性需要在.h中定义, 父类/父接口不需要 + getHDefineOfVariable(name, type, variable) + } + variable.middleValue += ` static napi_value getvalue_%s(napi_env env, napi_callback_info info) { @@ -129,11 +139,13 @@ function generateInterface(name, data, inNamespace) { } middleInit += `\n pxt->DefineClass("%s", %s%s_middle::constructor, valueList ,funcList%s);\n}\n` .format(name, inNamespace, name, selfNs) + let extendsStr = (data.parentNameList && data.parentNameList.length > 0) ? + " : public %s".format(data.parentNameList.join(", public ")) : "" let result = { implH: ` -class %s { +class %s%s { public:%s -};`.format(name, implH), +};\n`.format(name, extendsStr, implH), implCpp: implCpp, middleBody: middleBodyTmplete.replaceAll("[className]", name).replaceAll("[static_funcs]", middleFunc), middleInit: middleInit @@ -141,6 +153,21 @@ public:%s return result } +// 递归获取接口及接口父类的所有成员属性和方法 +function getAllPropties(interfaceBody, properties, isParentClass) { + for (let i in interfaceBody.value) { + interfaceBody.value[i].isParentMember = isParentClass + addUniqObj2List(interfaceBody.value[i], properties.values) + } + for (let i in interfaceBody.function) { + interfaceBody.function[i].isParentMember = isParentClass + addUniqFunc2List(interfaceBody.function[i], properties.functions) + } + if (!isParentClass && interfaceBody.parentNameList.length > 0) { + getAllPropties(interfaceBody.parentBody, properties, true) + } +} + function connectResult(data, inNamespace, name) { let implH = "" let implCpp = "" @@ -151,9 +178,11 @@ function connectResult(data, inNamespace, name) { middleValue: "", } middleInit = `{\n std::map> valueList;` - for (let i in data.value) { - let v = data.value[i] - generateVariable(v.name, v.type, variable, name) + data.allProperties = {values:[], functions:[]} + getAllPropties(data, data.allProperties, false) + for (let i in data.allProperties.values) { + let v = data.allProperties.values[i] + generateVariable(v, variable, name) middleInit += ` valueList["%s"]["getvalue"]=%s%s_middle::getvalue_%s; valueList["%s"]["setvalue"]=%s%s_middle::setvalue_%s;` @@ -162,8 +191,8 @@ function connectResult(data, inNamespace, name) { implH += variable.hDefine middleFunc += variable.middleValue middleInit += `\n std::map funcList;` - for (let i in data.function) { - let func = data.function[i] + for (let i in data.allProperties.functions) { + let func = data.allProperties.functions[i] let tmp; switch (func.type) { case FuncType.DIRECT: @@ -184,6 +213,10 @@ function connectResult(data, inNamespace, name) { implCpp += tmp[2] middleInit += `\n funcList["%s"] = %s%s_middle::%s_middle;`.format(func.name, inNamespace, name, func.name) } + if (data.childList.length > 0) { + // 如果是父类,增加虚析构函数使其具备泛型特征 (基类必须有虚函数才能正确使用dynamic_cast和typeinfo等方法) + implH += "\n virtual ~%s(){};".format(name) + } return [middleFunc, implH, implCpp, middleInit] } diff --git a/src/gen/generate/namespace.js b/src/gen/generate/namespace.js index 8aaf9eaf..834e31b5 100644 --- a/src/gen/generate/namespace.js +++ b/src/gen/generate/namespace.js @@ -20,6 +20,79 @@ const { generateClass } = require("./class"); const { FuncType, InterfaceList, EnumList } = require("../tools/common"); const { generateEnum } = require("./enum"); const { generateFunctionOnOff } = require("./function_onoff"); +const { NapiLog } = require("../tools/NapiLog"); +const { addUniqFunc2List, addUniqObj2List } = require("../tools/tool"); + +function findParentByName(parentName, data) { + for (let i in data.interface) { + if (parentName == data.interface[i].name) { + return data.interface[i] + } + } + + for (let i in data.class) { + if (parentName == data.class[i].name) { + return data.class[i] + } + } + return null +} + +/** + * 生成父类的成员变量和方法 + * @param currentObj 当前类 + * @param data 全局数据上下文 + * @param parentBody 输出参数,保存父类的成员变量和方法 + * @returns void + */ +function genParentPropties(currentObj, data, parentBody) { + for (let i in currentObj.body.parentNameList) { + let parentName = currentObj.body.parentNameList[i] + let parentObj = findParentByName(parentName, data) + if (!parentObj) { + NapiLog.logError("Failed to find %s's parent by name [%s]".format(currentObj.body.name, parentName)) + return + } + + // 为父类添加子类的对象信息 + addUniqObj2List(currentObj, parentObj.body.childList) + + // 为当前类添加父类对象信息 + addUniqObj2List(parentObj, currentObj.body.parentList) + + for (let i in parentObj.body.value) { + // 添加父类的所有成员属性到parentBody + addUniqObj2List(parentObj.body.value[i], parentBody.value) + } + for (let i in parentObj.body.function) { + // 添加父类的所有成员方法到parentBody + addUniqFunc2List(parentObj.body.function[i], parentBody.function) + } + if (parentObj.body.parentNameList.length > 0) { + // 递归查找父类的父类 + genParentPropties(parentObj, data, parentBody) + } + } +} + +// 为有继承关系的interface和class类型建立父子类关系信息 +function genExtendsRelation(data) { + for (let i in data.interface) { + let ifObj = data.interface[i] + if (ifObj.body.parentNameList.length > 0) { + ifObj.body.parentBody = {value:[], function:[]} + genParentPropties(ifObj, data, ifObj.body.parentBody) + } + } + + for (let i in data.class) { + let classObj = data.class[i] + if (classObj.body.parentName) { + classObj.body.parentBody = {value:[], function:[]} + genParentPropties(classObj, data, classObj.body.parentBody) + } + } +} //生成module_middle.cpp、module.h、module.cpp function generateNamespace(name, data, inNamespace = "") { @@ -31,6 +104,7 @@ function generateNamespace(name, data, inNamespace = "") { } namespaceResult.middleInit += formatMiddleInit(inNamespace, name) + genExtendsRelation(data) InterfaceList.push(data.interface) EnumList.push(data.enum) let result = generateEnumResult(data); diff --git a/src/gen/generate/return_generate.js b/src/gen/generate/return_generate.js index 9548a2e0..116073d9 100644 --- a/src/gen/generate/return_generate.js +++ b/src/gen/generate/return_generate.js @@ -352,7 +352,7 @@ function returnGenerate(returnInfo, param, data) { returnGenerate2(returnInfo, param, data) } else { - NapiLog.logError("function returnGenerate:The current version do not support this type return %s".format(type)); + NapiLog.logError("Do not support returning the type [%s].".format(type)); } } diff --git a/src/gen/tools/common.js b/src/gen/tools/common.js index 5a160741..8d9b0f0b 100644 --- a/src/gen/tools/common.js +++ b/src/gen/tools/common.js @@ -74,7 +74,7 @@ InterfaceList.getValue = function (name) { let ifs = InterfaceList.interfacess_[InterfaceList.interfacess_.length - 1] for (let i in ifs) { if (ifs[i].name == name) { - return ifs[i].body.value; + return ifs[i].body.allProperties.values; } } return null; diff --git a/src/gen/tools/tool.js b/src/gen/tools/tool.js index 48fe2854..596b1793 100644 --- a/src/gen/tools/tool.js +++ b/src/gen/tools/tool.js @@ -170,6 +170,82 @@ function replaceAll(s, sfrom, sto) { return s; } +/** + * 比较两个方法是否完全相同 + * @param func1 方法1 + * @param func2 方法2 + * @returns 方法名称与形参是否完全相同 + */ + function isSameFunc(func1, func2) { + if (func1.name != func2.name) { // 判断方法名称是否相同 + return false; + } + + let func1ParamCount = func1.value.length + if (func1ParamCount != func2.value.length) { // 判断方法形参个数是否一样 + return false; + } + + for (let i in func1.value) { // 判断方法每个形参数据类型是否相同 + if (func1.value[i].type != func2.value[i].type) { + if (!(func1.value[i].type.indexOf("NUMBER_TYPE_") >= 0 && + func2.value[i].type.indexOf("NUMBER_TYPE_") >= 0)) { + return false; + } + } + } + + // 以上全部相同,判定为相同方法 + return true; +} + +/** + * 将方法对象插入列表(重复的方法对象不插入) + * @param obj 待插入的方法对象 + * @param list 目标列表 + * @returns void + */ + function addUniqFunc2List(obj, list) { + for (let i in list) { + if (isSameFunc(obj, list[i])) { + return + } + } + list.push(obj) +} + +/** + * 将对象插入列表(名称重复的属性对象不插入) + * @param obj 待插入的对象 + * @param list 目标列表 + * @returns void + */ + function addUniqObj2List(obj, list) { + for (let i in list) { + if (list[i].name === obj.name) { + return + } + } + list.push(obj) +} + +/** + * 如果方法所在的类为基类,生成的c++函数定义为虚函数 + * @param data 方法所在的类信息 + * @param isStatic ts方法是否定义为静态方法 + * return tabStr 缩进,staticStr 静态函数关键词,virtualStr 虚函数关键词 + */ + function getPrefix(data, isStatic) { + let tabStr = "" + let virtualStr = "" + let staticStr = isStatic ? "static " : "" + if (data.childList) { + tabStr = " " // 类中的方法增加一个缩进 + virtualStr = (data.childList.length > 0 && !isStatic) ? "virtual " : "" //如果是基类中的非静态方法,定义为虚函数 + } + return [tabStr, staticStr, virtualStr] +} + module.exports = { checkOutBody, removeExplains, @@ -178,5 +254,8 @@ module.exports = { replaceAll, print, getLicense, - replaceTab + replaceTab, + addUniqObj2List, + addUniqFunc2List, + getPrefix } diff --git a/test/storytest/test_extends/@ohos.test.d.ts b/test/storytest/test_extends/@ohos.test.d.ts new file mode 100644 index 00000000..b663dda9 --- /dev/null +++ b/test/storytest/test_extends/@ohos.test.d.ts @@ -0,0 +1,87 @@ +/* +* Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +import { AsyncCallback, Callback } from './../basic'; + +declare namespace napitest { + interface Human { + name: string; + age: number; + } + + interface GrandFar extends Human{ + eyesType: number; + getSkin(v: number): string; + getSkinSync(v: number, skin: Callback): void; + getSkinAsync(v: number, skin: AsyncCallback): void; + } + + interface Farther extends GrandFar { + getShoes(): string; + getShoesSync(shoes: Callback): void; + getShoesAsync(shoes: AsyncCallback): void; + } + + class Animal { + aniName: string; + size: number; + static getAnimalType(aniId: number): string; + setAnimalId(id: number): void; + } + + class Cat extends Animal { + catName:string; + static getCatType(catId: number): string; + } + + interface SuperAnimal { + aniName: string; + size: number; + setAnimalId(id: number): void; + } + + class SuperHuman { + name: string; + age: number; + static getAnimalType(aniId: number): string; + } + + interface Bob extends Human, Animal { + bobSkill: string; + getBobCardId(): number; + } + + class Juliya extends SuperHuman implements SuperAnimal { + aniName: string; + size: number; + setAnimalId(id: number): void; + juliyaSkill: string; + getJuliyaCardId(): number; + } + + function findJuliya(v1: Juliya): Juliya; + function findJuliyaSync(v1: string, callback: Callback): void; + function findJuliyaAsync(v1: string, callback: AsyncCallback): void; + + interface Tom { + name: string; + friends: Cat; + } + + interface TestMember { + getTomcat(v1: string, v2: Array): Tom; + } +} + +export default napitest; diff --git a/test/storytest/test_extends/test.js b/test/storytest/test_extends/test.js new file mode 100644 index 00000000..f57779d1 --- /dev/null +++ b/test/storytest/test_extends/test.js @@ -0,0 +1,157 @@ +/* +* Copyright (c) 2022 Shenzhen Kaihong Digital Industry Development Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +const { Farther, Cat, Bob, Juliya, Tom, TestMember } = require("./out/build/Release/napitest") +const test = require("./out/build/Release/napitest") +var assert = require("assert"); +const { consumers } = require("stream"); + +describe('Basic extends', function () { + function getSkinCallback (skin) { + assert.strictEqual(skin, ''); + } + function getSkinAsyncCallback (err, skin) { + assert.strictEqual(err.code, 0); + assert.strictEqual(skin, ''); + } + function getShoesCallback (shoes) { + assert.strictEqual(shoes, ''); + } + function getShoesAsyncCallback (err, shoes) { + assert.strictEqual(err.code, 0); + assert.strictEqual(shoes, ''); + } + it('test interface extends', function () { + let farther = new Farther(); + assert.strictEqual(farther.name, ''); + assert.strictEqual(farther.age, 0); + assert.strictEqual(farther.getSkin(1), ''); + farther.getSkinSync(1, getSkinCallback); + farther.getSkinAsync(1, getSkinAsyncCallback); + assert.strictEqual(farther.getShoes(), ''); + farther.getShoesSync(getShoesCallback); + farther.getShoesAsync(getShoesAsyncCallback); + }); + + it('test class extends', function () { + let cat = new Cat(); + assert.strictEqual(cat.aniName, ''); + assert.strictEqual(cat.size, 0); + assert.strictEqual(cat.catName, ''); + assert.strictEqual(cat.getAnimalType(1), ''); + assert.strictEqual(cat.setAnimalId(1), undefined); + assert.strictEqual(cat.getCatType(1), ''); + }); +}); + +describe('Multi extends', function () { + it('test interface extends', function () { + let bob = new Bob(); + assert.strictEqual(bob.name, ''); + assert.strictEqual(bob.aniName, ''); + assert.strictEqual(bob.bobSkill, ''); + assert.strictEqual(bob.getAnimalType(1), ''); + assert.strictEqual(bob.getBobCardId(), 0); + }); + + it('test extends and implements', function () { + let juliya = new Juliya(); + assert.strictEqual(juliya.name, ''); + assert.strictEqual(juliya.aniName, ''); + assert.strictEqual(juliya.juliyaSkill, ''); + assert.strictEqual(juliya.getAnimalType(1), ''); + assert.strictEqual(juliya.getJuliyaCardId(), 0); + }); +}); + +describe('Function test', function () { + it('test parameter and return', function () { + let juliya = new Juliya(); + let ret = test.findJuliya(juliya); + // parent properties + assert.strictEqual(ret.name, ''); + assert.strictEqual(ret.age, 0); + // own properties + assert.strictEqual(ret.aniName, ''); + assert.strictEqual(ret.size, 0); + assert.strictEqual(ret.juliyaSkill, ''); + }); + + it('test sync callback', function () { + function getSyncCallback (juliya) { + // parent properties + assert.strictEqual(juliya.name, ''); + assert.strictEqual(juliya.age, 0); + // own properties + assert.strictEqual(juliya.aniName, ''); + assert.strictEqual(juliya.size, 0); + assert.strictEqual(juliya.juliyaSkill, ''); + } + + test.findJuliyaSync("juli", getSyncCallback); + }); + + it('test async callback', function () { + function getAsyncCallback (err, juliya) { + assert.strictEqual(err.code, 0); + // parent properties + assert.strictEqual(juliya.name, ''); + assert.strictEqual(juliya.age, 0); + // own properties + assert.strictEqual(juliya.aniName, ''); + assert.strictEqual(juliya.size, 0); + assert.strictEqual(juliya.juliyaSkill, ''); + } + + test.findJuliyaAsync("juli", getAsyncCallback); + }); +}); + +describe('Interface member test', function () { + it('test member', function () { + + let tomObj1 = { + name: 'tom1', + friends: { // Cat object + catName: 'tomcat1', + // parent properties + aniName: 'ani1', + size: 101 + + } + }; + let tomObj2 = { + name: 'tom2', + friends: { // Cat object + catName: 'tomcat1', + // parent properties + aniName: 'ani2', + size: 102 + + } + }; + let tomArray = [tomObj1, tomObj2]; + let test = new TestMember(); + let retTom = test.getTomcat('my tom', tomArray); + assert.strictEqual(retTom.name, ''); + // class member + assert.strictEqual(retTom.friends.catName, ''); + assert.strictEqual(retTom.friends.aniName, ''); + assert.strictEqual(retTom.friends.size, 0); + }); +}); + + + + diff --git a/test/unittest/analyze.test.js b/test/unittest/analyze.test.js index b714ab2f..9f2072a8 100755 --- a/test/unittest/analyze.test.js +++ b/test/unittest/analyze.test.js @@ -120,28 +120,28 @@ function partOfFunction(correctResult){ it('test gen/analyze/function analyzeDirectFunction', function () { let data = "if_direct(v1: string, v2: boolean): string;"; - let ret = analyzeFunction(data, `if_direct`, "v1: string, v2: boolean", "asdfgh"); + let ret = analyzeFunction(data, false, `if_direct`, "v1: string, v2: boolean", "asdfgh"); let retJson = JSON.stringify(ret) assert.strictEqual(retJson, correctResult['Analyze']['analyzeDirectFunction']); }); it('test gen/analyze/function analyzeAsyncFunction', function () { let data = "if_async(v1: string, cb: AsyncCallback): string;"; - let ret = analyzeFunction(data, `if_async`, "v1: string, cb: AsyncCallback", "qwerty"); + let ret = analyzeFunction(data, false, `if_async`, "v1: string, cb: AsyncCallback", "qwerty"); let retJson = JSON.stringify(ret) assert.strictEqual(retJson, correctResult['Analyze']['analyzeAsyncFunction']); }); it('test gen/analyze/function analyzeSyncFunction', function () { let data = "if_callback(v1: string, cb: Callback>): string;"; - let ret = analyzeFunction(data, `if_callback`, "v1: string, cb: Callback>", "zxcvbn"); + let ret = analyzeFunction(data, false, `if_callback`, "v1: string, cb: Callback>", "zxcvbn"); let retJson = JSON.stringify(ret) assert.strictEqual(retJson, correctResult['Analyze']['analyzeSyncFunction']); }); it('test gen/analyze/function analyzePromiseFunction', function () { let data = "if_promise(v1: Array): Promise;"; - let ret = analyzeFunction(data, `if_promise`, "v1: Array", "Promise"); + let ret = analyzeFunction(data, false, `if_promise`, "v1: Array", "Promise"); assert.strictEqual(ret, null); }); } -- Gitee