github.com/solo-io/cue@v0.4.7/cue/instance.go (about)

     1  // Copyright 2018 The 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 cue
    16  
    17  import (
    18  	"github.com/solo-io/cue/cue/ast"
    19  	"github.com/solo-io/cue/cue/build"
    20  	"github.com/solo-io/cue/cue/errors"
    21  	"github.com/solo-io/cue/internal"
    22  	"github.com/solo-io/cue/internal/core/adt"
    23  	"github.com/solo-io/cue/internal/core/compile"
    24  	"github.com/solo-io/cue/internal/core/runtime"
    25  )
    26  
    27  // An InstanceOrValue is implemented by Value and *Instance.
    28  //
    29  // This is a placeholder type that is used to allow Instance-based APIs to
    30  // transition to Value-based APIs. The goals is to get rid of the Instance
    31  // type before v1.0.0.
    32  type InstanceOrValue interface {
    33  	Value() Value
    34  
    35  	internal()
    36  }
    37  
    38  func (Value) internal()     {}
    39  func (*Instance) internal() {}
    40  
    41  // Value implements value.Instance.
    42  func (v hiddenValue) Value() Value { return v }
    43  
    44  // An Instance defines a single configuration based on a collection of
    45  // underlying CUE files.
    46  type Instance struct {
    47  	index *runtime.Runtime
    48  
    49  	root *adt.Vertex
    50  
    51  	ImportPath  string
    52  	Dir         string
    53  	PkgName     string
    54  	DisplayName string
    55  
    56  	Incomplete bool         // true if Pkg and all its dependencies are free of errors
    57  	Err        errors.Error // non-nil if the package had errors
    58  
    59  	inst *build.Instance
    60  }
    61  
    62  type hiddenInstance = Instance
    63  
    64  func addInst(x *runtime.Runtime, p *Instance) *Instance {
    65  	if p.inst == nil {
    66  		p.inst = &build.Instance{
    67  			ImportPath: p.ImportPath,
    68  			PkgName:    p.PkgName,
    69  		}
    70  	}
    71  	x.AddInst(p.ImportPath, p.root, p.inst)
    72  	x.SetBuildData(p.inst, p)
    73  	p.index = x
    74  	return p
    75  }
    76  
    77  func lookupInstance(x *runtime.Runtime, p *build.Instance) *Instance {
    78  	if x, ok := x.BuildData(p); ok {
    79  		return x.(*Instance)
    80  	}
    81  	return nil
    82  }
    83  
    84  func getImportFromBuild(x *runtime.Runtime, p *build.Instance, v *adt.Vertex) *Instance {
    85  	inst := lookupInstance(x, p)
    86  
    87  	if inst != nil {
    88  		return inst
    89  	}
    90  
    91  	inst = &Instance{
    92  		ImportPath:  p.ImportPath,
    93  		Dir:         p.Dir,
    94  		PkgName:     p.PkgName,
    95  		DisplayName: p.ImportPath,
    96  		root:        v,
    97  		inst:        p,
    98  		index:       x,
    99  	}
   100  	if p.Err != nil {
   101  		inst.setListOrError(p.Err)
   102  	}
   103  
   104  	x.SetBuildData(p, inst)
   105  
   106  	return inst
   107  }
   108  
   109  func getImportFromNode(x *runtime.Runtime, v *adt.Vertex) *Instance {
   110  	p := x.GetInstanceFromNode(v)
   111  	if p == nil {
   112  		return nil
   113  	}
   114  
   115  	return getImportFromBuild(x, p, v)
   116  }
   117  
   118  func getImportFromPath(x *runtime.Runtime, id string) *Instance {
   119  	node, _ := x.LoadImport(id)
   120  	if node == nil {
   121  		return nil
   122  	}
   123  	b := x.GetInstanceFromNode(node)
   124  	inst := lookupInstance(x, b)
   125  	if inst == nil {
   126  		inst = &Instance{
   127  			ImportPath: b.ImportPath,
   128  			PkgName:    b.PkgName,
   129  			root:       node,
   130  			inst:       b,
   131  			index:      x,
   132  		}
   133  	}
   134  	return inst
   135  }
   136  
   137  func init() {
   138  	internal.MakeInstance = func(value interface{}) interface{} {
   139  		v := value.(Value)
   140  		x := v.eval(v.ctx())
   141  		st, ok := x.(*adt.Vertex)
   142  		if !ok {
   143  			st = &adt.Vertex{}
   144  			st.AddConjunct(adt.MakeRootConjunct(nil, x))
   145  		}
   146  		return addInst(v.idx, &Instance{
   147  			root: st,
   148  		})
   149  	}
   150  }
   151  
   152  // newInstance creates a new instance. Use Insert to populate the instance.
   153  func newInstance(x *runtime.Runtime, p *build.Instance, v *adt.Vertex) *Instance {
   154  	// TODO: associate root source with structLit.
   155  	inst := &Instance{
   156  		root: v,
   157  		inst: p,
   158  	}
   159  	if p != nil {
   160  		inst.ImportPath = p.ImportPath
   161  		inst.Dir = p.Dir
   162  		inst.PkgName = p.PkgName
   163  		inst.DisplayName = p.ImportPath
   164  		if p.Err != nil {
   165  			inst.setListOrError(p.Err)
   166  		}
   167  	}
   168  
   169  	x.AddInst(p.ImportPath, v, p)
   170  	x.SetBuildData(p, inst)
   171  	inst.index = x
   172  	return inst
   173  }
   174  
   175  func (inst *Instance) setListOrError(err errors.Error) {
   176  	inst.Incomplete = true
   177  	inst.Err = errors.Append(inst.Err, err)
   178  }
   179  
   180  func (inst *Instance) setError(err errors.Error) {
   181  	inst.Incomplete = true
   182  	inst.Err = errors.Append(inst.Err, err)
   183  }
   184  
   185  func (inst *Instance) eval(ctx *adt.OpContext) adt.Value {
   186  	// TODO: remove manifest here?
   187  	v := manifest(ctx, inst.root)
   188  	return v
   189  }
   190  
   191  // ID returns the package identifier that uniquely qualifies module and
   192  // package name.
   193  func (inst *Instance) ID() string {
   194  	if inst == nil || inst.inst == nil {
   195  		return ""
   196  	}
   197  	return inst.inst.ID()
   198  }
   199  
   200  // Doc returns the package comments for this instance.
   201  //
   202  // Deprecated: use inst.Value().Doc()
   203  func (inst *hiddenInstance) Doc() []*ast.CommentGroup {
   204  	return inst.Value().Doc()
   205  }
   206  
   207  // Value returns the root value of the configuration. If the configuration
   208  // defines in emit value, it will be that value. Otherwise it will be all
   209  // top-level values.
   210  func (inst *Instance) Value() Value {
   211  	ctx := newContext(inst.index)
   212  	inst.root.Finalize(ctx)
   213  	return newVertexRoot(inst.index, ctx, inst.root)
   214  }
   215  
   216  // Eval evaluates an expression within an existing instance.
   217  //
   218  // Expressions may refer to builtin packages if they can be uniquely identified.
   219  //
   220  // Deprecated: use
   221  // inst.Value().Context().BuildExpr(expr, Scope(inst.Value), InferBuiltins(true))
   222  func (inst *hiddenInstance) Eval(expr ast.Expr) Value {
   223  	v := inst.Value()
   224  	return v.Context().BuildExpr(expr, Scope(v), InferBuiltins(true))
   225  }
   226  
   227  // DO NOT USE.
   228  //
   229  // Deprecated: do not use.
   230  func Merge(inst ...*Instance) *Instance {
   231  	v := &adt.Vertex{}
   232  
   233  	i := inst[0]
   234  	ctx := newContext(i.index)
   235  
   236  	// TODO: interesting test: use actual unification and then on K8s corpus.
   237  
   238  	for _, i := range inst {
   239  		w := i.Value()
   240  		v.AddConjunct(adt.MakeRootConjunct(nil, w.v.ToDataAll()))
   241  	}
   242  	v.Finalize(ctx)
   243  
   244  	p := addInst(i.index, &Instance{
   245  		root: v,
   246  	})
   247  	return p
   248  }
   249  
   250  // Build creates a new instance from the build instances, allowing unbound
   251  // identifier to bind to the top-level field in inst. The top-level fields in
   252  // inst take precedence over predeclared identifier and builtin functions.
   253  //
   254  // Deprecated: use Context.Build
   255  func (inst *hiddenInstance) Build(p *build.Instance) *Instance {
   256  	p.Complete()
   257  
   258  	idx := inst.index
   259  	r := inst.index
   260  
   261  	rErr := r.ResolveFiles(p)
   262  
   263  	cfg := &compile.Config{Scope: valueScope(Value{idx: r, v: inst.root})}
   264  	v, err := compile.Files(cfg, r, p.ID(), p.Files...)
   265  
   266  	v.AddConjunct(adt.MakeRootConjunct(nil, inst.root))
   267  
   268  	i := newInstance(idx, p, v)
   269  	if rErr != nil {
   270  		i.setListOrError(rErr)
   271  	}
   272  	if i.Err != nil {
   273  		i.setListOrError(i.Err)
   274  	}
   275  
   276  	if err != nil {
   277  		i.setListOrError(err)
   278  	}
   279  
   280  	return i
   281  }
   282  
   283  func (inst *Instance) value() Value {
   284  	return newVertexRoot(inst.index, newContext(inst.index), inst.root)
   285  }
   286  
   287  // Lookup reports the value at a path starting from the top level struct. The
   288  // Exists method of the returned value will report false if the path did not
   289  // exist. The Err method reports if any error occurred during evaluation. The
   290  // empty path returns the top-level configuration struct. Use LookupDef for definitions or LookupField for
   291  // any kind of field.
   292  //
   293  // Deprecated: use Value.LookupPath
   294  func (inst *hiddenInstance) Lookup(path ...string) Value {
   295  	return inst.value().Lookup(path...)
   296  }
   297  
   298  // LookupDef reports the definition with the given name within struct v. The
   299  // Exists method of the returned value will report false if the definition did
   300  // not exist. The Err method reports if any error occurred during evaluation.
   301  //
   302  // Deprecated: use Value.LookupPath
   303  func (inst *hiddenInstance) LookupDef(path string) Value {
   304  	return inst.value().LookupDef(path)
   305  }
   306  
   307  // LookupField reports a Field at a path starting from v, or an error if the
   308  // path is not. The empty path returns v itself.
   309  //
   310  // It cannot look up hidden or unexported fields.
   311  //
   312  // Deprecated: this API does not work with new-style definitions. Use
   313  // FieldByName defined on inst.Value().
   314  //
   315  // Deprecated: use Value.LookupPath
   316  func (inst *hiddenInstance) LookupField(path ...string) (f FieldInfo, err error) {
   317  	v := inst.value()
   318  	for _, k := range path {
   319  		s, err := v.Struct()
   320  		if err != nil {
   321  			return f, err
   322  		}
   323  
   324  		f, err = s.FieldByName(k, true)
   325  		if err != nil {
   326  			return f, err
   327  		}
   328  		if f.IsHidden {
   329  			return f, errNotFound
   330  		}
   331  		v = f.Value
   332  	}
   333  	return f, err
   334  }
   335  
   336  // Fill creates a new instance with the values of the old instance unified with
   337  // the given value. It is not possible to update the emit value.
   338  //
   339  // Values may be any Go value that can be converted to CUE, an ast.Expr or
   340  // a Value. In the latter case, it will panic if the Value is not from the same
   341  // Runtime.
   342  //
   343  // Deprecated: use Value.FillPath()
   344  func (inst *hiddenInstance) Fill(x interface{}, path ...string) (*Instance, error) {
   345  	v := inst.Value().Fill(x, path...)
   346  
   347  	inst = addInst(inst.index, &Instance{
   348  		root: v.v,
   349  		inst: nil,
   350  
   351  		// Omit ImportPath to indicate this is not an importable package.
   352  		Dir:        inst.Dir,
   353  		PkgName:    inst.PkgName,
   354  		Incomplete: inst.Incomplete,
   355  	})
   356  	return inst, nil
   357  }