github.com/joomcode/cue@v0.4.4-0.20221111115225-539fe3512047/internal/core/runtime/imports.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 runtime
    16  
    17  import (
    18  	"path"
    19  	"sync"
    20  
    21  	"github.com/joomcode/cue/cue/build"
    22  	"github.com/joomcode/cue/cue/errors"
    23  	"github.com/joomcode/cue/internal/core/adt"
    24  )
    25  
    26  type PackageFunc func(ctx adt.Runtime) (*adt.Vertex, errors.Error)
    27  
    28  func RegisterBuiltin(importPath string, f PackageFunc) {
    29  	sharedIndex.RegisterBuiltin(importPath, f)
    30  }
    31  
    32  func (x *index) RegisterBuiltin(importPath string, f PackageFunc) {
    33  	if x.builtinPaths == nil {
    34  		x.builtinPaths = map[string]PackageFunc{}
    35  		x.builtinShort = map[string]string{}
    36  	}
    37  	x.builtinPaths[importPath] = f
    38  	base := path.Base(importPath)
    39  	if _, ok := x.builtinShort[base]; ok {
    40  		importPath = "" // Don't allow ambiguous base paths.
    41  	}
    42  	x.builtinShort[base] = importPath
    43  }
    44  
    45  var SharedRuntime = &Runtime{index: sharedIndex}
    46  
    47  // BuiltinPackagePath converts a short-form builtin package identifier to its
    48  // full path or "" if this doesn't exist.
    49  func (x *Runtime) BuiltinPackagePath(path string) string {
    50  	return x.index.shortBuiltinToPath(path)
    51  }
    52  
    53  // sharedIndex is used for indexing builtins and any other labels common to
    54  // all instances.
    55  var sharedIndex = newIndex()
    56  
    57  // index maps conversions from label names to internal codes.
    58  //
    59  // All instances belonging to the same package should share this index.
    60  type index struct {
    61  	// lock is used to guard imports-related maps.
    62  	// TODO: makes these per cuecontext.
    63  	lock           sync.RWMutex
    64  	imports        map[*adt.Vertex]*build.Instance
    65  	importsByPath  map[string]*adt.Vertex
    66  	importsByBuild map[*build.Instance]*adt.Vertex
    67  
    68  	// These are initialized during Go package initialization time and do not
    69  	// need to be guarded.
    70  	builtinPaths map[string]PackageFunc // Full path
    71  	builtinShort map[string]string      // Commandline shorthand
    72  
    73  	typeCache sync.Map // map[reflect.Type]evaluated
    74  }
    75  
    76  func newIndex() *index {
    77  	i := &index{
    78  		imports:        map[*adt.Vertex]*build.Instance{},
    79  		importsByPath:  map[string]*adt.Vertex{},
    80  		importsByBuild: map[*build.Instance]*adt.Vertex{},
    81  	}
    82  	return i
    83  }
    84  
    85  func (x *index) shortBuiltinToPath(id string) string {
    86  	if x == nil || x.builtinPaths == nil {
    87  		return ""
    88  	}
    89  	return x.builtinShort[id]
    90  }
    91  
    92  func (r *Runtime) AddInst(path string, key *adt.Vertex, p *build.Instance) {
    93  	r.index.lock.Lock()
    94  	defer r.index.lock.Unlock()
    95  
    96  	x := r.index
    97  	if key == nil {
    98  		panic("key must not be nil")
    99  	}
   100  	x.imports[key] = p
   101  	x.importsByBuild[p] = key
   102  	if path != "" {
   103  		x.importsByPath[path] = key
   104  	}
   105  }
   106  
   107  func (r *Runtime) GetInstanceFromNode(key *adt.Vertex) *build.Instance {
   108  	r.index.lock.RLock()
   109  	defer r.index.lock.RUnlock()
   110  
   111  	return r.index.imports[key]
   112  }
   113  
   114  func (r *Runtime) getNodeFromInstance(key *build.Instance) *adt.Vertex {
   115  	r.index.lock.RLock()
   116  	defer r.index.lock.RUnlock()
   117  
   118  	return r.index.importsByBuild[key]
   119  }
   120  
   121  func (r *Runtime) LoadImport(importPath string) *adt.Vertex {
   122  	r.index.lock.Lock()
   123  	defer r.index.lock.Unlock()
   124  
   125  	x := r.index
   126  
   127  	key := x.importsByPath[importPath]
   128  	if key != nil {
   129  		return key
   130  	}
   131  
   132  	if x.builtinPaths != nil {
   133  		if f := x.builtinPaths[importPath]; f != nil {
   134  			p, err := f(r)
   135  			if err != nil {
   136  				return adt.ToVertex(&adt.Bottom{Err: err})
   137  			}
   138  			inst := &build.Instance{
   139  				ImportPath: importPath,
   140  				PkgName:    path.Base(importPath),
   141  			}
   142  			x.imports[p] = inst
   143  			x.importsByPath[importPath] = p
   144  			x.importsByBuild[inst] = p
   145  			return p
   146  		}
   147  	}
   148  
   149  	return key
   150  }