golang的代码结构

golang的源码中含有go fmt,go build等工具,这些工具都会涉及到对golang的源码的文件进行相关分析,因此,可以从这些工具的源代码入手,看看golang的代码是如何解析的,并将代码中的相关信息进行提取。

分析go fmt工具,入口: src/cmd/gofmt. 从main函数入口,通过查看源代码发现,可以通过go/parser的parse函数对文档进行解析,解析后返回的是一个ast.File的实例

type File struct {
	Doc        *CommentGroup   // 文档注释
	Package    token.Pos       // package位置
	Name       *Ident          // package name
	Decls      []Decl          // top-level declarations; or nil
	Scope      *Scope          // package scope (this file only)
	Imports    []*ImportSpec   // imports in this file
	Unresolved []*Ident        // unresolved identifiers in this file
	Comments   []*CommentGroup // list of all comments in the source file
}

其中,关键点在Decls,里面包含有const、var定义,结构体、函数等信息。

golang的parser函数从上到下进行解析token包中可以查看到golang的关键字、运算符等相关信息。
decl中包括const、var;type(struct,interface);func

下面是一个从代码中获取相关信息的例子(获取struct和field的注释信息)

func docStruct(fp string) {
	fs, _ := parser.ParseFile(token.NewFileSet(), fp, nil, parser.ParseComments)
	if fs.Name != nil {
		if fs.Name.Obj != nil {
		}
	}

	for _, item := range fs.Decls {
		switch item.(type) {
		case *ast.BadDecl:
		case *ast.GenDecl:
			decl := item.(*ast.GenDecl)
			for _, subitem := range decl.Specs {

				switch decl.Tok {
				case token.IMPORT:
				case token.CONST:
				case token.TYPE:
					spec := subitem.(*ast.TypeSpec)
					switch spec.Type.(type) {
					case *ast.Ident:
					case *ast.ArrayType:
					case *ast.StructType:
						st := spec.Type.(*ast.StructType)
						sinfo := StructInfo{
							Name:   spec.Name.Name,
							Fields: StructFieldInfo(st),
						}
						dir := filepath.Dir(fp)
						if strings.HasSuffix(dir, "inner") {
							sinfo.Name = "inner_" + sinfo.Name
						} else if strings.HasSuffix(dir, "models") {
							sinfo.Name = "AE_" + sinfo.Name
						} else {
							continue
						}
						filestream.WriteString(fmt.Sprintf("UPDATE tableinfo SET pcomment='%s' WHERE pname='%s';\n", strings.TrimSpace(decl.Doc.Text()), sinfo.Name))
					case *ast.StarExpr:
					case *ast.ParenExpr:
					case *ast.SelectorExpr:
					}

				case token.VAR:
				}
			}

		case *ast.FuncDecl:
			//fmt.Println(item.(*ast.FuncDecl).Doc.Text())
		}
	}
}

type StructInfo struct {
	Name   string
	Fields []FieldInfo
}

type FieldInfo struct {
	Name    string
	Tag     string
	Comment string
}

func StructFieldInfo(sinfo *ast.StructType) []FieldInfo {
	if sinfo == nil || sinfo.Fields == nil {
		return []FieldInfo{}
	}
	result := make([]FieldInfo, 0)
	var info FieldInfo
	for _, field := range sinfo.Fields.List {
		info = FieldInfo{}
		for _, fnames := range field.Names {
			info.Name += fnames.Name
		}
		if field.Tag != nil {
			info.Tag = field.Tag.Value
		}
		if field.Comment != nil {
			info.Comment = strings.TrimSpace(field.Comment.Text())
		}
		result = append(result, info)
	}
	return result
}

//COMMENT ON COLUMN "private"."info"."Id" IS 'ceshi';

posted @ 2019-08-12 19:14  zhao379028604  阅读(819)  评论(0)    收藏  举报