// ParseTags will create a TagMap from comments given by // parameter func ParseTags(commentMap ast.CommentMap) *TagMap { tagMap := NewTagMap() for _, comment := range commentMap.Comments() { // split comment to lines lines := strings.Split(comment.Text(), "\n") for _, line := range lines { // if line does not match this regexp made by Miro do not read tags from line if !regexp.MustCompile(`(\@\S+)(:? ([\S]+))*`).Match([]byte(line)) { continue } line, tagName, _ := parseValue(line) // if there is a tag on the line read its parameters and their values if len(tagName) > 0 && tagName[0] == '@' { tag := NewTag(tagName) //fmt.Println("Tag Name:", tagName) // while there is some input check for parameters for line != "" { var parName, parVal string line, parName, parVal = parseValue(line) if parName != "" { //fmt.Println("Parameter name:", parName, "Parameter value", parVal) tag.Set(parName, parVal) } } // save tag to map tagMap.Set(tagName, tag) } } } return tagMap }
// ParseStruct will create a structure // with parameters given and return it func ParseStruct(spec *ast.TypeSpec, parent *ast.StructType, comments ast.CommentMap) *Structure { fMap := make(map[string]*StructField) for _, field := range parent.Fields.List { if len(field.Names) == 0 { continue } fMap[field.Names[0].Name] = ParseStructField(field, comments.Filter(field)) } s := NewStructure(parent, spec, fMap, ParseTags(comments)) return s }
// ParseFileAST creates a File parse with all necessary // structures. func ParseFileAST(name string, tree *ast.File, commentMap ast.CommentMap) (*File, error) { f := NewFile(name, tree) for _, i := range tree.Imports { f.AddImport(ParseImport(i, commentMap.Filter(i))) } for _, declaration := range tree.Decls { switch decValue := declaration.(type) { // catch only generic declarations case *ast.GenDecl: for _, spec := range decValue.Specs { switch specValue := spec.(type) { case *ast.TypeSpec: // all cases should pass in also specValue as // it is the underlying spec switch typeValue := specValue.Type.(type) { case *ast.StructType: f.AddStruct(ParseStruct(specValue, typeValue, commentMap.Filter(declaration))) case *ast.InterfaceType: f.AddInterface(ParseInterface(specValue, typeValue, commentMap.Filter(declaration))) } case *ast.ImportSpec: // just ignore for now case *ast.ValueSpec: f.AddConstant(ParseConstant(specValue, commentMap.Filter(declaration))) default: fmt.Println("Generic value not recognized: ", specValue) } } // catch function declarations case *ast.FuncDecl: fun := ParseFunction(decValue, commentMap.Filter(declaration)) if !fun.IsMethod() { // add the function to the top level map f.AddFunction(fun) } else { // add the function to the structure it belongs to if len(fun.parent.Recv.List) <= 0 { // TODO: no receiver defined report? break } // struct that should be assigned the method var structType *ast.StructType switch receiver := fun.parent.Recv.List[0].Type.(type) { // pointer receiver case *ast.StarExpr: structType = receiver.X.(*ast.Ident).Obj.Decl.(*ast.TypeSpec).Type.(*ast.StructType) // copy receiver case *ast.Ident: structType = receiver.Obj.Decl.(*ast.TypeSpec).Type.(*ast.StructType) } // search for the structures that receive the method // and bind it for _, st := range f.structures { if st.parent == structType { st.AddMethod(fun) } } } } } return f, nil }