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