...

Source file src/cuelang.org/go/internal/core/export/value.go

Documentation: cuelang.org/go/internal/core/export

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

View as plain text