github.com/solo-io/cue@v0.4.7/internal/core/compile/label.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 compile 16 17 import ( 18 "github.com/cockroachdb/apd/v2" 19 "golang.org/x/text/unicode/norm" 20 21 "github.com/solo-io/cue/cue/ast" 22 "github.com/solo-io/cue/cue/literal" 23 "github.com/solo-io/cue/cue/token" 24 "github.com/solo-io/cue/internal/core/adt" 25 ) 26 27 // LabelFromNode converts an ADT node to a feature. 28 func (c *compiler) label(n ast.Node) adt.Feature { 29 index := c.index 30 switch x := n.(type) { 31 case *ast.Ident: 32 return adt.MakeIdentLabel(c.index, x.Name, c.pkgPath) 33 34 case *ast.BasicLit: 35 switch x.Kind { 36 case token.STRING: 37 const msg = "invalid string label: %v" 38 s, err := literal.Unquote(x.Value) 39 if err != nil { 40 c.errf(n, msg, err) 41 return adt.InvalidLabel 42 } 43 44 i := int64(index.StringToIndex(norm.NFC.String(s))) 45 f, err := adt.MakeLabel(n, i, adt.StringLabel) 46 if err != nil { 47 c.errf(n, msg, err) 48 } 49 return f 50 51 case token.INT: 52 const msg = "invalid int label: %v" 53 if err := literal.ParseNum(x.Value, &c.num); err != nil { 54 c.errf(n, msg, err) 55 return adt.InvalidLabel 56 } 57 58 var d apd.Decimal 59 if err := c.num.Decimal(&d); err != nil { 60 c.errf(n, msg, err) 61 return adt.InvalidLabel 62 } 63 64 i, err := d.Int64() 65 if err != nil { 66 c.errf(n, msg, err) 67 return adt.InvalidLabel 68 } 69 70 f, err := adt.MakeLabel(n, i, adt.IntLabel) 71 if err != nil { 72 c.errf(n, msg, err) 73 return adt.InvalidLabel 74 } 75 return f 76 77 case token.FLOAT: 78 _ = c.errf(n, "float %s cannot be used as label", x.Value) 79 return adt.InvalidLabel 80 81 default: // keywords (null, true, false, for, in, if, let) 82 i := index.StringToIndex(x.Kind.String()) 83 f, err := adt.MakeLabel(n, i, adt.StringLabel) 84 if err != nil { 85 c.errf(n, "invalid string label: %v", err) 86 } 87 return f 88 } 89 90 default: 91 c.errf(n, "unsupported label node type %T", n) 92 return adt.InvalidLabel 93 } 94 } 95 96 // A labeler converts an AST node to a string representation. 97 type labeler interface { 98 labelString() string 99 } 100 101 type fieldLabel ast.Field 102 103 func (l *fieldLabel) labelString() string { 104 lab := l.Label 105 106 if a, ok := lab.(*ast.Alias); ok { 107 if x, _ := a.Expr.(ast.Label); x != nil { 108 lab = x 109 } 110 } 111 112 switch x := lab.(type) { 113 case *ast.Ident: 114 return x.Name 115 116 case *ast.BasicLit: 117 if x.Kind == token.STRING { 118 s, err := literal.Unquote(x.Value) 119 if err == nil && ast.IsValidIdent(s) { 120 return s 121 } 122 } 123 return x.Value 124 125 case *ast.ListLit: 126 return "[]" // TODO: more detail 127 128 case *ast.Interpolation: 129 return "?" 130 // case *ast.ParenExpr: 131 } 132 return "<unknown>" 133 } 134 135 type forScope ast.ForClause 136 137 func (l *forScope) labelString() string { 138 // TODO: include more info in square brackets. 139 return "for[]" 140 } 141 142 type letScope ast.LetClause 143 144 func (l *letScope) labelString() string { 145 // TODO: include more info in square brackets. 146 return "let[]" 147 }