cuelang.org/go@v0.10.1/cue/ast/walk.go (about)

     1  // Copyright 2018 The CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package ast
    16  
    17  import (
    18  	"fmt"
    19  )
    20  
    21  func walkList[N Node](list []N, before func(Node) bool, after func(Node)) {
    22  	for _, node := range list {
    23  		Walk(node, before, after)
    24  	}
    25  }
    26  
    27  // Walk traverses an AST in depth-first order: It starts by calling f(node);
    28  // node must not be nil. If before returns true, Walk invokes f recursively for
    29  // each of the non-nil children of node, followed by a call of after. Both
    30  // functions may be nil. If before is nil, it is assumed to always return true.
    31  func Walk(node Node, before func(Node) bool, after func(Node)) {
    32  	if before != nil && !before(node) {
    33  		return
    34  	}
    35  
    36  	// TODO: record the comment groups and interleave with the values like for
    37  	// parsing and printing?
    38  	walkList(Comments(node), before, after)
    39  
    40  	// walk children
    41  	// (the order of the cases matches the order
    42  	// of the corresponding node types in go)
    43  	switch n := node.(type) {
    44  	// Comments and fields
    45  	case *Comment:
    46  		// nothing to do
    47  
    48  	case *CommentGroup:
    49  		walkList(n.List, before, after)
    50  
    51  	case *Attribute:
    52  		// nothing to do
    53  
    54  	case *Field:
    55  		Walk(n.Label, before, after)
    56  		if n.Value != nil {
    57  			Walk(n.Value, before, after)
    58  		}
    59  		walkList(n.Attrs, before, after)
    60  
    61  	case *Func:
    62  		walkList(n.Args, before, after)
    63  		Walk(n.Ret, before, after)
    64  
    65  	case *StructLit:
    66  		walkList(n.Elts, before, after)
    67  
    68  	// Expressions
    69  	case *BottomLit, *BadExpr, *Ident, *BasicLit:
    70  		// nothing to do
    71  
    72  	case *Interpolation:
    73  		walkList(n.Elts, before, after)
    74  
    75  	case *ListLit:
    76  		walkList(n.Elts, before, after)
    77  
    78  	case *Ellipsis:
    79  		if n.Type != nil {
    80  			Walk(n.Type, before, after)
    81  		}
    82  
    83  	case *ParenExpr:
    84  		Walk(n.X, before, after)
    85  
    86  	case *SelectorExpr:
    87  		Walk(n.X, before, after)
    88  		Walk(n.Sel, before, after)
    89  
    90  	case *IndexExpr:
    91  		Walk(n.X, before, after)
    92  		Walk(n.Index, before, after)
    93  
    94  	case *SliceExpr:
    95  		Walk(n.X, before, after)
    96  		if n.Low != nil {
    97  			Walk(n.Low, before, after)
    98  		}
    99  		if n.High != nil {
   100  			Walk(n.High, before, after)
   101  		}
   102  
   103  	case *CallExpr:
   104  		Walk(n.Fun, before, after)
   105  		walkList(n.Args, before, after)
   106  
   107  	case *UnaryExpr:
   108  		Walk(n.X, before, after)
   109  
   110  	case *BinaryExpr:
   111  		Walk(n.X, before, after)
   112  		Walk(n.Y, before, after)
   113  
   114  	// Declarations
   115  	case *ImportSpec:
   116  		if n.Name != nil {
   117  			Walk(n.Name, before, after)
   118  		}
   119  		Walk(n.Path, before, after)
   120  
   121  	case *BadDecl:
   122  		// nothing to do
   123  
   124  	case *ImportDecl:
   125  		walkList(n.Specs, before, after)
   126  
   127  	case *EmbedDecl:
   128  		Walk(n.Expr, before, after)
   129  
   130  	case *LetClause:
   131  		Walk(n.Ident, before, after)
   132  		Walk(n.Expr, before, after)
   133  
   134  	case *Alias:
   135  		Walk(n.Ident, before, after)
   136  		Walk(n.Expr, before, after)
   137  
   138  	case *Comprehension:
   139  		walkList(n.Clauses, before, after)
   140  		Walk(n.Value, before, after)
   141  
   142  	// Files and packages
   143  	case *File:
   144  		walkList(n.Decls, before, after)
   145  
   146  	case *Package:
   147  		Walk(n.Name, before, after)
   148  
   149  	case *ForClause:
   150  		if n.Key != nil {
   151  			Walk(n.Key, before, after)
   152  		}
   153  		Walk(n.Value, before, after)
   154  		Walk(n.Source, before, after)
   155  
   156  	case *IfClause:
   157  		Walk(n.Condition, before, after)
   158  
   159  	default:
   160  		panic(fmt.Sprintf("Walk: unexpected node type %T", n))
   161  	}
   162  
   163  	if after != nil {
   164  		after(node)
   165  	}
   166  }