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