refactory h2dts

Signed-off-by: wangshi <wangshi@kaihong.com>
This commit is contained in:
wangshi 2024-10-29 17:03:51 +08:00
parent e18849d2dd
commit 90297f68c5
6 changed files with 877 additions and 242 deletions

View File

@ -59,6 +59,7 @@ export interface ClassObj {
}
export interface FuncObj {
type: string;
name: string;
returns: string;
parameters: ParamObj[];
@ -90,6 +91,13 @@ export interface FuncTransferMap {
tranferContent: string[];
}
// h2dts
export interface GenInfo {
parseObj: ParseObj;
rawFilePath: string;
fileName: string;
}
// h2dtscpp
export interface DtscppRootInfo {
funcs: FuncObj[];

View File

@ -19,7 +19,7 @@ import * as vscode from 'vscode';
import * as path from 'path';
import * as ts from 'typescript';
import { parseHeaderFile } from './parsec';
import { DtscppRootInfo } from './datatype';
import { DtscppRootInfo, GenInfo } from './datatype';
import { parseTsFile } from './parsets';
import { genServiceFile } from './gensa';
import { genDtsFile } from './gendts';
@ -129,22 +129,21 @@ export function activate(context: vscode.ExtensionContext) {
// The code you place here will be executed every time your command is executed
if (uri && uri.fsPath) {
// parse
let funDescList = await parseHeaderFile(uri.fsPath);
console.log('parse header file res: ', funDescList);
console.log('parse header file jsonstr: ', JSON.stringify(funDescList));
let fileName = path.basename(uri.fsPath, '.h');
let rootInfo: DtscppRootInfo = {
funcs: funDescList.funcs,
let parseRes = await parseHeaderFile(uri.fsPath);
console.log('parse header file res: ', parseRes);
let rootInfo: GenInfo = {
parseObj: parseRes,
rawFilePath: uri.fsPath, // e://xxx.h
fileName: fileName // xxx
fileName: path.basename(uri.fsPath, '.h') // xxx
};
// generator
let out = path.dirname(uri.fsPath);
genDtsFile(rootInfo, out);
let outPath = genDtsFile(rootInfo);
vscode.window.showInformationMessage(`h2dts: gen dts to ${outPath}`);
} else {
// Display a message box to the user
vscode.window.showErrorMessage(`h2dts: error uri ${JSON.stringify(uri)}!`);
}
// Display a message box to the user
vscode.window.showInformationMessage('h2dts!');
});
context.subscriptions.push(h2dts);

View File

@ -0,0 +1,418 @@
/*
* Copyright (c) 2024 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 re = require('./common/re');
import fs = require('fs');
import util = require('util');
import { DtscppRootInfo, FuncInfo, FuncObj, InterfaceBody, InterfaceList, ParamObj, TypeList } from './datatype';
import { dtsFuncTemplate } from './template/func_template';
import { generateRandomInteger, removeComments, removeTab, replaceAll } from './common/tool';
import path = require('path');
const MIN_RANDOM = 100;
const MAX_RANDOM = 999
export function isStringType(cType: string) {
switch (cType) {
case 'string':
case 'std::string':
case 'char':
case 'wchar_t':
case 'char16_t':
case 'char32_t':
return true;
default:
return false;
}
}
export function isBoolType(cType: string) {
if (cType === 'bool') {
return true;
}
return false;
}
export function isNumberType(cType: string) {
switch (cType) {
case 'short':
case 'int':
case 'uint32_t':
case 'size_t':
case 'long':
case 'long long':
case 'float':
case 'double':
case 'long double':
case 'int16_t':
case 'uint16_t':
case 'int32_t':
case 'int64_t':
case 'uint64_t':
case 'double_t':
case 'float_t':
return true;
default:
return false;
}
}
function basicC2js(cType: string) {
let jsType = '';
if (isStringType(cType)) {
jsType = 'string';
} else if (isBoolType(cType)) {
jsType = 'boolean';
} else if (isNumberType(cType)) {
jsType = 'number';
} else {
jsType = cType;
}
return jsType;
}
export function getJsTypeFromC(cType: string) {
let basicCtype = cType;
let matchs = re.match('(std::)?vector<([\x21-\x7e ]+)>', basicCtype);
let isArray = 0;
if (matchs) {
basicCtype = re.getReg(basicCtype, matchs.regs[2]).trim();
isArray = 1;
}
let unsignedIdx = basicCtype.indexOf('unsigned');
if (unsignedIdx >= 0) {
// cut off the keywords 'unsigned'
basicCtype = basicCtype.substring(unsignedIdx + 8, basicCtype.length).trim();
}
let jsType = basicC2js(basicCtype);
if (isArray) {
jsType = util.format('Array<%s>', jsType);
}
// 去掉const
jsType = replaceAll(jsType, 'const', '');
// struct cJson * 的情况
let matchStruct = re.match('(struct)?[A-Z_a-z0-9 *]+', basicCtype);
if (matchStruct) {
let index = basicCtype.indexOf('struct');
// 去掉struct和*
if (index >= 0) {
jsType = jsType.substring(index + 6, basicCtype.length);
}
jsType = replaceAll(jsType, '*', '').trim();
}
jsType = basicC2js(jsType);
return jsType;
}
function isJsBasicType(type: string) {
if (type === 'number' || type === 'string' || type === 'boolean') {
return true;
} else {
return false;
}
}
function getInterFuncName(str: string) {
let strArr = str.split(' ');
return replaceAll(strArr[1], '*', '');
}
function getInterFuncRetType(str: string) {
let strArr = str.split(' ');
// let retType = getJsTypeFromC(replaceAll(strArr[0], '*', ''));
return replaceAll(strArr[0], '*', '');
}
function getInterFuncParams(str: string, paramObj: ParamObj[]) {
let paramsStr = '';
let paramObject: ParamObj = {
name: '',
type: '',
arraySize: 0
}
let paramArr = replaceAll(str, '*', '').split(',');
for (let i = 0; i < paramArr.length; i++) {
let param = removeTab(paramArr[i]).split(' ');
const paramType = replaceAll(param[0], ' ', '');
const paramVal = replaceAll(param[1], ' ', '');
paramObject.name = paramVal;
paramObject.type = paramType;
paramObj.push(paramObject);
let rawType = getJsTypeFromC(paramType);
paramsStr += paramVal + ': ' + rawType;
if (i !== paramArr.length - 1) {
paramsStr += ', ';
}
}
return paramsStr;
}
export function getTypeBody(testType: string, typeList: TypeList[]) {
for (let i = 0; i < typeList.length; i++)
{
if (typeList[i].typeName === testType) {
return typeList[i].typeBody;
}
return '';
}
}
export function getInterfaceBody(testType: string, interfaceList: InterfaceList[]) {
for (let i = 0; i < interfaceList.length; i++)
{
if (interfaceList[i].interfaceName === testType) {
return interfaceList[i].interfaceBody;
}
}
}
export function genDtsInterface(path: string, typeList: TypeList[], interfaceList: InterfaceList[]) {
// 解析typedef: 使用正则表达式提取typedef struct定义
const typedefsRegex1 = /typedef\s+struct\s+\w+\s*{\s*[\s\S]*?}\s*\w+;/g;
// 正则表达式匹配 typedef 后跟基本数据类型和自定义类型名称
const typedefsRegex2 = /typedef\s+\w+\s+\w+\s*;/g;
// 正则表达式匹配 class xxx {};
const classRegex = /class\s+(\w+)\s+([a-zA-Z0-9_]+)?\s*(\{[^}]*\};)/g;
let rawContent = removeComments(fs.readFileSync(path).toString());
let structMatch = rawContent.match(typedefsRegex1);
if (!structMatch) {
structMatch = rawContent.match(classRegex);
}
let basicTypeMatch = rawContent.match(typedefsRegex2);
let interfaceListDef: string = '';
// 使用正则表达式的 exec 方法来获取匹配项
if (structMatch) {
for (let index = 0; index < structMatch.length; index++) {
let matchs = removeComments(structMatch[index]);
let structIndex = matchs.indexOf('struct');
let classIndex = matchs.indexOf('class')
let leftIndex = matchs.indexOf('{');
let rightIndex = matchs.indexOf('}');
let interfaceName = '';
if (structIndex >= 0) {
interfaceName = matchs.substring(structIndex + 6, leftIndex).trim();
} else if (classIndex >= 0) {
interfaceName = matchs.substring(classIndex + 5, leftIndex).trim();
}
let params = matchs.substring(leftIndex + 1, rightIndex).split(';');
let interDefine = 'interface ' + interfaceName + ' {\n';
let paramsContent: ParamObj[] = [];
let interFuncsContent: FuncObj[] = [];
let interfaceBody: InterfaceBody = {
params: paramsContent,
funcs: interFuncsContent
}
let interfaceContent: InterfaceList = {
interfaceName: interfaceName,
interfaceBody: interfaceBody
}
for (let i = 0; i < params.length; i++) {
// 去除空格和换行符
let paramStr = removeTab(params[i]);
if (paramStr === '') {
continue;
}
// 成员函数的处理
const funcRegex = /\w+\s+\*?\(([^\)]+)\)\s*\(([^\)]*)\)\s*/;
const funcRegex2 = /(\w+)\s+(::\w+|[\w:]+)\s*\(([^)]*)\)\s*/;
let match = paramStr.match(funcRegex);
let match2 = paramStr.match(funcRegex2);
if (match) {
// 处理成员函数 仅仅限于成员函数是函数指针的情况
let interFuncParams: ParamObj[] = []
let returnType = getInterFuncRetType(match[0]);
let funcName = getInterFuncName(match[1]);
funcName = util.format('KH%s_%s', generateRandomInteger(MIN_RANDOM, MAX_RANDOM), funcName);
let params = getInterFuncParams(match[2], interFuncParams);
interDefine += util.format(' %s:(%s) => %s;\n',funcName, params, returnType);
let funcObj: FuncObj = {
name: funcName,
returns: returnType,
parameters: interFuncParams
}
interFuncsContent.push(funcObj);
} else if (match2) {
let interFuncParams: ParamObj[] = []
let returnType = getInterFuncRetType(match2[1]);
let funcName = match2[2];
funcName = util.format('KH%s_%s', generateRandomInteger(MIN_RANDOM, MAX_RANDOM), funcName);
let params = getInterFuncParams(match2[3], interFuncParams);
interDefine += util.format(' %s:(%s) => %s;\n',funcName, params, returnType);
let funcObj: FuncObj = {
name: funcName,
returns: returnType,
parameters: interFuncParams
}
interFuncsContent.push(funcObj);
} else {
let lastTabIndex = paramStr.lastIndexOf(' ');
const variableName = paramStr.substring(lastTabIndex + 1, paramStr.length).replace('*', '')
const variabletype = paramStr.substring(0, lastTabIndex);
let rawType = getJsTypeFromC(variabletype);
if (!isJsBasicType(rawType)) {
rawType += ' | null';
}
let variableDefine = ' ' + variableName + ': ' + rawType + ';\n'
interDefine += variableDefine;
let paramObj: ParamObj = {
name: variableName,
type: replaceAll(variabletype, 'struct', '').trim(),
arraySize: 0
}
paramsContent.push(paramObj);
}
}
interfaceBody.funcs = interFuncsContent;
interfaceBody.params = paramsContent;
interfaceContent.interfaceBody = interfaceBody;
interfaceList.push(interfaceContent);
interDefine += '}\n';
interfaceListDef += interDefine;
}
}
if (basicTypeMatch) {
for (let index = 0; index < basicTypeMatch.length; index++) {
console.log('Basic type typedef match:', basicTypeMatch[0]); // 输出匹配的基本类型定义
let matchs = basicTypeMatch[index].split(' ');
let rawType = getJsTypeFromC(matchs[1].trim());
let defineType = matchs[2].split(';')
let typedefine = 'type ' + defineType[0] + ' = ' + rawType + ';\n';
interfaceListDef += typedefine;
let typeListContent: TypeList = {
typeName: defineType[0],
typeBody: matchs[1].trim()
}
typeList.push(typeListContent);
}
}
return interfaceListDef;
}
export function genTsFunction(func: FuncInfo, rawFileName: string) {
let funcParams = '';
for (let i = 0; i < func.params.length; ++i) {
funcParams += i > 0 ? ', ' : '';
funcParams += func.params[i].name + ': ' + func.params[i].type;
}
let funcContent = replaceAll(dtsFuncTemplate, '[file_introduce_replace]', rawFileName);
funcContent = replaceAll(funcContent, '[func_introduce_replace]', func.name);
funcContent = replaceAll(funcContent, '[input_introduce_replace]', funcParams === '' ? 'void' : funcParams);
funcContent = replaceAll(funcContent, '[func_name_replace]', func.genName);
funcContent = replaceAll(funcContent, '[func_param_replace]', funcParams);
funcContent = replaceAll(funcContent, '[func_return_replace]', func.retType);
return funcContent;
}
function createParam(parseParamInfo: ParamObj) {
let tsParam: ParamObj = {
name: '',
type: '',
arraySize: 0
};
let cppParam: ParamObj = {
name: '',
type: '',
arraySize: 0
};
tsParam.name = replaceAll(parseParamInfo.name, '*', '');
cppParam.name = tsParam.name;
cppParam.type = removeMarco(parseParamInfo.type);
let rawType = getJsTypeFromC(parseParamInfo.type);
tsParam.type = removeMarco(rawType);
return [tsParam, cppParam];
}
function removeMarco(type: string) {
// 去掉宏定义
let leftCraftIndex = type.indexOf('(');
let rightCraftIndex = type.indexOf(')');
if (leftCraftIndex >= 0 && rightCraftIndex > 0) {
type = removeTab(type.substring(leftCraftIndex + 1, rightCraftIndex));
}
return type;
}
function createFuncInfo(parseFuncInfo: FuncObj) {
let funcInfo: FuncInfo = {
name: '',
params: [],
retType: '',
genName: ''
};
let cppFuncInfo: FuncInfo = {
name: '',
params: [],
retType: '',
genName: ''
}
funcInfo.name = parseFuncInfo.name;
cppFuncInfo.name = parseFuncInfo.name;
funcInfo.genName = util.format('KH%s_%s', generateRandomInteger(MIN_RANDOM, MAX_RANDOM), funcInfo.name);
cppFuncInfo.genName = funcInfo.genName;
let parseParams = parseFuncInfo.parameters;
for (let i = 0; i < parseParams.length; ++i) {
let paramsRes = createParam(parseParams[i]);
let tsParam = paramsRes[0]
let cppParam = paramsRes[1];
if (tsParam.type !== '') {
funcInfo.params.push(tsParam);
cppFuncInfo.params.push(cppParam);
}
}
let retType = parseFuncInfo.returns === '' ? 'void' : parseFuncInfo.returns;
retType = removeMarco(retType);
cppFuncInfo.retType = retType;
funcInfo.retType = getJsTypeFromC(retType);
return [funcInfo, cppFuncInfo];
}
export function analyzeRootFunction(funcInfo: FuncInfo[], cppFuncInfo: FuncInfo[], parseFunctions: FuncObj[]) {
for (let i = 0; i < parseFunctions.length; ++i) {
let result = createFuncInfo(parseFunctions[i]);
funcInfo[i] = result[0];
cppFuncInfo[i] = result[1];
}
}
export function genDtsFile(rootInfo: DtscppRootInfo, out: string) {
let typeList: TypeList[] = []
let interfaceList: InterfaceList[] = []
let interDef = genDtsInterface(rootInfo.rawFilePath, typeList, interfaceList);
let tsFuncContent = '';
// analyze
let tsfunctions: FuncInfo[] = [];
let cppfunctions: FuncInfo[] = [];
analyzeRootFunction(tsfunctions, cppfunctions, rootInfo.funcs);
let rawFileName = path.basename(rootInfo.rawFilePath);
for (let i = 0; i < rootInfo.funcs.length; i++) {
// gen dts function
tsFuncContent += genTsFunction(tsfunctions[i], rawFileName);
}
let dtsFileName = rootInfo.fileName + '.d.ts';
let dtsContent = interDef + tsFuncContent;
let outPath = path.join(out, dtsFileName);
fs.writeFileSync(outPath, dtsContent);
console.info('generate success!')
}

