cuelang.org/go@v0.10.1/internal/core/export/value.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  	"strings"
    20  
    21  	"cuelang.org/go/cue/ast"
    22  	"cuelang.org/go/cue/ast/astutil"
    23  	"cuelang.org/go/cue/literal"
    24  	"cuelang.org/go/cue/token"
    25  	"cuelang.org/go/internal"
    26  	"cuelang.org/go/internal/core/adt"
    27  )
    28  
    29  func (e *exporter) bareValue(v adt.Value) ast.Expr {
    30  	switch x := v.(type) {
    31  	case *adt.Vertex:
    32  		return e.vertex(x)
    33  	case adt.Value:
    34  		a := &adt.Vertex{BaseValue: x}
    35  		return e.vertex(a)
    36  	default:
    37  		panic("unreachable")
    38  	}
    39  	// TODO: allow a Value context wrapper.
    40  }
    41  
    42  // TODO: if the original value was a single reference, we could replace the
    43  // value with a reference in graph mode.
    44  
    45  func (e *exporter) vertex(n *adt.Vertex) (result ast.Expr) {
    46  	var attrs []*ast.Attribute
    47  	if e.cfg.ShowAttributes {
    48  		attrs = ExtractDeclAttrs(n)
    49  	}
    50  
    51  	s, saved := e.pushFrame(n, n.Conjuncts)
    52  	e.top().upCount++
    53  	defer func() {
    54  		e.top().upCount--
    55  		e.popFrame(saved)
    56  	}()
    57  
    58  	for _, c := range n.Conjuncts {
    59  		e.markLets(c.Expr().Source(), s)
    60  	}
    61  
    62  	switch x := n.BaseValue.(type) {
    63  	case nil:
    64  		// bare
    65  	case *adt.StructMarker:
    66  		result = e.structComposite(n, attrs)
    67  
    68  	case *adt.ListMarker:
    69  		if e.showArcs(n) || attrs != nil {
    70  			result = e.structComposite(n, attrs)
    71  		} else {
    72  			result = e.listComposite(n)
    73  		}
    74  
    75  	case *adt.Bottom:
    76  		switch {
    77  		case n.ArcType == adt.ArcOptional:
    78  			// Optional fields may always be the original value.
    79  
    80  		case e.cfg.ShowErrors && x.ChildError:
    81  			// TODO(perf): use precompiled arc statistics
    82  			if len(n.Arcs) > 0 && n.Arcs[0].Label.IsInt() && !e.showArcs(n) && attrs == nil {
    83  				result = e.listComposite(n)
    84  			} else {
    85  				result = e.structComposite(n, attrs)
    86  			}
    87  
    88  		case !x.IsIncomplete() || len(n.Conjuncts) == 0 || e.cfg.Final:
    89  			result = e.bottom(x)
    90  		}
    91  
    92  	case adt.Value:
    93  		if e.showArcs(n) || attrs != nil {
    94  			result = e.structComposite(n, attrs)
    95  		} else {
    96  			result = e.value(x, n.Conjuncts...)
    97  		}
    98  
    99  	default:
   100  		panic("unknown value")
   101  	}
   102  	if result == nil {
   103  		// fall back to expression mode
   104  		a := []ast.Expr{}
   105  		n.VisitLeafConjuncts(func(c adt.Conjunct) bool {
   106  			if x := e.expr(c.Env, c.Elem()); x != dummyTop {
   107  				a = append(a, x)
   108  			}
   109  			return true
   110  		})
   111  		result = ast.NewBinExpr(token.AND, a...)
   112  	}
   113  
   114  	if len(s.Elts) > 0 {
   115  		filterUnusedLets(s)
   116  	}
   117  	if result != s && len(s.Elts) > 0 {
   118  		// There are used let expressions within a non-struct.
   119  		// For now we just fall back to the original expressions.
   120  		result = e.adt(nil, n)
   121  	}
   122  
   123  	return result
   124  }
   125  
   126  func (e *exporter) value(n adt.Value, a ...adt.Conjunct) (result ast.Expr) {
   127  	if e.cfg.TakeDefaults {
   128  		n = adt.Default(n)
   129  	}
   130  	// Evaluate arc if needed?
   131  
   132  	// if e.concrete && !adt.IsConcrete(n.Value) {
   133  	// 	return e.errf("non-concrete value: %v", e.bareValue(n.Value))
   134  	// }
   135  
   136  	switch x := n.(type) {
   137  	case *adt.Bottom:
   138  		result = e.bottom(x)
   139  
   140  	case *adt.Null:
   141  		result = e.null(x)
   142  
   143  	case *adt.Bool:
   144  		result = e.bool(x)
   145  
   146  	case *adt.Num:
   147  		result = e.num(x, a)
   148  
   149  	case *adt.String:
   150  		result = e.string(x, a)
   151  
   152  	case *adt.Bytes:
   153  		result = e.bytes(x, a)
   154  
   155  	case *adt.BasicType:
   156  		result = e.basicType(x)
   157  
   158  	case *adt.Top:
   159  		result = ast.NewIdent("_")
   160  
   161  	case *adt.BoundValue:
   162  		result = e.boundValue(x)
   163  
   164  	case *adt.Builtin:
   165  		result = e.builtin(x)
   166  
   167  	case *adt.BuiltinValidator:
   168  		result = e.builtinValidator(x)
   169  
   170  	case *adt.Vertex:
   171  		result = e.vertex(x)
   172  
   173  	case *adt.Conjunction:
   174  		switch len(x.Values) {
   175  		case 0:
   176  			return ast.NewIdent("_")
   177  		case 1:
   178  			if e.cfg.Simplify {
   179  				return e.expr(nil, x.Values[0])
   180  			}
   181  			return e.bareValue(x.Values[0])
   182  		}
   183  
   184  		a := []adt.Value{}
   185  		b := boundSimplifier{e: e}
   186  		for _, v := range x.Values {
   187  			if !e.cfg.Simplify || !b.add(v) {
   188  				a = append(a, v)
   189  			}
   190  		}
   191  
   192  		result = b.expr(e.ctx)
   193  		if result == nil {
   194  			a = x.Values
   195  		}
   196  
   197  		for _, x := range a {
   198  			result = wrapBin(result, e.bareValue(x), adt.AndOp)
   199  		}
   200  
   201  	case *adt.Disjunction:
   202  		a := []ast.Expr{}
   203  		for i, v := range x.Values {
   204  			var expr ast.Expr
   205  			if e.cfg.Simplify {
   206  				expr = e.bareValue(v)
   207  			} else {
   208  				expr = e.expr(nil, v)
   209  			}
   210  			if i < x.NumDefaults {
   211  				expr = &ast.UnaryExpr{Op: token.MUL, X: expr}
   212  			}
   213  			a = append(a, expr)
   214  		}
   215  		result = ast.NewBinExpr(token.OR, a...)
   216  
   217  	default:
   218  		panic(fmt.Sprintf("unsupported type %T", x))
   219  	}
   220  
   221  	// TODO: Add comments from original.
   222  
   223  	return result
   224  }
   225  
   226  func (e *exporter) bottom(n *adt.Bottom) *ast.BottomLit {
   227  	err := &ast.BottomLit{}
   228  	if x := n.Err; x != nil {
   229  		msg := x.Error()
   230  		comment := &ast.Comment{Text: "// " + msg}
   231  		err.AddComment(&ast.CommentGroup{
   232  			Line:     true,
   233  			Position: 2,
   234  			List:     []*ast.Comment{comment},
   235  		})
   236  	}
   237  	return err
   238  }
   239  
   240  func (e *exporter) null(n *adt.Null) *ast.BasicLit {
   241  	return &ast.BasicLit{Kind: token.NULL, Value: "null"}
   242  }
   243  
   244  func (e *exporter) bool(n *adt.Bool) (b *ast.BasicLit) {
   245  	return ast.NewBool(n.B)
   246  }
   247  
   248  func extractBasic(a []adt.Conjunct) *ast.BasicLit {
   249  	for _, v := range a {
   250  		if b, ok := v.Source().(*ast.BasicLit); ok {
   251  			return &ast.BasicLit{Kind: b.Kind, Value: b.Value}
   252  		}
   253  	}
   254  	return nil
   255  }
   256  
   257  func (e *exporter) num(n *adt.Num, orig []adt.Conjunct) *ast.BasicLit {
   258  	// TODO: take original formatting into account.
   259  	if b := extractBasic(orig); b != nil {
   260  		return b
   261  	}
   262  	kind := token.FLOAT
   263  	if n.K&adt.IntKind != 0 {
   264  		kind = token.INT
   265  	}
   266  	s := n.X.String()
   267  	if kind == token.FLOAT && !strings.ContainsAny(s, "eE.") {
   268  		s += "."
   269  	}
   270  	return &ast.BasicLit{Kind: kind, Value: s}
   271  }
   272  
   273  func (e *exporter) string(n *adt.String, orig []adt.Conjunct) *ast.BasicLit {
   274  	// TODO: take original formatting into account.
   275  	if b := extractBasic(orig); b != nil {
   276  		return b
   277  	}
   278  	s := literal.String.WithOptionalTabIndent(len(e.stack)).Quote(n.Str)
   279  	return &ast.BasicLit{
   280  		Kind:  token.STRING,
   281  		Value: s,
   282  	}
   283  }
   284  
   285  func (e *exporter) bytes(n *adt.Bytes, orig []adt.Conjunct) *ast.BasicLit {
   286  	// TODO: take original formatting into account.
   287  	if b := extractBasic(orig); b != nil {
   288  		return b
   289  	}
   290  	s := literal.Bytes.WithOptionalTabIndent(len(e.stack)).Quote(string(n.B))
   291  	return &ast.BasicLit{
   292  		Kind:  token.STRING,
   293  		Value: s,
   294  	}
   295  }
   296  
   297  func (e *exporter) basicType(n *adt.BasicType) ast.Expr {
   298  	// TODO: allow multi-bit types?
   299  	return ast.NewIdent(n.K.String())
   300  }
   301  
   302  func (e *exporter) boundValue(n *adt.BoundValue) ast.Expr {
   303  	return &ast.UnaryExpr{Op: n.Op.Token(), X: e.value(n.Value)}
   304  }
   305  
   306  func (e *exporter) builtin(x *adt.Builtin) ast.Expr {
   307  	if x.Package == 0 {
   308  		return ast.NewIdent(x.Name)
   309  	}
   310  	spec := ast.NewImport(nil, x.Package.StringValue(e.index))
   311  	info, _ := astutil.ParseImportSpec(spec)
   312  	ident := ast.NewIdent(info.Ident)
   313  	ident.Node = spec
   314  	return ast.NewSel(ident, x.Name)
   315  }
   316  
   317  func (e *exporter) builtinValidator(n *adt.BuiltinValidator) ast.Expr {
   318  	call := ast.NewCall(e.builtin(n.Builtin))
   319  	for _, a := range n.Args {
   320  		call.Args = append(call.Args, e.value(a))
   321  	}
   322  	return call
   323  }
   324  
   325  func (e *exporter) listComposite(v *adt.Vertex) ast.Expr {
   326  	l := &ast.ListLit{}
   327  	for _, a := range v.Arcs {
   328  		if !a.Label.IsInt() {
   329  			continue
   330  		}
   331  		elem := e.vertex(a)
   332  
   333  		if e.cfg.ShowDocs {
   334  			docs := ExtractDoc(a)
   335  			ast.SetComments(elem, docs)
   336  		}
   337  
   338  		l.Elts = append(l.Elts, elem)
   339  	}
   340  	m, ok := v.BaseValue.(*adt.ListMarker)
   341  	if !e.cfg.TakeDefaults && ok && m.IsOpen {
   342  		ellipsis := &ast.Ellipsis{}
   343  		typ := &adt.Vertex{
   344  			Parent: v,
   345  			Label:  adt.AnyIndex,
   346  		}
   347  		v.MatchAndInsert(e.ctx, typ)
   348  		typ.Finalize(e.ctx)
   349  		if typ.Kind() != adt.TopKind {
   350  			ellipsis.Type = e.value(typ)
   351  		}
   352  
   353  		l.Elts = append(l.Elts, ellipsis)
   354  	}
   355  	return l
   356  }
   357  
   358  func (e exporter) showArcs(v *adt.Vertex) bool {
   359  	p := e.cfg
   360  	if !p.ShowHidden && !p.ShowDefinitions {
   361  		return false
   362  	}
   363  	for _, a := range v.Arcs {
   364  		switch {
   365  		case a.Label.IsDef() && p.ShowDefinitions:
   366  			return true
   367  		case a.Label.IsHidden() && p.ShowHidden:
   368  			return true
   369  		}
   370  	}
   371  	return false
   372  }
   373  
   374  func (e *exporter) structComposite(v *adt.Vertex, attrs []*ast.Attribute) ast.Expr {
   375  	s := e.top().scope
   376  
   377  	showRegular := false
   378  	switch x := v.BaseValue.(type) {
   379  	case *adt.StructMarker:
   380  		showRegular = true
   381  	case *adt.ListMarker:
   382  		// As lists may be long, put them at the end.
   383  		defer e.addEmbed(e.listComposite(v))
   384  	case *adt.Bottom:
   385  		if !e.cfg.ShowErrors || !x.ChildError {
   386  			// Should not be reachable, but just in case. The output will be
   387  			// correct.
   388  			e.addEmbed(e.value(x))
   389  			return s
   390  		}
   391  		// Always also show regular fields, even when list, as we are in
   392  		// debugging mode.
   393  		showRegular = true
   394  		// TODO(perf): do something better
   395  		for _, a := range v.Arcs {
   396  			if a.Label.IsInt() {
   397  				defer e.addEmbed(e.listComposite(v))
   398  				break
   399  			}
   400  		}
   401  
   402  	case adt.Value:
   403  		e.addEmbed(e.value(x))
   404  	}
   405  
   406  	for _, a := range attrs {
   407  		s.Elts = append(s.Elts, a)
   408  	}
   409  
   410  	p := e.cfg
   411  	for _, label := range VertexFeatures(e.ctx, v) {
   412  		show := false
   413  		switch label.Typ() {
   414  		case adt.StringLabel:
   415  			show = showRegular
   416  		case adt.IntLabel:
   417  			continue
   418  		case adt.DefinitionLabel:
   419  			show = p.ShowDefinitions
   420  		case adt.HiddenLabel, adt.HiddenDefinitionLabel:
   421  			show = p.ShowHidden && label.PkgID(e.ctx) == e.pkgID
   422  		}
   423  		if !show {
   424  			continue
   425  		}
   426  
   427  		f := &ast.Field{Label: e.stringLabel(label)}
   428  
   429  		e.addField(label, f, f.Value)
   430  
   431  		if label.IsDef() {
   432  			e.inDefinition++
   433  		}
   434  
   435  		arc := v.LookupRaw(label)
   436  		if arc == nil {
   437  			continue
   438  		}
   439  
   440  		if arc.ArcType == adt.ArcOptional && !p.ShowOptional {
   441  			continue
   442  		}
   443  		// TODO: report an error for required fields in Final mode?
   444  		// This package typically does not create errors that did not result
   445  		// from evaluation already.
   446  
   447  		internal.SetConstraint(f, arc.ArcType.Token())
   448  
   449  		f.Value = e.vertex(arc.DerefValue())
   450  
   451  		if label.IsDef() {
   452  			e.inDefinition--
   453  		}
   454  
   455  		if p.ShowAttributes {
   456  			f.Attrs = ExtractFieldAttrs(arc)
   457  		}
   458  
   459  		if p.ShowDocs {
   460  			docs := ExtractDoc(arc)
   461  			ast.SetComments(f, docs)
   462  		}
   463  
   464  		s.Elts = append(s.Elts, f)
   465  	}
   466  
   467  	return s
   468  }