Skip to content

Instantly share code, notes, and snippets.

@zephyrtronium
Created August 11, 2013 08:40
Show Gist options
  • Select an option

  • Save zephyrtronium/6204018 to your computer and use it in GitHub Desktop.

Select an option

Save zephyrtronium/6204018 to your computer and use it in GitHub Desktop.
go run scnt.go packages...
package main
import (
"fmt"
"go/ast"
"go/build"
"go/parser"
"go/token"
"os"
"path/filepath"
"strings"
)
type visitor struct {
stmts, decls int
comments int
bs, be, bd int
es int
}
func (v *visitor) Visit(node ast.Node) ast.Visitor {
switch node.(type) {
case *ast.BadStmt:
v.bs++
return nil
case *ast.BadExpr:
v.be++
return nil
case *ast.BadDecl:
v.bd++
return nil
case *ast.EmptyStmt:
v.es++
return nil
case *ast.ExprStmt, *ast.SendStmt, *ast.IncDecStmt, *ast.AssignStmt,
*ast.GoStmt, *ast.DeferStmt, *ast.ReturnStmt, *ast.BranchStmt,
*ast.IfStmt, *ast.CaseClause, *ast.SwitchStmt, *ast.TypeSwitchStmt,
*ast.CommClause, *ast.SelectStmt, *ast.ForStmt, *ast.RangeStmt:
v.stmts++
case *ast.ImportSpec, *ast.ValueSpec, *ast.TypeSpec, *ast.FuncDecl:
v.decls++
case *ast.CommentGroup:
v.comments++
return nil
}
return v
}
func filter(fi os.FileInfo) bool {
s := fi.Name()
return len(s) > 3 && strings.EqualFold(s[len(s)-3:], ".go")
}
const sep = string(filepath.Separator)
func walker(base string, trim int, args *[]string) filepath.WalkFunc {
return func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
if len(path) == len(base) {
return nil
}
if len(path) > trim {
path = path[trim:]
}
for _, part := range strings.Split(path, sep) {
if strings.HasPrefix(part, ".") || strings.HasPrefix(part, "_") {
return nil
}
}
if err != nil {
return filepath.SkipDir
}
*args = append(*args, path)
}
return nil
}
}
func main() {
args := os.Args[1:]
for i, dir := range args {
if dir == "..." {
// all packages
args = args[:0]
base := filepath.Join(build.Default.GOROOT, "src", "pkg")
filepath.Walk(base, walker(base, len(base)+len(sep), &args))
for _, gopath := range filepath.SplitList(build.Default.GOPATH) {
base := filepath.Join(gopath, "src")
filepath.Walk(base, walker(base, len(base)+len(sep), &args))
}
} else if filepath.Base(dir) == "..." {
copy(args[i:], args[i+1:])
args = args[:len(args)-1]
pkg, err := build.Import(filepath.Dir(dir), ".", build.FindOnly)
if err != nil {
panic(err)
}
base := pkg.Dir
filepath.Walk(base, walker(base, len(pkg.Root)+5, &args))
}
}
for _, dir := range args {
path, err := build.Import(dir, ".", build.FindOnly)
if err != nil {
panic(err)
}
pkgs, err := parser.ParseDir(token.NewFileSet(), path.Dir, filter, parser.ParseComments|parser.AllErrors)
if err != nil {
fmt.Println(err)
if len(pkgs) == 0 {
fmt.Println("")
}
}
for pkg, nn := range pkgs {
if !strings.HasSuffix(dir, pkg) {
fmt.Println(filepath.ToSlash(dir), "("+pkg+"):")
} else {
fmt.Println(filepath.ToSlash(dir) + ":")
}
v := visitor{}
ast.Walk(&v, nn)
fmt.Printf("%d statements, %d decls\n%d comments\n", v.stmts, v.decls, v.comments)
if v.bs+v.be+v.bd > 0 {
fmt.Printf("%d bad statements, %d bad expressions, %d bad decls\n", v.bs, v.be, v.bd)
}
if v.es > 0 {
fmt.Printf("%d empty statements\n", v.es)
}
fmt.Println()
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment