blob: 97f718de693b7c1429e75b5074b4af3501c93b75 [file] [log] [blame]
// Copyright 2020 CUE Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package runtime
import (
"path"
"sync"
"cuelang.org/go/cue/build"
"cuelang.org/go/cue/errors"
"cuelang.org/go/internal/core/adt"
)
type PackageFunc func(ctx adt.Runtime) (*adt.Vertex, errors.Error)
func RegisterBuiltin(importPath string, f PackageFunc) {
sharedIndex.RegisterBuiltin(importPath, f)
}
func (x *index) RegisterBuiltin(importPath string, f PackageFunc) {
if x.builtins == nil {
x.builtins = map[string]PackageFunc{}
}
x.builtins[importPath] = f
}
var SharedRuntime = &Runtime{index: sharedIndex}
func (x *Runtime) IsBuiltinPackage(path string) bool {
return x.index.isBuiltin(path)
}
// sharedIndex is used for indexing builtins and any other labels common to
// all instances.
var sharedIndex = newIndex()
// index maps conversions from label names to internal codes.
//
// All instances belonging to the same package should share this index.
type index struct {
// Change this to Instance at some point.
// From *structLit/*Vertex -> Instance
imports map[*adt.Vertex]*build.Instance
importsByPath map[string]*adt.Vertex
importsByBuild map[*build.Instance]*adt.Vertex
builtins map[string]PackageFunc
// mutex sync.Mutex
typeCache sync.Map // map[reflect.Type]evaluated
}
func newIndex() *index {
i := &index{
imports: map[*adt.Vertex]*build.Instance{},
importsByPath: map[string]*adt.Vertex{},
importsByBuild: map[*build.Instance]*adt.Vertex{},
}
return i
}
func (x *index) isBuiltin(id string) bool {
if x == nil || x.builtins == nil {
return false
}
_, ok := x.builtins[id]
return ok
}
func (r *Runtime) AddInst(path string, key *adt.Vertex, p *build.Instance) {
x := r.index
if key == nil {
panic("key must not be nil")
}
x.imports[key] = p
x.importsByBuild[p] = key
if path != "" {
x.importsByPath[path] = key
}
}
func (r *Runtime) GetInstanceFromNode(key *adt.Vertex) *build.Instance {
return r.index.imports[key]
}
func (r *Runtime) getNodeFromInstance(key *build.Instance) *adt.Vertex {
return r.index.importsByBuild[key]
}
func (r *Runtime) LoadImport(importPath string) (*adt.Vertex, errors.Error) {
x := r.index
key := x.importsByPath[importPath]
if key != nil {
return key, nil
}
if x.builtins != nil {
if f := x.builtins[importPath]; f != nil {
p, err := f(r)
if err != nil {
return adt.ToVertex(&adt.Bottom{Err: err}), nil
}
inst := &build.Instance{
ImportPath: importPath,
PkgName: path.Base(importPath),
}
x.imports[p] = inst
x.importsByPath[importPath] = p
x.importsByBuild[inst] = p
return p, nil
}
}
return key, nil
}