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