blob: 81cb5154d395263b21877d631ebf3c6a76bc394a [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 (
"reflect"
"sync"
"cuelang.org/go/cue/ast"
"cuelang.org/go/internal"
"cuelang.org/go/internal/core/adt"
)
// Index maps conversions from label names to internal codes.
//
// All instances belonging to the same package should share this Index.
//
// INDEX IS A TRANSITIONAL TYPE TO BRIDGE THE OLD AND NEW
// IMPLEMENTATIONS. USE RUNTIME.
type Index struct {
labelMap map[string]int64
labels []string
// Change this to Instance at some point.
// From *structLit/*Vertex -> Instance
imports map[interface{}]interface{}
importsByPath map[string]interface{}
// imports map[string]*adt.Vertex
offset int64
parent *Index
// mutex sync.Mutex
typeCache sync.Map // map[reflect.Type]evaluated
}
// SharedIndex is used for indexing builtins and any other labels common to
// all instances.
var SharedIndex = newSharedIndex()
var SharedIndexNew = newSharedIndex()
var SharedRuntimeNew = &Runtime{index: SharedIndexNew}
func newSharedIndex() *Index {
i := &Index{
labelMap: map[string]int64{"": 0},
labels: []string{""},
imports: map[interface{}]interface{}{},
importsByPath: map[string]interface{}{},
}
return i
}
// NewIndex creates a new index.
func NewIndex(parent *Index) *Index {
i := &Index{
labelMap: map[string]int64{},
imports: map[interface{}]interface{}{},
importsByPath: map[string]interface{}{},
offset: int64(len(parent.labels)) + parent.offset,
parent: parent,
}
return i
}
func (x *Index) IndexToString(i int64) string {
for ; i < x.offset; x = x.parent {
}
return x.labels[i-x.offset]
}
func (x *Index) StringToIndex(s string) int64 {
for p := x; p != nil; p = p.parent {
if f, ok := p.labelMap[s]; ok {
return int64(f)
}
}
index := int64(len(x.labelMap)) + x.offset
x.labelMap[s] = index
x.labels = append(x.labels, s)
return int64(index)
}
func (x *Index) HasLabel(s string) (ok bool) {
for c := x; c != nil; c = c.parent {
_, ok = c.labelMap[s]
if ok {
break
}
}
return ok
}
func (x *Index) StoreType(t reflect.Type, v interface{}) {
x.typeCache.Store(t, v)
}
func (x *Index) LoadType(t reflect.Type) (v interface{}, ok bool) {
v, ok = x.typeCache.Load(t)
return v, ok
}
func (x *Index) StrLabel(str string) adt.Feature {
return x.Label(str, false)
}
func (x *Index) NodeLabel(n ast.Node) (f adt.Feature, ok bool) {
switch label := n.(type) {
case *ast.BasicLit:
name, _, err := ast.LabelName(label)
return x.Label(name, false), err == nil
case *ast.Ident:
name, err := ast.ParseIdent(label)
return x.Label(name, true), err == nil
}
return 0, false
}
func (x *Index) Label(s string, isIdent bool) adt.Feature {
index := x.StringToIndex(s)
typ := adt.StringLabel
if isIdent {
switch {
case internal.IsDef(s) && internal.IsHidden(s):
typ = adt.HiddenDefinitionLabel
case internal.IsDef(s):
typ = adt.DefinitionLabel
case internal.IsHidden(s):
typ = adt.HiddenLabel
}
}
f, _ := adt.MakeLabel(nil, index, typ)
return f
}
func (idx *Index) LabelStr(l adt.Feature) string {
index := int64(l.Index())
return idx.IndexToString(index)
}
func (x *Index) AddInst(path string, key, p interface{}) {
if key == nil {
panic("key must not be nil")
}
x.imports[key] = p
if path != "" {
x.importsByPath[path] = key
}
}
func (x *Index) GetImportFromNode(key interface{}) interface{} {
imp := x.imports[key]
if imp == nil && x.parent != nil {
return x.parent.GetImportFromNode(key)
}
return imp
}
func (x *Index) GetImportFromPath(id string) interface{} {
key := x.importsByPath[id]
if key == nil && x.parent != nil {
return x.parent.GetImportFromPath(id)
}
return key
}