package parser import ( "fmt" "os" "regexp" "strings" ) // ModuleInfo 表示 Erlang 模块信息 type ModuleInfo struct { ModuleName string Functions []ErlangFunction FilePath string } // ParseErlangFile 解析 Erlang 文件 func ParseErlangFile(filePath string) (*ModuleInfo, error) { content, err := os.ReadFile(filePath) if err != nil { return nil, fmt.Errorf("读取文件失败: %v", err) } return ParseErlangFileByBytes(filePath, content) } func ParseErlangFileByBytes(filePath string, content []byte) (*ModuleInfo, error) { lines := strings.Split(string(content), "\n") moduleInfo := &ModuleInfo{ FilePath: filePath, } // 提取模块名 moduleInfo.ModuleName = extractModuleName(lines) // 提取导出函数列表 exportedFunctions := extractExportedFunctions(lines) // 解析函数 moduleInfo.Functions = parseFunctions(lines, exportedFunctions) return moduleInfo, nil } // 提取模块名 func extractModuleName(lines []string) string { moduleRegex := regexp.MustCompile(`^-module\(([^)]+)\)\.`) for _, line := range lines { matches := moduleRegex.FindStringSubmatch(line) if len(matches) > 1 { return strings.Trim(matches[1], " '\"") } } return "" } // 提取导出函数列表 func extractExportedFunctions(lines []string) map[string]bool { exported := make(map[string]bool) // 匹配 -export([...]) 格式 exportRegex := regexp.MustCompile(`-export\(\[([^]]+)]\)`) functionRegex := regexp.MustCompile(`(\w+)/(\d+)`) for _, line := range lines { if matches := exportRegex.FindStringSubmatch(line); len(matches) > 1 { exports := strings.Split(matches[1], ",") for _, export := range exports { export = strings.TrimSpace(export) if funcMatches := functionRegex.FindStringSubmatch(export); len(funcMatches) > 2 { functionKey := fmt.Sprintf("%s/%s", funcMatches[1], funcMatches[2]) exported[functionKey] = true } } } } return exported } // 解析所有函数 func parseFunctions(lines []string, exportedFunctions map[string]bool) []ErlangFunction { var functions []ErlangFunction var currentComments []string inFunction := false var currentFunction ErlangFunction braceCount := 0 parenCount := 0 for i, line := range lines { trimmedLine := strings.TrimSpace(line) // 收集注释 if strings.HasPrefix(trimmedLine, "%") { comment := strings.TrimPrefix(trimmedLine, "%") comment = strings.TrimSpace(comment) currentComments = append(currentComments, comment) continue } // 检测函数开始 if !inFunction && isFunctionStart(trimmedLine) { if funcInfo := parseFunctionSignature(trimmedLine); funcInfo != nil { inFunction = true currentFunction = *funcInfo currentFunction.Comments = append([]string(nil), currentComments...) currentFunction.StartLine = i + 1 currentFunction.Export = isExported(currentFunction, exportedFunctions) // 重置注释收集 currentComments = nil braceCount = 0 parenCount = 0 } } if inFunction { // 统计括号和花括号来检测函数结束 braceCount += strings.Count(line, "{") - strings.Count(line, "}") parenCount += strings.Count(line, "(") - strings.Count(line, ")") // 函数结束条件:行以 . 结束,且括号和花括号匹配 if strings.HasSuffix(trimmedLine, ".") && braceCount == 0 && parenCount == 0 { currentFunction.EndLine = i + 1 functions = append(functions, currentFunction.ParseComments()) inFunction = false currentFunction = ErlangFunction{} } // 函数结束条件:行以 ; 结束,且括号和花括号匹配 if strings.HasSuffix(trimmedLine, ";") && braceCount == 0 && parenCount == 0 { currentFunction.EndLine = i + 1 functions = append(functions, currentFunction.ParseComments()) inFunction = false currentFunction = ErlangFunction{} } } else { // 不在函数中时,遇到非注释行就清空注释缓存 if trimmedLine != "" && !strings.HasPrefix(trimmedLine, "%") { currentComments = nil } } } return functions } // 检测是否为函数开始行 func isFunctionStart(line string) bool { // 匹配函数定义模式: 函数名(参数) -> 或 函数名(参数) when ... -> functionPattern := `^(\w+)\([^)]*\)\s*(when\s+[^>]*)?->` matched, _ := regexp.MatchString(functionPattern, line) return matched } // 解析函数签名 func parseFunctionSignature(line string) *ErlangFunction { // 匹配函数名和参数 pattern := `^(\w+)\(([^)]*)\)\s*(when\s+[^>]*)?->` regex := regexp.MustCompile(pattern) matches := regex.FindStringSubmatch(line) if len(matches) < 3 { return nil } function := &ErlangFunction{ Name: matches[1], } // 解析参数 params := strings.Split(matches[2], ",") for _, param := range params { param = strings.TrimSpace(param) if param != "" { function.Parameters = append(function.Parameters, param) } } function.Arity = len(function.Parameters) return function } // 检查函数是否被导出 func isExported(function ErlangFunction, exportedFunctions map[string]bool) bool { key := fmt.Sprintf("%s/%d", function.Name, function.Arity) return exportedFunctions[key] }