初版提交
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ErlangFunction 表示 Erlang 函数
|
||||
type ErlangFunction struct {
|
||||
Name string // 函数名
|
||||
Arity int // 参数个数
|
||||
Parameters []string // 参数列表
|
||||
Comments []string // 函数注释
|
||||
StartLine int // 函数起始行号
|
||||
EndLine int // 函数结束行号
|
||||
Export bool // 是否被导出
|
||||
KeyMap map[string]map[string][]string // 注解
|
||||
}
|
||||
|
||||
func (function *ErlangFunction) ParseComments() ErlangFunction {
|
||||
var keyMap = make(map[string]map[string][]string)
|
||||
//var parameters = make(map[string]string)
|
||||
|
||||
for _, comment := range function.Comments {
|
||||
// 匹配注解格式: @keyword(param1=value1, param2=value2)
|
||||
re := regexp.MustCompile(`@(\w+)(?:\s*\((.*)\))?`)
|
||||
matches := re.FindStringSubmatch(comment)
|
||||
|
||||
if len(matches) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
keyword := matches[1]
|
||||
parameters, is := keyMap[keyword]
|
||||
if !is {
|
||||
parameters = make(map[string][]string)
|
||||
}
|
||||
|
||||
// 解析参数
|
||||
if len(matches) > 2 && matches[2] != "" {
|
||||
paramsStr := matches[2]
|
||||
paramRe := regexp.MustCompile(`(\w+)\s*=\s*('[^']*'|"[^"]*"|[^,]+)`)
|
||||
paramMatches := paramRe.FindAllStringSubmatch(paramsStr, -1)
|
||||
|
||||
for _, match := range paramMatches {
|
||||
if len(match) >= 3 {
|
||||
value := strings.TrimSpace(match[2])
|
||||
// 移除引号
|
||||
value = strings.Trim(value, `'"`)
|
||||
parameters[strings.TrimSpace(match[1])] = append(parameters[strings.TrimSpace(match[1])], value)
|
||||
}
|
||||
}
|
||||
}
|
||||
keyMap[keyword] = parameters
|
||||
}
|
||||
function.KeyMap = keyMap
|
||||
return *function
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
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)
|
||||
}
|
||||
|
||||
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]
|
||||
}
|
||||
Reference in New Issue
Block a user