github.com/joomcode/cue@v0.4.4-0.20221111115225-539fe3512047/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/joomcode/cue/cue/ast" 23 "github.com/joomcode/cue/cue/ast/astutil" 24 "github.com/joomcode/cue/cue/literal" 25 "github.com/joomcode/cue/cue/token" 26 "github.com/joomcode/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.Elem, 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 return e.resolveLet(x) 183 184 case *adt.SelectorExpr: 185 return &ast.SelectorExpr{ 186 X: e.expr(x.X), 187 Sel: e.stringLabel(x.Sel), 188 } 189 190 case *adt.IndexExpr: 191 return &ast.IndexExpr{ 192 X: e.expr(x.X), 193 Index: e.expr(x.Index), 194 } 195 196 case *adt.SliceExpr: 197 var lo, hi ast.Expr 198 if x.Lo != nil { 199 lo = e.expr(x.Lo) 200 } 201 if x.Hi != nil { 202 hi = e.expr(x.Hi) 203 } 204 // TODO: Stride not yet? implemented. 205 // if x.Stride != nil { 206 // stride = e.expr(x.Stride) 207 // } 208 return &ast.SliceExpr{X: e.expr(x.X), Low: lo, High: hi} 209 210 case *adt.Interpolation: 211 var ( 212 tripple = `"""` 213 openQuote = `"` 214 closeQuote = `"` 215 f = literal.String 216 ) 217 if x.K&adt.BytesKind != 0 { 218 tripple = `'''` 219 openQuote = `'` 220 closeQuote = `'` 221 f = literal.Bytes 222 } 223 toString := func(v adt.Expr) string { 224 str := "" 225 switch x := v.(type) { 226 case *adt.String: 227 str = x.Str 228 case *adt.Bytes: 229 str = string(x.B) 230 } 231 return str 232 } 233 t := &ast.Interpolation{} 234 f = f.WithGraphicOnly() 235 indent := "" 236 // TODO: mark formatting in interpolation itself. 237 for i := 0; i < len(x.Parts); i += 2 { 238 if strings.IndexByte(toString(x.Parts[i]), '\n') >= 0 { 239 f = f.WithTabIndent(len(e.stack)) 240 indent = strings.Repeat("\t", len(e.stack)) 241 openQuote = tripple + "\n" + indent 242 closeQuote = tripple 243 break 244 } 245 } 246 prefix := openQuote 247 suffix := `\(` 248 for i, elem := range x.Parts { 249 if i%2 == 1 { 250 t.Elts = append(t.Elts, e.expr(elem)) 251 } else { 252 // b := strings.Builder{} 253 buf := []byte(prefix) 254 str := toString(elem) 255 buf = f.AppendEscaped(buf, str) 256 if i == len(x.Parts)-1 { 257 if len(closeQuote) > 1 { 258 buf = append(buf, '\n') 259 buf = append(buf, indent...) 260 } 261 buf = append(buf, closeQuote...) 262 } else { 263 if bytes.HasSuffix(buf, []byte("\n")) { 264 buf = append(buf, indent...) 265 } 266 buf = append(buf, suffix...) 267 } 268 t.Elts = append(t.Elts, &ast.BasicLit{ 269 Kind: token.STRING, 270 Value: string(buf), 271 }) 272 } 273 prefix = ")" 274 } 275 return t 276 277 case *adt.BoundExpr: 278 return &ast.UnaryExpr{ 279 Op: x.Op.Token(), 280 X: e.expr(x.Expr), 281 } 282 283 case *adt.UnaryExpr: 284 return &ast.UnaryExpr{ 285 Op: x.Op.Token(), 286 X: e.expr(x.X), 287 } 288 289 case *adt.BinaryExpr: 290 return &ast.BinaryExpr{ 291 Op: x.Op.Token(), 292 X: e.expr(x.X), 293 Y: e.expr(x.Y), 294 } 295 296 case *adt.CallExpr: 297 a := []ast.Expr{} 298 for _, arg := range x.Args { 299 v := e.expr(arg) 300 if v == nil { 301 e.expr(arg) 302 panic("") 303 } 304 a = append(a, v) 305 } 306 fun := e.expr(x.Fun) 307 return &ast.CallExpr{Fun: fun, Args: a} 308 309 case *adt.DisjunctionExpr: 310 a := []ast.Expr{} 311 for _, d := range x.Values { 312 v := e.expr(d.Val) 313 if d.Default { 314 v = &ast.UnaryExpr{Op: token.MUL, X: v} 315 } 316 a = append(a, v) 317 } 318 return ast.NewBinExpr(token.OR, a...) 319 320 default: 321 panic(fmt.Sprintf("unknown field %T", x)) 322 } 323 } 324 325 func (e *exporter) decl(d adt.Decl) ast.Decl { 326 switch x := d.(type) { 327 case adt.Elem: 328 return e.elem(x) 329 330 case *adt.Field: 331 e.setDocs(x) 332 f := &ast.Field{ 333 Label: e.stringLabel(x.Label), 334 } 335 336 frame := e.frame(0) 337 entry := frame.fields[x.Label] 338 entry.field = f 339 entry.node = f.Value 340 frame.fields[x.Label] = entry 341 342 f.Value = e.expr(x.Value) 343 344 // extractDocs(nil) 345 return f 346 347 case *adt.OptionalField: 348 e.setDocs(x) 349 f := &ast.Field{ 350 Label: e.stringLabel(x.Label), 351 Optional: token.NoSpace.Pos(), 352 } 353 354 frame := e.frame(0) 355 entry := frame.fields[x.Label] 356 entry.field = f 357 entry.node = f.Value 358 frame.fields[x.Label] = entry 359 360 f.Value = e.expr(x.Value) 361 362 // extractDocs(nil) 363 return f 364 365 case *adt.BulkOptionalField: 366 e.setDocs(x) 367 // set bulk in frame. 368 frame := e.frame(0) 369 370 expr := e.expr(x.Filter) 371 frame.labelExpr = expr // see astutil.Resolve. 372 373 if x.Label != 0 { 374 expr = &ast.Alias{Ident: e.ident(x.Label), Expr: expr} 375 } 376 f := &ast.Field{ 377 Label: ast.NewList(expr), 378 } 379 380 frame.field = f 381 382 f.Value = e.expr(x.Value) 383 384 return f 385 386 case *adt.DynamicField: 387 e.setDocs(x) 388 key := e.expr(x.Key) 389 if _, ok := key.(*ast.Interpolation); !ok { 390 key = &ast.ParenExpr{X: key} 391 } 392 f := &ast.Field{ 393 Label: key.(ast.Label), 394 } 395 396 frame := e.frame(0) 397 frame.field = f 398 frame.labelExpr = key 399 // extractDocs(nil) 400 401 f.Value = e.expr(x.Value) 402 403 return f 404 405 default: 406 panic(fmt.Sprintf("unknown field %T", x)) 407 } 408 } 409 410 func (e *exporter) elem(d adt.Elem) ast.Expr { 411 412 switch x := d.(type) { 413 case adt.Expr: 414 return e.expr(x) 415 416 case *adt.Ellipsis: 417 t := &ast.Ellipsis{} 418 if x.Value != nil { 419 t.Type = e.expr(x.Value) 420 } 421 return t 422 423 case *adt.Comprehension: 424 return e.comprehension(x) 425 426 default: 427 panic(fmt.Sprintf("unknown field %T", x)) 428 } 429 } 430 431 func (e *exporter) comprehension(comp *adt.Comprehension) *ast.Comprehension { 432 c := &ast.Comprehension{} 433 434 y := comp.Clauses 435 436 loop: 437 for { 438 switch x := y.(type) { 439 case *adt.ForClause: 440 value := e.ident(x.Value) 441 clause := &ast.ForClause{ 442 Value: value, 443 Source: e.expr(x.Src), 444 } 445 c.Clauses = append(c.Clauses, clause) 446 447 _, saved := e.pushFrame(nil) 448 defer e.popFrame(saved) 449 450 if x.Key != adt.InvalidLabel || 451 (x.Syntax != nil && x.Syntax.Key != nil) { 452 key := e.ident(x.Key) 453 clause.Key = key 454 e.addField(x.Key, nil, clause) 455 } 456 e.addField(x.Value, nil, clause) 457 458 y = x.Dst 459 460 case *adt.IfClause: 461 clause := &ast.IfClause{Condition: e.expr(x.Condition)} 462 c.Clauses = append(c.Clauses, clause) 463 y = x.Dst 464 465 case *adt.LetClause: 466 clause := &ast.LetClause{ 467 Ident: e.ident(x.Label), 468 Expr: e.expr(x.Expr), 469 } 470 c.Clauses = append(c.Clauses, clause) 471 472 _, saved := e.pushFrame(nil) 473 defer e.popFrame(saved) 474 475 e.addField(x.Label, nil, clause) 476 477 y = x.Dst 478 479 case *adt.ValueClause: 480 break loop 481 482 default: 483 panic(fmt.Sprintf("unknown field %T", x)) 484 } 485 } 486 487 v := e.expr(comp.Value) 488 if _, ok := v.(*ast.StructLit); !ok { 489 v = ast.NewStruct(ast.Embed(v)) 490 } 491 c.Value = v 492 return c 493 }