github.com/joomcode/cue@v0.4.4-0.20221111115225-539fe3512047/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/joomcode/cue/cue/ast"
    22  	"github.com/joomcode/cue/cue/token"
    23  	"github.com/joomcode/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.Elem) (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  	s, saved := e.pushFrame(orig)
    95  	defer e.popFrame(saved)
    96  
    97  	// Handle value aliases and lets
    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  		x.markLets(c.c.Expr().Source())
   114  	}
   115  
   116  	defer filterUnusedLets(s)
   117  
   118  	defer func() {
   119  		if valueAlias != nil {
   120  			valueAlias.Expr = expr
   121  			expr = valueAlias
   122  		}
   123  	}()
   124  
   125  	hasAlias := len(s.Elts) > 0
   126  
   127  	for _, c := range a {
   128  		e.top().upCount = c.up
   129  		x := c.c.Elem()
   130  		e.addExpr(c.c.Env, src, x, false)
   131  	}
   132  
   133  	if src != nil {
   134  		for _, a := range src.Arcs {
   135  			if x, ok := e.fields[a.Label]; ok {
   136  				x.arc = a
   137  				e.fields[a.Label] = x
   138  			}
   139  		}
   140  	}
   141  
   142  	for _, a := range e.attrs {
   143  		s.Elts = append(s.Elts, a)
   144  	}
   145  
   146  	// Unify values only for one level.
   147  	if a := e.values.Conjuncts; len(a) > 0 {
   148  		e.values.Finalize(e.ctx)
   149  		e.embed = append(e.embed, e.value(e.values, a...))
   150  	}
   151  
   152  	// Collect and order set of fields.
   153  
   154  	fields := []adt.Feature{}
   155  	for f := range e.fields {
   156  		fields = append(fields, f)
   157  	}
   158  
   159  	// Sort fields in case features lists are missing to ensure
   160  	// predictability. Also sort in reverse order, so that bugs
   161  	// are more likely exposed.
   162  	sort.Slice(fields, func(i, j int) bool {
   163  		return fields[i] > fields[j]
   164  	})
   165  
   166  	if adt.DebugSort == 0 {
   167  		m := sortArcs(extractFeatures(e.structs))
   168  		sort.SliceStable(fields, func(i, j int) bool {
   169  			if m[fields[j]] == 0 {
   170  				return m[fields[i]] != 0
   171  			}
   172  			return m[fields[i]] > m[fields[j]]
   173  		})
   174  	} else {
   175  		adt.DebugSortFields(e.ctx, fields)
   176  	}
   177  
   178  	if len(e.fields) == 0 && !e.hasEllipsis {
   179  		switch len(e.embed) + len(e.conjuncts) {
   180  		case 0:
   181  			if len(e.attrs) > 0 {
   182  				break
   183  			}
   184  			if len(e.structs) > 0 || e.isData {
   185  				return e.wrapCloseIfNecessary(s, src)
   186  			}
   187  			return ast.NewIdent("_")
   188  		case 1:
   189  			var x ast.Expr
   190  			if len(e.conjuncts) == 1 {
   191  				x = e.conjuncts[0]
   192  			} else {
   193  				x = e.embed[0]
   194  			}
   195  			if len(e.attrs) == 0 && !hasAlias {
   196  				return x
   197  			}
   198  			if st, ok := x.(*ast.StructLit); ok {
   199  				s.Elts = append(s.Elts, st.Elts...)
   200  				return e.wrapCloseIfNecessary(s, src)
   201  			}
   202  		}
   203  	}
   204  
   205  	for _, x := range e.embed {
   206  		s.Elts = append(s.Elts, &ast.EmbedDecl{Expr: x})
   207  	}
   208  
   209  	for _, f := range fields {
   210  		field := e.fields[f]
   211  		c := field.conjuncts
   212  
   213  		label := e.stringLabel(f)
   214  
   215  		if f.IsDef() {
   216  			x.inDefinition++
   217  		}
   218  
   219  		a := []adt.Conjunct{}
   220  		for _, cc := range c {
   221  			a = append(a, cc.c)
   222  		}
   223  
   224  		d := &ast.Field{Label: label}
   225  
   226  		top := e.frame(0)
   227  		if fr, ok := top.fields[f]; ok && fr.alias != "" {
   228  			setFieldAlias(d, fr.alias)
   229  			fr.node = d
   230  			top.fields[f] = fr
   231  		}
   232  
   233  		d.Value = e.mergeValues(f, field.arc, c, a...)
   234  
   235  		if f.IsDef() {
   236  			x.inDefinition--
   237  		}
   238  
   239  		if isOptional(a) {
   240  			d.Optional = token.Blank.Pos()
   241  		}
   242  		if x.cfg.ShowDocs {
   243  			docs := extractDocs(src, a)
   244  			ast.SetComments(d, docs)
   245  		}
   246  		if x.cfg.ShowAttributes {
   247  			for _, c := range a {
   248  				d.Attrs = extractFieldAttrs(d.Attrs, c)
   249  			}
   250  		}
   251  		s.Elts = append(s.Elts, d)
   252  	}
   253  	if e.hasEllipsis {
   254  		s.Elts = append(s.Elts, &ast.Ellipsis{})
   255  	}
   256  
   257  	ws := e.wrapCloseIfNecessary(s, src)
   258  	switch {
   259  	case len(e.conjuncts) == 0:
   260  		return ws
   261  
   262  	case len(e.structs) > 0, len(s.Elts) > 0:
   263  		e.conjuncts = append(e.conjuncts, ws)
   264  	}
   265  
   266  	return ast.NewBinExpr(token.AND, e.conjuncts...)
   267  }
   268  
   269  func (e *conjuncts) wrapCloseIfNecessary(s *ast.StructLit, v *adt.Vertex) ast.Expr {
   270  	if !e.hasEllipsis && v != nil {
   271  		if st, ok := v.BaseValue.(*adt.StructMarker); ok && st.NeedClose {
   272  			return ast.NewCall(ast.NewIdent("close"), s)
   273  		}
   274  	}
   275  	return s
   276  }
   277  
   278  // Conjuncts if for collecting values of a single vertex.
   279  type conjuncts struct {
   280  	*exporter
   281  	// Values is used to collect non-struct values.
   282  	values      *adt.Vertex
   283  	embed       []ast.Expr
   284  	conjuncts   []ast.Expr
   285  	structs     []*adt.StructInfo
   286  	fields      map[adt.Feature]field
   287  	attrs       []*ast.Attribute
   288  	hasEllipsis bool
   289  
   290  	// A value is a struct if it has a non-zero structs slice or if isData is
   291  	// set to true. Data vertices may not have conjuncts associated with them.
   292  	isData bool
   293  }
   294  
   295  func (c *conjuncts) addValueConjunct(src *adt.Vertex, env *adt.Environment, x adt.Elem) {
   296  	switch b, ok := x.(adt.BaseValue); {
   297  	case ok && src != nil && isTop(b) && !isTop(src.BaseValue):
   298  		// drop top
   299  	default:
   300  		c.values.AddConjunct(adt.MakeRootConjunct(env, x))
   301  	}
   302  }
   303  
   304  func (c *conjuncts) addConjunct(f adt.Feature, env *adt.Environment, n adt.Node) {
   305  	x := c.fields[f]
   306  	v := adt.MakeRootConjunct(env, n)
   307  	x.conjuncts = append(x.conjuncts, conjunct{
   308  		c:  v,
   309  		up: c.top().upCount,
   310  	})
   311  	// x.upCounts = append(x.upCounts, c.top().upCount)
   312  	c.fields[f] = x
   313  }
   314  
   315  type field struct {
   316  	docs      []*ast.CommentGroup
   317  	arc       *adt.Vertex
   318  	conjuncts []conjunct
   319  }
   320  
   321  type conjunct struct {
   322  	c  adt.Conjunct
   323  	up int32
   324  }
   325  
   326  func (e *conjuncts) addExpr(env *adt.Environment, src *adt.Vertex, x adt.Elem, isEmbed bool) {
   327  	switch x := x.(type) {
   328  	case *adt.StructLit:
   329  		e.top().upCount++
   330  
   331  		if e.cfg.ShowAttributes {
   332  			e.attrs = extractDeclAttrs(e.attrs, x.Src)
   333  		}
   334  
   335  		// Only add if it only has no bulk fields or elipsis.
   336  		if isComplexStruct(x) {
   337  			_, saved := e.pushFrame(nil)
   338  			e.embed = append(e.embed, e.adt(x, nil))
   339  			e.top().upCount-- // not necessary, but for proper form
   340  			e.popFrame(saved)
   341  			return
   342  		}
   343  		// Used for sorting.
   344  		e.structs = append(e.structs, &adt.StructInfo{StructLit: x, Env: env})
   345  
   346  		for _, d := range x.Decls {
   347  			var label adt.Feature
   348  			switch f := d.(type) {
   349  			case *adt.Field:
   350  				label = f.Label
   351  			case *adt.OptionalField:
   352  				// TODO: mark optional here.
   353  				label = f.Label
   354  			case *adt.Ellipsis:
   355  				e.hasEllipsis = true
   356  				continue
   357  			case adt.Expr:
   358  				e.addExpr(env, nil, f, true)
   359  				continue
   360  
   361  				// TODO: also handle dynamic fields
   362  			default:
   363  				panic(fmt.Sprintf("Unexpected type %T", d))
   364  			}
   365  			e.addConjunct(label, env, d)
   366  		}
   367  		e.top().upCount--
   368  
   369  	case adt.Value: // other values.
   370  		switch v := x.(type) {
   371  		case nil:
   372  		default:
   373  			e.addValueConjunct(src, env, x)
   374  
   375  		case *adt.Vertex:
   376  			if b, ok := v.BaseValue.(*adt.Bottom); ok {
   377  				if !b.IsIncomplete() || e.cfg.Final {
   378  					e.addExpr(env, v, b, false)
   379  					return
   380  				}
   381  			}
   382  
   383  			switch {
   384  			default:
   385  				for _, c := range v.Conjuncts {
   386  					e.addExpr(c.Env, v, c.Elem(), false)
   387  				}
   388  
   389  			case v.IsData():
   390  				e.structs = append(e.structs, v.Structs...)
   391  				e.isData = true
   392  
   393  				if y, ok := v.BaseValue.(adt.Value); ok {
   394  					e.addValueConjunct(src, env, y)
   395  				}
   396  
   397  				for _, a := range v.Arcs {
   398  					a.Finalize(e.ctx) // TODO: should we do this?
   399  
   400  					e.addConjunct(a.Label, env, a)
   401  				}
   402  			}
   403  		}
   404  
   405  	case *adt.BinaryExpr:
   406  		switch {
   407  		case x.Op == adt.AndOp && !isEmbed:
   408  			e.addExpr(env, src, x.X, false)
   409  			e.addExpr(env, src, x.Y, false)
   410  		case isSelfContained(x):
   411  			e.addValueConjunct(src, env, x)
   412  		default:
   413  			if isEmbed {
   414  				e.embed = append(e.embed, e.expr(x))
   415  			} else {
   416  				e.conjuncts = append(e.conjuncts, e.expr(x))
   417  			}
   418  		}
   419  
   420  	default:
   421  		switch {
   422  		case isSelfContained(x):
   423  			e.addValueConjunct(src, env, x)
   424  		case isEmbed:
   425  			e.embed = append(e.embed, e.expr(x))
   426  		default:
   427  			e.conjuncts = append(e.conjuncts, e.expr(x))
   428  		}
   429  	}
   430  }
   431  
   432  func isTop(x adt.BaseValue) bool {
   433  	switch v := x.(type) {
   434  	case *adt.Top:
   435  		return true
   436  	case *adt.BasicType:
   437  		return v.K == adt.TopKind
   438  	default:
   439  		return false
   440  	}
   441  }
   442  
   443  // TODO: find a better way to annotate optionality. Maybe a special conjunct
   444  // or store it in the field information?
   445  func isOptional(a []adt.Conjunct) bool {
   446  	if len(a) == 0 {
   447  		return false
   448  	}
   449  	for _, c := range a {
   450  		if v, ok := c.Elem().(*adt.Vertex); ok && !v.IsData() && len(v.Conjuncts) > 0 {
   451  			return isOptional(v.Conjuncts)
   452  		}
   453  		switch f := c.Source().(type) {
   454  		case nil:
   455  			return false
   456  		case *ast.Field:
   457  			if f.Optional == token.NoPos {
   458  				return false
   459  			}
   460  		}
   461  	}
   462  	return true
   463  }
   464  
   465  func isComplexStruct(s *adt.StructLit) bool {
   466  	for _, d := range s.Decls {
   467  		switch x := d.(type) {
   468  		case *adt.Field:
   469  			// TODO: remove this and also handle field annotation in expr().
   470  			// This allows structs to be merged. Ditto below.
   471  			if x.Src != nil {
   472  				if _, ok := x.Src.Label.(*ast.Alias); ok {
   473  					return ok
   474  				}
   475  			}
   476  
   477  		case *adt.OptionalField:
   478  			if x.Src != nil {
   479  				if _, ok := x.Src.Label.(*ast.Alias); ok {
   480  					return ok
   481  				}
   482  			}
   483  
   484  		case adt.Expr:
   485  
   486  		case *adt.Ellipsis:
   487  			if x.Value != nil {
   488  				return true
   489  			}
   490  
   491  		default:
   492  			return true
   493  		}
   494  	}
   495  	return false
   496  }
   497  
   498  func isSelfContained(expr adt.Elem) bool {
   499  	switch x := expr.(type) {
   500  	case *adt.BinaryExpr:
   501  		return isSelfContained(x.X) && isSelfContained(x.Y)
   502  	case *adt.UnaryExpr:
   503  		return isSelfContained(x.X)
   504  	case *adt.BoundExpr:
   505  		return isSelfContained(x.Expr)
   506  	case adt.Value:
   507  		return true
   508  	}
   509  	return false
   510  }