cuelang.org/go@v0.13.0/internal/core/runtime/resolve.go (about) 1 // Copyright 2020 CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package runtime 16 17 import ( 18 "path" 19 "strconv" 20 21 "cuelang.org/go/cue/ast" 22 "cuelang.org/go/cue/build" 23 "cuelang.org/go/cue/errors" 24 ) 25 26 // TODO(resolve): this is also done in compile, do we need both? 27 func (r *Runtime) ResolveFiles(p *build.Instance) (errs errors.Error) { 28 idx := r.index 29 30 // Link top-level declarations. As top-level entries get unified, an entry 31 // may be linked to any top-level entry of any of the files. 32 allFields := map[string]ast.Node{} 33 for _, f := range p.Files { 34 if f.PackageName() == "" { 35 continue 36 } 37 for _, d := range f.Decls { 38 if f, ok := d.(*ast.Field); ok && f.Value != nil { 39 if ident, ok := f.Label.(*ast.Ident); ok { 40 allFields[ident.Name] = f.Value 41 } 42 } 43 } 44 } 45 for _, f := range p.Files { 46 err := resolveFile(idx, f, p, allFields) 47 errs = errors.Append(errs, err) 48 } 49 return errs 50 } 51 52 func resolveFile( 53 idx *index, 54 f *ast.File, 55 p *build.Instance, 56 allFields map[string]ast.Node, 57 ) errors.Error { 58 unresolved := map[string][]*ast.Ident{} 59 for _, u := range f.Unresolved { 60 unresolved[u.Name] = append(unresolved[u.Name], u) 61 } 62 fields := map[string]ast.Node{} 63 for _, d := range f.Decls { 64 if f, ok := d.(*ast.Field); ok && f.Value != nil { 65 if ident, ok := f.Label.(*ast.Ident); ok { 66 fields[ident.Name] = d 67 } 68 } 69 } 70 var errs errors.Error 71 72 specs := []*ast.ImportSpec{} 73 74 for _, spec := range f.Imports { 75 id, err := strconv.Unquote(spec.Path.Value) 76 if err != nil { 77 continue // quietly ignore the error 78 } 79 name := path.Base(id) 80 if imp := p.LookupImport(id); imp != nil { 81 name = imp.PkgName 82 } else if _, ok := idx.builtinPaths[id]; !ok { 83 errs = errors.Append(errs, 84 nodeErrorf(spec, "package %q not found", id)) 85 continue 86 } 87 if spec.Name != nil { 88 name = spec.Name.Name 89 } 90 if n, ok := fields[name]; ok { 91 errs = errors.Append(errs, nodeErrorf(spec, 92 "%s redeclared as imported package name\n"+ 93 "\tprevious declaration at %s", name, n.Pos())) 94 continue 95 } 96 fields[name] = spec 97 used := false 98 for _, u := range unresolved[name] { 99 used = true 100 u.Node = spec 101 } 102 if !used { 103 specs = append(specs, spec) 104 } 105 } 106 107 // Verify each import is used. 108 if len(specs) > 0 { 109 // Find references to imports. This assumes that identifiers in labels 110 // are not resolved or that such errors are caught elsewhere. 111 ast.Walk(f, nil, func(n ast.Node) { 112 if x, ok := n.(*ast.Ident); ok { 113 // As we also visit labels, most nodes will be nil. 114 if x.Node == nil { 115 return 116 } 117 for i, s := range specs { 118 if s == x.Node { 119 specs[i] = nil 120 return 121 } 122 } 123 } 124 }) 125 126 // Add errors for unused imports. 127 for _, spec := range specs { 128 if spec == nil { 129 continue 130 } 131 if spec.Name == nil { 132 errs = errors.Append(errs, nodeErrorf(spec, 133 "imported and not used: %s", spec.Path.Value)) 134 } else { 135 errs = errors.Append(errs, nodeErrorf(spec, 136 "imported and not used: %s as %s", spec.Path.Value, spec.Name)) 137 } 138 } 139 } 140 141 k := 0 142 for _, u := range f.Unresolved { 143 if u.Node != nil { 144 continue 145 } 146 if n, ok := allFields[u.Name]; ok { 147 u.Node = n 148 u.Scope = f 149 continue 150 } 151 f.Unresolved[k] = u 152 k++ 153 } 154 f.Unresolved = f.Unresolved[:k] 155 // TODO: also need to resolve types. 156 // if len(f.Unresolved) > 0 { 157 // n := f.Unresolved[0] 158 // return ctx.mkErr(newBase(n), "unresolved reference %s", n.Name) 159 // } 160 return errs 161 }