cuelang.org/go@v0.10.1/cue/format/simplify.go (about) 1 // Copyright 2019 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 format 16 17 import ( 18 "strconv" 19 20 "cuelang.org/go/cue/ast" 21 "cuelang.org/go/cue/ast/astutil" 22 "cuelang.org/go/internal" 23 ) 24 25 // labelSimplifier rewrites string labels to identifiers if 26 // no identifiers will subsequently bind to the exposed label. 27 // In other words, string labels are only replaced if this does 28 // not change the semantics of the CUE code. 29 type labelSimplifier struct { 30 parent *labelSimplifier 31 scope map[string]bool 32 } 33 34 func (s *labelSimplifier) processDecls(decls []ast.Decl) { 35 sc := labelSimplifier{parent: s, scope: map[string]bool{}} 36 for _, d := range decls { 37 switch x := d.(type) { 38 case *ast.Field: 39 ast.Walk(x.Label, sc.markStrings, nil) 40 } 41 } 42 43 for _, d := range decls { 44 switch x := d.(type) { 45 case *ast.Field: 46 ast.Walk(x.Value, sc.markReferences, nil) 47 default: 48 ast.Walk(x, sc.markReferences, nil) 49 } 50 } 51 52 for _, d := range decls { 53 switch x := d.(type) { 54 case *ast.Field: 55 if _, ok := x.Label.(*ast.BasicLit); ok { 56 x.Label = astutil.Apply(x.Label, nil, sc.replace).(ast.Label) 57 } 58 } 59 } 60 } 61 62 func (s *labelSimplifier) markReferences(n ast.Node) bool { 63 // Record strings at this level. 64 switch x := n.(type) { 65 case *ast.File: 66 s.processDecls(x.Decls) 67 return false 68 69 case *ast.StructLit: 70 s.processDecls(x.Elts) 71 return false 72 73 case *ast.SelectorExpr: 74 ast.Walk(x.X, s.markReferences, nil) 75 return false 76 77 case *ast.Ident: 78 for c := s; c != nil; c = c.parent { 79 if _, ok := c.scope[x.Name]; ok { 80 c.scope[x.Name] = false 81 break 82 } 83 } 84 } 85 return true 86 } 87 88 func (s *labelSimplifier) markStrings(n ast.Node) bool { 89 switch x := n.(type) { 90 case *ast.BasicLit: 91 str, err := strconv.Unquote(x.Value) 92 if err != nil || !ast.IsValidIdent(str) || internal.IsDefOrHidden(str) { 93 return false 94 } 95 s.scope[str] = true 96 97 case *ast.Ident: 98 s.scope[x.Name] = true 99 100 case *ast.ListLit, *ast.Interpolation: 101 return false 102 } 103 return true 104 } 105 106 func (s *labelSimplifier) replace(c astutil.Cursor) bool { 107 switch x := c.Node().(type) { 108 case *ast.BasicLit: 109 str, err := strconv.Unquote(x.Value) 110 if err == nil && s.scope[str] && !internal.IsDefOrHidden(str) { 111 c.Replace(ast.NewIdent(str)) 112 } 113 } 114 return false 115 }