git.wit.org/jcarr/packr@v1.10.8/builder/visitor.go (about) 1 package builder 2 3 import ( 4 "go/ast" 5 "go/parser" 6 "go/token" 7 "io/ioutil" 8 "sort" 9 "strings" 10 11 "github.com/pkg/errors" 12 ) 13 14 type visitor struct { 15 Path string 16 Package string 17 Boxes []string 18 Errors []error 19 } 20 21 func newVisitor(path string) *visitor { 22 return &visitor{ 23 Path: path, 24 Boxes: []string{}, 25 Errors: []error{}, 26 } 27 } 28 29 func (v *visitor) Run() error { 30 b, err := ioutil.ReadFile(v.Path) 31 if err != nil { 32 return errors.WithStack(err) 33 } 34 35 fset := token.NewFileSet() 36 file, err := parser.ParseFile(fset, v.Path, string(b), parser.ParseComments) 37 if err != nil { 38 return errors.WithStack(err) 39 } 40 41 v.Package = file.Name.Name 42 ast.Walk(v, file) 43 44 m := map[string]string{} 45 for _, s := range v.Boxes { 46 m[s] = s 47 } 48 v.Boxes = []string{} 49 for k := range m { 50 v.Boxes = append(v.Boxes, k) 51 } 52 53 sort.Strings(v.Boxes) 54 55 if len(v.Errors) > 0 { 56 s := make([]string, len(v.Errors)) 57 for i, e := range v.Errors { 58 s[i] = e.Error() 59 } 60 return errors.New(strings.Join(s, "\n")) 61 } 62 return nil 63 } 64 65 func (v *visitor) Visit(node ast.Node) ast.Visitor { 66 if node == nil { 67 return v 68 } 69 if err := v.eval(node); err != nil { 70 v.Errors = append(v.Errors, err) 71 } 72 return v 73 } 74 75 func (v *visitor) eval(node ast.Node) error { 76 switch t := node.(type) { 77 case *ast.CallExpr: 78 return v.evalExpr(t) 79 case *ast.Ident: 80 return v.evalIdent(t) 81 case *ast.GenDecl: 82 for _, n := range t.Specs { 83 if err := v.eval(n); err != nil { 84 return errors.WithStack(err) 85 } 86 } 87 case *ast.FuncDecl: 88 if t.Body == nil { 89 return nil 90 } 91 for _, b := range t.Body.List { 92 if err := v.evalStmt(b); err != nil { 93 return errors.WithStack(err) 94 } 95 } 96 return nil 97 case *ast.ValueSpec: 98 for _, e := range t.Values { 99 if err := v.evalExpr(e); err != nil { 100 return errors.WithStack(err) 101 } 102 } 103 } 104 return nil 105 } 106 107 func (v *visitor) evalStmt(stmt ast.Stmt) error { 108 switch t := stmt.(type) { 109 case *ast.ExprStmt: 110 return v.evalExpr(t.X) 111 case *ast.AssignStmt: 112 for _, e := range t.Rhs { 113 if err := v.evalArgs(e); err != nil { 114 return errors.WithStack(err) 115 } 116 } 117 } 118 return nil 119 } 120 121 func (v *visitor) evalExpr(expr ast.Expr) error { 122 switch t := expr.(type) { 123 case *ast.CallExpr: 124 if t.Fun == nil { 125 return nil 126 } 127 for _, a := range t.Args { 128 switch at := a.(type) { 129 case *ast.CallExpr: 130 if sel, ok := t.Fun.(*ast.SelectorExpr); ok { 131 return v.evalSelector(at, sel) 132 } 133 134 if err := v.evalArgs(at); err != nil { 135 return errors.WithStack(err) 136 } 137 case *ast.CompositeLit: 138 for _, e := range at.Elts { 139 if err := v.evalExpr(e); err != nil { 140 return errors.WithStack(err) 141 } 142 } 143 } 144 } 145 if ft, ok := t.Fun.(*ast.SelectorExpr); ok { 146 return v.evalSelector(t, ft) 147 } 148 case *ast.KeyValueExpr: 149 return v.evalExpr(t.Value) 150 } 151 return nil 152 } 153 154 func (v *visitor) evalArgs(expr ast.Expr) error { 155 switch at := expr.(type) { 156 case *ast.CompositeLit: 157 for _, e := range at.Elts { 158 if err := v.evalExpr(e); err != nil { 159 return errors.WithStack(err) 160 } 161 } 162 // case *ast.BasicLit: 163 // fmt.Println("evalArgs", at.Value) 164 // v.addBox(at.Value) 165 case *ast.CallExpr: 166 if at.Fun == nil { 167 return nil 168 } 169 switch st := at.Fun.(type) { 170 case *ast.SelectorExpr: 171 if err := v.evalSelector(at, st); err != nil { 172 return errors.WithStack(err) 173 } 174 case *ast.Ident: 175 return v.evalIdent(st) 176 } 177 for _, a := range at.Args { 178 if err := v.evalArgs(a); err != nil { 179 return errors.WithStack(err) 180 } 181 } 182 } 183 return nil 184 } 185 186 func (v *visitor) evalSelector(expr *ast.CallExpr, sel *ast.SelectorExpr) error { 187 x, ok := sel.X.(*ast.Ident) 188 if !ok { 189 return nil 190 } 191 if x.Name == "packr" && sel.Sel.Name == "NewBox" { 192 for _, e := range expr.Args { 193 switch at := e.(type) { 194 case *ast.Ident: 195 return v.evalIdent(at) 196 case *ast.BasicLit: 197 v.addBox(at.Value) 198 case *ast.CallExpr: 199 return v.evalExpr(at) 200 } 201 } 202 } 203 204 return nil 205 } 206 207 func (v *visitor) evalIdent(i *ast.Ident) error { 208 if i.Obj == nil { 209 return nil 210 } 211 if s, ok := i.Obj.Decl.(*ast.AssignStmt); ok { 212 return v.evalStmt(s) 213 } 214 return nil 215 } 216 217 func (v *visitor) addBox(b string) { 218 b = strings.Replace(b, "\"", "", -1) 219 v.Boxes = append(v.Boxes, b) 220 }