Go提供了ast库,用于将源代码转换成抽象语法树,从而为元编程提供了支持。

一、方法实现

package util

import (
    "fmt"
    "go-less/exception"
    "go/ast"
    "go/parser"
    "go/token"
    "io/ioutil"
    "strings"
)

// ASTFunction AST函数对象
type ASTFunction struct {
    Package  string              // 函数所在包
    Name     string              // 函数名字
    Exported bool                // 是否向外公开
    Recv     []map[string]string // 函数接收者
    Params   []map[string]string // 函数参数
    Results  []map[string]string // 函数返回值
}

// Println Debug Only
func (f ASTFunction) Println() {
    fmt.Print("所在包:" + f.Package)
    fmt.Print(",是否公开:", f.Exported)
    fmt.Print(",函数名字:" + f.Name)
    fmt.Print(",函数接收者:")
    fmt.Print(f.Recv)
    fmt.Print(",函数参数:")
    fmt.Print(f.Params)
    fmt.Print(",函数返回值:")
    fmt.Print(f.Results)
    fmt.Println()
}

// 1.数组或者切片类型           √
// 2.用户定义的类型或基本数据类型 √
// 3.选择表达式              √
// 4.指针表达式              √
// 5.映射类型                   √
// 6.函数类型                   √
// 7.管道类型                   √
// 8.匿名结构体              ×
func exprToTypeStringRecursively(expr ast.Expr) string {

    if arr, ok := expr.(*ast.ArrayType); ok {
        if arr.Len == nil {
            return "[]" + exprToTypeStringRecursively(arr.Elt)
        } else if lit, ok := arr.Len.(*ast.BasicLit); ok {
            return "[" + lit.Value + "]" + exprToTypeStringRecursively(arr.Elt)
        } else {
            // TODO 完备性检查
            panic(1)
        }
    }
    if _, ok := expr.(*ast.InterfaceType); ok {
        return "interface{}"
    }
    if indent, ok := expr.(*ast.Ident); ok {
        return indent.Name
    } else if selExpr, ok := expr.(*ast.SelectorExpr); ok {
        return exprToTypeStringRecursively(selExpr.X) + "." + exprToTypeStringRecursively(selExpr.Sel)
    } else if star, ok := expr.(*ast.StarExpr); ok {
        return "*" + exprToTypeStringRecursively(star.X)
    } else if mapType, ok := expr.(*ast.MapType); ok {
        return "map[" + exprToTypeStringRecursively(mapType.Key) + "]" + exprToTypeStringRecursively(mapType.Value)
    } else if funcType, ok := expr.(*ast.FuncType); ok {
        params := parseFieldList(funcType.Params)
        results := parseFieldList(funcType.Results)
        tf := func(data []map[string]string) string {
            ts := make([]string, 0)
            for _, v := range data {
                ts = append(ts, v["Name"]+" "+v["Type"])
            }
            return strings.Join(ts, ",")
        }
        return "func(" + tf(params) + ")" + " (" + tf(results) + ")"
    } else if chanType, ok := expr.(*ast.ChanType); ok {
        if chanType.Dir == ast.SEND {
            return "chan <- " + exprToTypeStringRecursively(chanType.Value)
        } else if chanType.Dir == ast.RECV {
            return "<- chan " + exprToTypeStringRecursively(chanType.Value)
        } else {
            return "chan " + exprToTypeStringRecursively(chanType.Value)
        }
    }
    //ast.StructType    不考虑这个类型
    // TODO 完备性检查
    fmt.Println(expr)
    panic(1)
}

