179 lines
4.7 KiB
Go
179 lines
4.7 KiB
Go
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{}
|
|
}
|
|
} 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]
|
|
}
|