github.com/solo-io/cue@v0.4.7/internal/core/export/adt.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 export 16 17 import ( 18 "bytes" 19 "fmt" 20 "strings" 21 22 "github.com/solo-io/cue/cue/ast" 23 "github.com/solo-io/cue/cue/ast/astutil" 24 "github.com/solo-io/cue/cue/literal" 25 "github.com/solo-io/cue/cue/token" 26 "github.com/solo-io/cue/internal/core/adt" 27 ) 28 29 func (e *exporter) ident(x adt.Feature) *ast.Ident { 30 s := x.IdentString(e.ctx) 31 if !ast.IsValidIdent(s) { 32 panic(s + " is not a valid identifier") 33 } 34 return ast.NewIdent(s) 35 } 36 37 func (e *exporter) adt(expr adt.Expr, conjuncts []adt.Conjunct) ast.Expr { 38 switch x := expr.(type) { 39 case adt.Value: 40 return e.expr(x) 41 42 case *adt.ListLit: 43 a := []ast.Expr{} 44 for _, x := range x.Elems { 45 a = append(a, e.elem(x)) 46 } 47 return ast.NewList(a...) 48 49 case *adt.StructLit: 50 // TODO: should we use pushFrame here? 51 // _, saved := e.pushFrame([]adt.Conjunct{adt.MakeConjunct(nil, x)}) 52 // defer e.popFrame(saved) 53 // s := e.frame(0).scope 54 55 s := &ast.StructLit{} 56 57 for _, d := range x.Decls { 58 var a *ast.Alias 59 if orig, ok := d.Source().(*ast.Field); ok { 60 if alias, ok := orig.Value.(*ast.Alias); ok { 61 if e.valueAlias == nil { 62 e.valueAlias = map[*ast.Alias]*ast.Alias{} 63 } 64 a = &ast.Alias{Ident: ast.NewIdent(alias.Ident.Name)} 65 e.valueAlias[alias] = a 66 } 67 } 68 decl := e.decl(d) 69 70 if a != nil { 71 if f, ok := decl.(*ast.Field); ok { 72 a.Expr = f.Value 73 f.Value = a 74 } 75 } 76 77 s.Elts = append(s.Elts, decl) 78 } 79 80 return s 81 82 case *adt.FieldReference: 83 f := e.frame(x.UpCount) 84 entry := f.fields[x.Label] 85 86 name := x.Label.IdentString(e.ctx) 87 switch { 88 case entry.alias != "": 89 name = entry.alias 90 91 case !ast.IsValidIdent(name): 92 name = "X" 93 if x.Src != nil { 94 name = x.Src.Name 95 } 96 name = e.uniqueAlias(name) 97 entry.alias = name 98 } 99 100 ident := ast.NewIdent(name) 101 entry.references = append(entry.references, ident) 102 103 if f.fields != nil { 104 f.fields[x.Label] = entry 105 } 106 107 return ident 108 109 case *adt.ValueReference: 110 name := x.Label.IdentString(e.ctx) 111 if a, ok := x.Src.Node.(*ast.Alias); ok { // Should always pass 112 if b, ok := e.valueAlias[a]; ok { 113 name = b.Ident.Name 114 } 115 } 116 ident := ast.NewIdent(name) 117 return ident 118 119 case *adt.LabelReference: 120 // get potential label from Source. Otherwise use X. 121 f := e.frame(x.UpCount) 122 if f.field == nil { 123 // This can happen when the LabelReference is evaluated outside of 124 // normal evaluation, that is, if a pattern constraint or 125 // additional constraint is evaluated by itself. 126 return ast.NewIdent("string") 127 } 128 list, ok := f.field.Label.(*ast.ListLit) 129 if !ok || len(list.Elts) != 1 { 130 panic("label reference to non-pattern constraint field or invalid list") 131 } 132 name := "" 133 if a, ok := list.Elts[0].(*ast.Alias); ok { 134 name = a.Ident.Name 135 } else { 136 if x.Src != nil { 137 name = x.Src.Name 138 } 139 name = e.uniqueAlias(name) 140 list.Elts[0] = &ast.Alias{ 141 Ident: ast.NewIdent(name), 142 Expr: list.Elts[0], 143 } 144 } 145 ident := ast.NewIdent(name) 146 ident.Scope = f.field 147 ident.Node = f.labelExpr 148 return ident 149 150 case *adt.DynamicReference: 151 // get potential label from Source. Otherwise use X. 152 name := "X" 153 f := e.frame(x.UpCount) 154 if d := f.field; d != nil { 155 if x.Src != nil { 156 name = x.Src.Name 157 } 158 name = e.getFieldAlias(d, name) 159 } 160 ident := ast.NewIdent(name) 161 ident.Scope = f.field 162 ident.Node = f.field 163 return ident 164 165 case *adt.ImportReference: 166 importPath := x.ImportPath.StringValue(e.index) 167 spec := ast.NewImport(nil, importPath) 168 169 info, _ := astutil.ParseImportSpec(spec) 170 name := info.PkgName 171 if x.Label != 0 { 172 name = x.Label.StringValue(e.index) 173 if name != info.PkgName { 174 spec.Name = ast.NewIdent(name) 175 } 176 } 177 ident := ast.NewIdent(name) 178 ident.Node = spec 179 return ident 180 181 case *adt.LetReference: 182 // TODO: Handle references that went out of scope. In case of aliases 183 // this means they may need to be reproduced locally. Most of these 184 // issues can be avoided by either fully expanding a configuration 185 // (export) or not at all (def). 186 // 187 i := len(e.stack) - 1 - int(x.UpCount) - 1 188 if i < 0 { 189 i = 0 190 } 191 f := &(e.stack[i]) 192 let := f.let[x.X] 193 if let == nil { 194 if f.let == nil { 195 f.let = map[adt.Expr]*ast.LetClause{} 196 } 197 label := e.uniqueLetIdent(x.Label, x.X) 198 199 name := label.IdentString(e.ctx) 200 201 // A let may be added multiple times to the same scope as a result 202 // of how merging works. If that happens here it must be one 203 // originating from the same expression, and it is safe to drop. 204 for _, elt := range f.scope.Elts { 205 if a, ok := elt.(*ast.LetClause); ok { 206 if a.Ident.Name == name { 207 let = a 208 break 209 } 210 } 211 } 212 213 if let == nil { 214 let = &ast.LetClause{ 215 Ident: e.ident(label), 216 Expr: e.expr(x.X), 217 } 218 f.scope.Elts = append(f.scope.Elts, let) 219 } 220 221 f.let[x.X] = let 222 } 223 ident := ast.NewIdent(let.Ident.Name) 224 ident.Node = let 225 ident.Scope = f.scope 226 return ident 227 228 case *adt.SelectorExpr: 229 return &ast.SelectorExpr{ 230 X: e.expr(x.X), 231 Sel: e.stringLabel(x.Sel), 232 } 233 234 case *adt.IndexExpr: 235 return &ast.IndexExpr{ 236 X: e.expr(x.X), 237 Index: e.expr(x.Index), 238 } 239 240 case *adt.SliceExpr: 241 var lo, hi ast.Expr 242 if x.Lo != nil { 243 lo = e.expr(x.Lo) 244 } 245 if x.Hi != nil { 246 hi = e.expr(x.Hi) 247 } 248 // TODO: Stride not yet? implemented. 249 // if x.Stride != nil { 250 // stride = e.expr(x.Stride) 251 // } 252 return &ast.SliceExpr{X: e.expr(x.X), Low: lo, High: hi} 253 254 case *adt.Interpolation: 255 var ( 256 tripple = `"""` 257 openQuote = `"` 258 closeQuote = `"` 259 f = literal.String 260 ) 261 if x.K&adt.BytesKind != 0 { 262 tripple = `'''` 263 openQuote = `'` 264 closeQuote = `'` 265 f = literal.Bytes 266 } 267 toString := func(v adt.Expr) string { 268 str := "" 269 switch x := v.(type) { 270 case *adt.String: 271 str = x.Str 272 case *adt.Bytes: 273 str = string(x.B) 274 } 275 return str 276 } 277 t := &ast.Interpolation{} 278 f = f.WithGraphicOnly() 279 indent := "" 280 // TODO: mark formatting in interpolation itself. 281 for i := 0; i < len(x.Parts); i += 2 { 282 if strings.IndexByte(toString(x.Parts[i]), '\n') >= 0 { 283 f = f.WithTabIndent(len(e.stack)) 284 indent = strings.Repeat("\t", len(e.stack)) 285 openQuote = tripple + "\n" + indent 286 closeQuote = tripple 287 break 288 } 289 } 290 prefix := openQuote 291 suffix := `\(` 292 for i, elem := range x.Parts { 293 if i%2 == 1 { 294 t.Elts = append(t.Elts, e.expr(elem)) 295 } else { 296 // b := strings.Builder{} 297 buf := []byte(prefix) 298 str := toString(elem) 299 buf = f.AppendEscaped(buf, str) 300 if i == len(x.Parts)-1 { 301 if len(closeQuote) > 1 { 302 buf = append(buf, '\n') 303 buf = append(buf, indent...) 304 } 305 buf = append(buf, closeQuote...) 306 } else { 307 if bytes.HasSuffix(buf, []byte("\n")) { 308 buf = append(buf, indent...) 309 } 310 buf = append(buf, suffix...) 311 } 312 t.Elts = append(t.Elts, &ast.BasicLit{ 313 Kind: token.STRING, 314 Value: string(buf), 315 }) 316 } 317 prefix = ")" 318 } 319 return t 320 321 case *adt.BoundExpr: 322 return &ast.UnaryExpr{ 323 Op: x.Op.Token(), 324 X: e.expr(x.Expr), 325 } 326 327 case *adt.UnaryExpr: 328 return &ast.UnaryExpr{ 329 Op: x.Op.Token(), 330 X: e.expr(x.X), 331 } 332 333 case *adt.BinaryExpr: 334 return &ast.BinaryExpr{ 335 Op: x.Op.Token(), 336 X: e.expr(x.X), 337 Y: e.expr(x.Y), 338 } 339 340 case *adt.CallExpr: 341 a := []ast.Expr{} 342 for _, arg := range x.Args { 343 v := e.expr(arg) 344 if v == nil { 345 e.expr(arg) 346 panic("") 347 } 348 a = append(a, v) 349 } 350 fun := e.expr(x.Fun) 351 return &ast.CallExpr{Fun: fun, Args: a} 352 353 case *adt.DisjunctionExpr: 354 a := []ast.Expr{} 355 for _, d := range x.Values { 356 v := e.expr(d.Val) 357 if d.Default { 358 v = &ast.UnaryExpr{Op: token.MUL, X: v} 359 } 360 a = append(a, v) 361 } 362 return ast.NewBinExpr(token.OR, a...) 363 364 default: 365 panic(fmt.Sprintf("unknown field %T", x)) 366 } 367 } 368 369 func (e *exporter) decl(d adt.Decl) ast.Decl { 370 switch x := d.(type) { 371 case adt.Elem: 372 return e.elem(x) 373 374 case *adt.Field: 375 e.setDocs(x) 376 f := &ast.Field{ 377 Label: e.stringLabel(x.Label), 378 } 379 380 frame := e.frame(0) 381 entry := frame.fields[x.Label] 382 entry.field = f 383 entry.node = f.Value 384 frame.fields[x.Label] = entry 385 386 f.Value = e.expr(x.Value) 387 388 // extractDocs(nil) 389 return f 390 391 case *adt.OptionalField: 392 e.setDocs(x) 393 f := &ast.Field{ 394 Label: e.stringLabel(x.Label), 395 Optional: token.NoSpace.Pos(), 396 } 397 398 frame := e.frame(0) 399 entry := frame.fields[x.Label] 400 entry.field = f 401 entry.node = f.Value 402 frame.fields[x.Label] = entry 403 404 f.Value = e.expr(x.Value) 405 406 // extractDocs(nil) 407 return f 408 409 case *adt.BulkOptionalField: 410 e.setDocs(x) 411 // set bulk in frame. 412 frame := e.frame(0) 413 414 expr := e.expr(x.Filter) 415 frame.labelExpr = expr // see astutil.Resolve. 416 417 if x.Label != 0 { 418 expr = &ast.Alias{Ident: e.ident(x.Label), Expr: expr} 419 } 420 f := &ast.Field{ 421 Label: ast.NewList(expr), 422 } 423 424 frame.field = f 425 426 f.Value = e.expr(x.Value) 427 428 return f 429 430 case *adt.DynamicField: 431 e.setDocs(x) 432 key := e.expr(x.Key) 433 if _, ok := key.(*ast.Interpolation); !ok { 434 key = &ast.ParenExpr{X: key} 435 } 436 f := &ast.Field{ 437 Label: key.(ast.Label), 438 } 439 440 frame := e.frame(0) 441 frame.field = f 442 frame.labelExpr = key 443 // extractDocs(nil) 444 445 f.Value = e.expr(x.Value) 446 447 return f 448 449 default: 450 panic(fmt.Sprintf("unknown field %T", x)) 451 } 452 } 453 454 func (e *exporter) elem(d adt.Elem) ast.Expr { 455 456 switch x := d.(type) { 457 case adt.Expr: 458 return e.expr(x) 459 460 case *adt.Ellipsis: 461 t := &ast.Ellipsis{} 462 if x.Value != nil { 463 t.Type = e.expr(x.Value) 464 } 465 return t 466 467 case adt.Yielder: 468 return e.comprehension(x) 469 470 default: 471 panic(fmt.Sprintf("unknown field %T", x)) 472 } 473 } 474 475 func (e *exporter) comprehension(y adt.Yielder) ast.Expr { 476 c := &ast.Comprehension{} 477 478 for { 479 switch x := y.(type) { 480 case *adt.ForClause: 481 value := e.ident(x.Value) 482 clause := &ast.ForClause{ 483 Value: value, 484 Source: e.expr(x.Src), 485 } 486 c.Clauses = append(c.Clauses, clause) 487 488 _, saved := e.pushFrame(nil) 489 defer e.popFrame(saved) 490 491 if x.Key != 0 { 492 key := e.ident(x.Key) 493 clause.Key = key 494 e.addField(x.Key, nil, clause) 495 } 496 e.addField(x.Value, nil, clause) 497 498 y = x.Dst 499 500 case *adt.IfClause: 501 clause := &ast.IfClause{Condition: e.expr(x.Condition)} 502 c.Clauses = append(c.Clauses, clause) 503 y = x.Dst 504 505 case *adt.LetClause: 506 clause := &ast.LetClause{ 507 Ident: e.ident(x.Label), 508 Expr: e.expr(x.Expr), 509 } 510 c.Clauses = append(c.Clauses, clause) 511 512 _, saved := e.pushFrame(nil) 513 defer e.popFrame(saved) 514 515 e.addField(x.Label, nil, clause) 516 517 y = x.Dst 518 519 case *adt.ValueClause: 520 v := e.expr(x.StructLit) 521 if _, ok := v.(*ast.StructLit); !ok { 522 v = ast.NewStruct(ast.Embed(v)) 523 } 524 c.Value = v 525 return c 526 527 default: 528 panic(fmt.Sprintf("unknown field %T", x)) 529 } 530 } 531 532 }