func parseFieldList(fList *ast.FieldList) []map[string]string {
    dst := make([]map[string]string, 0)
    if fList != nil {
        list := fList.List
        for i := 0; i < len(list); i++ {
            names := list[i].Names
            typeStr := exprToTypeStringRecursively(list[i].Type)
            for j := 0; j < len(names); j++ {
                dst = append(dst, map[string]string{
                    "Name": names[j].Name,
                    "Type": typeStr,
                })
            }
            if len(names) == 0 {
                dst = append(dst, map[string]string{
                    "Name": "",
                    "Type": typeStr,
                })
            }
        }
    }
    return dst
}
func CreateASTFunctionFromASTNode(node ast.Node, pack string) *ASTFunction {
    fn, ok := node.(*ast.FuncDecl)
    if ok {
        astFunction := ASTFunction{
            Package:  pack,
            Name:     fn.Name.Name,
            Exported: fn.Name.IsExported(),
        }
        astFunction.Params = parseFieldList(fn.Type.Params)
        astFunction.Results = parseFieldList(fn.Type.Results)
        astFunction.Recv = parseFieldList(fn.Recv)
        return &astFunction
    }
    return nil
}
func CreateASTFunctionsFromFile(target string) []*ASTFunction {
    rawData, err := ioutil.ReadFile(target)
    if err != nil {
        panic(exception.NewDefaultException(exception.IOException, err.Error()))
    }
    fileSet := token.NewFileSet()
    file, err := parser.ParseFile(fileSet, "", string(rawData), 0)
    if err != nil {
        panic(exception.NewDefaultException(exception.ASTParseException, err.Error()))
    }
    pack := ""
    ast.Print(fileSet, file)

    functions := make([]*ASTFunction, 0)
    ast.Inspect(file, func(node ast.Node) bool {
        pk, ok := node.(*ast.Ident)
        if ok {
            if pack == "" {
                pack = pk.Name
            }
        }
        fn := CreateASTFunctionFromASTNode(node, pack)
        if fn != nil {
            functions = append(functions, fn)
        }
        return true
    })
    return functions
}

二、测试代码

functions := util.CreateASTFunctionsFromFile("C:\\Program Files\\Go\\src\\go\\ast\\ast.go")
for _, f := range functions {
    f.Println()
}

三、运行结果

所在包:ast,是否公开:true,函数名字:Pos,函数接收者:[map[Name:c Type:*Comment]],函数参数:[],函数返回值:[map[Name: Type:token.Pos]]
所在包:ast,是否公开:true,函数名字:End,函数接收者:[map[Name:c Type:*Comment]],函数参数:[],函数返回值:[map[Name: Type:token.Pos]]
所在包:ast,是否公开:true,函数名字:Pos,函数接收者:[map[Name:g Type:*CommentGroup]],函数参数:[],函数返回值:[map[Name: Type:token.Pos]]
...
分类: 编程

20 条评论

נערות ליווי במרכז · 2022年4月20日 下午8:58

Next time I read a blog, Hopefully it does not disappoint me as much as this one. After all, Yes, it was my choice to read through, nonetheless I truly thought youd have something helpful to talk about. All I hear is a bunch of crying about something that you can fix if you were not too busy seeking attention.

נערות ליווי באתר ישראל לאדי · 2022年8月2日 上午9:18

Next time I read a blog, I hope that it wont disappoint me just as much as this particular one. After all, Yes, it was my choice to read through, nonetheless I actually believed you would have something helpful to talk about. All I hear is a bunch of moaning about something you could possibly fix if you werent too busy looking for attention.

bahis · 2022年8月18日 上午9:19

The best approach for the men which you can understand more about today. Marion Kriegh

bahis · 2022年8月20日 上午12:53

There is certainly a great deal to learn about this subject. I love all of the points you made. Stepha Garey Chaffin

bahis oyna · 2022年8月20日 上午5:38

This paragraph is really a fastidious one it assists new web visitors, who are wishing in favor of blogging. Chase Neveu

erotik · 2022年8月20日 上午11:23

If some one needs expert view concerning running a blog then i advise him/her to pay a visit this web site, Keep up the pleasant work. Damian Jiminian

bets10 giris · 2022年8月20日 下午8:54

Hey, thanks for the blog post. Thanks Again. Want more. Otis Bidell

liseli · 2022年8月23日 下午3:06

Make it easy for readers to share your blog posts using their favorite social media outlets. Marlin Nibler

שירותי נערות ליווי בתל אביב · 2022年8月24日 下午10:11

