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  }