cuelang.org/go@v0.13.0/internal/core/adt/default.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  package adt
    16  
    17  import (
    18  	"slices"
    19  )
    20  
    21  // Default returns the default value or itself if there is no default.
    22  func Default(v Value) Value {
    23  	switch x := v.(type) {
    24  	case *Vertex:
    25  		return x.Default()
    26  	case *Disjunction:
    27  		return x.Default()
    28  	default:
    29  		return v
    30  	}
    31  }
    32  
    33  func (d *Disjunction) Default() Value {
    34  	switch d.NumDefaults {
    35  	case 0:
    36  		return d
    37  	case 1:
    38  		return d.Values[0]
    39  	default:
    40  		return &Disjunction{
    41  			Src:         d.Src,
    42  			Values:      d.Values[:d.NumDefaults],
    43  			NumDefaults: 0,
    44  		}
    45  	}
    46  }
    47  
    48  // Default returns the default value or itself if there is no default.
    49  //
    50  // It also closes a list, representing its default value.
    51  func (v *Vertex) Default() *Vertex {
    52  	v = v.DerefValue()
    53  	switch d := v.BaseValue.(type) {
    54  	default:
    55  		return v
    56  
    57  	case *Disjunction:
    58  		var w *Vertex
    59  
    60  		switch d.NumDefaults {
    61  		case 0:
    62  			return v
    63  		case 1:
    64  			w = ToVertex(Default(d.Values[0]))
    65  		default:
    66  			x := *v
    67  			x.state = nil
    68  			x.BaseValue = &Disjunction{
    69  				Src:         d.Src,
    70  				Values:      d.Values[:d.NumDefaults],
    71  				NumDefaults: 0,
    72  			}
    73  			w = &x
    74  			w.Conjuncts = nil
    75  		}
    76  
    77  		if w.Conjuncts == nil {
    78  			for _, c := range v.Conjuncts {
    79  				// TODO: preserve field information.
    80  				expr, _ := stripNonDefaults(c.Elem())
    81  				w.Conjuncts = append(w.Conjuncts, MakeRootConjunct(c.Env, expr))
    82  			}
    83  		}
    84  		return w
    85  
    86  	case *ListMarker:
    87  		m := *d
    88  		m.IsOpen = false
    89  
    90  		w := *v
    91  		w.BaseValue = &m
    92  		w.state = nil
    93  		return &w
    94  	}
    95  }
    96  
    97  // TODO: this should go: record preexpanded disjunctions in Vertex.
    98  func stripNonDefaults(elem Elem) (r Elem, stripped bool) {
    99  	expr, ok := elem.(Expr)
   100  	if !ok {
   101  		return elem, false
   102  	}
   103  	switch x := expr.(type) {
   104  	case *DisjunctionExpr:
   105  		if !x.HasDefaults {
   106  			return x, false
   107  		}
   108  		d := *x
   109  		d.Values = []Disjunct{}
   110  		for _, v := range x.Values {
   111  			if v.Default {
   112  				d.Values = append(d.Values, v)
   113  			}
   114  		}
   115  		if len(d.Values) == 1 {
   116  			return d.Values[0].Val, true
   117  		}
   118  		return &d, true
   119  
   120  	case *BinaryExpr:
   121  		if x.Op != AndOp {
   122  			return x, false
   123  		}
   124  		a, sa := stripNonDefaults(x.X)
   125  		b, sb := stripNonDefaults(x.Y)
   126  		if sa || sb {
   127  			bin := *x
   128  			bin.X = a.(Expr)
   129  			bin.Y = b.(Expr)
   130  			return &bin, true
   131  		}
   132  		return x, false
   133  
   134  	case *ConjunctGroup:
   135  		// NOTE: this code requires allocations unconditional. This should be
   136  		// mitigated once we optimize conjunct groupings.
   137  		isNew := false
   138  		a := slices.Clone(*x)
   139  		for i, c := range a {
   140  			a[i].x, ok = stripNonDefaults(c.Elem())
   141  			if ok {
   142  				isNew = true
   143  			}
   144  		}
   145  		if isNew {
   146  			return &a, true
   147  		}
   148  		return x, false
   149  
   150  	default:
   151  		return x, false
   152  	}
   153  }