Skip to content

Commit

Permalink
refactor: 优化 go 函数参数解析
Browse files Browse the repository at this point in the history
Co-authored-by: ygqygq2 <ygqygq2@qq.com>
  • Loading branch information
ygqygq2 committed Apr 21, 2024
1 parent 11dd825 commit a45966a
Show file tree
Hide file tree
Showing 16 changed files with 199 additions and 74 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
func testFunc() (string) {
return "test"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* @description
* @return default {string}
*/
func testFunc() (string) {
return "test"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
func testFunc() {
fmt.Println("test")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/**
* @description
*/
func testFunc() {
fmt.Println("test")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
func funcName(param1 string, param2 []int) (r1 string, r2 []int) {
return param1, param2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* @description
* @return r1 {string}
* @return r2 {[]int}
* @param param1 {string}
* @param param2 {[]int}
*/
func funcName(param1 string, param2 []int) (r1 string, r2 []int) {
return param1, param2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
func funcName(param1 string, param2 []int) {
return param1, param2
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* @description
* @param param1 {string}
* @param param2 {[]int}
*/
func funcName(param1 string, param2 []int) {
return param1, param2
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/**
* @description
* @return default {string}
* @param a {string}
* @param b {{key: string}}
* @description test
* @return default {string} returnValue
* @param a {string} stringA
* @param b {{key: string}} stringB
*/
const func = function(a: string, b: {key: string}): string {
console.log(a + b);
Expand Down
4 changes: 2 additions & 2 deletions src/fileheader/FileheaderManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ export class FileheaderManager {
range,
) || {
paramsInfo: {},
returnInfo: { default: { type: '', description: '' } },
returnInfo: {},
descriptionInfo: '',
};
const functionCommentInfo = parser?.generateFunctionCommentInfo(
Expand All @@ -187,7 +187,7 @@ export class FileheaderManager {
);

if (functionCommentInfo) {
const originFunctionComment = generateFunctionComment(originFunctionInfo);
const originFunctionComment = generateFunctionComment(originFunctionInfo, true);
const functionComment = generateFunctionComment(functionCommentInfo);
// 函数注释没有变化
if (originFunctionComment === functionComment) {
Expand Down
108 changes: 50 additions & 58 deletions src/function-params-parser/GoProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ import * as vscode from 'vscode';
import { ConfigManager } from '@/configuration/ConfigManager';
import { logger } from '@/extension';
import { LanguageFunctionCommentSettings } from '@/typings/types';
import { escapeRegexString } from '@/utils/str';

import { extractFunctionParamsString } from './extractFunctionParamsString';
import { FunctionParamsParser } from './FunctionParamsParser';
import { splitParams } from './go-splitParams';
import { FunctionParamsInfo, ParamsInfo, ReturnInfo } from './types';

function matchNormalFunction(
Expand All @@ -16,25 +19,30 @@ function matchNormalFunction(
params: ParamsInfo;
} {
const { defaultReturnName = 'default' } = languageSettings;
let returnType = {};
const returnType: ReturnInfo = {};
let matched = false;
const params: ParamsInfo = {};
let params: ParamsInfo = {};

// 普通写法,一个小括号一个大括号,可能有参数,可能有一个返回值,但返回值没有命令,没有括号
const functionPattern = /func\s+([a-zA-Z0-9_]+)\s*\((.*?)\)\s*([a-zA-Z0-9_]+)?\s*{[\s\S]*?}/m;
// 提取参数括号里的字符串
const functionParamsStr = extractFunctionParamsString(functionDefinition);
const functionParamsRegStr = escapeRegexString(functionParamsStr);
// 普通写法,一个小括号一个大括号,参数使用上面变量,可能有一个返回值,但返回值没有命名,没有括号
const functionPattern = new RegExp(
`func\\s+([a-zA-Z0-9_]+)\\s*\\(${functionParamsRegStr}\\)\\s*([a-zA-Z0-9_]+)?\\s*{[\\s\\S]*?}`,
'm',
);

const match = functionPattern.exec(functionDefinition);

if (match) {
matched = true;
returnType = { [defaultReturnName]: { type: match[3], description: '' } };

const paramsString = match[2];
const paramsArray = paramsString.split(',');
for (const param of paramsArray) {
const [name, type] = param.trim().split(' ');
params[name] = { type, description: '' };
const returnString = match[2];
if (returnString) {
const returnTypeStr = returnString.trim();
returnType[defaultReturnName] = { type: returnTypeStr, description: '' };
}

params = splitParams(functionParamsStr, languageSettings);
}

return { matched, returnType, params };
Expand All @@ -48,32 +56,25 @@ function matchMultiReturnTypeFunction(
returnType: ReturnInfo;
params: ParamsInfo;
} {
const { defaultReturnName = 'default' } = languageSettings;
const returnType: ReturnInfo = {};
let returnType: ReturnInfo = {};
let matched = false;
const params: ParamsInfo = {};
let params: ParamsInfo = {};

// 函数可能有参数,一定有一个或多个返回值,返回值可能有命名,也可能无命名,但一定有括号包住返回值
const functionPattern = /func\s+([a-zA-Z0-9_]+)\s*\((.*?)\)\s*\((.*?)\)\s*{[\s\S]*?}/m;
const functionParamsStr = extractFunctionParamsString(functionDefinition);
const functionParamsRegStr = escapeRegexString(functionParamsStr);
// 函数参数使用上面变量,一定有一个或多个返回值,返回值可能有命名,也可能无命名,但一定有括号包住返回值
const functionPattern = new RegExp(
`func\\s+([a-zA-Z0-9_]+)\\s*\\(${functionParamsRegStr}\\)\\s*\\((.*?)\\)\\s*{[\\s\\S]*?}`,
'm',
);
const match = functionPattern.exec(functionDefinition);

if (match) {
matched = true;
params = splitParams(functionParamsStr, languageSettings);

const paramsString = match[2];
const paramsArray = paramsString.split(',');
for (const param of paramsArray) {
const [name, type] = param.trim().split(' ');
params[name] = { type, description: '' };
}

const returnString = match[3];
const returnArray = returnString.split(',');
let defaultCount = 0;
for (const ret of returnArray) {
const [name, type] = ret.trim().split(' ');
returnType[name || `${defaultReturnName}${defaultCount++}`] = { type, description: '' };
}
const returnString = match[2] || '';
returnType = splitParams(returnString, languageSettings);
}

return { matched, returnType, params };
Expand All @@ -87,31 +88,26 @@ function matchBindTypeFunction(
returnType: ReturnInfo;
params: ParamsInfo;
} {
const { defaultReturnName = 'default' } = languageSettings;
const returnType: ReturnInfo = {};
let returnType: ReturnInfo = {};
let matched = false;
const params: ParamsInfo = {};
let params: ParamsInfo = {};

// 绑定到类型的函数,可能有参数,可能有一个或多个返回值,返回值可能有命名
const functionPattern =
/func\s+\((.*?)\s*\*\s*([a-zA-Z0-9_]+)\)\s*([a-zA-Z0-9_]+)\s*\((.*?)\)\s*\((.*?)\)\s*{[\s\S]*?}/m;
const functionParamsStr = extractFunctionParamsString(functionDefinition);
const functionParamsRegStr = escapeRegexString(functionParamsStr);
// 绑定到类型的函数,参数使用上面变量,可能有一个或多个返回值,返回值可能有命名
const functionPattern = new RegExp(
`func\\s+([a-zA-Z0-9_]+)\\s*\\(${functionParamsRegStr}\\)\\s*\\((.*?)\\)\\s*{[\\s\\S]*?}`,
'm',
);

const match = functionPattern.exec(functionDefinition);
if (match) {
matched = true;
const paramsString = match[4];
const paramsArray = paramsString.split(',');
for (const param of paramsArray) {
const [name, type] = param.trim().split(' ');
params[name] = { type, description: '' };
}
const functionParamsStr = match[4] || '';
params = splitParams(functionParamsStr, languageSettings);

const returnString = match[5];
const returnArray = returnString.split(',');
for (const ret of returnArray) {
const [name, type] = ret.trim().split(' ');
returnType[name || defaultReturnName] = { type, description: '' };
}
returnType = splitParams(returnString, languageSettings);
}

return { matched, returnType, params };
Expand All @@ -133,18 +129,14 @@ function matchFunction(
let params: ParamsInfo = {};

const matchers = [matchNormalFunction, matchMultiReturnTypeFunction, matchBindTypeFunction];
const result = matchers
.map((matcher) => matcher(functionDefinition, languageSettings))
.find((result) => result.matched);
if (result?.matched) {
matched = result.matched;
params = result.params;
if (
Object.keys(result.returnType).length === 1 &&
defaultReturnName in result.returnType &&
result.returnType?.[defaultReturnName]?.type !== undefined
) {

for (const matcher of matchers) {
const result = matcher(functionDefinition, languageSettings);
if (result.matched) {
matched = result.matched;
params = result.params;
returnType = result.returnType;
break;
}
}

Expand Down
23 changes: 23 additions & 0 deletions src/function-params-parser/extractFunctionParamsString.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export function extractFunctionParamsString(functionDefinition: string): string {
let bracketCount = 0;
let paramsStartIndex = 0;
let paramsEndIndex = 0;

for (let i = 0; i < functionDefinition.length; i++) {
const char = functionDefinition[i];
if (char === '(') {
if (bracketCount === 0) {
paramsStartIndex = i + 1;
}
bracketCount++;
} else if (char === ')') {
bracketCount--;
if (bracketCount === 0) {
paramsEndIndex = i;
break;
}
}
}

return functionDefinition.slice(paramsStartIndex, paramsEndIndex);
}
46 changes: 46 additions & 0 deletions src/function-params-parser/go-splitParams.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { LanguageFunctionCommentSettings } from '@/typings/types';

import { ParamsInfo } from './types';

export function splitParams(
paramsStr: string,
languageSettings: LanguageFunctionCommentSettings,
): ParamsInfo {
const { defaultParamType = 'any', defaultReturnName = 'default' } = languageSettings;
let bracketCount = 0;
let paramStartIndex = 0;
let defaultCount = 0;
const params: ParamsInfo = {};
for (let i = 0; i < paramsStr?.length; i++) {
const char = paramsStr[i];
if (char === '(' || char === '[' || char === '{' || char === '<') {
bracketCount++;
} else if (char === ')' || char === ']' || char === '}' || char === '>') {
bracketCount--;
} else if (
(char === ',' && bracketCount === 0) ||
(i === paramsStr.length - 1 && bracketCount === 0)
) {
const paramStr = paramsStr
.slice(paramStartIndex, i === paramsStr.length - 1 ? i + 1 : i)
.trim();
const paramPattern = /^(\w+)?\s*(.*)$/;
const match = paramPattern.exec(paramStr);
if (match) {
let name, type;
if (match[2]) {
name =
match[1] ||
(defaultCount > 0 ? `${defaultReturnName}${defaultCount++}` : defaultReturnName);
type = match[2].trim() || defaultParamType;
} else {
name = defaultCount > 0 ? `${defaultReturnName}${defaultCount++}` : defaultReturnName;
type = match[1].trim() || defaultParamType;
}
params[name] = { type, description: '' };
}
paramStartIndex = i + 1;
}
}
return params;
}
17 changes: 17 additions & 0 deletions src/test/suite/go-functionComment.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { functionCommentTester } from './common/functionCommentTester';
import { TestInfo } from './types';

const testInfo: TestInfo = [
{
testName: 'go-function',
workspaceName: 'function-comment-for-go',
files: [
{ fileName: 'function-none-params-with-return.go', cursorLine: 0 },
{ fileName: 'function-none-params-without-return.go', cursorLine: 0 },
{ fileName: 'function-with-params-type-with-return.go', cursorLine: 0 },
{ fileName: 'function-with-params-type-without-return.go', cursorLine: 0 },
],
},
];

functionCommentTester(testInfo);
15 changes: 14 additions & 1 deletion src/utils/vscode-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,9 +273,22 @@ export function updateBlockCommentState(
return isInsideBlockComment;
}

export function generateFunctionComment(functionCommentInfo: FunctionCommentInfo): string {
export function generateFunctionComment(
functionCommentInfo: FunctionCommentInfo,
isOrigin: boolean = false,
): string {
const { paramsInfo, returnInfo, descriptionInfo } = functionCommentInfo;

if (isOrigin) {
if (
Object.keys(paramsInfo).length === 0 &&
Object.keys(returnInfo).length === 0 &&
!descriptionInfo
) {
return '';
}
}

let functionComment = '/**\n';
functionComment += ` * @description ${descriptionInfo}\n`;

Expand Down

0 comments on commit a45966a

Please sign in to comment.