Files
toolset/parser/go.go
2022-03-29 15:20:24 +08:00

430 lines
9.3 KiB
Go

package parser
import (
"fmt"
"strings"
)
// GoFileParser 非完整token实现
type GoFileParser struct {
PackageName string
PackageDoc string
Imports map[string]string
Types map[string]GoType
Funds map[string]GoFunc
}
func NewGoParserForDir(path string) map[string][]GoFileParser {
got := make(map[string][]GoFileParser)
for _, dir := range GetChildrenDir(path) {
arr := make([]GoFileParser, 0)
for _, file := range dir.GetFiles(".go") {
gof, _ := GetFileParser(file.Path)
arr = append(arr, gof)
}
got[dir.Path] = arr
}
return got
}
// go 关键字语法块
// map\[]\interface{}
func getWordsWitchGo(l *GoWords) GoWords {
var got = GoWords{
list: make([]*word, 0),
}
for offset := 0; offset < len(l.list); offset++ {
work := l.list[offset]
switch work.Ty {
case wordT_word:
switch work.Str {
case "interface":
if len(l.list) >= (offset+2) && l.list[offset+1].Str == "{" && l.list[offset+2].Str == "}" {
offset = offset + 2
work.Str = work.Str + "{}"
got.list = append(got.list, work)
} else {
got.list = append(got.list, work)
}
default:
got.list = append(got.list, work)
}
default:
got.list = append(got.list, work)
}
}
return got
}
func GetFileParser(path string) (GoFileParser, error) {
d := GoFileParser{
PackageName: "",
PackageDoc: "",
Imports: make(map[string]string),
Types: make(map[string]GoType),
Funds: make(map[string]GoFunc),
}
l := getWordsWitchFile(path)
l = getWordsWitchGo(&l)
lastDoc := ""
for offset := 0; offset < len(l.list); offset++ {
work := l.list[offset]
// 原则上, 每个块级别的作用域必须自己处理完, 返回的偏移必须是下一个块的开始
switch work.Ty {
case wordT_line:
lastDoc += work.Str
case wordT_division:
case wordT_doc:
lastDoc += work.Str
case wordT_word:
switch work.Str {
case "package":
d.PackageDoc = lastDoc
d.PackageName, offset = handlePackageName(l.list, offset)
lastDoc = ""
case "import":
var imap map[string]string
imap, offset = handleImports(l.list, offset)
for k, v := range imap {
d.Imports[k] = v
}
lastDoc = ""
case "type":
var imap GoType
imap, offset = handleTypes(l.list, offset, d)
imap.Doc = GoDoc(lastDoc)
d.Types[imap.Name] = imap
lastDoc = ""
case "func":
var gf GoFunc
gf, offset = handleFunds(l.list, offset)
d.Funds[gf.Name] = gf
lastDoc = ""
case "const":
_, offset = handleCosts(l.list, offset)
lastDoc = ""
case "var":
_, offset = handleVars(l.list, offset)
lastDoc = ""
default:
nl := l.list[offset:]
str := ""
for _, w := range nl {
str += w.Str
}
fmt.Println("文件块作用域似乎解析有错误", path, offset, str)
}
}
}
return d, nil
}
func handlePackageName(l []*word, offset int) (string, int) {
name, i := GetFistWordBehindStr(l[offset:], "package")
return name, offset + i
}
func getImport(sl []string) (string, string) {
if len(sl) == 2 {
return sl[0], sl[1][1 : len(sl[1])-1]
}
str := sl[0][1 : len(sl[0])-1]
temp := strings.Split(str, "/")
key := temp[len(temp)-1]
return key, str
}
func handleImports(l []*word, offset int) (map[string]string, int) {
newOffset := offset
imap := make(map[string]string)
var key, val string
ft, fti := GetFistStr(l[offset+1:])
if ft != "(" {
arr := make([]string, 0)
for i, w := range l[offset+fti:] {
if wordT_line == w.Ty {
newOffset = offset + fti + i
key, val = getImport(arr)
imap[key] = val
return imap, newOffset
}
if w.Ty == wordT_word {
arr = append(arr, w.Str)
}
}
} else {
st, et := GetBrackets(l[offset+1:], "(", ")")
st = st + offset + 1
et = et + offset + 1
newOffset = et
arr := make([]string, 0)
for _, w := range l[st : et+1] {
if wordT_line == w.Ty && len(arr) != 0 {
key, val = getImport(arr)
imap[key] = val
arr = make([]string, 0)
}
if w.Ty == wordT_word {
arr = append(arr, w.Str)
}
}
}
return imap, newOffset
}
type GoType struct {
Doc GoDoc
Name string
Attrs map[string]GoTypeAttr
}
type GoTypeAttr struct {
Name string
TypeName string
TypeAlias string
TypeImport string
InPackage bool // 是否本包的引用
Tag map[string]TagDoc
}
type TagDoc string
func (t TagDoc) Get(num int) string {
s := string(t)
sr := strings.Split(s, ",")
return strings.Trim(sr[num], " ")
}
func (t TagDoc) Count() int {
s := string(t)
sr := strings.Split(s, ",")
return len(sr)
}
type GoDoc string
// HasAnnotation 是否存在某个注解
func (d GoDoc) HasAnnotation(check string) bool {
return strings.Index(string(d), check) != -1
}
func (d GoDoc) GetAlias() string {
l := GetWords(string(d)[2:])
num := 0
for i, w := range l {
if w.Ty == wordT_word {
if w.Str == "Bean" {
if l[i-1].Str == "@" {
num = 1
}
} else if num == 1 {
return w.Str[1 : len(w.Str)-1]
}
}
}
return ""
}
// IsPointer 普通指针
func (receiver GoTypeAttr) IsPointer() bool {
return receiver.TypeName[0:1] == "*"
}
func (receiver GoTypeAttr) HasTag(name string) bool {
for s := range receiver.Tag {
if s == name {
return true
}
}
return false
}
// 组装成数组, 只限name type other\n结构
func getArrGoWord(l []*word) [][]string {
got := make([][]string, 0)
arr := GetArrWord(l)
for _, i := range arr {
lis := i[len(i)-1].Str
if lis[0:1] == "`" && len(i) >= 3 {
ty := ""
for in := 1; in < len(i)-1; in++ {
if i[in].Ty != wordT_doc {
ty = ty + i[in].Str
}
}
got = append(got, []string{i[0].Str, ty, lis})
}
}
return got
}
// 把go结构的tag格式化成数组 source = `inject:"" json:"orm"`
func getArrGoTag(source string) [][]string {
tagStr := source[1 : len(source)-1]
wl := GetWords(tagStr)
// 每三个一组
i := 0
got := make([][]string, 0)
arr := make([]string, 0)
for _, w := range wl {
if w.Ty == wordT_word {
arr = append(arr, w.Str)
i++
if i >= 2 {
i = 0
got = append(got, arr)
arr = make([]string, 0)
}
}
}
return got
}
func handleTypes(l []*word, offset int, d GoFileParser) (GoType, int) {
newOffset := offset
nl := l[offset:]
got := GoType{
Doc: "",
Name: "",
Attrs: map[string]GoTypeAttr{},
}
ok, off := GetLastIsIdentifier(nl, "{")
if ok {
// 新结构
var i int
got.Name, i = GetFistWordBehindStr(nl, "type")
nl = nl[i+1:]
st, et := GetBrackets(nl, "{", "}")
newOffset = offset + i + et + 1
nl := nl[st+1 : et]
arrLn := getArrGoWord(nl)
for _, wordAttrs := range arrLn {
// 获取属性信息
// TODO 当前仅支持有tag的
if len(wordAttrs) == 3 && strings.Index(wordAttrs[2], "`") == 0 {
attr := GoTypeAttr{
Name: wordAttrs[0],
TypeName: wordAttrs[1],
Tag: map[string]TagDoc{},
}
getTypeAlias(wordAttrs[1], d, &attr)
// 解析 go tag
tagArr := getArrGoTag(wordAttrs[2])
for _, tagStrArr := range tagArr {
td := tagStrArr[1]
attr.Tag[tagStrArr[0]] = TagDoc(td[1 : len(td)-1])
}
got.Attrs[attr.Name] = attr
}
}
} else {
// struct 别名
got.Name, _ = GetFistWordBehindStr(nl, "type")
newOffset = off + offset
}
return got, newOffset
}
// 根据属性声明类型或者类型的引入名称
func getTypeAlias(str string, d GoFileParser, attr *GoTypeAttr) {
wArr := GetWords(str)
wf := wArr[0]
if wf.Ty == wordT_word || wf.Str == "*" {
if (wf.Str == "*" && len(wArr) >= 3) || (wf.Str != "*" && len(wArr) >= 2) {
attr.TypeAlias, _ = GetFistWord(wArr)
attr.TypeImport = d.Imports[attr.TypeAlias]
return
}
}
// 本包
attr.TypeAlias = d.PackageName
attr.TypeImport = "" // TODO
attr.InPackage = true
}
type GoFunc struct {
Name string
Stu string
}
func handleFunds(l []*word, offset int) (GoFunc, int) {
ft, _ := GetFistStr(l[offset+1:])
name := ""
if ft != "(" {
// 普通函数
var i int
name, i = GetFistWordBehindStr(l[offset:], "func")
offset = offset + i
_, et := GetBrackets(l[offset:], "(", ")")
offset = offset + et
} else {
// 结构函数
_, et := GetBrackets(l[offset:], "(", ")")
offset = offset + et
name, _ = GetFistWord(l[offset:])
_, et = GetBrackets(l[offset:], "(", ")")
offset = offset + et
}
// 排除返回值的interface{}
st, et := GetBrackets(l[offset:], "{", "}")
interCount := 0
for _, w := range l[offset : offset+st] {
if w.Str == "interface" {
interCount++
}
}
if interCount != 0 {
for i := 0; i <= interCount; i++ {
_, et := GetBrackets(l[offset:], "{", "}")
offset = offset + et
}
} else {
offset = offset + et
}
return GoFunc{Name: name}, offset
}
func handleCosts(l []*word, offset int) (map[string]string, int) {
return handleVars(l, offset)
}
func handleVars(l []*word, offset int) (map[string]string, int) {
ft, _ := GetFistStr(l[offset+1:])
if ft != "(" {
ok, _ := GetLastIsIdentifier(l[offset:], "{")
if ok {
last := NextLine(l[offset:])
ss := l[offset+last-1]
if ss.Str == "{" {
nl := l[offset+last-1:]
offset = offset + last - 1
_, et := GetBrackets(nl, "{", "}")
return nil, offset + et + 1
} else {
nl := l[offset:]
_, et := GetBrackets(nl, "{", "}")
return nil, offset + et + 1
}
} else {
last := NextLine(l[offset:])
offset = offset + last
return nil, offset
}
} else {
nl := l[offset:]
_, et := GetBrackets(nl, "(", ")")
return nil, offset + et + 1
}
}