github.com/solo-io/cue@v0.4.7/internal/core/export/expr.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 export
    16  
    17  import (
    18  	"fmt"
    19  	"sort"
    20  
    21  	"github.com/solo-io/cue/cue/ast"
    22  	"github.com/solo-io/cue/cue/token"
    23  	"github.com/solo-io/cue/internal/core/adt"
    24  )
    25  
    26  // Modes:
    27  //   raw: as is
    28  //   def: merge structs, print reset as is.
    29  //
    30  // Possible simplifications in def mode:
    31  //    - merge contents of multiple _literal_ structs.
    32  //      - this is not possible if some of the elements are bulk optional
    33  //        (or is it?).
    34  //    - still do not ever resolve references.
    35  //    - to do this, fields must be pre-linked to their destinations.
    36  //    - use astutil.Sanitize to resolve shadowing and imports.
    37  //
    38  //
    39  // Categories of printing:
    40  //   - concrete
    41  //   - optionals
    42  //   - references
    43  //   - constraints
    44  //
    45  // Mixed mode is also not supported in the old implementation (at least not
    46  // correctly). It requires references to resolve properly, backtracking to
    47  // a common root and prefixing that to the reference. This is now possible
    48  // with the Environment construct and could be done later.
    49  
    50  func (e *exporter) expr(v adt.Expr) (result ast.Expr) {
    51  	switch x := v.(type) {
    52  	case nil:
    53  		return nil
    54  
    55  	case *adt.Vertex:
    56  		if len(x.Conjuncts) == 0 || x.IsData() {
    57  			// Treat as literal value.
    58  			return e.value(x)
    59  		} // Should this be the arcs label?
    60  
    61  		a := []conjunct{}
    62  		for _, c := range x.Conjuncts {
    63  			a = append(a, conjunct{c, 0})
    64  		}
    65  
    66  		return e.mergeValues(adt.InvalidLabel, x, a, x.Conjuncts...)
    67  
    68  	case *adt.StructLit:
    69  		c := adt.MakeRootConjunct(nil, x)
    70  		return e.mergeValues(adt.InvalidLabel, nil, []conjunct{{c: c, up: 0}}, c)
    71  
    72  	case adt.Value:
    73  		return e.value(x) // Use conjuncts.
    74  
    75  	default:
    76  		return e.adt(v, nil)
    77  	}
    78  }
    79  
    80  // Piece out values:
    81  
    82  // For a struct, piece out conjuncts that are already values. Those can be
    83  // unified. All other conjuncts are added verbatim.
    84  
    85  func (x *exporter) mergeValues(label adt.Feature, src *adt.Vertex, a []conjunct, orig ...adt.Conjunct) (expr ast.Expr) {
    86  
    87  	e := conjuncts{
    88  		exporter: x,
    89  		values:   &adt.Vertex{},
    90  		fields:   map[adt.Feature]field{},
    91  		attrs:    []*ast.Attribute{},
    92  	}
    93  
    94  	_, saved := e.pushFrame(orig)
    95  	defer e.popFrame(saved)
    96  
    97  	// Handle value aliases
    98  	var valueAlias *ast.Alias
    99  	for _, c := range a {
   100  		if f, ok := c.c.Field().Source().(*ast.Field); ok {
   101  			if a, ok := f.Value.(*ast.Alias); ok {
   102  				if valueAlias == nil {
   103  					if e.valueAlias == nil {
   104  						e.valueAlias = map[*ast.Alias]*ast.Alias{}
   105  					}
   106  					name := a.Ident.Name
   107  					name = e.uniqueAlias(name)
   108  					valueAlias = &ast.Alias{Ident: ast.NewIdent(name)}
   109  				}
   110  				e.valueAlias[a] = valueAlias
   111  			}
   112  		}
   113  	}
   114  	defer func() {
   115  		if valueAlias != nil {
   116  			valueAlias.Expr = expr
   117  			expr = valueAlias
   118  		}
   119  	}()
   120  
   121  	for _, c := range a {
   122  		e.top().upCount = c.up
   123  		x := c.c.Expr()
   124  		e.addExpr(c.c.Env, src, x, false)
   125  	}
   126  
   127  	if src != nil {
   128  		for _, a := range src.Arcs {
   129  			if x, ok := e.fields[a.Label]; ok {
   130  				x.arc = a
   131  				e.fields[a.Label] = x
   132  			}
   133  		}
   134  	}
   135  
   136  	s := x.top().scope
   137  
   138  	for _, a := range e.attrs {
   139  		s.Elts = append(s.Elts, a)
   140  	}
   141  
   142  	// Unify values only for one level.
   143  	if a := e.values.Conjuncts; len(a) > 0 {
   144  		e.values.Finalize(e.ctx)
   145  		e.embed = append(e.embed, e.value(e.values, a...))
   146  	}
   147  
   148  	// Collect and order set of fields.
   149  
   150  	fields := []adt.Feature{}
   151  	for f := range e.fields {
   152  		fields = append(fields, f)
   153  	}
   154  
   155  	// Sort fields in case features lists are missing to ensure
   156  	// predictability. Also sort in reverse order, so that bugs
   157  	// are more likely exposed.
   158  	sort.Slice(fields, func(i, j int) bool {
   159  		return fields[i] > fields[j]
   160  	})
   161  
   162  	m := sortArcs(extractFeatures(e.structs))
   163  	sort.SliceStable(fields, func(i, j int) bool {
   164  		if m[fields[j]] == 0 {
   165  			return m[fields[i]] != 0
   166  		}
   167  		return m[fields[i]] > m[fields[j]]
   168  	})
   169  
   170  	if len(e.fields) == 0 && !e.hasEllipsis {
   171  		switch len(e.embed) + len(e.conjuncts) {
   172  		case 0:
   173  			if len(e.attrs) > 0 {
   174  				break
   175  			}
   176  			if len(e.structs) > 0 {
   177  				return s
   178  			}
   179  			return ast.NewIdent("_")
   180  		case 1:
   181  			var x ast.Expr
   182  			if len(e.conjuncts) == 1 {
   183  				x = e.conjuncts[0]
   184  			} else {
   185  				x = e.embed[0]
   186  			}
   187  			if len(e.attrs) == 0 {
   188  				return x
   189  			}
   190  			if st, ok := x.(*ast.StructLit); ok {
   191  				s.Elts = append(s.Elts, st.Elts...)
   192  				return s
   193  			}
   194  		case 2:
   195  			if len(e.attrs) > 0 {
   196  				break
   197  			}
   198  			// Simplify.
   199  			e.conjuncts = append(e.conjuncts, e.embed...)
   200  			return ast.NewBinExpr(token.AND, e.conjuncts...)
   201  		}
   202  	}
   203  
   204  	for _, x := range e.embed {
   205  		s.Elts = append(s.Elts, &ast.EmbedDecl{Expr: x})
   206  	}
   207  
   208  	for _, f := range fields {
   209  		field := e.fields[f]
   210  		c := field.conjuncts
   211  
   212  		label := e.stringLabel(f)
   213  
   214  		if f.IsDef() {
   215  			x.inDefinition++
   216  		}
   217  
   218  		a := []adt.Conjunct{}
   219  		for _, cc := range c {
   220  			a = append(a, cc.c)
   221  		}
   222  
   223  		d := &ast.Field{Label: label}
   224  
   225  		top := e.frame(0)
   226  		if fr, ok := top.fields[f]; ok && fr.alias != "" {
   227  			setFieldAlias(d, fr.alias)
   228  			fr.node = d
   229  			top.fields[f] = fr
   230  		}
   231  
   232  		d.Value = e.mergeValues(f, field.arc, c, a...)
   233  
   234  		if f.IsDef() {
   235  			x.inDefinition--
   236  		}
   237  
   238  		if isOptional(a) {
   239  			d.Optional = token.Blank.Pos()
   240  		}
   241  		if x.cfg.ShowDocs {
   242  			docs := extractDocs(src, a)
   243  			ast.SetComments(d, docs)
   244  		}
   245  		if x.cfg.ShowAttributes {
   246  			for _, c := range a {
   247  				d.Attrs = extractFieldAttrs(d.Attrs, c)
   248  			}
   249  		}
   250  		s.Elts = append(s.Elts, d)
   251  	}
   252  	if e.hasEllipsis {
   253  		s.Elts = append(s.Elts, &ast.Ellipsis{})
   254  	}
   255  
   256  	// TODO: why was this necessary?
   257  	// else if src != nil && src.IsClosedStruct() && e.inDefinition == 0 {
   258  	// return ast.NewCall(ast.NewIdent("close"), s)
   259  	// }
   260  
   261  	e.conjuncts = append(e.conjuncts, s)
   262  
   263  	return ast.NewBinExpr(token.AND, e.conjuncts...)
   264  }
   265  
   266  // Conjuncts if for collecting values of a single vertex.
   267  type conjuncts struct {
   268  	*exporter
   269  	// Values is used to collect non-struct values.
   270  	values      *adt.Vertex
   271  	embed       []ast.Expr
   272  	conjuncts   []ast.Expr
   273  	structs     []*adt.StructInfo
   274  	fields      map[adt.Feature]field
   275  	attrs       []*ast.Attribute
   276  	hasEllipsis bool
   277  }
   278  
   279  func (c *conjuncts) addValueConjunct(src *adt.Vertex, env *adt.Environment, x adt.Expr) {
   280  	switch b, ok := x.(adt.BaseValue); {
   281  	case ok && src != nil && isTop(b) && !isTop(src.BaseValue):
   282  		// drop top
   283  	default:
   284  		c.values.AddConjunct(adt.MakeRootConjunct(env, x))
   285  	}
   286  }
   287  
   288  func (c *conjuncts) addConjunct(f adt.Feature, env *adt.Environment, n adt.Node) {
   289  	x := c.fields[f]
   290  	v := adt.MakeRootConjunct(env, n)
   291  	x.conjuncts = append(x.conjuncts, conjunct{
   292  		c:  v,
   293  		up: c.top().upCount,
   294  	})
   295  	// x.upCounts = append(x.upCounts, c.top().upCount)
   296  	c.fields[f] = x
   297  }
   298  
   299  type field struct {
   300  	docs      []*ast.CommentGroup
   301  	arc       *adt.Vertex
   302  	conjuncts []conjunct
   303  }
   304  
   305  type conjunct struct {
   306  	c  adt.Conjunct
   307  	up int32
   308  }
   309  
   310  func (e *conjuncts) addExpr(env *adt.Environment, src *adt.Vertex, x adt.Expr, isEmbed bool) {
   311  	switch x := x.(type) {
   312  	case *adt.StructLit:
   313  		e.top().upCount++
   314  
   315  		if e.cfg.ShowAttributes {
   316  			e.attrs = extractDeclAttrs(e.attrs, x.Src)
   317  		}
   318  
   319  		// Only add if it only has no bulk fields or elipsis.
   320  		if isComplexStruct(x) {
   321  			_, saved := e.pushFrame(nil)
   322  			e.embed = append(e.embed, e.adt(x, nil))
   323  			e.top().upCount-- // not necessary, but for proper form
   324  			e.popFrame(saved)
   325  			return
   326  		}
   327  		// Used for sorting.
   328  		e.structs = append(e.structs, &adt.StructInfo{StructLit: x, Env: env})
   329  
   330  		for _, d := range x.Decls {
   331  			var label adt.Feature
   332  			switch f := d.(type) {
   333  			case *adt.Field:
   334  				label = f.Label
   335  			case *adt.OptionalField:
   336  				// TODO: mark optional here.
   337  				label = f.Label
   338  			case *adt.Ellipsis:
   339  				e.hasEllipsis = true
   340  				continue
   341  			case adt.Expr:
   342  				e.addExpr(env, nil, f, true)
   343  				continue
   344  
   345  				// TODO: also handle dynamic fields
   346  			default:
   347  				panic(fmt.Sprintf("Unexpected type %T", d))
   348  			}
   349  			e.addConjunct(label, env, d)
   350  		}
   351  		e.top().upCount--
   352  
   353  	case adt.Value: // other values.
   354  		switch v := x.(type) {
   355  		case nil:
   356  		default:
   357  			e.addValueConjunct(src, env, x)
   358  
   359  		case *adt.Vertex:
   360  			if b, ok := v.BaseValue.(*adt.Bottom); ok {
   361  				if !b.IsIncomplete() || e.cfg.Final {
   362  					e.addExpr(env, v, b, false)
   363  					return
   364  				}
   365  			}
   366  
   367  			switch {
   368  			default:
   369  				for _, c := range v.Conjuncts {
   370  					e.addExpr(c.Env, v, c.Expr(), false)
   371  				}
   372  
   373  			case v.IsData():
   374  				e.structs = append(e.structs, v.Structs...)
   375  
   376  				if y, ok := v.BaseValue.(adt.Value); ok {
   377  					e.addValueConjunct(src, env, y)
   378  				}
   379  
   380  				for _, a := range v.Arcs {
   381  					a.Finalize(e.ctx) // TODO: should we do this?
   382  
   383  					e.addConjunct(a.Label, env, a)
   384  				}
   385  			}
   386  		}
   387  
   388  	case *adt.BinaryExpr:
   389  		switch {
   390  		case x.Op == adt.AndOp && !isEmbed:
   391  			e.addExpr(env, src, x.X, false)
   392  			e.addExpr(env, src, x.Y, false)
   393  		case isSelfContained(x):
   394  			e.addValueConjunct(src, env, x)
   395  		default:
   396  			if isEmbed {
   397  				e.embed = append(e.embed, e.expr(x))
   398  			} else {
   399  				e.conjuncts = append(e.conjuncts, e.expr(x))
   400  			}
   401  		}
   402  
   403  	default:
   404  		switch {
   405  		case isSelfContained(x):
   406  			e.addValueConjunct(src, env, x)
   407  		case isEmbed:
   408  			e.embed = append(e.embed, e.expr(x))
   409  		default:
   410  			e.conjuncts = append(e.conjuncts, e.expr(x))
   411  		}
   412  	}
   413  }
   414  
   415  func isTop(x adt.BaseValue) bool {
   416  	switch v := x.(type) {
   417  	case *adt.Top:
   418  		return true
   419  	case *adt.BasicType:
   420  		return v.K == adt.TopKind
   421  	default:
   422  		return false
   423  	}
   424  }
   425  
   426  // TODO: find a better way to annotate optionality. Maybe a special conjunct
   427  // or store it in the field information?
   428  func isOptional(a []adt.Conjunct) bool {
   429  	if len(a) == 0 {
   430  		return false
   431  	}
   432  	for _, c := range a {
   433  		if v, ok := c.Expr().(*adt.Vertex); ok && !v.IsData() && len(v.Conjuncts) > 0 {
   434  			return isOptional(v.Conjuncts)
   435  		}
   436  		switch f := c.Source().(type) {
   437  		case nil:
   438  			return false
   439  		case *ast.Field:
   440  			if f.Optional == token.NoPos {
   441  				return false
   442  			}
   443  		}
   444  	}
   445  	return true
   446  }
   447  
   448  func isComplexStruct(s *adt.StructLit) bool {
   449  	for _, d := range s.Decls {
   450  		switch x := d.(type) {
   451  		case *adt.Field:
   452  			// TODO: remove this and also handle field annotation in expr().
   453  			// This allows structs to be merged. Ditto below.
   454  			if x.Src != nil {
   455  				if _, ok := x.Src.Label.(*ast.Alias); ok {
   456  					return ok
   457  				}
   458  			}
   459  
   460  		case *adt.OptionalField:
   461  			if x.Src != nil {
   462  				if _, ok := x.Src.Label.(*ast.Alias); ok {
   463  					return ok
   464  				}
   465  			}
   466  
   467  		case adt.Expr:
   468  
   469  		case *adt.Ellipsis:
   470  			if x.Value != nil {
   471  				return true
   472  			}
   473  
   474  		default:
   475  			return true
   476  		}
   477  	}
   478  	return false
   479  }
   480  
   481  func isSelfContained(expr adt.Expr) bool {
   482  	switch x := expr.(type) {
   483  	case *adt.BinaryExpr:
   484  		return isSelfContained(x.X) && isSelfContained(x.Y)
   485  	case *adt.UnaryExpr:
   486  		return isSelfContained(x.X)
   487  	case *adt.BoundExpr:
   488  		return isSelfContained(x.Expr)
   489  	case adt.Value:
   490  		return true
   491  	}
   492  	return false
   493  }