internal/core/eval: implement core evaluator
Does not yet implement imports and builtins.
- adds implementations for adt types
- adds eval package with higher-level evaluation
- some tweaks to compile
Change-Id: Ie91bd0bde8a03ed9957f306166042f56aebe19ce
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/6280
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/internal/core/adt/feature.go b/internal/core/adt/feature.go
index 684a74e..bc2a32c 100644
--- a/internal/core/adt/feature.go
+++ b/internal/core/adt/feature.go
@@ -16,6 +16,7 @@
import (
"strconv"
+ "strings"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/errors"
@@ -27,6 +28,8 @@
// representation of an integer or string label as well as a label type.
type Feature uint32
+// TODO: create labels such that list are sorted first (or last with index.)
+
// InvalidLabel is an encoding of an erroneous label.
const InvalidLabel Feature = 0x7 // 0xb111
@@ -68,9 +71,121 @@
}
}
+// StringValue reports the string value of f, which must be a string label.
+func (f Feature) StringValue(index StringIndexer) string {
+ if !f.IsString() {
+ panic("not a string label")
+ }
+ x := f.Index()
+ return index.IndexToString(int64(x))
+}
+
+// ToValue converts a label to a value, which will be a Num for integer labels
+// and a String for string labels. It panics when f is not a regular label.
+func (f Feature) ToValue(ctx *OpContext) Value {
+ if !f.IsRegular() {
+ panic("not a regular label")
+ }
+ if f.IsInt() {
+ return ctx.NewInt64(int64(f.Index()))
+ }
+ x := f.Index()
+ str := ctx.IndexToString(int64(x))
+ return ctx.NewString(str)
+}
+
+// StringLabel converts s to a string label.
+func (c *OpContext) StringLabel(s string) Feature {
+ return labelFromValue(c, &String{Str: s})
+}
+
+// MakeStringLabel creates a label for the given string.
+func MakeStringLabel(r StringIndexer, s string) Feature {
+ i := r.StringToIndex(s)
+
+ // TODO: set position if it exists.
+ f, err := MakeLabel(nil, i, StringLabel)
+ if err != nil {
+ panic("out of free string slots")
+ }
+ return f
+}
+
+// MakeIdentLabel creates a label for the given identifier.
+func MakeIdentLabel(r StringIndexer, s string) Feature {
+ i := r.StringToIndex(s)
+ t := StringLabel
+ switch {
+ case strings.HasPrefix(s, "#_"):
+ t = HiddenDefinitionLabel
+ case strings.HasPrefix(s, "#"):
+ t = DefinitionLabel
+ case strings.HasPrefix(s, "_"):
+ t = HiddenLabel
+ }
+ f, err := MakeLabel(nil, i, t)
+ if err != nil {
+ panic("out of free string slots")
+ }
+ return f
+}
+
+const msgGround = "invalid non-ground value %s (must be concrete %s)"
+
+func labelFromValue(ctx *OpContext, v Value) Feature {
+ var i int64
+ var t FeatureType
+ if isError(v) {
+ return InvalidLabel
+ }
+ switch v.Kind() {
+ case IntKind, NumKind:
+ x, _ := v.(*Num)
+ if x == nil {
+ ctx.addErrf(IncompleteError, pos(v), msgGround, v, "int")
+ return InvalidLabel
+ }
+ t = IntLabel
+ var err error
+ i, err = x.X.Int64()
+ if err != nil || x.K != IntKind {
+ ctx.AddErrf("invalid label %v: %v", v, err)
+ return InvalidLabel
+ }
+ if i < 0 {
+ ctx.AddErrf("invalid negative index %s", ctx.Str(x))
+ return InvalidLabel
+ }
+
+ case StringKind:
+ x, _ := v.(*String)
+ if x == nil {
+ ctx.addErrf(IncompleteError, pos(v), msgGround, v, "string")
+ return InvalidLabel
+ }
+ t = StringLabel
+ i = ctx.StringToIndex(x.Str)
+
+ default:
+ ctx.AddErrf("invalid label type %v", v.Kind())
+ return InvalidLabel
+ }
+
+ // TODO: set position if it exists.
+ f, err := MakeLabel(nil, i, t)
+ if err != nil {
+ ctx.AddErr(err)
+ }
+ return f
+}
+
// MakeLabel creates a label. It reports an error if the index is out of range.
-func MakeLabel(p token.Pos, index int64, f FeatureType) (Feature, errors.Error) {
+func MakeLabel(src ast.Node, index int64, f FeatureType) (Feature, errors.Error) {
if 0 > index || index > MaxIndex {
+ p := token.NoPos
+ if src != nil {
+ p = src.Pos()
+ }
return InvalidLabel,
errors.Newf(p, "int label out of range (%d not >=0 and <= %d)",
index, MaxIndex)