בעבר הלא רחוק חדרים לפי שעה בצפון הציעו חדר
קטן, במקומות נידחים שממש היה קשה לאתר אותם, רמת הניקיון שלהם הייתה מתחת לכל ביקורת ובחדר
הייתה רק מיטה עם מצעים עליה. מכאן,
אנו למדים כי עיסוי אינו רק בילוי
של שעה עם מומחה/ית במגע אם
אתם גברים הגרים באזור חולון, מומלץ להזמין עיסוי מגבר לגבר בחולון.
מאמינים כי פוליפפטידים אלה הם מתווכים של מערכת
בקרת הכאב (משכך כאבים טבעי). שרירים עייפים מקבלים חיים חדשים, מקומות תפוסים משתחררים ואיתם כאבים ישנים שכבר שכחתם.
עיסוי שוודי – עיסוי קלאסי ואהוב,
משחרר שרירים תפוסים ומרגיע את הנפש.
עיסוי מקצועי בראשון לציון מסאג’
מקצועי בראשון לציון לחובבי עיסוי
אמיתיים – מסאז’ שוודי כללי לכל הגוף,
כולל עיסוי כפות רגליים ממעסה מקצועית, מדופלמת ובעלת ניסיון רב שנים.
גרסה חזקה יותר של עיסוי שוודי מכונה עיסוי רקמות עמוק, ומטרתה לסייע ולשחרר את השרירים הממוקמים בשכבות התחתונות יותר של עורנו,
והעיסוי המקצועי בדרך-כלל כולל שימוש
בעוצמות חזקות יותר, ואף שימוש במפרקים ובאמות.

עיסוי תאילנדי ברמת הגולן עיסוי נפוץ נוסף שבו המעסה משתמש בכובד גופו לבצע לחיצות שמטרתן לשחרר את השרירים של המטופל.

נערות ליווי בתל אביב · 2022年8月24日 下午11:20

סטליס רהיטים מתמחים בייצור רהיטים לבית ולגן תוך דגש על איכות הרהיט, מראהו ומחירו!

בפורטל Xfinder תוכלו למצוא מידע נרחב
על מבחר השירותים כאשר כולם נבחרו בקפידה תוך
דגש על פרמטרים חשובים כמו: איכות
בשירות, ניקיון והיגיינה, מחירים, וחלוקה לפי קטגוריות ומקומות בארץ.

כאשר תיכנסו לדירות דיסקרטיות בחיפה תוכלו מייד להבחין שהן מעוצבות בהקפדה ושרמת
הניקיון בהן גבוהה מאוד. דירות דיסקרטיות בנתניה זו
התשובה שלכם והפתרון המושלם.
מצד שני, בזכות האתר דירות דיסקרטיות לכולם כבר לא צריך אפילו להתאמץ.

בואו להגשים את החלומות הרטובים ביותר באמצעות
דירות דיסקרטיות. בוא ותכיר נערות ליווי בהוד השרון שיגיעו אליך לחדר ואפילו
כאלה שישמחו לארח אותך בדירתן הפרטית ב-100% דיסקרטיות.

נערות ליווי בירושלים להזמנה עד אליך – בכל שעה ביום.
חיפוש מהיר באינטרנט יביא לך תוצאות של מאות נשים חושניות הנמצאות בירושלים ונערות ליווי שמוכנות לקריאתך ויגיעו עד אליך תוך זמן קצר.

את בוחרת מה לקנות, מתי לקנות וכמה לקנות ואנחנו אורזים ושולחים
לך הכל עד הבית!

king putin · 2022年9月2日 下午7:54

Good handcuffs made of stainless steel. My product quality is primarily due to the professjional quality steel used for their manufacture. Noe Muri

freespin · 2022年9月2日 下午8:39

Dead indited content, Really enjoyed looking through. Salvatore Ransone

king putin · 2022年9月4日 下午11:36

Your website is extraordinary. It is actually rapid and also regards with respect to making it possible for remarks. Coleman Noeldner

russian bet · 2022年9月6日 下午8:41

Your means of telling all in this article is really good, all be able to without difficulty know it, Thanks a lot. Hipolito Filson

Looking for sex tonight in your area · 2022年9月6日 下午11:10

I like this post, enjoyed this one thank you for posting. Allen Kay

russian bet · 2022年9月7日 上午3:26

Great post. I will be dealing with many of these issues as well.. Errol Wienert

freespin · 2022年9月7日 下午9:13

I think that everything said was actually very reasonable. Frances Mendolia

sikis · 2022年9月8日 上午3:32

Hi there friends, how is everything, and what you wish for to say regarding this piece of writing, in my view its genuinely amazing designed for me. Clyde Minicucci

Cindie Wiinikainen · 2022年9月15日 下午5:23

I would considering to thank you for the efforts youve put in penning this blog. I really wish to view the similar high-grade content from you vanguard upon as well. In truth, your creative writing abilities has provoked me to acquire my own, personal blog now

Malisa Heimerdinger · 2022年9月16日 上午1:57

I cannot thank you enough for the article post.Much thanks again. Will read on…

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注