github.com/mattn/anko@v0.1.10/ast/astutil/walk.go (about)

     1  // +build !appengine
     2  
     3  package astutil
     4  
     5  import (
     6  	"fmt"
     7  	"reflect"
     8  
     9  	"github.com/mattn/anko/ast"
    10  )
    11  
    12  // WalkFunc is used in Walk to walk the AST
    13  type WalkFunc func(interface{}) error
    14  
    15  // Walk walks the ASTs associated with a statement list generated by parser.ParseSrc
    16  // each expression and/or statement is passed to the WalkFunc function.
    17  // If the WalkFunc returns an error the walk is aborted and the error is returned
    18  func Walk(stmt ast.Stmt, f WalkFunc) error {
    19  	return walkStmt(stmt, f)
    20  }
    21  
    22  func walkStmts(stmts []ast.Stmt, f WalkFunc) error {
    23  	for _, stmt := range stmts {
    24  		if err := walkStmt(stmt, f); err != nil {
    25  			return err
    26  		}
    27  	}
    28  	return nil
    29  }
    30  
    31  func walkExprs(exprs []ast.Expr, f WalkFunc) error {
    32  	for _, exp := range exprs {
    33  		if err := walkExpr(exp, f); err != nil {
    34  			return err
    35  		}
    36  	}
    37  	return nil
    38  }
    39  
    40  func walkStmt(stmt ast.Stmt, f WalkFunc) error {
    41  	//short circuit out if there are no functions
    42  	if stmt == nil || f == nil {
    43  		return nil
    44  	}
    45  	if err := callFunc(stmt, f); err != nil {
    46  		return err
    47  	}
    48  	switch stmt := stmt.(type) {
    49  	case *ast.StmtsStmt:
    50  		if err := walkStmts(stmt.Stmts, f); err != nil {
    51  			return err
    52  		}
    53  	case *ast.BreakStmt:
    54  	case *ast.ContinueStmt:
    55  	case *ast.LetMapItemStmt:
    56  		if err := walkExpr(stmt.RHS, f); err != nil {
    57  			return err
    58  		}
    59  		return walkExprs(stmt.LHSS, f)
    60  	case *ast.ReturnStmt:
    61  		return walkExprs(stmt.Exprs, f)
    62  	case *ast.ExprStmt:
    63  		return walkExpr(stmt.Expr, f)
    64  	case *ast.VarStmt:
    65  		return walkExprs(stmt.Exprs, f)
    66  	case *ast.LetsStmt:
    67  		if err := walkExprs(stmt.RHSS, f); err != nil {
    68  			return err
    69  		}
    70  		return walkExprs(stmt.LHSS, f)
    71  	case *ast.IfStmt:
    72  		if err := walkExpr(stmt.If, f); err != nil {
    73  			return err
    74  		}
    75  		if err := walkStmt(stmt.Then, f); err != nil {
    76  			return err
    77  		}
    78  		if err := walkStmts(stmt.ElseIf, f); err != nil {
    79  			return err
    80  		}
    81  		if err := walkStmt(stmt.Else, f); err != nil {
    82  			return err
    83  		}
    84  	case *ast.TryStmt:
    85  		if err := walkStmt(stmt.Try, f); err != nil {
    86  			return err
    87  		}
    88  		if err := walkStmt(stmt.Catch, f); err != nil {
    89  			return err
    90  		}
    91  		if err := walkStmt(stmt.Finally, f); err != nil {
    92  			return err
    93  		}
    94  	case *ast.LoopStmt:
    95  		if err := walkExpr(stmt.Expr, f); err != nil {
    96  			return err
    97  		}
    98  		if err := walkStmt(stmt.Stmt, f); err != nil {
    99  			return err
   100  		}
   101  	case *ast.ForStmt:
   102  		if err := walkExpr(stmt.Value, f); err != nil {
   103  			return err
   104  		}
   105  		if err := walkStmt(stmt.Stmt, f); err != nil {
   106  			return err
   107  		}
   108  	case *ast.CForStmt:
   109  		if err := walkStmt(stmt.Stmt1, f); err != nil {
   110  			return err
   111  		}
   112  		if err := walkExpr(stmt.Expr2, f); err != nil {
   113  			return err
   114  		}
   115  		if err := walkExpr(stmt.Expr3, f); err != nil {
   116  			return err
   117  		}
   118  		if err := walkStmt(stmt.Stmt, f); err != nil {
   119  			return err
   120  		}
   121  	case *ast.ThrowStmt:
   122  		if err := walkExpr(stmt.Expr, f); err != nil {
   123  			return err
   124  		}
   125  	case *ast.ModuleStmt:
   126  		if err := walkStmt(stmt.Stmt, f); err != nil {
   127  			return err
   128  		}
   129  	case *ast.SwitchStmt:
   130  		if err := walkExpr(stmt.Expr, f); err != nil {
   131  			return err
   132  		}
   133  		for _, switchCaseStmt := range stmt.Cases {
   134  			caseStmt := switchCaseStmt.(*ast.SwitchCaseStmt)
   135  			if err := walkStmt(caseStmt.Stmt, f); err != nil {
   136  				return err
   137  			}
   138  		}
   139  		if err := walkStmt(stmt.Default, f); err != nil {
   140  			return err
   141  		}
   142  	case *ast.GoroutineStmt:
   143  		return walkExpr(stmt.Expr, f)
   144  	default:
   145  		return fmt.Errorf("unknown statement %v", reflect.TypeOf(stmt))
   146  	}
   147  	return nil
   148  }
   149  
   150  func walkExpr(expr ast.Expr, f WalkFunc) error {
   151  	//short circuit out if there are no functions
   152  	if expr == nil || f == nil {
   153  		return nil
   154  	}
   155  	if err := callFunc(expr, f); err != nil {
   156  		return err
   157  	}
   158  	switch expr := expr.(type) {
   159  	case *ast.OpExpr:
   160  		return walkOperator(expr.Op, f)
   161  	case *ast.LenExpr:
   162  	case *ast.LiteralExpr:
   163  	case *ast.IdentExpr:
   164  	case *ast.MemberExpr:
   165  		return walkExpr(expr.Expr, f)
   166  	case *ast.ItemExpr:
   167  		if err := walkExpr(expr.Item, f); err != nil {
   168  			return err
   169  		}
   170  		return walkExpr(expr.Index, f)
   171  	case *ast.SliceExpr:
   172  		if err := walkExpr(expr.Item, f); err != nil {
   173  			return err
   174  		}
   175  		if err := walkExpr(expr.Begin, f); err != nil {
   176  			return err
   177  		}
   178  		return walkExpr(expr.End, f)
   179  	case *ast.ArrayExpr:
   180  		return walkExprs(expr.Exprs, f)
   181  	case *ast.MapExpr:
   182  		for i := range expr.Keys {
   183  			if err := walkExpr(expr.Keys[i], f); err != nil {
   184  				return err
   185  			}
   186  			if err := walkExpr(expr.Values[i], f); err != nil {
   187  				return err
   188  			}
   189  		}
   190  	case *ast.DerefExpr:
   191  		return walkExpr(expr.Expr, f)
   192  	case *ast.AddrExpr:
   193  		return walkExpr(expr.Expr, f)
   194  	case *ast.UnaryExpr:
   195  		return walkExpr(expr.Expr, f)
   196  	case *ast.ParenExpr:
   197  		return walkExpr(expr.SubExpr, f)
   198  	case *ast.FuncExpr:
   199  		return walkStmt(expr.Stmt, f)
   200  	case *ast.LetsExpr:
   201  		if err := walkExprs(expr.LHSS, f); err != nil {
   202  			return err
   203  		}
   204  		return walkExprs(expr.RHSS, f)
   205  	case *ast.AnonCallExpr:
   206  		if err := walkExpr(expr.Expr, f); err != nil {
   207  			return err
   208  		}
   209  		return walkExpr(&ast.CallExpr{Func: reflect.Value{}, SubExprs: expr.SubExprs, VarArg: expr.VarArg, Go: expr.Go}, f)
   210  	case *ast.CallExpr:
   211  		return walkExprs(expr.SubExprs, f)
   212  	case *ast.TernaryOpExpr:
   213  		if err := walkExpr(expr.Expr, f); err != nil {
   214  			return err
   215  		}
   216  		if err := walkExpr(expr.LHS, f); err != nil {
   217  			return err
   218  		}
   219  		return walkExpr(expr.RHS, f)
   220  	case *ast.ImportExpr:
   221  		return walkExpr(expr.Name, f)
   222  	case *ast.MakeExpr:
   223  		if err := walkExpr(expr.LenExpr, f); err != nil {
   224  			return err
   225  		}
   226  		return walkExpr(expr.CapExpr, f)
   227  	case *ast.ChanExpr:
   228  		if err := walkExpr(expr.RHS, f); err != nil {
   229  			return err
   230  		}
   231  		return walkExpr(expr.LHS, f)
   232  	case *ast.IncludeExpr:
   233  		if err := walkExpr(expr.ItemExpr, f); err != nil {
   234  			return err
   235  		}
   236  		return walkExpr(expr.ListExpr, f)
   237  	default:
   238  		return fmt.Errorf("unknown expression %v", reflect.TypeOf(expr))
   239  	}
   240  	return nil
   241  }
   242  
   243  func walkOperator(op ast.Operator, f WalkFunc) error {
   244  	//short circuit out if there are no functions
   245  	if op == nil || f == nil {
   246  		return nil
   247  	}
   248  	if err := callFunc(op, f); err != nil {
   249  		return err
   250  	}
   251  	switch op := op.(type) {
   252  	case *ast.BinaryOperator:
   253  		if err := walkExpr(op.LHS, f); err != nil {
   254  			return err
   255  		}
   256  		return walkExpr(op.RHS, f)
   257  	case *ast.ComparisonOperator:
   258  		if err := walkExpr(op.LHS, f); err != nil {
   259  			return err
   260  		}
   261  		return walkExpr(op.RHS, f)
   262  	case *ast.AddOperator:
   263  		if err := walkExpr(op.LHS, f); err != nil {
   264  			return err
   265  		}
   266  		return walkExpr(op.RHS, f)
   267  	case *ast.MultiplyOperator:
   268  		if err := walkExpr(op.LHS, f); err != nil {
   269  			return err
   270  		}
   271  		return walkExpr(op.RHS, f)
   272  	}
   273  	return nil
   274  }
   275  
   276  func callFunc(x interface{}, f WalkFunc) error {
   277  	if x == nil || f == nil {
   278  		return nil
   279  	}
   280  	return f(x)
   281  }