...

Source file src/cuelang.org/go/cue/ast/astutil/walk.go

Documentation: cuelang.org/go/cue/ast/astutil

     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 astutil
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"cuelang.org/go/cue/ast"
    21  )
    22  
    23  // TODO: use ast.Walk or adopt that version to allow visitors.
    24  
    25  // A visitor's before method is invoked for each node encountered by Walk.
    26  // If the result visitor w is not nil, Walk visits each of the children
    27  // of node with the visitor w, followed by a call of w.After.
    28  type visitor interface {
    29  	Before(node ast.Node) (w visitor)
    30  	After(node ast.Node)
    31  }
    32  
    33  // Helper functions for common node lists. They may be empty.
    34  
    35  func walkExprList(v visitor, list []ast.Expr) {
    36  	for _, x := range list {
    37  		walk(v, x)
    38  	}
    39  }
    40  
    41  func walkDeclList(v visitor, list []ast.Decl) {
    42  	for _, x := range list {
    43  		walk(v, x)
    44  	}
    45  }
    46  
    47  // walk traverses an AST in depth-first order: It starts by calling
    48  // v.Visit(node); node must not be nil. If the visitor w returned by
    49  // v.Visit(node) is not nil, walk is invoked recursively with visitor
    50  // w for each of the non-nil children of node, followed by a call of
    51  // w.Visit(nil).
    52  func walk(v visitor, node ast.Node) {
    53  	if v = v.Before(node); v == nil {
    54  		return
    55  	}
    56  
    57  	// TODO: record the comment groups and interleave with the values like for
    58  	// parsing and printing?
    59  	for _, c := range node.Comments() {
    60  		walk(v, c)
    61  	}
    62  
    63  	// walk children
    64  	// (the order of the cases matches the order
    65  	// of the corresponding node types in go)
    66  	switch n := node.(type) {
    67  	// Comments and fields
    68  	case *ast.Comment:
    69  		// nothing to do
    70  
    71  	case *ast.CommentGroup:
    72  		for _, c := range n.List {
    73  			walk(v, c)
    74  		}
    75  
    76  	case *ast.Attribute:
    77  		// nothing to do
    78  
    79  	case *ast.Field:
    80  		walk(v, n.Label)
    81  		if n.Value != nil {
    82  			walk(v, n.Value)
    83  		}
    84  		for _, a := range n.Attrs {
    85  			walk(v, a)
    86  		}
    87  
    88  	case *ast.Func:
    89  		walkExprList(v, n.Args)
    90  		walk(v, n.Ret)
    91  
    92  	case *ast.StructLit:
    93  		for _, f := range n.Elts {
    94  			walk(v, f)
    95  		}
    96  
    97  	// Expressions
    98  	case *ast.BottomLit, *ast.BadExpr, *ast.Ident, *ast.BasicLit:
    99  		// nothing to do
   100  
   101  	case *ast.Interpolation:
   102  		for _, e := range n.Elts {
   103  			walk(v, e)
   104  		}
   105  
   106  	case *ast.ListLit:
   107  		walkExprList(v, n.Elts)
   108  
   109  	case *ast.Ellipsis:
   110  		if n.Type != nil {
   111  			walk(v, n.Type)
   112  		}
   113  
   114  	case *ast.ParenExpr:
   115  		walk(v, n.X)
   116  
   117  	case *ast.SelectorExpr:
   118  		walk(v, n.X)
   119  		walk(v, n.Sel)
   120  
   121  	case *ast.IndexExpr:
   122  		walk(v, n.X)
   123  		walk(v, n.Index)
   124  
   125  	case *ast.SliceExpr:
   126  		walk(v, n.X)
   127  		if n.Low != nil {
   128  			walk(v, n.Low)
   129  		}
   130  		if n.High != nil {
   131  			walk(v, n.High)
   132  		}
   133  
   134  	case *ast.CallExpr:
   135  		walk(v, n.Fun)
   136  		walkExprList(v, n.Args)
   137  
   138  	case *ast.UnaryExpr:
   139  		walk(v, n.X)
   140  
   141  	case *ast.BinaryExpr:
   142  		walk(v, n.X)
   143  		walk(v, n.Y)
   144  
   145  	// Declarations
   146  	case *ast.ImportSpec:
   147  		if n.Name != nil {
   148  			walk(v, n.Name)
   149  		}
   150  		walk(v, n.Path)
   151  
   152  	case *ast.BadDecl:
   153  		// nothing to do
   154  
   155  	case *ast.ImportDecl:
   156  		for _, s := range n.Specs {
   157  			walk(v, s)
   158  		}
   159  
   160  	case *ast.EmbedDecl:
   161  		walk(v, n.Expr)
   162  
   163  	case *ast.Alias:
   164  		walk(v, n.Ident)
   165  		walk(v, n.Expr)
   166  
   167  	case *ast.Comprehension:
   168  		for _, c := range n.Clauses {
   169  			walk(v, c)
   170  		}
   171  		walk(v, n.Value)
   172  
   173  	// Files and packages
   174  	case *ast.File:
   175  		walkDeclList(v, n.Decls)
   176  
   177  	case *ast.Package:
   178  		// The package identifier isn't really an identifier. Skip it.
   179  
   180  	case *ast.LetClause:
   181  		walk(v, n.Ident)
   182  		walk(v, n.Expr)
   183  
   184  	case *ast.ForClause:
   185  		if n.Key != nil {
   186  			walk(v, n.Key)
   187  		}
   188  		walk(v, n.Value)
   189  		walk(v, n.Source)
   190  
   191  	case *ast.IfClause:
   192  		walk(v, n.Condition)
   193  
   194  	default:
   195  		panic(fmt.Sprintf("Walk: unexpected node type %T", n))
   196  	}
   197  
   198  	v.After(node)
   199  }
   200  

View as plain text