Skip to content

Commit 050844f

Browse files
committed
internal/filetypes: remove dependency on CUE evaluator
We remove the CUE-evaluator-based implementation of the filetypes logic and use the "emulated" version exclusively. Fixes #3280. Signed-off-by: Roger Peppe <[email protected]> Change-Id: I1528f71bebf7a05e587ec23646cac01c7a9e7825 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1214223 TryBot-Result: CUEcueckoo <[email protected]> Unity-Result: CUE porcuepine <[email protected]> Reviewed-by: Daniel Martí <[email protected]>
1 parent f37ff95 commit 050844f

File tree

4 files changed

+20
-234
lines changed

4 files changed

+20
-234
lines changed

cmd/cue/cmd/testdata/script/stats.txtar

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,14 @@ contents overwritten
4646
{
4747
"CUE": {
4848
"EvalVersion": 3,
49-
"Unifications": 5,
49+
"Unifications": 4,
5050
"Disjuncts": 2,
51-
"Conjuncts": 10,
51+
"Conjuncts": 8,
5252
"CloseIDElems": 0,
53-
"NumCloseIDs": 3,
53+
"NumCloseIDs": 2,
5454
"Freed": 0,
5555
"Reused": 0,
56-
"Allocs": 7,
56+
"Allocs": 6,
5757
"Retained": 0
5858
},
5959
"Go": {
@@ -64,14 +64,14 @@ contents overwritten
6464
-- out/stats.cue --
6565
CUE: {
6666
EvalVersion: 3
67-
Unifications: 5
67+
Unifications: 4
6868
Disjuncts: 2
69-
Conjuncts: 10
69+
Conjuncts: 8
7070
CloseIDElems: 0
71-
NumCloseIDs: 3
71+
NumCloseIDs: 2
7272
Freed: 0
7373
Reused: 0
74-
Allocs: 7
74+
Allocs: 6
7575
Retained: 0
7676
}
7777
Go: {
@@ -81,14 +81,14 @@ Go: {
8181
-- out/stats.yaml --
8282
CUE:
8383
EvalVersion: 3
84-
Unifications: 5
84+
Unifications: 4
8585
Disjuncts: 2
86-
Conjuncts: 10
86+
Conjuncts: 8
8787
CloseIDElems: 0
88-
NumCloseIDs: 3
88+
NumCloseIDs: 2
8989
Freed: 0
9090
Reused: 0
91-
Allocs: 7
91+
Allocs: 6
9292
Retained: 0
9393
Go:
9494
AllocBytes: 300456
@@ -97,14 +97,14 @@ Go:
9797
{
9898
"CUE": {
9999
"EvalVersion": 3,
100-
"Unifications": 5,
100+
"Unifications": 4,
101101
"Disjuncts": 2,
102-
"Conjuncts": 10,
102+
"Conjuncts": 8,
103103
"CloseIDElems": 0,
104-
"NumCloseIDs": 3,
104+
"NumCloseIDs": 2,
105105
"Freed": 0,
106106
"Reused": 0,
107-
"Allocs": 7,
107+
"Allocs": 6,
108108
"Retained": 0
109109
},
110110
"Go": {

internal/filetypes/filetypes.go

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,9 @@ type FileInfo = internal.FileInfo
7171
//
7272
// json: foo.data bar.data json+schema: bar.schema
7373
func ParseArgs(args []string) (files []*build.File, err error) {
74-
evalMu.Lock()
75-
defer evalMu.Unlock()
76-
typesInit()
77-
7874
qualifier := ""
7975
hasFiles := false
8076

81-
emptyScope := true
8277
sc := &scope{}
8378
for i, s := range args {
8479
a := strings.Split(s, ":")
@@ -87,14 +82,6 @@ func ParseArgs(args []string) (files []*build.File, err error) {
8782
if s == "" {
8883
return nil, errors.Newf(token.NoPos, "empty file name")
8984
}
90-
if emptyScope && len(a) == 1 && strings.HasSuffix(a[0], ".cue") {
91-
// Handle majority case.
92-
f := *fileForCUE
93-
f.Filename = a[0]
94-
files = append(files, &f)
95-
hasFiles = true
96-
continue
97-
}
9885
f, err := toFile(Input, sc, s)
9986
if err != nil {
10087
return nil, err
@@ -121,7 +108,6 @@ func ParseArgs(args []string) (files []*build.File, err error) {
121108
if err != nil {
122109
return nil, err
123110
}
124-
emptyScope = false
125111
qualifier = a[0]
126112
hasFiles = false
127113
}
@@ -136,9 +122,6 @@ func DefaultTagsForInterpretation(interp build.Interpretation, mode Mode) map[st
136122
if interp == "" {
137123
return nil
138124
}
139-
evalMu.Lock()
140-
defer evalMu.Unlock()
141-
// TODO this could be done once only.
142125

143126
// This should never fail if called with a legitimate build.Interpretation constant.
144127
f, err := toFile(mode, &scope{
@@ -182,9 +165,6 @@ func ParseFile(s string, mode Mode) (*build.File, error) {
182165

183166
// ParseFileAndType parses a file and type combo.
184167
func ParseFileAndType(file, scope string, mode Mode) (*build.File, error) {
185-
evalMu.Lock()
186-
defer evalMu.Unlock()
187-
typesInit()
188168
sc, err := parseScope(scope)
189169
if err != nil {
190170
return nil, err

internal/filetypes/tofile.go

Lines changed: 2 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -15,161 +15,19 @@
1515
package filetypes
1616

1717
import (
18-
"fmt"
19-
"sync"
20-
21-
"cuelang.org/go/cue"
2218
"cuelang.org/go/cue/build"
23-
"cuelang.org/go/cue/cuecontext"
24-
"cuelang.org/go/cue/errors"
25-
"cuelang.org/go/cue/token"
26-
"github.com/google/go-cmp/cmp"
2719
)
2820

29-
// evalMu guards against concurrent execution of the CUE evaluator.
30-
// See issue https://cuelang.org/issue/2733
31-
var evalMu sync.Mutex
32-
3321
//go:generate go run -tags bootstrap ./generate.go
3422

3523
func toFile(mode Mode, sc *scope, filename string) (*build.File, error) {
36-
f0, err0 := toFileGenerated(mode, sc, filename)
37-
f1, err1 := toFileOrig(mode, sc, filename)
38-
if (err0 != nil) != (err1 != nil) {
39-
panic(fmt.Errorf("toFile discrepancy on error return; mode %v; scope %v; filename %v:\nold: %v\nnew: %v", mode, sc, filename, err1, err0))
40-
} else if diff := cmp.Diff(f0, f1); diff != "" {
41-
panic(fmt.Errorf("toFile result discrepancy; mode %v; scope %v; filename %v:\n%s", mode, sc, filename, diff))
42-
}
43-
44-
return f0, err0
45-
}
46-
47-
func toFileOrig(mode Mode, sc *scope, filename string) (*build.File, error) {
48-
fileVal := cuecontext.New().CompileString("{}")
49-
for tagName := range sc.topLevel {
50-
info := lookup(typesValue, "tagInfo", tagName)
51-
if info.Exists() {
52-
fileVal = fileVal.Unify(info)
53-
} else {
54-
return nil, errors.Newf(token.NoPos, "unknown filetype %s", tagName)
55-
}
56-
}
57-
modeVal := lookup(typesValue, "modes", mode.String())
58-
fileVal = fileVal.Unify(lookup(modeVal, "FileInfo"))
59-
return toFile1(modeVal, fileVal, filename, sc)
60-
}
61-
62-
func toFile1(modeVal, fileVal cue.Value, filename string, sc *scope) (*build.File, error) {
63-
if !lookup(fileVal, "encoding").Exists() {
64-
if ext := fileExt(filename); ext != "" {
65-
extFile := lookup(modeVal, "extensions", ext)
66-
if !extFile.Exists() {
67-
return nil, errors.Newf(token.NoPos, "unknown file extension %s", ext)
68-
}
69-
fileVal = fileVal.Unify(extFile)
70-
} else {
71-
return nil, errors.Newf(token.NoPos, "no encoding specified for file %q", filename)
72-
}
73-
}
74-
allowedSubsidiaryBool := lookup(fileVal, "boolTags")
75-
for tagName, val := range sc.subsidiaryBool {
76-
if !lookup(allowedSubsidiaryBool, tagName).Exists() {
77-
return nil, errors.Newf(token.NoPos, "tag %s is not allowed in this context", tagName)
78-
}
79-
fileVal = fileVal.FillPath(cue.MakePath(cue.Str("boolTags"), cue.Str(tagName)), val)
80-
}
81-
allowedSubsidiaryString := lookup(fileVal, "tags")
82-
for tagName, val := range sc.subsidiaryString {
83-
if !lookup(allowedSubsidiaryString, tagName).Exists() {
84-
return nil, errors.Newf(token.NoPos, "tag %s is not allowed in this context", tagName)
85-
}
86-
fileVal = fileVal.FillPath(cue.MakePath(cue.Str("tags"), cue.Str(tagName)), val)
87-
}
88-
89-
// Note that the filename is only filled in the Go value, and not the CUE value.
90-
// This makes no difference to the logic, but saves a non-trivial amount of evaluator work.
91-
f := &build.File{Filename: filename}
92-
if err := fileVal.Decode(f); err != nil {
93-
return nil, errors.Wrapf(err, token.NoPos,
94-
"could not determine file type")
95-
}
96-
return f, nil
24+
return toFileGenerated(mode, sc, filename)
9725
}
9826

9927
// FromFile returns detailed file info for a given build file. It ignores b.Tags and
10028
// b.BoolTags, instead assuming that any tag handling has already been processed
10129
// by [ParseArgs] or similar.
10230
// The b.Encoding field must be non-empty.
10331
func FromFile(b *build.File, mode Mode) (*FileInfo, error) {
104-
fi0, err0 := fromFileGenerated(b, mode)
105-
fi1, err1 := fromFileOrig(b, mode)
106-
if (err0 != nil) != (err1 != nil) {
107-
panic(fmt.Errorf("toFile discrepancy on error return; mode %v; file %#v:\nold: %v\nnew: %v", mode, b, err1, err0))
108-
} else if diff := cmp.Diff(fi1, fi0); diff != "" {
109-
panic(fmt.Errorf("toFile result discrepancy; mode %v; file %#v\n%s", mode, b, diff))
110-
}
111-
112-
return fi0, err0
113-
}
114-
115-
func fromFileOrig(b *build.File, mode Mode) (*FileInfo, error) {
116-
evalMu.Lock()
117-
defer evalMu.Unlock()
118-
typesInit()
119-
modeVal := lookup(typesValue, "modes", mode.String())
120-
fileVal := lookup(modeVal, "FileInfo")
121-
if b.Encoding != "" {
122-
fileVal = fileVal.FillPath(cue.MakePath(cue.Str("encoding")), b.Encoding)
123-
}
124-
if b.Interpretation != "" {
125-
fileVal = fileVal.FillPath(cue.MakePath(cue.Str("interpretation")), b.Interpretation)
126-
}
127-
if b.Form != "" {
128-
fileVal = fileVal.FillPath(cue.MakePath(cue.Str("form")), b.Form)
129-
}
130-
if b.Encoding == "" {
131-
return nil, errors.Newf(token.NoPos, "no encoding specified")
132-
}
133-
var errs errors.Error
134-
interpretation, _ := lookup(fileVal, "interpretation").String()
135-
if b.Form != "" {
136-
fileVal, errs = unifyWith(errs, fileVal, typesValue, "forms", string(b.Form))
137-
// may leave some encoding-dependent options open in data mode.
138-
} else if interpretation != "" {
139-
// always sets form=*schema
140-
fileVal, errs = unifyWith(errs, fileVal, typesValue, "interpretations", interpretation)
141-
}
142-
if interpretation == "" {
143-
s, err := lookup(fileVal, "encoding").String()
144-
if err != nil {
145-
return nil, err
146-
}
147-
fileVal, errs = unifyWith(errs, fileVal, modeVal, "encodings", s)
148-
}
149-
150-
fi := &FileInfo{}
151-
if err := fileVal.Decode(fi); err != nil {
152-
return nil, errors.Wrapf(err, token.NoPos, "could not parse arguments")
153-
}
154-
fi.Filename = b.Filename
155-
return fi, errs
156-
}
157-
158-
// unifyWith returns the equivalent of `v1 & v2[field][value]`.
159-
func unifyWith(errs errors.Error, v1, v2 cue.Value, field, value string) (cue.Value, errors.Error) {
160-
v1 = v1.Unify(lookup(v2, field, value))
161-
if err := v1.Err(); err != nil {
162-
errs = errors.Append(errs,
163-
errors.Newf(token.NoPos, "unknown %s %s", field, value))
164-
}
165-
return v1, errs
166-
}
167-
168-
// lookup looks up the given string field path in v.
169-
func lookup(v cue.Value, elems ...string) cue.Value {
170-
sels := make([]cue.Selector, len(elems))
171-
for i := range elems {
172-
sels[i] = cue.Str(elems[i])
173-
}
174-
return v.LookupPath(cue.MakePath(sels...))
32+
return fromFileGenerated(b, mode)
17533
}

internal/filetypes/types.go

Lines changed: 2 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,6 @@ package filetypes
1616

1717
import (
1818
_ "embed"
19-
"fmt"
20-
"iter"
21-
"sync"
22-
23-
"cuelang.org/go/cue"
24-
"cuelang.org/go/cue/build"
25-
"cuelang.org/go/cue/cuecontext"
26-
)
27-
28-
//go:embed types.cue
29-
var typesCUE string
30-
31-
var (
32-
typesValue cue.Value
33-
fileForExt map[string]*build.File
34-
fileForCUE *build.File
35-
tagTypes map[string]TagType
3619
)
3720

3821
//go:generate go run golang.org/x/tools/cmd/stringer -type=TagType -linecomment
@@ -46,40 +29,5 @@ const (
4629
TagSubsidiaryString
4730
)
4831

49-
var typesInit = sync.OnceFunc(func() {
50-
ctx := cuecontext.New()
51-
typesValue = ctx.CompileString(typesCUE, cue.Filename("types.cue"))
52-
if err := typesValue.Err(); err != nil {
53-
panic(err)
54-
}
55-
// Reading a file in input mode with a non-explicit scope is a very
56-
// common operation, so cache the build.File value for all
57-
// the known file extensions.
58-
if err := typesValue.LookupPath(cue.MakePath(cue.Str("fileForExtVanilla"))).Decode(&fileForExt); err != nil {
59-
panic(err)
60-
}
61-
fileForCUE = fileForExt[".cue"]
62-
// Check invariants assumed by FromFile
63-
if fileForCUE.Form != "" || fileForCUE.Interpretation != "" || fileForCUE.Encoding != build.CUE {
64-
panic(fmt.Errorf("unexpected value for CUE file type: %#v", fileForCUE))
65-
}
66-
})
67-
68-
// structFields returns an iterator over the names of all the regulat fields
69-
// in v and their values.
70-
func structFields(v cue.Value) iter.Seq2[string, cue.Value] {
71-
return func(yield func(string, cue.Value) bool) {
72-
if !v.Exists() {
73-
return
74-
}
75-
iter, err := v.Fields()
76-
if err != nil {
77-
return
78-
}
79-
for iter.Next() {
80-
if !yield(iter.Selector().Unquoted(), iter.Value()) {
81-
break
82-
}
83-
}
84-
}
85-
}
32+
// initialized by types_gen.go
33+
var tagTypes map[string]TagType

0 commit comments

Comments
 (0)