cuelang.org/go@v0.13.0/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  // ID returns the package identifier that uniquely qualifies module and
   169  // package name.
   170  func (inst *Instance) ID() string {
   171  	if inst == nil || inst.inst == nil {
   172  		return ""
   173  	}
   174  	return inst.inst.ID()
   175  }
   176  
   177  // Value returns the root value of the configuration. If the configuration
   178  // defines in emit value, it will be that value. Otherwise it will be all
   179  // top-level values.
   180  func (inst *Instance) Value() Value {
   181  	ctx := newContext(inst.index)
   182  	inst.root.Finalize(ctx)
   183  	// TODO: consider including these statistics as well. Right now, this only
   184  	// seems to be used in cue cmd for "auxiliary" evaluations, like filetypes.
   185  	// These arguably skew the actual statistics for the cue command line, so
   186  	// it is convenient to not include these.
   187  	// adt.AddStats(ctx)
   188  	return newVertexRoot(inst.index, ctx, inst.root)
   189  }
   190  
   191  // Eval evaluates an expression within an existing instance.
   192  //
   193  // Expressions may refer to builtin packages if they can be uniquely identified.
   194  //
   195  // Deprecated: use
   196  // inst.Value().Context().BuildExpr(expr, Scope(inst.Value), InferBuiltins(true))
   197  func (inst *hiddenInstance) Eval(expr ast.Expr) Value {
   198  	v := inst.Value()
   199  	return v.Context().BuildExpr(expr, Scope(v), InferBuiltins(true))
   200  }
   201  
   202  // DO NOT USE.
   203  //
   204  // Deprecated: do not use.
   205  func Merge(inst ...*Instance) *Instance {
   206  	v := &adt.Vertex{}
   207  
   208  	i := inst[0]
   209  	ctx := newContext(i.index)
   210  
   211  	// TODO: interesting test: use actual unification and then on K8s corpus.
   212  
   213  	for _, i := range inst {
   214  		w := i.Value()
   215  		v.AddConjunct(adt.MakeRootConjunct(nil, w.v.ToDataAll(ctx)))
   216  	}
   217  	v.Finalize(ctx)
   218  
   219  	p := addInst(i.index, &Instance{
   220  		root: v,
   221  	})
   222  	return p
   223  }
   224  
   225  // Build creates a new instance from the build instances, allowing unbound
   226  // identifier to bind to the top-level field in inst. The top-level fields in
   227  // inst take precedence over predeclared identifier and builtin functions.
   228  //
   229  // Deprecated: use [Context.BuildInstance]
   230  func (inst *hiddenInstance) Build(p *build.Instance) *Instance {
   231  	p.Complete()
   232  
   233  	idx := inst.index
   234  	r := inst.index
   235  
   236  	rErr := r.ResolveFiles(p)
   237  
   238  	cfg := &compile.Config{Scope: valueScope(Value{idx: r, v: inst.root})}
   239  	v, err := compile.Files(cfg, r, p.ID(), p.Files...)
   240  
   241  	// Just like [runtime.Runtime.Build], ensure that the @embed compiler is run as needed.
   242  	err = errors.Append(err, r.InjectImplementations(p, v))
   243  
   244  	v.AddConjunct(adt.MakeRootConjunct(nil, inst.root))
   245  
   246  	i := newInstance(idx, p, v)
   247  	if rErr != nil {
   248  		i.setListOrError(rErr)
   249  	}
   250  	if i.Err != nil {
   251  		i.setListOrError(i.Err)
   252  	}
   253  
   254  	if err != nil {
   255  		i.setListOrError(err)
   256  	}
   257  
   258  	return i
   259  }
   260  
   261  // Lookup reports the value at a path starting from the top level struct. The
   262  // Exists method of the returned value will report false if the path did not
   263  // exist. The Err method reports if any error occurred during evaluation. The
   264  // empty path returns the top-level configuration struct. Use LookupDef for definitions or LookupField for
   265  // any kind of field.
   266  //
   267  // Deprecated: use [Value.LookupPath]
   268  func (inst *hiddenInstance) Lookup(path ...string) Value {
   269  	return inst.Value().Lookup(path...)
   270  }
   271  
   272  // LookupDef reports the definition with the given name within struct v. The
   273  // Exists method of the returned value will report false if the definition did
   274  // not exist. The Err method reports if any error occurred during evaluation.
   275  //
   276  // Deprecated: use [Value.LookupPath]
   277  func (inst *hiddenInstance) LookupDef(path string) Value {
   278  	return inst.Value().LookupDef(path)
   279  }
   280  
   281  // LookupField reports a Field at a path starting from v, or an error if the
   282  // path is not. The empty path returns v itself.
   283  //
   284  // It cannot look up hidden or unexported fields.
   285  //
   286  // Deprecated: use [Value.LookupPath]
   287  func (inst *hiddenInstance) LookupField(path ...string) (f FieldInfo, err error) {
   288  	v := inst.Value()
   289  	for _, k := range path {
   290  		s, err := v.Struct()
   291  		if err != nil {
   292  			return f, err
   293  		}
   294  
   295  		f, err = s.FieldByName(k, true)
   296  		if err != nil {
   297  			return f, err
   298  		}
   299  		if f.IsHidden {
   300  			return f, errNotFound
   301  		}
   302  		v = f.Value
   303  	}
   304  	return f, err
   305  }
   306  
   307  // Fill creates a new instance with the values of the old instance unified with
   308  // the given value. It is not possible to update the emit value.
   309  //
   310  // Values may be any Go value that can be converted to CUE, an ast.Expr or
   311  // a Value. In the latter case, it will panic if the Value is not from the same
   312  // Runtime.
   313  //
   314  // Deprecated: use [Value.FillPath]
   315  func (inst *hiddenInstance) Fill(x interface{}, path ...string) (*Instance, error) {
   316  	v := inst.Value().Fill(x, path...)
   317  
   318  	inst = addInst(inst.index, &Instance{
   319  		root: v.v,
   320  		inst: nil,
   321  
   322  		// Omit ImportPath to indicate this is not an importable package.
   323  		Dir:        inst.Dir,
   324  		PkgName:    inst.PkgName,
   325  		Incomplete: inst.Incomplete,
   326  	})
   327  	return inst, nil
   328  }