View File

@ -12,13 +12,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import re = require('./common/re');
import fs = require('fs');
import util = require('util');
import { DtscppRootInfo, FuncInfo, FuncObj, InterfaceBody, InterfaceList, ParamObj, TypeList } from './datatype';
import { dtsFuncTemplate } from './template/func_template';
import { generateRandomInteger, removeComments, removeTab, replaceAll } from './common/tool';
import { DtscppRootInfo, FuncObj, InterfaceBody, ParamObj, FuncInfo, GenInfo, InterfaceList, TypeList } from './datatype';
import { dts2cpp_key } from './template/dtscpp/dts2cpp_key';
import path = require('path');
import { generateRandomInteger, removeComments, removeTab, replaceAll } from './common/tool';
import util = require('util');
import re = require('./common/re');
import { dtsFuncTemplate } from './template/func_template';
const MIN_RANDOM = 100;
const MAX_RANDOM = 999
@ -43,6 +46,22 @@ export function isBoolType(cType: string) {
return false;
}
export function genTsFunction(func: FuncInfo, rawFileName: string) {
let funcParams = '';
for (let i = 0; i < func.params.length; ++i) {
funcParams += i > 0 ? ', ' : '';
funcParams += func.params[i].name + ': ' + func.params[i].type;
}
let funcContent = replaceAll(dtsFuncTemplate, '[file_introduce_replace]', rawFileName);
funcContent = replaceAll(funcContent, '[func_introduce_replace]', func.name);
funcContent = replaceAll(funcContent, '[input_introduce_replace]', funcParams === '' ? 'void' : funcParams);
funcContent = replaceAll(funcContent, '[func_name_replace]', func.genName);
funcContent = replaceAll(funcContent, '[func_param_replace]', funcParams);
funcContent = replaceAll(funcContent, '[func_return_replace]', func.retType);
return funcContent;
}
export function isNumberType(cType: string) {
switch (cType) {
case 'short':
@ -81,6 +100,17 @@ function basicC2js(cType: string) {
return jsType;
}
function getInterFuncRetType(str: string) {
let strArr = str.split(' ');
// let retType = getJsTypeFromC(replaceAll(strArr[0], '*', ''));
return replaceAll(strArr[0], '*', '');
}
function getInterFuncName(str: string) {
let strArr = str.split(' ');
return replaceAll(strArr[1], '*', '');
}
export function getJsTypeFromC(cType: string) {
let basicCtype = cType;
let matchs = re.match('(std::)?vector<([\x21-\x7e ]+)>', basicCtype);
@ -115,25 +145,6 @@ export function getJsTypeFromC(cType: string) {
return jsType;
}
function isJsBasicType(type: string) {
if (type === 'number' || type === 'string' || type === 'boolean') {
return true;
} else {
return false;
}
}
function getInterFuncName(str: string) {
let strArr = str.split(' ');
return replaceAll(strArr[1], '*', '');
}
function getInterFuncRetType(str: string) {
let strArr = str.split(' ');
// let retType = getJsTypeFromC(replaceAll(strArr[0], '*', ''));
return replaceAll(strArr[0], '*', '');
}
function getInterFuncParams(str: string, paramObj: ParamObj[]) {
let paramsStr = '';
let paramObject: ParamObj = {
@ -158,166 +169,22 @@ function getInterFuncParams(str: string, paramObj: ParamObj[]) {
return paramsStr;
}
export function getTypeBody(testType: string, typeList: TypeList[]) {
for (let i = 0; i < typeList.length; i++)
{
if (typeList[i].typeName === testType) {
return typeList[i].typeBody;
}
return '';
function isJsBasicType(type: string) {
if (type === 'number' || type === 'string' || type === 'boolean') {
return true;
} else {
return false;
}
}
export function getInterfaceBody(testType: string, interfaceList: InterfaceList[]) {
for (let i = 0; i < interfaceList.length; i++)
{
if (interfaceList[i].interfaceName === testType) {
return interfaceList[i].interfaceBody;
}
function removeMarco(type: string) {
// 去掉宏定义
let leftCraftIndex = type.indexOf('(');
let rightCraftIndex = type.indexOf(')');
if (leftCraftIndex >= 0 && rightCraftIndex > 0) {
type = removeTab(type.substring(leftCraftIndex + 1, rightCraftIndex));
}
}
export function genDtsInterface(path: string, typeList: TypeList[], interfaceList: InterfaceList[]) {
// 解析typedef: 使用正则表达式提取typedef struct定义
const typedefsRegex1 = /typedef\s+struct\s+\w+\s*{\s*[\s\S]*?}\s*\w+;/g;
// 正则表达式匹配 typedef 后跟基本数据类型和自定义类型名称
const typedefsRegex2 = /typedef\s+\w+\s+\w+\s*;/g;
// 正则表达式匹配 class xxx {};
const classRegex = /class\s+(\w+)\s+([a-zA-Z0-9_]+)?\s*(\{[^}]*\};)/g;
let rawContent = removeComments(fs.readFileSync(path).toString());
let structMatch = rawContent.match(typedefsRegex1);
if (!structMatch) {
structMatch = rawContent.match(classRegex);
}
let basicTypeMatch = rawContent.match(typedefsRegex2);
let interfaceListDef: string = '';
// 使用正则表达式的 exec 方法来获取匹配项
if (structMatch) {
for (let index = 0; index < structMatch.length; index++) {
let matchs = removeComments(structMatch[index]);
let structIndex = matchs.indexOf('struct');
let classIndex = matchs.indexOf('class')
let leftIndex = matchs.indexOf('{');
let rightIndex = matchs.indexOf('}');
let interfaceName = '';
if (structIndex >= 0) {
interfaceName = matchs.substring(structIndex + 6, leftIndex).trim();
} else if (classIndex >= 0) {
interfaceName = matchs.substring(classIndex + 5, leftIndex).trim();
}
let params = matchs.substring(leftIndex + 1, rightIndex).split(';');
let interDefine = 'interface ' + interfaceName + ' {\n';
let paramsContent: ParamObj[] = [];
let interFuncsContent: FuncObj[] = [];
let interfaceBody: InterfaceBody = {
params: paramsContent,
funcs: interFuncsContent
}
let interfaceContent: InterfaceList = {
interfaceName: interfaceName,
interfaceBody: interfaceBody
}
for (let i = 0; i < params.length; i++) {
// 去除空格和换行符
let paramStr = removeTab(params[i]);
if (paramStr === '') {
continue;
}
// 成员函数的处理
const funcRegex = /\w+\s+\*?\(([^\)]+)\)\s*\(([^\)]*)\)\s*/;
const funcRegex2 = /(\w+)\s+(::\w+|[\w:]+)\s*\(([^)]*)\)\s*/;
let match = paramStr.match(funcRegex);
let match2 = paramStr.match(funcRegex2);
if (match) {
// 处理成员函数 仅仅限于成员函数是函数指针的情况
let interFuncParams: ParamObj[] = []
let returnType = getInterFuncRetType(match[0]);
let funcName = getInterFuncName(match[1]);
funcName = util.format('KH%s_%s', generateRandomInteger(MIN_RANDOM, MAX_RANDOM), funcName);
let params = getInterFuncParams(match[2], interFuncParams);
interDefine += util.format(' %s:(%s) => %s;\n',funcName, params, returnType);
let funcObj: FuncObj = {
name: funcName,
returns: returnType,
parameters: interFuncParams
}
interFuncsContent.push(funcObj);
} else if (match2) {
let interFuncParams: ParamObj[] = []
let returnType = getInterFuncRetType(match2[1]);
let funcName = match2[2];
funcName = util.format('KH%s_%s', generateRandomInteger(MIN_RANDOM, MAX_RANDOM), funcName);
let params = getInterFuncParams(match2[3], interFuncParams);
interDefine += util.format(' %s:(%s) => %s;\n',funcName, params, returnType);
let funcObj: FuncObj = {
name: funcName,
returns: returnType,
parameters: interFuncParams
}
interFuncsContent.push(funcObj);
} else {
let lastTabIndex = paramStr.lastIndexOf(' ');
const variableName = paramStr.substring(lastTabIndex + 1, paramStr.length).replace('*', '')
const variabletype = paramStr.substring(0, lastTabIndex);
let rawType = getJsTypeFromC(variabletype);
if (!isJsBasicType(rawType)) {
rawType += ' | null';
}
let variableDefine = ' ' + variableName + ': ' + rawType + ';\n'
interDefine += variableDefine;
let paramObj: ParamObj = {
name: variableName,
type: replaceAll(variabletype, 'struct', '').trim(),
arraySize: 0
}
paramsContent.push(paramObj);
}
}
interfaceBody.funcs = interFuncsContent;
interfaceBody.params = paramsContent;
interfaceContent.interfaceBody = interfaceBody;
interfaceList.push(interfaceContent);
interDefine += '}\n';
interfaceListDef += interDefine;
}
}
if (basicTypeMatch) {
for (let index = 0; index < basicTypeMatch.length; index++) {
console.log('Basic type typedef match:', basicTypeMatch[0]); // 输出匹配的基本类型定义
let matchs = basicTypeMatch[index].split(' ');
let rawType = getJsTypeFromC(matchs[1].trim());
let defineType = matchs[2].split(';')
let typedefine = 'type ' + defineType[0] + ' = ' + rawType + ';\n';
interfaceListDef += typedefine;
let typeListContent: TypeList = {
typeName: defineType[0],
typeBody: matchs[1].trim()
}
typeList.push(typeListContent);
}
}
return interfaceListDef;
}
export function genTsFunction(func: FuncInfo, rawFileName: string) {
let funcParams = '';
for (let i = 0; i < func.params.length; ++i) {
funcParams += i > 0 ? ', ' : '';
funcParams += func.params[i].name + ': ' + func.params[i].type;
}
let funcContent = replaceAll(dtsFuncTemplate, '[file_introduce_replace]', rawFileName);
funcContent = replaceAll(funcContent, '[func_introduce_replace]', func.name);
funcContent = replaceAll(funcContent, '[input_introduce_replace]', funcParams === '' ? 'void' : funcParams);
funcContent = replaceAll(funcContent, '[func_name_replace]', func.genName);
funcContent = replaceAll(funcContent, '[func_param_replace]', funcParams);
funcContent = replaceAll(funcContent, '[func_return_replace]', func.retType);
return funcContent;
return type;
}
function createParam(parseParamInfo: ParamObj) {
@ -340,16 +207,6 @@ function createParam(parseParamInfo: ParamObj) {
return [tsParam, cppParam];
}
function removeMarco(type: string) {
// 去掉宏定义
let leftCraftIndex = type.indexOf('(');
let rightCraftIndex = type.indexOf(')');
if (leftCraftIndex >= 0 && rightCraftIndex > 0) {
type = removeTab(type.substring(leftCraftIndex + 1, rightCraftIndex));
}
return type;
}
function createFuncInfo(parseFuncInfo: FuncObj) {
let funcInfo: FuncInfo = {
name: '',
@ -394,25 +251,301 @@ export function analyzeRootFunction(funcInfo: FuncInfo[], cppFuncInfo: FuncInfo[
}
}
export function genDtsFile(rootInfo: DtscppRootInfo, out: string) {
let typeList: TypeList[] = []
let interfaceList: InterfaceList[] = []
let interDef = genDtsInterface(rootInfo.rawFilePath, typeList, interfaceList);
let tsFuncContent = '';
// analyze
let tsfunctions: FuncInfo[] = [];
let cppfunctions: FuncInfo[] = [];
analyzeRootFunction(tsfunctions, cppfunctions, rootInfo.funcs);
let rawFileName = path.basename(rootInfo.rawFilePath);
for (let i = 0; i < rootInfo.funcs.length; i++) {
// gen dts function
tsFuncContent += genTsFunction(tsfunctions[i], rawFileName);
export function genDtsInterface(path: string, typeList: TypeList[], interfaceList: InterfaceList[]) {
// 解析typedef: 使用正则表达式提取typedef struct定义
const typedefsRegex1 = /typedef\s+struct\s+\w+\s*{\s*[\s\S]*?}\s*\w+;/g;
// 正则表达式匹配 typedef 后跟基本数据类型和自定义类型名称
const typedefsRegex2 = /typedef\s+\w+\s+\w+\s*;/g;
// 正则表达式匹配 class xxx {};
const classRegex = /class\s+(\w+)\s+([a-zA-Z0-9_]+)?\s*(\{[^}]*\};)/g;
let rawContent = removeComments(fs.readFileSync(path).toString());
let structMatch = rawContent.match(typedefsRegex1);
if (!structMatch) {
structMatch = rawContent.match(classRegex);
}
let basicTypeMatch = rawContent.match(typedefsRegex2);
let interfaceListDef: string = '';
// 使用正则表达式的 exec 方法来获取匹配项
if (structMatch) {
for (let index = 0; index < structMatch.length; index++) {
let matchs = removeComments(structMatch[index]);
let structIndex = matchs.indexOf('struct');
let classIndex = matchs.indexOf('class')
let leftIndex = matchs.indexOf('{');
let rightIndex = matchs.indexOf('}');
let interfaceName = '';
if (structIndex >= 0) {
interfaceName = matchs.substring(structIndex + 6, leftIndex).trim();
} else if (classIndex >= 0) {
interfaceName = matchs.substring(classIndex + 5, leftIndex).trim();
}
let params = matchs.substring(leftIndex + 1, rightIndex).split(';');
let interDefine = 'interface ' + interfaceName + ' {\n';
let paramsContent: ParamObj[] = [];
let interFuncsContent: FuncObj[] = [];
let interfaceBody: InterfaceBody = {
params: paramsContent,
funcs: interFuncsContent
}
let interfaceContent: InterfaceList = {
interfaceName: interfaceName,
interfaceBody: interfaceBody
}
for (let i = 0; i < params.length; i++) {
// 去除空格和换行符
let paramStr = removeTab(params[i]);
if (paramStr === '') {
continue;
}
// 成员函数的处理
const funcRegex = /\w+\s+\*?\(([^\)]+)\)\s*\(([^\)]*)\)\s*/;
const funcRegex2 = /(\w+)\s+(::\w+|[\w:]+)\s*\(([^)]*)\)\s*/;
let match = paramStr.match(funcRegex);
let match2 = paramStr.match(funcRegex2);
if (match) {
// 处理成员函数 仅仅限于成员函数是函数指针的情况
let interFuncParams: ParamObj[] = []
let returnType = getInterFuncRetType(match[0]);
let funcName = getInterFuncName(match[1]);
funcName = util.format('KH%s_%s', generateRandomInteger(MIN_RANDOM, MAX_RANDOM), funcName);
let params = getInterFuncParams(match[2], interFuncParams);
interDefine += util.format(' %s:(%s) => %s;\n',funcName, params, returnType);
let funcObj: FuncObj = {
type: '',
name: funcName,
returns: returnType,
parameters: interFuncParams
}
interFuncsContent.push(funcObj);
} else if (match2) {
let interFuncParams: ParamObj[] = []
let returnType = getInterFuncRetType(match2[1]);
let funcName = match2[2];
funcName = util.format('KH%s_%s', generateRandomInteger(MIN_RANDOM, MAX_RANDOM), funcName);
let params = getInterFuncParams(match2[3], interFuncParams);
interDefine += util.format(' %s:(%s) => %s;\n',funcName, params, returnType);
let funcObj: FuncObj = {
type: '',
name: funcName,
returns: returnType,
parameters: interFuncParams
}
interFuncsContent.push(funcObj);
} else {
let lastTabIndex = paramStr.lastIndexOf(' ');
const variableName = paramStr.substring(lastTabIndex + 1, paramStr.length).replace('*', '')
const variabletype = paramStr.substring(0, lastTabIndex);
let rawType = getJsTypeFromC(variabletype);
if (!isJsBasicType(rawType)) {
rawType += ' | null';
}
let variableDefine = ' ' + variableName + ': ' + rawType + ';\n'
interDefine += variableDefine;
let paramObj: ParamObj = {
name: variableName,
type: replaceAll(variabletype, 'struct', '').trim(),
arraySize: 0
}
paramsContent.push(paramObj);
}
}
interfaceBody.funcs = interFuncsContent;
interfaceBody.params = paramsContent;
interfaceContent.interfaceBody = interfaceBody;
interfaceList.push(interfaceContent);
interDefine += '}\n';
interfaceListDef += interDefine;
}
}
if (basicTypeMatch) {
for (let index = 0; index < basicTypeMatch.length; index++) {
console.log('Basic type typedef match:', basicTypeMatch[0]); // 输出匹配的基本类型定义
let matchs = basicTypeMatch[index].split(' ');
let rawType = getJsTypeFromC(matchs[1].trim());
let defineType = matchs[2].split(';')
let typedefine = 'type ' + defineType[0] + ' = ' + rawType + ';\n';
interfaceListDef += typedefine;
let typeListContent: TypeList = {
typeName: defineType[0],
typeBody: matchs[1].trim()
}
typeList.push(typeListContent);
}
}
return interfaceListDef;
}
export function getTypeBody(testType: string, typeList: TypeList[]) {
for (let i = 0; i < typeList.length; i++)
{
if (typeList[i].typeName === testType) {
return typeList[i].typeBody;
}
return '';
}
}
export function getInterfaceBody(testType: string, interfaceList: InterfaceList[]) {
for (let i = 0; i < interfaceList.length; i++)
{
if (interfaceList[i].interfaceName === testType) {
return interfaceList[i].interfaceBody;
}
}
}
//----------------------------
function transTskey2Ckey(key: string) {
for(const keyItem of dts2cpp_key) {
for(const str of keyItem.keys) {
if (key.includes(str)) {
return keyItem.value;
}
}
}
let replaceKeyList = ['enum', 'struct', 'union'];
for(const rkey of replaceKeyList) {
key = key.replace(rkey, '').trim();
}
return key;
}
function getDtsEnum(rootInfo: GenInfo) {
let enumList = rootInfo.parseObj.enums;
let out = '';
for(const enumItem of enumList) {
let enumHead = `export enum ${enumItem.name} {\n`
let enumBody = ''
enumItem.members.forEach(element => {
enumBody += `\t${element},\n`
});
out += enumHead + enumBody + '};\n\n'
if (enumItem.name && enumItem.alias && enumItem.name !== enumItem.alias) {
out += `export type ${enumItem.alias} = ${enumItem.name};\n\n`
}
}
return out;
}
function getDtsFunction(rootInfo: GenInfo) {
let funcList = rootInfo.parseObj.funcs;
let out = '';
for(const funcItem of funcList) {
let funcHead = '';
let funcTail = '';
let enumBody = ''
let returnType = transTskey2Ckey(funcItem.returns);
if (funcItem.type === 'typedef') {
funcHead = `export interface ${funcItem.name} {\n`;
funcTail = '};\n\n';
funcItem.parameters.forEach(element => {
if (element.name && element.type) {
enumBody += `${element.name}: ${transTskey2Ckey(element.type)}, `
}
});
enumBody = `\t(${enumBody.slice(0, -2)}): ${returnType};\n`
out += funcHead + `${enumBody}` + funcTail;
} else {
funcHead = `export function ${funcItem.name}(`
funcTail = `): ${returnType};\n\n`;
funcItem.parameters.forEach(element => {
if (element.name && element.type) {
enumBody += `${element.name}: ${transTskey2Ckey(element.type)}, `
}
});
out += funcHead + enumBody.slice(0, -2) + funcTail;
}
}
return out;
}
function getDtsClasses(rootInfo: GenInfo) {
let classList = rootInfo.parseObj.classes;
let out = '';
for(const classItem of classList) {
let classHead = `export class ${classItem.name} {\n`
let classBody = ''
for(const attribute of classItem.variableList) {
classBody += `\t${attribute.name}: ${transTskey2Ckey(attribute.type)};\n`
};
for(const method of classItem.functionList) {
let methodContent = '';
for(const param of method.parameters) {
methodContent = `${param.name}: ${transTskey2Ckey(param.type)}, `;
}
classBody += `\t${method.name}(${methodContent.slice(0, -2)}): ${transTskey2Ckey(method.returns)};\n`
};
out += classHead + classBody + '};\n\n'
if (classItem.name && classItem.alias) {
out += `export type ${classItem.alias} = ${classItem.name};\n\n`
}
}
return out;
}
function getDtsStructs(rootInfo: GenInfo) {
let structList = rootInfo.parseObj.structs;
let out = '';
for(const structItem of structList) {
let structHead = `export type ${structItem.name} = {\n`
let structBody = ''
for(const attribute of structItem.members) {
structBody += `\t${attribute.name}: ${transTskey2Ckey(attribute.type)};\n`
};
for(const method of structItem.functions) {
let methodContent = '';
for(const param of method.parameters) {
if (param.name && param.type) {
methodContent = `${param.name}: ${transTskey2Ckey(param.type)}, `;
}
}
structBody += `\t${method.name}(${methodContent.slice(0, -2)}): ${transTskey2Ckey(method.returns)};\n`
};
out += structHead + structBody + '};\n\n'
if (structItem.name && structItem.alias && structItem.name !== structItem.alias) {
out += `export type ${structItem.alias} = ${structItem.name};\n\n`
}
}
return out;
}
function getDtsUnions(rootInfo: GenInfo) {
let unionList = rootInfo.parseObj.unions;
let out = '';
for(const unionItem of unionList) {
let unionHead = `export type ${unionItem.name} = `
let unionBody = ''
for(const element of unionItem.members) {
unionBody += `${transTskey2Ckey(element.type)} | `
};
out += unionHead + unionBody.slice(0, -2) + ';\n\n'
if (unionItem.name && unionItem.alias && unionItem.name !== unionItem.alias) {
out += `export type ${unionItem.alias} = ${unionItem.name};\n\n`
}
}
return out;
}
export function genDtsFile(rootInfo: GenInfo) {
// gen enums
let fileContent = getDtsEnum(rootInfo);
// gen functions
fileContent += getDtsFunction(rootInfo);
// gen classes
fileContent += getDtsClasses(rootInfo);
// gen struct
fileContent += getDtsStructs(rootInfo);
// gen union
fileContent += getDtsUnions(rootInfo);
let dtsFileName = rootInfo.fileName + '.d.ts';
let dtsContent = interDef + tsFuncContent;
let outPath = path.join(out, dtsFileName);
fs.writeFileSync(outPath, dtsContent);
let dirPath = path.dirname(rootInfo.rawFilePath);
let outPath = path.join(dirPath, dtsFileName);
fs.writeFileSync(outPath, fileContent);
console.info('generate success!')
return outPath;
}

View File

@ -29,7 +29,7 @@ function parseEnum(data: string) {
const enumName = match[1] ||match[3] || match[4];
const aliasName = match[3];
const membersString = match[2] || match[5];
const members = membersString.split(';')
const members = membersString.split(',')
.map(member => member.trim().replace(/[\n\r\s]/g, ''))
.filter(member => member.length > 0);
let enumItem = {
@ -45,7 +45,7 @@ function parseEnum(data: string) {
function parseUnion(data: string) {
// 使用正则表达式提取联合体定义
const unionRegex = /typedef\s+struct\s*(\w*)\s*{([^}]*)}\s*(\w+)\s*;|union\s+(\w+)\s*{([^}]*)}\s*;/g;
const unionRegex = /typedef\s+union\s*(\w*)\s*{([^}]*)}\s*(\w+)\s*;|union\s+(\w+)\s*{([^}]*)}\s*;/g;
const unions: UnionObj[] = [];
let match;
while ((match = unionRegex.exec(data)) !== null) {
@ -64,7 +64,8 @@ function parseUnion(data: string) {
members.forEach(declaration => {
// 使用正则表达式匹配类型和变量名
const match = declaration.match(/(\w+)\s+(\w+)(\[(\d+)\])?/);
// const match = declaration.match(/(\w+)\s+(\w+)(\[(\d+)\])?/);
const match = declaration.match(/(\w[\w\s\*]+)\s+(\w+)\s*/);
if (match) {
const type = match[1]; // 类型
const variable = match[2]; // 变量名
@ -101,25 +102,59 @@ function parseStruct(data: string) {
const members = membersString.split(';')
.map(member => member.trim().replace(/[\n\r]/g, ''))
.filter(member => member.length > 0);
const variables: string[] = [];
const methods: string[] = [];
members.forEach(member => {
// 匹配方法声明
const methodRegex = /(\w[\w\s\*]+)\s+(\w+)\(([^)]*)\)\s*/;
const variableRegex = /(\w[\w\s\*]+)\s+(\w+)\s*/;
if (methodRegex.test(member)) {
methods.push(member.trim().replace(/[\n\r]/g, ''));
} else if (variableRegex.test(member)) {
variables.push(member.trim().replace(/[\n\r]/g, ''));
}
});
let structItem: StructObj = {
"name": structName,
"alias": alias,
"members": parseMembers(members),
"functions": []
"members": parseMembers(variables),
"functions": parseMethods(methods)
}
structs.push(structItem);
}
console.info(` return structs: ${JSON.stringify(structs)}`);
// console.info(` return structs: ${JSON.stringify(structs)}`);
return structs;
}
// /^(const\s+)?([\w\s*]+)\s+(\w+)(?:\[(\d+)\])?$/
function parseParameters(members: string[]): ParamObj[] {
// const memberRegex = /^(const\s+)?([\w\s*]+)\s+(\w+)(?:\[(\d+)\])?$/;
const memberRegex = /^(const\s+)?([\w\s*]+)\s+(\w+)(?:\[(\d*)\])?$/;
// console.info(` parseParameters members: ${JSON.stringify(members)}`);
return members.map(member => {
const match = member.trim().match(memberRegex);
// console.info(` parseParameters match: ${JSON.stringify(match)}`);
if (match) {
const type = match[2];
const name = match[3];
// const arraySize = match[4] ? parseInt(match[4], 10) : -1;
const arraySize = match[4] && match[4] !== "" ? parseInt(match[4], 10) : -1;
return { type, name, arraySize };
}
return {};
}).filter((m): m is ParamObj => m !== null); // 类型保护
}
function parseMembers(members: string[]): ParamObj[] {
const memberRegex = /(?:public:|private:)?\s*(\w+(?:\s+\w+)?)\s+(\w+)(?:\[(\d+)\])?/;
// console.info(` parseMembers members: ${JSON.stringify(members)}`);
return members.map(member => {
const match = member.trim().match(memberRegex);
// console.info(` parseMembers match: ${JSON.stringify(match)}`);
if (match) {
const type = match[1];
const name = match[2];
@ -130,8 +165,9 @@ function parseMembers(members: string[]): ParamObj[] {
}).filter((m): m is ParamObj => m !== null); // 类型保护
}
function parseFunctions(functions: string[]): FuncObj[] {
const functionRegex = /(\w+)\s+(\w+)\(([^)]*)\)/; // 正则表达式匹配返回值、函数名和参数
function parseMethods(functions: string[]): FuncObj[] {
const functionRegex = /^(\w[\w\s]*\*?)\s+(\w+)\((.*?)\)$/;
// const functionRegex = /(\w+)\s+(\w+)\(([^)]*)\)/; // 正则表达式匹配返回值、函数名和参数
return functions.map(func => {
const match = func.trim().match(functionRegex);
@ -139,7 +175,7 @@ function parseFunctions(functions: string[]): FuncObj[] {
const returns = match[1]; // 返回值类型
const name = match[2]; // 方法名
const parameterstr = match[3].split(',').map(param => param.trim()).filter(Boolean); // 分割参数并去除空值
const parameters = parseMembers(parameterstr);
const parameters = parseParameters(parameterstr);
return { returns, name, parameters };
}
return {};
@ -176,7 +212,7 @@ function parseClass(data: string) {
const variableList = parseMembers(variables);
// console.log(`parseMembers: ${JSON.stringify(variableList)}`)
const functionList: FuncObj[] = parseFunctions(methods);
const functionList: FuncObj[] = parseMethods(methods);
// console.log(`parsedFunctions: ${JSON.stringify(functionList)}`);
const classItem: ClassObj = {
@ -187,11 +223,11 @@ function parseClass(data: string) {
}
classes.push(classItem);
}
console.info(` return classes: ${JSON.stringify(classes)}`);
// console.info(` return classes: ${JSON.stringify(classes)}`);
return classes;
}
function parseFunction(data: string) {
function parseFunctionOld(data: string) {
// 使用正则表达式提取函数定义
const functionRegex1 = /([a-zA-Z_]\w*\s+)+([*a-zA-Z_]\w+)\s*\(([^)]*)\)\s*(?={|;)/g;
const functionRegex2 = /(\w+\s*\(.*?\)\s+)(\w+)\s*\((.*?)\);\s*/g;
@ -237,17 +273,19 @@ function parseFunction(data: string) {
arraySize: 0,
})
}
console.info(`ret: ${returnType} func: ${functionName} params:(${paramResList.map(ditem => {
return ' type: ' + ditem.type + ', ' + 'name: ' + ditem.name;
})})`)
// console.info(`ret: ${returnType} func: ${functionName} params:(${paramResList.map(ditem => {
// return ' type: ' + ditem.type + ', ' + 'name: ' + ditem.name;
// })})`)
let funcRes: FuncObj = {
name: functionName,
returns: returnType,
parameters: paramResList
type: 'function',
name: functionName,
returns: returnType,
parameters: paramResList
}
return funcRes;
}
let res: FuncObj = {
type: '',
name: '',
returns: '',
parameters: []
@ -256,6 +294,7 @@ function parseFunction(data: string) {
})
.filter(detail => detail !== null);
console.log(`parse oldfunc : ${JSON.stringify(functionDetails)}`)
return functionDetails;
// if (functionDetails.length > 0) {
// const funcs = [...functionDetails.filter((funcItem) : funcItem is FuncObj => funcItem !== null)];
@ -266,13 +305,37 @@ function parseFunction(data: string) {
// return ' type: ' + ditem.type + ', ' + 'name: ' + ditem.name;
// })})`
// ).join('\n');
// console.info(` return parseFunctions: ${JSON.stringify(funcs)}`);
// console.info(` return parseMethods: ${JSON.stringify(funcs)}`);
// return funcs;
// } else {
// vscode.window.showInformationMessage('No functions found.');
// }
}
function parseFunction(data: string): FuncObj[] {
// const funcRegex = /^(static\s+)?(const\s+)?([\w\s\[\]*]+)\s+(\w+)\s*\(([^)]*)\);/gm;
const funcRegex = /(?:typedef\s+([\w\s\[\]*]+)\s+\(\*\s*(\w+)\)\s*\(([^)]*)\);|^(static\s+)?(const\s+)?([\w\s\[\]*]+)\s+(\w+)\s*\(([^)]*)\);)/gm
const functions: FuncObj[] = []
let match;
while ((match = funcRegex.exec(data)) !== null) {
// console.log(`func match: ${JSON.stringify(match)}`)
const returnType = match[1] ? match[1].trim() : match[6].trim(); //match[3].trim();
const name = match[2] ? match[2].trim() : match[7].trim(); //match[4].trim();
const params = (match[3] ? match[3] : match[8] || "").split(',').map(param => param.trim()).filter(param => param); //match[5].split(',').map(param => param.trim()).filter(param => param);
let isInterface = match[0].includes('typedef');
let funcItem: FuncObj = {
"type": isInterface ? "typedef" : "function",
"returns": returnType,
"name": name,
"parameters": parseParameters(params)
}
functions.push(funcItem);
}
// console.info(` return functions: ${JSON.stringify(functions)}`);
return functions;
}
export function parseHeaderFile(filePath: string): Promise<ParseObj> {
return new Promise((resolve, reject) => {
let parseRes: ParseObj = {
@ -303,7 +366,7 @@ export function parseHeaderFile(filePath: string): Promise<ParseObj> {
classes: classList,
funcs: funcList
}
console.info(` return parse result: ${JSON.stringify(parseRes)}`);
// console.info(` return parse result: ${JSON.stringify(parseRes)}`);
resolve(parseRes);
});
});

View File

@ -0,0 +1,14 @@
export let dts2cpp_key = [
{
keys: ['char', 'string'],
value: 'string'
},
{
keys: ['size_t', 'int', 'short', 'long', 'double', 'float'],
value: 'number'
},
{
keys: ['bool'],
value: 'boolean'
}
]