Files
complie-erlang/parser/erlang_module.go
T
2025-10-03 00:54:22 +08:00

187 lines
5.0 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{}
}
// 函数结束条件:行以 ; 结束,且括号和花括号匹配
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]
}