this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

cue/load: factor out syntax cache

We need to be able to read the file syntax
before creating the loader so we can determine
imports from command line files, but currently the syntax
cache is only created as part of the loader.

This CL factors out the syntax cache into its own
value so it can be used independently of the loader.

For #3144
For #3147

Signed-off-by: Roger Peppe <rogpeppe@gmail.com>
Change-Id: I2845406e7006a2ff9cc0b6d5dbb59798a8b1b30d
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1194764
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>

+69 -45
+2 -1
cue/load/instances.go
··· 66 66 if err != nil { 67 67 return []*build.Instance{c.newErrInstance(err)} 68 68 } 69 + synCache := newSyntaxCache(c) 69 70 70 71 // Pass all arguments that look like packages to loadPackages 71 72 // so that they'll be available when looking up the packages ··· 78 79 return []*build.Instance{c.newErrInstance(err)} 79 80 } 80 81 tg := newTagger(c) 81 - l := newLoader(c, tg, pkgs) 82 + l := newLoader(c, tg, synCache, pkgs) 82 83 83 84 if c.Context == nil { 84 85 c.Context = build.NewContext(
+66 -44
cue/load/loader.go
··· 22 22 import ( 23 23 "path/filepath" 24 24 25 + "cuelang.org/go/cue" 25 26 "cuelang.org/go/cue/ast" 26 27 "cuelang.org/go/cue/build" 27 28 "cuelang.org/go/cue/cuecontext" ··· 43 44 stk importStack 44 45 pkgs *modpkgload.Packages 45 46 47 + // syntaxCache caches the work involved when decoding a file into an *ast.File. 48 + // This can happen multiple times for the same file, for example when it is present in 49 + // multiple different build instances in the same directory hierarchy. 50 + syntaxCache *syntaxCache 51 + 52 + // dirCachedBuildFiles caches the work involved when reading a directory 53 + // and determining what build files it contains. 54 + // It is keyed by directory name. 46 55 // When we descend into subdirectories to load patterns such as ./... 47 - // we often end up loading parent directories many times over; cache that work by directory. 56 + // we often end up loading parent directories many times over; 57 + // this cache amortizes that work. 48 58 dirCachedBuildFiles map[string]cachedFileFiles 49 - 50 - // The same file may be decoded into an *ast.File multiple times, e.g. when it is present in 51 - // multiple different build instances in the same directory hierarchy; cache that work by file name. 52 - fileCachedSyntaxFiles map[string]cachedSyntaxFiles 53 59 } 54 60 55 - type ( 56 - cachedFileFiles struct { 57 - err errors.Error 58 - buildFiles []*build.File 59 - unknownFiles []*build.File 60 - } 61 + type cachedFileFiles struct { 62 + err errors.Error 63 + buildFiles []*build.File 64 + unknownFiles []*build.File 65 + } 61 66 62 - cachedSyntaxFiles struct { 63 - err error 64 - files []*ast.File 65 - } 66 - ) 67 - 68 - func newLoader(c *Config, tg *tagger, pkgs *modpkgload.Packages) *loader { 67 + func newLoader(c *Config, tg *tagger, syntaxCache *syntaxCache, pkgs *modpkgload.Packages) *loader { 69 68 return &loader{ 70 - cfg: c, 71 - tagger: tg, 72 - pkgs: pkgs, 73 - dirCachedBuildFiles: map[string]cachedFileFiles{}, 74 - fileCachedSyntaxFiles: map[string]cachedSyntaxFiles{}, 69 + cfg: c, 70 + tagger: tg, 71 + pkgs: pkgs, 72 + dirCachedBuildFiles: map[string]cachedFileFiles{}, 73 + syntaxCache: syntaxCache, 75 74 } 76 75 } 77 76 ··· 94 93 // cueFilesPackage creates a package for building a collection of CUE files 95 94 // (typically named on the command line). 96 95 func (l *loader) cueFilesPackage(files []*build.File) *build.Instance { 97 - 98 96 // ModInit() // TODO: support modules 99 97 pkg := l.cfg.Context.NewInstance(l.cfg.Dir, l.loadFunc) 100 98 ··· 120 118 fp.allPackages = true 121 119 pkg.PkgName = "_" 122 120 } 123 - for _, file := range files { 124 - fp.add(l.cfg.Dir, file, allowAnonymous|allowExcludedFiles) 121 + for _, bf := range files { 122 + fp.add(l.cfg.Dir, bf, allowAnonymous|allowExcludedFiles) 125 123 } 126 124 127 125 // TODO: ModImportFromFiles(files) ··· 149 147 return pkg 150 148 } 151 149 150 + // addFiles populates p.Files by reading CUE syntax from p.BuildFiles. 152 151 func (l *loader) addFiles(p *build.Instance) { 153 152 for _, bf := range p.BuildFiles { 154 - syntax, ok := l.fileCachedSyntaxFiles[bf.Filename] 155 - if !ok { 156 - syntax = cachedSyntaxFiles{} 157 - // TODO(mvdan): reuse the same context for an entire loader 158 - d := encoding.NewDecoder(cuecontext.New(), bf, &encoding.Config{ 159 - Stdin: l.cfg.stdin(), 160 - ParseFile: l.cfg.ParseFile, 161 - }) 162 - for ; !d.Done(); d.Next() { 163 - syntax.files = append(syntax.files, d.File()) 164 - } 165 - syntax.err = d.Err() 166 - d.Close() 167 - l.fileCachedSyntaxFiles[bf.Filename] = syntax 168 - } 169 - 170 - if err := syntax.err; err != nil { 153 + files, err := l.syntaxCache.getSyntax(bf) 154 + if err != nil { 171 155 p.ReportError(errors.Promote(err, "load")) 172 156 } 173 - for _, f := range syntax.files { 157 + for _, f := range files { 174 158 _ = p.AddSyntax(f) 175 159 } 176 160 } 177 161 } 162 + 163 + type syntaxCache struct { 164 + config encoding.Config 165 + ctx *cue.Context 166 + cache map[string]syntaxCacheEntry 167 + } 168 + 169 + type syntaxCacheEntry struct { 170 + err error 171 + files []*ast.File 172 + } 173 + 174 + func newSyntaxCache(cfg *Config) *syntaxCache { 175 + return &syntaxCache{ 176 + config: encoding.Config{ 177 + Stdin: cfg.stdin(), 178 + ParseFile: cfg.ParseFile, 179 + }, 180 + ctx: cuecontext.New(), 181 + cache: make(map[string]syntaxCacheEntry), 182 + } 183 + } 184 + 185 + // getSyntax returns the CUE syntax corresponding to the file argument f. 186 + func (c *syntaxCache) getSyntax(bf *build.File) ([]*ast.File, error) { 187 + syntax, ok := c.cache[bf.Filename] 188 + if ok { 189 + return syntax.files, syntax.err 190 + } 191 + d := encoding.NewDecoder(c.ctx, bf, &c.config) 192 + for ; !d.Done(); d.Next() { 193 + syntax.files = append(syntax.files, d.File()) 194 + } 195 + d.Close() 196 + syntax.err = d.Err() 197 + c.cache[bf.Filename] = syntax 198 + return syntax.files, syntax.err 199 + }
+1
cue/load/loader_common.go
··· 163 163 return nil 164 164 } 165 165 166 + // add adds the given file to the appropriate package in fp. 166 167 func (fp *fileProcessor) add(root string, file *build.File, mode importMode) (added bool) { 167 168 fullPath := file.Filename 168 169 if fullPath != "-" {