Files
squirrelVsis/src/functionExtractor.ts
2025-09-17 10:54:25 +08:00

315 lines
11 KiB
TypeScript

import * as vscode from 'vscode';
import { FileModel, FileEntry } from './model';
// 性能监控类
export class PerformanceMonitor {
private extractionTimes: number[] = [];
private fileCounts: number[] = [];
private functionCounts: number[] = [];
// 记录函数提取性能
recordExtraction(timeMs: number, fileCount: number, functionCount: number): void {
this.extractionTimes.push(timeMs);
this.fileCounts.push(fileCount);
this.functionCounts.push(functionCount);
}
// 获取平均提取时间
getAverageExtractionTime(): number {
if (this.extractionTimes.length === 0) return 0;
const sum = this.extractionTimes.reduce((a, b) => a + b, 0);
return sum / this.extractionTimes.length;
}
// 获取平均每文件处理时间
getAverageTimePerFile(): number {
if (this.fileCounts.length === 0 || this.extractionTimes.length === 0) return 0;
const totalTime = this.extractionTimes.reduce((a, b) => a + b, 0);
const totalFiles = this.fileCounts.reduce((a, b) => a + b, 0);
return totalFiles > 0 ? totalTime / totalFiles : 0;
}
// 获取性能统计信息
getStats(): {
averageExtractionTime: number;
averageTimePerFile: number;
totalExtractions: number;
} {
return {
averageExtractionTime: this.getAverageExtractionTime(),
averageTimePerFile: this.getAverageTimePerFile(),
totalExtractions: this.extractionTimes.length
};
}
// 清除统计数据
clearStats(): void {
this.extractionTimes = [];
this.fileCounts = [];
this.functionCounts = [];
}
}
// 函数信息接口
export interface FunctionInfo {
name: string; // 函数名称
filePath: string; // 文件路径
lineNumber: number; // 行号
parameters: string[]; // 参数列表
signature: string; // 函数签名
}
// 函数缓存管理类
export class FunctionCacheManager {
private functionCache = new Map<string, FunctionInfo[]>();
private fileProcessed = new Set<string>();
// 添加函数信息到缓存
addFunctions(filePath: string, functions: FunctionInfo[]): void {
this.functionCache.set(filePath, functions);
this.fileProcessed.add(filePath);
}
// 获取文件的函数信息
getFunctions(filePath: string): FunctionInfo[] | undefined {
return this.functionCache.get(filePath);
}
// 检查文件是否已处理
isFileProcessed(filePath: string): boolean {
return this.fileProcessed.has(filePath);
}
// 清除特定文件的缓存
clearFileCache(filePath: string): void {
this.functionCache.delete(filePath);
this.fileProcessed.delete(filePath);
}
// 清除所有缓存
clearAllCache(): void {
this.functionCache.clear();
this.fileProcessed.clear();
}
// 获取缓存统计信息
getCacheStats(): { fileCount: number; functionCount: number } {
let functionCount = 0;
for (const functions of this.functionCache.values()) {
functionCount += functions.length;
}
return {
fileCount: this.functionCache.size,
functionCount: functionCount
};
}
// 获取所有缓存的函数信息
getAllFunctions(): FunctionInfo[] {
const allFunctions: FunctionInfo[] = [];
for (const functions of this.functionCache.values()) {
allFunctions.push(...functions);
}
return allFunctions;
}
// 根据函数名称查找函数信息
findFunctionsByName(functionName: string): FunctionInfo[] {
const allFunctions = this.getAllFunctions();
return allFunctions.filter(func => func.name === functionName);
}
// 根据文件路径查找函数信息
findFunctionsByFilePath(filePath: string): FunctionInfo[] {
return this.getFunctions(filePath) || [];
}
}
// 函数提取器类
export class FunctionExtractor {
private cacheManager: FunctionCacheManager;
private isExtracting = false; // 防止重复提取
private performanceMonitor: PerformanceMonitor;
constructor() {
this.cacheManager = new FunctionCacheManager();
this.performanceMonitor = new PerformanceMonitor();
}
// 获取缓存管理器
getCacheManager(): FunctionCacheManager {
return this.cacheManager;
}
// 获取性能监控器
getPerformanceMonitor(): PerformanceMonitor {
return this.performanceMonitor;
}
// 检查是否正在提取函数
isExtractingFunctions(): boolean {
return this.isExtracting;
}
// 从文件内容中提取函数信息
extractFunctionsFromFile(filePath: string, content: string): FunctionInfo[] {
const functions: FunctionInfo[] = [];
const lines = content.split('\n');
// Squirrel语言函数定义的正则表达式
// 匹配类似: function functionName(param1, param2, ...)
const functionRegex = /^\s*function\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)/;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const match = line.match(functionRegex);
if (match) {
const functionName = match[1];
const paramsString = match[2];
const parameters = this.parseParameters(paramsString);
const functionInfo: FunctionInfo = {
name: functionName,
filePath: filePath,
lineNumber: i + 1,
parameters: parameters,
signature: `function ${functionName}(${paramsString})`
};
functions.push(functionInfo);
}
}
return functions;
}
// 解析参数字符串
private parseParameters(paramsString: string): string[] {
if (!paramsString.trim()) {
return [];
}
// 简单参数解析,按逗号分割
return paramsString.split(',').map(param => param.trim()).filter(param => param.length > 0);
}
// 批量提取函数信息
async extractFunctionsFromFiles(model: FileModel, filePaths: string[]): Promise<void> {
// 防止重复提取
if (this.isExtracting) {
console.log('函数提取已在进行中,跳过本次请求');
return;
}
this.isExtracting = true;
console.log(`开始提取 ${filePaths.length} 个文件中的函数信息`);
try {
// 分批处理文件,避免一次性处理过多文件
const batchSize = 50;
for (let i = 0; i < filePaths.length; i += batchSize) {
const batch = filePaths.slice(i, i + batchSize);
console.log(`正在处理批次 ${Math.floor(i/batchSize) + 1}/${Math.ceil(filePaths.length/batchSize)}: ${batch.length} 个文件`);
try {
// 并行处理批次中的文件
const promises = batch.map(async (filePath) => {
// 检查文件是否已处理过
if (this.cacheManager.isFileProcessed(filePath)) {
return;
}
try {
const entry = model.getFileEntry(filePath);
if (!entry) {
console.warn(`文件 ${filePath} 不存在于文件列表中`);
return;
}
// 如果文件内容尚未加载,则加载内容
let content = entry.content;
if (!content) {
content = await model.getFileContent(filePath);
}
if (content) {
const functions = this.extractFunctionsFromFile(filePath, content);
this.cacheManager.addFunctions(filePath, functions);
console.log(`文件 ${filePath} 提取到 ${functions.length} 个函数`);
}
} catch (error) {
console.error(`处理文件 ${filePath} 时出错:`, error);
}
});
// 等待批次处理完成
await Promise.all(promises);
console.log(`批次 ${Math.floor(i/batchSize) + 1} 处理完成`);
} catch (batchError) {
console.error(`处理批次 ${Math.floor(i/batchSize) + 1} 时出错:`, batchError);
}
}
console.log('所有文件的函数信息提取完成');
} finally {
this.isExtracting = false;
}
}
// 提取所有文件的函数信息
async extractAllFunctions(model: FileModel): Promise<void> {
const startTime = Date.now();
// 获取所有nut文件路径
const filePaths = model.getAllNutFiles();
console.log(`准备提取 ${filePaths.length} 个nut文件的函数信息`);
if (filePaths.length === 0) {
console.log('没有nut文件需要处理');
return;
}
await this.extractFunctionsFromFiles(model, filePaths);
// 输出缓存统计信息
const stats = this.cacheManager.getCacheStats();
const endTime = Date.now();
const durationMs = endTime - startTime;
const durationSec = durationMs / 1000; // 转换为秒
// 记录性能数据
this.performanceMonitor.recordExtraction(durationMs, filePaths.length, stats.functionCount);
console.log(`函数缓存统计: ${stats.fileCount} 个文件, ${stats.functionCount} 个函数`);
console.log(`函数提取完成,耗时: ${durationSec.toFixed(2)}`);
// 输出性能统计信息
const perfStats = this.performanceMonitor.getStats();
console.log(`性能统计: 平均提取时间 ${perfStats.averageExtractionTime.toFixed(2)}ms, 平均每文件处理时间 ${perfStats.averageTimePerFile.toFixed(2)}ms`);
}
// 更新特定文件的函数缓存
async updateFileCache(model: FileModel, filePath: string): Promise<void> {
console.log(`更新文件 ${filePath} 的函数缓存`);
try {
// 获取文件内容
const content = await model.getFileContent(filePath);
if (content) {
// 提取函数信息
const functions = this.extractFunctionsFromFile(filePath, content);
// 更新缓存
this.cacheManager.addFunctions(filePath, functions);
console.log(`文件 ${filePath} 的函数缓存已更新,提取到 ${functions.length} 个函数`);
} else {
console.warn(`无法获取文件 ${filePath} 的内容`);
}
} catch (error) {
console.error(`更新文件 ${filePath} 的函数缓存时出错:`, error);
}
}
}