github.com/google/skylark@v0.0.0-20181101142754-a5f7082aabed/syntax/walk.go (about)

     1  // Copyright 2017 The Bazel Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package syntax
     6  
     7  // Walk traverses a syntax tree in depth-first order.
     8  // It starts by calling f(n); n must not be nil.
     9  // If f returns true, Walk calls itself
    10  // recursively for each non-nil child of n.
    11  // Walk then calls f(nil).
    12  func Walk(n Node, f func(Node) bool) {
    13  	if !f(n) {
    14  		return
    15  	}
    16  
    17  	// TODO(adonovan): opt: order cases using profile data.
    18  	switch n := n.(type) {
    19  	case *File:
    20  		walkStmts(n.Stmts, f)
    21  
    22  	case *ExprStmt:
    23  		Walk(n.X, f)
    24  
    25  	case *BranchStmt:
    26  		// no-op
    27  
    28  	case *IfStmt:
    29  		Walk(n.Cond, f)
    30  		walkStmts(n.True, f)
    31  		walkStmts(n.False, f)
    32  
    33  	case *AssignStmt:
    34  		Walk(n.RHS, f)
    35  		Walk(n.LHS, f)
    36  
    37  	case *DefStmt:
    38  		Walk(n.Name, f)
    39  		for _, param := range n.Function.Params {
    40  			Walk(param, f)
    41  		}
    42  		walkStmts(n.Function.Body, f)
    43  
    44  	case *ForStmt:
    45  		Walk(n.Vars, f)
    46  		Walk(n.X, f)
    47  		walkStmts(n.Body, f)
    48  
    49  	case *ReturnStmt:
    50  		if n.Result != nil {
    51  			Walk(n.Result, f)
    52  		}
    53  
    54  	case *LoadStmt:
    55  		Walk(n.Module, f)
    56  		for _, from := range n.From {
    57  			Walk(from, f)
    58  		}
    59  		for _, to := range n.To {
    60  			Walk(to, f)
    61  		}
    62  
    63  	case *Ident, *Literal:
    64  		// no-op
    65  
    66  	case *ListExpr:
    67  		for _, x := range n.List {
    68  			Walk(x, f)
    69  		}
    70  
    71  	case *ParenExpr:
    72  		Walk(n.X, f)
    73  
    74  	case *CondExpr:
    75  		Walk(n.Cond, f)
    76  		Walk(n.True, f)
    77  		Walk(n.False, f)
    78  
    79  	case *IndexExpr:
    80  		Walk(n.X, f)
    81  		Walk(n.Y, f)
    82  
    83  	case *DictEntry:
    84  		Walk(n.Key, f)
    85  		Walk(n.Value, f)
    86  
    87  	case *SliceExpr:
    88  		Walk(n.X, f)
    89  		if n.Lo != nil {
    90  			Walk(n.Lo, f)
    91  		}
    92  		if n.Hi != nil {
    93  			Walk(n.Hi, f)
    94  		}
    95  		if n.Step != nil {
    96  			Walk(n.Step, f)
    97  		}
    98  
    99  	case *Comprehension:
   100  		for _, clause := range n.Clauses {
   101  			Walk(clause, f)
   102  		}
   103  		Walk(n.Body, f)
   104  
   105  	case *IfClause:
   106  		Walk(n.Cond, f)
   107  
   108  	case *ForClause:
   109  		Walk(n.Vars, f)
   110  		Walk(n.X, f)
   111  
   112  	case *TupleExpr:
   113  		for _, x := range n.List {
   114  			Walk(x, f)
   115  		}
   116  
   117  	case *DictExpr:
   118  		for _, entry := range n.List {
   119  			entry := entry.(*DictEntry)
   120  			Walk(entry.Key, f)
   121  			Walk(entry.Value, f)
   122  		}
   123  
   124  	case *UnaryExpr:
   125  		Walk(n.X, f)
   126  
   127  	case *BinaryExpr:
   128  		Walk(n.X, f)
   129  		Walk(n.Y, f)
   130  
   131  	case *DotExpr:
   132  		Walk(n.X, f)
   133  		Walk(n.Name, f)
   134  
   135  	case *CallExpr:
   136  		Walk(n.Fn, f)
   137  		for _, arg := range n.Args {
   138  			Walk(arg, f)
   139  		}
   140  
   141  	case *LambdaExpr:
   142  		for _, param := range n.Function.Params {
   143  			Walk(param, f)
   144  		}
   145  		walkStmts(n.Function.Body, f)
   146  
   147  	default:
   148  		panic(n)
   149  	}
   150  
   151  	f(nil)
   152  }
   153  
   154  func walkStmts(stmts []Stmt, f func(Node) bool) {
   155  	for _, stmt := range stmts {
   156  		Walk(stmt, f)
   157  	}
   158  }