func filter()

in unix/internal/mkmerge/mkmerge.go [139:217]


func filter(src interface{}, keep filterFn) ([]byte, error) {
	// Parse the src into an ast
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, "", src, parser.ParseComments)
	if err != nil {
		return nil, err
	}
	cmap := ast.NewCommentMap(fset, f, f.Comments)

	// Group const/type specs on adjacent lines
	var groups specGroups = make(map[string]int)
	var groupID int

	decls := f.Decls
	f.Decls = f.Decls[:0]
	for _, decl := range decls {
		switch decl := decl.(type) {
		case *ast.GenDecl:
			// Filter imports, consts, types, vars
			specs := decl.Specs
			decl.Specs = decl.Specs[:0]
			for i, spec := range specs {
				elem, err := newCodeElem(decl.Tok, spec)
				if err != nil {
					return nil, err
				}

				// Create new group if there are empty lines between this and the previous spec
				if i > 0 && fset.Position(specs[i-1].End()).Line < fset.Position(spec.Pos()).Line-1 {
					groupID++
				}

				// Check if we should keep this spec
				if keep(elem) {
					decl.Specs = append(decl.Specs, spec)
					groups.add(elem.src, groupID)
				}
			}
			// Check if we should keep this decl
			if len(decl.Specs) > 0 {
				f.Decls = append(f.Decls, decl)
			}
		case *ast.FuncDecl:
			// Filter funcs
			elem, err := newCodeElem(token.FUNC, decl)
			if err != nil {
				return nil, err
			}
			if keep(elem) {
				f.Decls = append(f.Decls, decl)
			}
		}
	}

	// Filter file level comments
	if cmap[f] != nil {
		commentGroups := cmap[f]
		cmap[f] = cmap[f][:0]
		for _, cGrp := range commentGroups {
			if keep(codeElem{token.COMMENT, cGrp.Text()}) {
				cmap[f] = append(cmap[f], cGrp)
			}
		}
	}
	f.Comments = cmap.Filter(f).Comments()

	// Generate code for the filtered ast
	var buf bytes.Buffer
	if err = format.Node(&buf, fset, f); err != nil {
		return nil, err
	}

	groupedSrc, err := groups.filterEmptyLines(&buf)
	if err != nil {
		return nil, err
	}

	return filterImports(groupedSrc)
}