/parser/parser_redux.go
Go | 190 lines | 149 code | 22 blank | 19 comment | 16 complexity | cb42ee02e4d008b808137a923f51f338 MD5 | raw file
- // Reference:
- // -http://golang.org/src/pkg/go/ast/ast.go
- // -http://golang.org/src/pkg/go/ast/walk.go
- package main
- import (
- "go/ast"
- "go/parser"
- "go/token"
- "fmt"
- "flag"
- "os"
- "reflect"
- "strings"
- )
- // Avoid typing "fmt.Printf("...\n", ...) every time
- func printf(format string, v ...interface{}) (n int, errno os.Error) {
- return fmt.Printf(format + "\n", v...)
- }
- // Visitor for ast.Walk
- type printVisitor struct {
- weight float
- priorWeight float
- }
- func (f *printVisitor) Visit(node ast.Node) ast.Visitor {
- if node == nil {
- return f
- }
- typ := reflect.NewValue(node).Type().String()
- // Get rid of redundant package prefix
- typ = strings.Split(typ, ".", -1)[1]
- w := 1.0
- // If statement then add weight
- if strings.Contains(typ, "Stmt") {
- w = f.weight
- }
- if strings.Contains(typ, "CaseClause") || strings.Contains(typ, "CommClause") {
- w = f.priorWeight
- }
- printf("%s: %f", typ, w)
- printf("%s.Pos: %d", typ, node.Pos()) // All nodes have Pos accessor method
- // 3 classes of nodes: Expression & type nodes,
- // statement nodes, and declaration nodes
- switch n := node.(type) {
- // Comments
- case *ast.Comment:
- printf("%s.Text.Length: %d", typ, len(n.Text))
- case *ast.CommentGroup:
- printf("%s.List.Length: %d", typ, len(n.List))
- // Expressions
- case *ast.Field:
- printf("%s.Names.Length: %d", typ, len(n.Names))
- case *ast.FieldList:
- printf("%s.List.Length: %d", typ, len(n.List))
- printf("%s.Closing: %d", typ, n.Closing)
- printf("%s.NumFields: %d", typ, n.NumFields())
- case *ast.Ident:
- printf("%s.Name.Length: %d", typ, len(n.Name))
- case *ast.CompositeLit:
- printf("%s.Lbrace: %d", typ, n.Lbrace)
- printf("%s.Elts.Length: %d", typ, len(n.Elts))
- printf("%s.Rbrace: %d", typ, n.Rbrace)
- case *ast.ParenExpr:
- printf("%s.Lparen: %d", typ, n.Lparen)
- printf("%s.Rparen: %d", typ, n.Rparen)
- case *ast.CallExpr:
- printf("%s.Lparen: %d", typ, n.Lparen)
- printf("%s.Args.Length: %d", typ, len(n.Args))
- printf("%s.Ellipsis: %d", typ, n.Ellipsis)
- printf("%s.Rparen: %d", typ, n.Rparen)
- case *ast.KeyValueExpr:
- printf("%s.Colon: %d", typ, n.Colon)
- case *ast.BinaryExpr:
- fmt.Println("Binary expression")
- // Types
- case *ast.StructType:
- printf("%s.Fields.Length: %d", typ, len(n.Fields.List))
- case *ast.FuncType:
- printf("%s.Params.Length: %d", typ, n.Params.NumFields())
- printf("%s.Results.Length: %d", typ, n.Results.NumFields())
- case *ast.InterfaceType:
- printf("%s.Methods.Length: %d", typ, len(n.Methods.List))
- // Statements
- case *ast.AssignStmt:
- printf("%s.Lhs.Length: %d", typ, len(n.Lhs))
- // Usage of "=" vs. ":="
- if n.Tok == token.DEFINE {
- printf("%s.Tok.DEFINE: 1", typ)
- return f
- }
- printf("%s.Tok.ASSIGN: 1", typ)
- case *ast.ReturnStmt:
- printf("%s.Results.Length: %d", typ, len(n.Results))
- case *ast.BlockStmt:
- printf("%s.Lbrace: %d", typ, n.Lbrace)
- printf("%s.List.Length: %d", typ, len(n.List))
- printf("%s.Rbrace: %d", typ, n.Rbrace)
- case *ast.CaseClause:
- printf("%s.Colon: %d", typ, n.Colon)
- printf("%s.Body.Length: %d", typ, len(n.Body))
- case *ast.TypeCaseClause:
- printf("%s.Types.Length: %d", typ, len(n.Types))
- printf("%s.Colon: %d", typ, n.Colon)
- printf("%s.Body.Length: %d", typ, len(n.Body))
- case *ast.CommClause:
- printf("%s.Colon: %d", typ, n.Colon)
- printf("%s.Body.Length: %d", typ, len(n.Body))
- // Handle weighting
- case *ast.IfStmt:
- var t printVisitor
- t.weight = f.weight/2
- t.priorWeight = f.weight
- return &t
- case *ast.SwitchStmt:
- case *ast.SelectStmt:
- case *ast.TypeSwitchStmt:
- numCases := len(n.Body.List)
- var t printVisitor
- t.weight = f.weight/float(numCases)
- t.priorWeight = f.weight
- return &t
- // Declarations
- case *ast.ValueSpec:
- printf("%s.Names.Length: %d", typ, len(n.Names))
- case *ast.GenDecl:
- printf("%s.Lparen: %d", typ, n.Lparen)
- printf("%s.Rparen: %d", typ, n.Rparen)
- case *ast.FuncDecl:
- if n.Recv != nil {
- printf("%s.Recv", typ)
- }
- printf("%s.Name.Length: %d", typ, len(n.Name.Name))
- printf("%s.Body.List.Length: %d", typ, len(n.Body.List))
- // Files & packages?
- default:
- return f
- } // End cases
- return f
- }
- // File size in kB of a file
- func size(name string) int64 {
- file, _ := os.Open(name, os.O_RDONLY, 0)
- defer file.Close()
- var buf [100]byte
- len := 0
- for {
- n, e := file.Read(buf[0:])
- len += n
- if e == os.EOF {
- break
- }
- }
- return int64(len)
- }
- func main() {
- flag.Parse()
- filename := flag.Arg(0)
- file, err := parser.ParseFile(token.NewFileSet(), filename, nil, 0)
- if err != nil {
- fmt.Println(filename + "\t" + err.String())
- return
- }
- fmt.Printf("FileSizeKB: %d\n", size(filename)/1000)
- // Instance
- var f printVisitor
- f.weight = 1
- f.priorWeight = 1
- ast.Walk(&f, file)
- }