Skip to content

Commit

Permalink
cue: prepare to hoist index type
Browse files Browse the repository at this point in the history
Change-Id: If27ae95cff0e43de01d1fc03938e487d57fc67eb
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/6507
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
  • Loading branch information
mpvl committed Jul 19, 2020
1 parent 18736bf commit 3efd10d
Show file tree
Hide file tree
Showing 16 changed files with 161 additions and 139 deletions.
22 changes: 11 additions & 11 deletions cue/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func (v *astVisitor) appendPath(a []string) []string {
func (v *astVisitor) resolve(n *ast.Ident) value {
ctx := v.ctx()
name := v.ident(n)
label := v.label(name, true)
label := v.Label(name, true)
if r := v.resolveRoot; r != nil {
for _, a := range r.arcs {
if a.feature == label {
Expand Down Expand Up @@ -254,7 +254,7 @@ func (v *astVisitor) walk(astNode ast.Node) (ret value) {
if i != len(n.Elts)-1 {
return v1.walk(x.Type) // Generate an error
}
f := v.ctx().label("_", true)
f := v.ctx().Label("_", true)
sig := &params{}
sig.add(f, &basicType{newNode(x), stringKind})
template := &lambdaExpr{newNode(x), sig, &top{newNode(x)}}
Expand Down Expand Up @@ -429,9 +429,9 @@ func (v *astVisitor) walk(astNode ast.Node) (ret value) {
a, ok := expr.(*ast.Alias)
if ok {
expr = a.Expr
f = v.label(v.ident(a.Ident), true)
f = v.Label(v.ident(a.Ident), true)
} else {
f = v.label("_", true)
f = v.Label("_", true)
}

// Parse the key filter or a bulk-optional field. The special value
Expand All @@ -456,7 +456,7 @@ func (v *astVisitor) walk(astNode ast.Node) (ret value) {
v.errf(x, "map element type cannot be a definition")
}
v.sel = "*"
f := v.label(v.ident(x.Ident), true)
f := v.Label(v.ident(x.Ident), true)

sig := &params{}
sig.add(f, &basicType{newNode(lab), stringKind})
Expand All @@ -474,7 +474,7 @@ func (v *astVisitor) walk(astNode ast.Node) (ret value) {
v.sel = "*"
}
}
f, ok := v.nodeLabel(x)
f, ok := v.NodeLabel(x)
if !ok {
return v.errf(lab, "invalid field name: %v", lab)
}
Expand Down Expand Up @@ -587,7 +587,7 @@ func (v *astVisitor) walk(astNode ast.Node) (ret value) {
break
}

f := v.label(name, true)
f := v.Label(name, true)
if _, ok := n.Node.(*ast.ImportSpec); ok {
n2 := v.mapScope(n.Node)
ref := &nodeRef{baseValue: newExpr(n), node: n2, label: f}
Expand Down Expand Up @@ -631,7 +631,7 @@ func (v *astVisitor) walk(astNode ast.Node) (ret value) {
ret = v.errf(n, "invalid label: %v", err)

case name != "":
f = v.label(name, true)
f = v.Label(name, true)
ret = &selectorExpr{newExpr(n), ret, f}

default:
Expand Down Expand Up @@ -704,7 +704,7 @@ func (v *astVisitor) walk(astNode ast.Node) (ret value) {
ret = &selectorExpr{
newExpr(n),
v.walk(n.X),
v.label(v.ident(n.Sel), true),
v.Label(v.ident(n.Sel), true),
}
v.inSelector--

Expand Down Expand Up @@ -822,10 +822,10 @@ func wrapClauses(v *astVisitor, y yielder, clauses []ast.Clause) yielder {
if n.Key != nil {
key = v.ident(n.Key)
}
f := v.label(key, true)
f := v.Label(key, true)
fn.add(f, &basicType{newExpr(n.Key), stringKind | intKind})

f = v.label(v.ident(n.Value), true)
f = v.Label(v.ident(n.Value), true)
fn.add(f, &top{})

y = &feed{newExpr(n.Source), v.walk(n.Source), fn}
Expand Down
8 changes: 4 additions & 4 deletions cue/binop.go
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,7 @@ func (x *customValidator) check(ctx *context, v evaluated) evaluated {
return ctx.mkErr(x, "invalid custom validator")
} else if !b.b {
var buf bytes.Buffer
fmt.Fprintf(&buf, "%s.%s", ctx.labelStr(x.call.pkg), x.call.Name)
fmt.Fprintf(&buf, "%s.%s", ctx.LabelStr(x.call.pkg), x.call.Name)
buf.WriteString("(")
for _, a := range x.args {
buf.WriteString(ctx.str(a))
Expand Down Expand Up @@ -672,7 +672,7 @@ func (x *structLit) binOp(ctx *context, src source, op op, other evaluated) eval
// TODO: pass position of key, not value. Currently does not have
// a position.
return ctx.mkErr(a.v, a.v, "field %q not allowed in closed struct",
ctx.labelStr(a.feature))
ctx.LabelStr(a.feature))
}
cp := ctx.copy(a.v)
obj.arcs = append(obj.arcs,
Expand All @@ -688,7 +688,7 @@ outer:
if a.definition != b.definition {
src := binSrc(x.Pos(), op, a.v, b.v)
return ctx.mkErr(src, "field %q declared as definition and regular field",
ctx.labelStr(a.feature))
ctx.LabelStr(a.feature))
}
w := b.v
if x.closeStatus.shouldFinalize() {
Expand Down Expand Up @@ -717,7 +717,7 @@ outer:
// TODO: pass position of key, not value. Currently does not have a
// position.
return ctx.mkErr(a.v, x, "field %q not allowed in closed struct",
ctx.labelStr(a.feature))
ctx.LabelStr(a.feature))
}
a.setValue(v)
obj.arcs = append(obj.arcs, a)
Expand Down
79 changes: 46 additions & 33 deletions cue/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"sync"

"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/ast/astutil"
"cuelang.org/go/cue/build"
"cuelang.org/go/cue/errors"
"cuelang.org/go/cue/token"
Expand Down Expand Up @@ -121,20 +122,11 @@ func (r *Runtime) CompileFile(file *ast.File) (*Instance, error) {
// may import builtin packages. Use Build to allow importing non-builtin
// packages.
func (r *Runtime) CompileExpr(expr ast.Expr) (*Instance, error) {
ctx := r.buildContext()
p := ctx.NewInstance("", dummyLoad)
switch x := expr.(type) {
case *ast.StructLit:
_ = p.AddSyntax(&ast.File{Decls: x.Elts})
default:
_ = p.AddSyntax(&ast.File{
Decls: []ast.Decl{&ast.EmbedDecl{Expr: expr}},
})
}
if p.Err != nil {
return nil, p.Err
f, err := astutil.ToFile(expr)
if err != nil {
return nil, err
}
return r.complete(p)
return r.CompileFile(f)
}

// Parse parses a CUE source value into a CUE Instance. The source code may
Expand Down Expand Up @@ -192,14 +184,9 @@ func (r *Runtime) build(instances []*build.Instance) ([]*Instance, error) {
//
// Deprecated: use CompileExpr
func (r *Runtime) FromExpr(expr ast.Expr) (*Instance, error) {
i := r.index().newInstance(nil)
err := i.insertFile(&ast.File{
return r.CompileFile(&ast.File{
Decls: []ast.Decl{&ast.EmbedDecl{Expr: expr}},
})
if err != nil {
return nil, err
}
return i, nil
}

// index maps conversions from label names to internal codes.
Expand Down Expand Up @@ -239,7 +226,6 @@ func newSharedIndex() *index {
// FileSet idea from the API. Just take the hit of the extra pointers for
// positions in the ast, and then optimize the storage in an abstract
// machine implementation for storing graphs.
token.NewFile("dummy", sharedOffset, 0)
i := &index{
labelMap: map[string]label{"": 0},
labels: []string{""},
Expand All @@ -262,22 +248,32 @@ func newIndex(parent *index) *index {
return i
}

func (idx *index) strLabel(str string) label {
return idx.label(str, false)
func (idx *index) StrLabel(str string) label {
return idx.Label(str, false)
}

func (idx *index) nodeLabel(n ast.Node) (f label, ok bool) {
func (idx *index) NodeLabel(n ast.Node) (f label, ok bool) {
switch x := n.(type) {
case *ast.BasicLit:
name, _, err := ast.LabelName(x)
return idx.label(name, false), err == nil
return idx.Label(name, false), err == nil
case *ast.Ident:
name, err := ast.ParseIdent(x)
return idx.label(name, true), err == nil
return idx.Label(name, true), err == nil
}
return 0, false
}

func (idx *index) HasLabel(s string) (ok bool) {
for x := idx; x != nil; x = x.parent {
_, ok = x.labelMap[s]
if ok {
break
}
}
return ok
}

func (idx *index) findLabel(s string) (f label, ok bool) {
for x := idx; x != nil; x = x.parent {
f, ok = x.labelMap[s]
Expand All @@ -288,7 +284,7 @@ func (idx *index) findLabel(s string) (f label, ok bool) {
return f, ok
}

func (idx *index) label(s string, isIdent bool) label {
func (idx *index) Label(s string, isIdent bool) label {
f, ok := idx.findLabel(s)
if !ok {
f = label(len(idx.labelMap)) + idx.offset
Expand All @@ -307,13 +303,18 @@ func (idx *index) label(s string, isIdent bool) label {
return f
}

func (idx *index) labelStr(l label) string {
func (idx *index) LabelStr(l label) string {
l >>= labelShift
for ; l < idx.offset; idx = idx.parent {
}
return idx.labels[l-idx.offset]
}

func isBuiltin(s string) bool {
_, ok := builtins[s]
return ok
}

func (idx *index) loadInstance(p *build.Instance) *Instance {
if inst := idx.loaded[p]; inst != nil {
if !inst.complete {
Expand All @@ -324,11 +325,13 @@ func (idx *index) loadInstance(p *build.Instance) *Instance {
return inst
}
files := p.Files
inst := idx.newInstance(p)
inst := newInstance(idx, p)
idx.loaded[p] = inst

if inst.Err == nil {
// inst.instance.index.state = s
// inst.instance.inst = p
inst.Err = resolveFiles(idx, p)
inst.Err = resolveFiles(idx, p, isBuiltin)
for _, f := range files {
err := inst.insertFile(f)
inst.Err = errors.Append(inst.Err, err)
Expand All @@ -344,7 +347,11 @@ func lineStr(idx *index, n ast.Node) string {
return n.Pos().String()
}

func resolveFiles(idx *index, p *build.Instance) errors.Error {
func resolveFiles(
idx *index,
p *build.Instance,
isBuiltin func(s string) bool,
) errors.Error {
// Link top-level declarations. As top-level entries get unified, an entry
// may be linked to any top-level entry of any of the files.
allFields := map[string]ast.Node{}
Expand All @@ -358,14 +365,20 @@ func resolveFiles(idx *index, p *build.Instance) errors.Error {
}
}
for _, f := range p.Files {
if err := resolveFile(idx, f, p, allFields); err != nil {
if err := resolveFile(idx, f, p, allFields, isBuiltin); err != nil {
return err
}
}
return nil
}

func resolveFile(idx *index, f *ast.File, p *build.Instance, allFields map[string]ast.Node) errors.Error {
func resolveFile(
idx *index,
f *ast.File,
p *build.Instance,
allFields map[string]ast.Node,
isBuiltin func(s string) bool,
) errors.Error {
unresolved := map[string][]*ast.Ident{}
for _, u := range f.Unresolved {
unresolved[u.Name] = append(unresolved[u.Name], u)
Expand All @@ -390,7 +403,7 @@ func resolveFile(idx *index, f *ast.File, p *build.Instance, allFields map[strin
name := path.Base(id)
if imp := p.LookupImport(id); imp != nil {
name = imp.PkgName
} else if _, ok := builtins[id]; !ok {
} else if !isBuiltin(id) {
errs = errors.Append(errs,
nodeErrorf(spec, "package %q not found", id))
continue
Expand Down
2 changes: 1 addition & 1 deletion cue/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func TestPartiallyResolved(t *testing.T) {
ImportPath: importPath,
PkgName: "foo",
}},
}, map[string]ast.Node{})
}, map[string]ast.Node{}, isBuiltin)

if err != nil {
t.Errorf("exected no error, found %v", err)
Expand Down

0 comments on commit 3efd10d

Please sign in to comment.