github.com/solo-io/cue@v0.4.7/internal/core/walk/walk.go (about)

     1  // Copyright 2020 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  // walk provides functions for visiting the nodes of an ADT tree.
    16  package walk
    17  
    18  import (
    19  	"fmt"
    20  
    21  	"github.com/solo-io/cue/internal/core/adt"
    22  )
    23  
    24  // Features calls f for all features used in x and indicates whether the
    25  // feature is used as a reference or not.
    26  func Features(x adt.Expr, f func(label adt.Feature, src adt.Node)) {
    27  	w := Visitor{
    28  		Feature: f,
    29  	}
    30  	w.Expr(x)
    31  }
    32  
    33  type Visitor struct {
    34  	// TODO: lets really should be special fields
    35  	letDone map[adt.Expr]bool
    36  
    37  	Feature func(f adt.Feature, src adt.Node)
    38  	Before  func(adt.Node) bool
    39  }
    40  
    41  func (w *Visitor) init() {
    42  	if w.letDone == nil {
    43  		w.letDone = map[adt.Expr]bool{}
    44  	}
    45  }
    46  
    47  func (w *Visitor) Expr(x adt.Expr) {
    48  	w.init()
    49  	w.node(x)
    50  }
    51  
    52  func (w *Visitor) feature(x adt.Feature, src adt.Node) {
    53  	if w.Feature != nil {
    54  		w.Feature(x, src)
    55  	}
    56  }
    57  
    58  func (w *Visitor) node(n adt.Node) {
    59  	if w.Before != nil && !w.Before(n) {
    60  		return
    61  	}
    62  
    63  	switch x := n.(type) {
    64  	case nil:
    65  
    66  	// TODO: special-case Vertex?
    67  	case adt.Value:
    68  
    69  	case *adt.ListLit:
    70  		for _, x := range x.Elems {
    71  			w.node(x)
    72  		}
    73  
    74  	case *adt.StructLit:
    75  		for _, x := range x.Decls {
    76  			w.node(x)
    77  		}
    78  
    79  	case *adt.FieldReference:
    80  		w.feature(x.Label, x)
    81  
    82  	case *adt.ValueReference:
    83  		w.feature(x.Label, x)
    84  
    85  	case *adt.LabelReference:
    86  
    87  	case *adt.DynamicReference:
    88  
    89  	case *adt.ImportReference:
    90  		w.feature(x.ImportPath, x)
    91  		w.feature(x.Label, x)
    92  
    93  	case *adt.LetReference:
    94  		w.feature(x.Label, x)
    95  		if w.letDone == nil {
    96  			w.letDone = map[adt.Expr]bool{}
    97  		}
    98  		if !w.letDone[x.X] {
    99  			w.letDone[x.X] = true
   100  			w.node(x.X)
   101  		}
   102  
   103  	case *adt.SelectorExpr:
   104  		w.node(x.X)
   105  		w.feature(x.Sel, x)
   106  
   107  	case *adt.IndexExpr:
   108  		w.node(x.X)
   109  		w.node(x.Index)
   110  
   111  	case *adt.SliceExpr:
   112  		w.node(x.X)
   113  		w.node(x.Lo)
   114  		w.node(x.Hi)
   115  		w.node(x.Stride)
   116  
   117  	case *adt.Interpolation:
   118  		for _, x := range x.Parts {
   119  			w.node(x)
   120  		}
   121  
   122  	case *adt.BoundExpr:
   123  		w.node(x.Expr)
   124  
   125  	case *adt.UnaryExpr:
   126  		w.node(x.X)
   127  
   128  	case *adt.BinaryExpr:
   129  		w.node(x.X)
   130  		w.node(x.Y)
   131  
   132  	case *adt.CallExpr:
   133  		w.node(x.Fun)
   134  		for _, arg := range x.Args {
   135  			w.node(arg)
   136  		}
   137  
   138  	case *adt.DisjunctionExpr:
   139  		for _, d := range x.Values {
   140  			w.node(d.Val)
   141  		}
   142  
   143  	// Fields
   144  
   145  	case *adt.Ellipsis:
   146  		if x.Value != nil {
   147  			w.node(x.Value)
   148  		}
   149  
   150  	case *adt.Field:
   151  		w.feature(x.Label, x)
   152  		w.node(x.Value)
   153  
   154  	case *adt.OptionalField:
   155  		w.feature(x.Label, x)
   156  		w.node(x.Value)
   157  
   158  	case *adt.BulkOptionalField:
   159  		w.node(x.Filter)
   160  		w.node(x.Value)
   161  
   162  	case *adt.DynamicField:
   163  		w.node(x.Key)
   164  		w.node(x.Value)
   165  
   166  	// Yielders
   167  
   168  	case *adt.ForClause:
   169  		w.feature(x.Key, x)
   170  		w.feature(x.Value, x)
   171  		w.node(x.Dst)
   172  
   173  	case *adt.IfClause:
   174  		w.node(x.Condition)
   175  		w.node(x.Dst)
   176  
   177  	case *adt.LetClause:
   178  		w.feature(x.Label, x)
   179  		w.node(x.Expr)
   180  		w.node(x.Dst)
   181  
   182  	case *adt.ValueClause:
   183  		w.node(x.StructLit)
   184  
   185  	default:
   186  		panic(fmt.Sprintf("unknown field %T", x))
   187  	}
   188  }