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