cuelang.org/go@v0.13.0/cue/ast/ast.go (about) 1 // Copyright 2018 The 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 ast declares the types used to represent syntax trees for CUE 16 // packages. 17 package ast 18 19 import ( 20 "fmt" 21 "strings" 22 23 "cuelang.org/go/cue/literal" 24 "cuelang.org/go/cue/token" 25 ) 26 27 // ---------------------------------------------------------------------------- 28 // Interfaces 29 // 30 // There are three main classes of nodes: expressions, clauses, and declaration 31 // nodes. The node names usually match the corresponding CUE spec production 32 // names to which they correspond. The node fields correspond to the individual 33 // parts of the respective productions. 34 // 35 // All nodes contain position information marking the beginning of the 36 // corresponding source text segment; it is accessible via the Pos accessor 37 // method. Nodes may contain additional position info for language constructs 38 // where comments may be found between parts of the construct (typically any 39 // larger, parenthesized subpart). That position information is needed to 40 // properly position comments when printing the construct. 41 42 // A Node represents any node in the abstract syntax tree. 43 type Node interface { 44 Pos() token.Pos // position of first character belonging to the node 45 End() token.Pos // position of first character immediately after the node 46 47 // pos reports the pointer to the position of first character belonging to 48 // the node or nil if there is no such position. 49 pos() *token.Pos 50 51 // Deprecated: use [Comments] 52 Comments() []*CommentGroup 53 54 // Deprecated: use [AddComment] 55 AddComment(*CommentGroup) 56 commentInfo() *comments 57 } 58 59 // Name describes the type of n. 60 func Name(n Node) string { 61 s := fmt.Sprintf("%T", n) 62 return strings.ToLower(s[strings.Index(s, "ast.")+4:]) 63 } 64 65 func getPos(n Node) token.Pos { 66 p := n.pos() 67 if p == nil { 68 return token.NoPos 69 } 70 return *p 71 } 72 73 // SetPos sets a node to the given position, if possible. 74 func SetPos(n Node, p token.Pos) { 75 ptr := n.pos() 76 if ptr == nil { 77 return 78 } 79 *ptr = p 80 } 81 82 // SetRelPos sets the relative position of a node without modifying its 83 // file position. Setting it to token.NoRelPos allows a node to adopt default 84 // formatting. 85 func SetRelPos(n Node, p token.RelPos) { 86 ptr := n.pos() 87 if ptr == nil { 88 return 89 } 90 pos := *ptr 91 *ptr = pos.WithRel(p) 92 } 93 94 // An Expr is implemented by all expression nodes. 95 type Expr interface { 96 Node 97 declNode() // An expression can be used as a declaration. 98 exprNode() 99 } 100 101 type expr struct{ decl } 102 103 func (expr) exprNode() {} 104 105 // A Decl node is implemented by all declarations. 106 type Decl interface { 107 Node 108 declNode() 109 } 110 111 type decl struct{} 112 113 func (decl) declNode() {} 114 115 // A Label is any production that can be used as an LHS label. 116 type Label interface { 117 Node 118 labelNode() 119 } 120 121 type label struct{} 122 123 func (l label) labelNode() {} 124 125 // Clause nodes are part of comprehensions. 126 type Clause interface { 127 Node 128 clauseNode() 129 } 130 131 type clause struct{} 132 133 func (clause) clauseNode() {} 134 135 // Comments 136 137 type comments struct { 138 groups *[]*CommentGroup 139 } 140 141 func (c *comments) commentInfo() *comments { return c } 142 143 func (c *comments) Comments() []*CommentGroup { 144 if c.groups == nil { 145 return []*CommentGroup{} 146 } 147 return *c.groups 148 } 149 150 // // AddComment adds the given comments to the fields. 151 // // If line is true the comment is inserted at the preceding token. 152 153 func (c *comments) AddComment(cg *CommentGroup) { 154 if cg == nil { 155 return 156 } 157 if c.groups == nil { 158 a := []*CommentGroup{cg} 159 c.groups = &a 160 return 161 } 162 163 *c.groups = append(*c.groups, cg) 164 a := *c.groups 165 for i := len(a) - 2; i >= 0 && a[i].Position > cg.Position; i-- { 166 a[i], a[i+1] = a[i+1], a[i] 167 } 168 } 169 170 func (c *comments) SetComments(cgs []*CommentGroup) { 171 if c.groups == nil { 172 a := cgs 173 c.groups = &a 174 return 175 } 176 *c.groups = cgs 177 } 178 179 // A Comment node represents a single //-style comment. 180 type Comment struct { 181 Slash token.Pos // position of "/" starting the comment 182 Text string // comment text excluding '\n' 183 } 184 185 func (c *Comment) Comments() []*CommentGroup { return nil } 186 func (c *Comment) AddComment(*CommentGroup) {} 187 func (c *Comment) commentInfo() *comments { return nil } 188 189 func (c *Comment) Pos() token.Pos { return c.Slash } 190 func (c *Comment) pos() *token.Pos { return &c.Slash } 191 func (c *Comment) End() token.Pos { return c.Slash.Add(len(c.Text)) } 192 193 // A CommentGroup represents a sequence of comments 194 // with no other tokens and no empty lines between. 195 type CommentGroup struct { 196 // TODO: remove and use the token position of the first comment. 197 Doc bool 198 Line bool // true if it is on the same line as the node's end pos. 199 200 // Position indicates where a comment should be attached if a node has 201 // multiple tokens. 0 means before the first token, 1 means before the 202 // second, etc. For instance, for a field, the positions are: 203 // <0> Label <1> ":" <2> Expr <3> "," <4> 204 Position int8 205 List []*Comment // len(List) > 0 206 207 decl 208 } 209 210 func (g *CommentGroup) Pos() token.Pos { return getPos(g) } 211 func (g *CommentGroup) pos() *token.Pos { return g.List[0].pos() } 212 func (g *CommentGroup) End() token.Pos { return g.List[len(g.List)-1].End() } 213 214 func (g *CommentGroup) Comments() []*CommentGroup { return nil } 215 func (g *CommentGroup) AddComment(*CommentGroup) {} 216 func (g *CommentGroup) commentInfo() *comments { return nil } 217 218 func isWhitespace(ch byte) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' } 219 220 func stripTrailingWhitespace(s string) string { 221 i := len(s) 222 for i > 0 && isWhitespace(s[i-1]) { 223 i-- 224 } 225 return s[0:i] 226 } 227 228 // Text returns the text of the comment. 229 // Comment markers ("//"), the first space of a line comment, and 230 // leading and trailing empty lines are removed. Multiple empty lines are 231 // reduced to one, and trailing space on lines is trimmed. Unless the result 232 // is empty, it is newline-terminated. 233 func (g *CommentGroup) Text() string { 234 if g == nil { 235 return "" 236 } 237 comments := make([]string, len(g.List)) 238 for i, c := range g.List { 239 comments[i] = c.Text 240 } 241 242 lines := make([]string, 0, 10) // most comments are less than 10 lines 243 for _, c := range comments { 244 // Remove comment markers. 245 // The parser has given us exactly the comment text. 246 c = c[2:] 247 // strip first space - required for Example tests 248 if len(c) > 0 && c[0] == ' ' { 249 c = c[1:] 250 } 251 252 // Split on newlines. 253 cl := strings.Split(c, "\n") 254 255 // Walk lines, stripping trailing white space and adding to list. 256 for _, l := range cl { 257 lines = append(lines, stripTrailingWhitespace(l)) 258 } 259 } 260 261 // Remove leading blank lines; convert runs of 262 // interior blank lines to a single blank line. 263 n := 0 264 for _, line := range lines { 265 if line != "" || n > 0 && lines[n-1] != "" { 266 lines[n] = line 267 n++ 268 } 269 } 270 lines = lines[0:n] 271 272 // Add final "" entry to get trailing newline from Join. 273 if n > 0 && lines[n-1] != "" { 274 lines = append(lines, "") 275 } 276 277 return strings.Join(lines, "\n") 278 } 279 280 // An Attribute provides meta data about a field. 281 type Attribute struct { 282 At token.Pos 283 Text string // must be a valid attribute format. 284 285 comments 286 decl 287 } 288 289 func (a *Attribute) Pos() token.Pos { return a.At } 290 func (a *Attribute) pos() *token.Pos { return &a.At } 291 func (a *Attribute) End() token.Pos { return a.At.Add(len(a.Text)) } 292 293 func (a *Attribute) Split() (key, body string) { 294 s := a.Text 295 p := strings.IndexByte(s, '(') 296 if p < 0 || !strings.HasPrefix(s, "@") || !strings.HasSuffix(s, ")") { 297 return "", "" 298 } 299 return a.Text[1:p], a.Text[p+1 : len(s)-1] 300 } 301 302 // A Field represents a field declaration in a struct. 303 type Field struct { 304 Label Label // must have at least one element. 305 // Deprecated: use [Field.Constraint] 306 Optional token.Pos 307 Constraint token.Token // token.ILLEGAL, token.OPTION, or token.NOT 308 309 // No TokenPos: Value must be an StructLit with one field. 310 TokenPos token.Pos 311 // Deprecated: the value is always [token.COLON] 312 Token token.Token 313 314 Value Expr // the value associated with this field. 315 316 Attrs []*Attribute 317 318 comments 319 decl 320 } 321 322 func (d *Field) Pos() token.Pos { return d.Label.Pos() } 323 func (d *Field) pos() *token.Pos { return d.Label.pos() } 324 func (d *Field) End() token.Pos { 325 if len(d.Attrs) > 0 { 326 return d.Attrs[len(d.Attrs)-1].End() 327 } 328 return d.Value.End() 329 } 330 331 // TODO: make Alias a type of Field. This is possible now we have different 332 // separator types. 333 334 // An Alias binds another field to the alias name in the current struct. 335 type Alias struct { 336 Ident *Ident // field name, always an Ident 337 Equal token.Pos // position of "=" 338 Expr Expr // An Ident or SelectorExpr 339 340 comments 341 clause 342 decl 343 expr 344 label 345 } 346 347 func (a *Alias) Pos() token.Pos { return a.Ident.Pos() } 348 func (a *Alias) pos() *token.Pos { return a.Ident.pos() } 349 func (a *Alias) End() token.Pos { return a.Expr.End() } 350 351 // A Comprehension node represents a comprehension declaration. 352 type Comprehension struct { 353 Clauses []Clause // There must be at least one clause. 354 Value Expr // Must be a struct TODO: change to Struct 355 356 comments 357 decl 358 expr // TODO: only allow Comprehension in "Embedding" productions. 359 } 360 361 func (x *Comprehension) Pos() token.Pos { return getPos(x) } 362 func (x *Comprehension) pos() *token.Pos { return x.Clauses[0].pos() } 363 func (x *Comprehension) End() token.Pos { 364 return x.Value.End() 365 } 366 367 // ---------------------------------------------------------------------------- 368 // Expressions and types 369 // 370 // An expression is represented by a tree consisting of one 371 // or more of the following concrete expression nodes. 372 373 // A BadExpr node is a placeholder for expressions containing 374 // syntax errors for which no correct expression nodes can be 375 // created. This is different from an ErrorExpr which represents 376 // an explicitly marked error in the source. 377 type BadExpr struct { 378 From, To token.Pos // position range of bad expression 379 380 comments 381 expr 382 } 383 384 // A BottomLit indicates an error. 385 type BottomLit struct { 386 Bottom token.Pos 387 388 comments 389 expr 390 } 391 392 // An Ident node represents a left-hand side identifier, 393 // including the underscore "_" identifier to represent top. 394 type Ident struct { 395 NamePos token.Pos // identifier position 396 397 // This LHS path element may be an identifier. Possible forms: 398 // foo: a normal identifier 399 // "foo": JSON compatible 400 Name string 401 402 Scope Node // scope in which node was found or nil if referring directly 403 Node Node 404 405 comments 406 label 407 expr 408 } 409 410 // A BasicLit node represents a literal of basic type. 411 type BasicLit struct { 412 ValuePos token.Pos // literal position 413 Kind token.Token // INT, FLOAT, DURATION, or STRING 414 Value string // literal string; e.g. 42, 0x7f, 3.14, 1_234_567, 1e-9, 2.4i, 'a', '\x7f', "foo", or '\m\n\o' 415 416 comments 417 expr 418 label 419 } 420 421 // TODO: introduce and use NewLabel and NewBytes and perhaps NewText (in the 422 // later case NewString would return a string or bytes type) to distinguish from 423 // NewString. Consider how to pass indentation information. 424 425 // NewString creates a new BasicLit with a string value without position. 426 // It quotes the given string. 427 // Useful for ASTs generated by code other than the CUE parser. 428 func NewString(str string) *BasicLit { 429 str = literal.String.Quote(str) 430 return &BasicLit{Kind: token.STRING, ValuePos: token.NoPos, Value: str} 431 } 432 433 // NewNull creates a new BasicLit configured to be a null value. 434 // Useful for ASTs generated by code other than the CUE parser. 435 func NewNull() *BasicLit { 436 return &BasicLit{Kind: token.NULL, Value: "null"} 437 } 438 439 // NewLit creates a new BasicLit with from a token type and string without 440 // position. 441 // Useful for ASTs generated by code other than the CUE parser. 442 func NewLit(tok token.Token, s string) *BasicLit { 443 return &BasicLit{Kind: tok, Value: s} 444 } 445 446 // NewBool creates a new BasicLit with a bool value without position. 447 // Useful for ASTs generated by code other than the CUE parser. 448 func NewBool(b bool) *BasicLit { 449 x := &BasicLit{} 450 if b { 451 x.Kind = token.TRUE 452 x.Value = "true" 453 } else { 454 x.Kind = token.FALSE 455 x.Value = "false" 456 } 457 return x 458 } 459 460 // TODO: 461 // - use CUE-specific quoting (hoist functionality in export) 462 // - NewBytes 463 464 // A Interpolation node represents a string or bytes interpolation. 465 type Interpolation struct { 466 Elts []Expr // interleaving of strings and expressions. 467 468 comments 469 expr 470 label 471 } 472 473 // A Func node represents a function type. 474 // 475 // This is an experimental type and the contents will change without notice. 476 type Func struct { 477 Func token.Pos // position of "func" 478 Args []Expr // list of elements; or nil 479 Ret Expr // return type, must not be nil 480 481 comments 482 expr 483 } 484 485 // A StructLit node represents a literal struct. 486 type StructLit struct { 487 Lbrace token.Pos // position of "{" 488 Elts []Decl // list of elements; or nil 489 Rbrace token.Pos // position of "}" 490 491 comments 492 expr 493 } 494 495 // NewStruct creates a struct from the given fields. 496 // 497 // A field is either a *Field, an *Ellipsis, *LetClause, a *CommentGroup, or a 498 // Label, optionally followed by a token.OPTION or token.NOT to indicate the 499 // field is optional or required, followed by an expression for the field value. 500 // 501 // It will panic if a values not matching these patterns are given. Useful for 502 // ASTs generated by code other than the CUE parser. 503 func NewStruct(fields ...interface{}) *StructLit { 504 s := &StructLit{ 505 // Set default positions so that comment attachment is as expected. 506 Lbrace: token.NoSpace.Pos(), 507 } 508 for i := 0; i < len(fields); i++ { 509 var ( 510 label Label 511 optional = token.NoPos 512 constraint = token.ILLEGAL 513 expr Expr 514 ) 515 516 switch x := fields[i].(type) { 517 case *Field: 518 s.Elts = append(s.Elts, x) 519 continue 520 case *CommentGroup: 521 s.Elts = append(s.Elts, x) 522 continue 523 case *Ellipsis: 524 s.Elts = append(s.Elts, x) 525 continue 526 case *LetClause: 527 s.Elts = append(s.Elts, x) 528 continue 529 case *embedding: 530 s.Elts = append(s.Elts, (*EmbedDecl)(x)) 531 continue 532 case Label: 533 label = x 534 case string: 535 label = NewString(x) 536 default: 537 panic(fmt.Sprintf("unsupported label type %T", x)) 538 } 539 540 inner: 541 for i++; i < len(fields); i++ { 542 switch x := (fields[i]).(type) { 543 case Expr: 544 expr = x 545 break inner 546 case token.Token: 547 switch x { 548 case token.OPTION: 549 constraint = x 550 optional = token.Blank.Pos() 551 case token.NOT: 552 constraint = x 553 case token.COLON, token.ILLEGAL: 554 default: 555 panic(fmt.Sprintf("invalid token %s", x)) 556 } 557 default: 558 panic(fmt.Sprintf("unsupported expression type %T", x)) 559 } 560 } 561 if expr == nil { 562 panic("label not matched with expression") 563 } 564 s.Elts = append(s.Elts, &Field{ 565 Label: label, 566 Optional: optional, 567 Constraint: constraint, 568 Value: expr, 569 }) 570 } 571 return s 572 } 573 574 // Embed can be used in conjunction with NewStruct to embed values. 575 func Embed(x Expr) *embedding { 576 return (*embedding)(&EmbedDecl{Expr: x}) 577 } 578 579 type embedding EmbedDecl 580 581 // A ListLit node represents a literal list. 582 type ListLit struct { 583 Lbrack token.Pos // position of "[" 584 585 // TODO: change to embedding or similar. 586 Elts []Expr // list of composite elements; or nil 587 Rbrack token.Pos // position of "]" 588 589 comments 590 expr 591 label 592 } 593 594 // NewList creates a list of Expressions. 595 // Useful for ASTs generated by code other than the CUE parser. 596 func NewList(exprs ...Expr) *ListLit { 597 return &ListLit{Elts: exprs} 598 } 599 600 type Ellipsis struct { 601 Ellipsis token.Pos // open list if set 602 Type Expr // type for the remaining elements 603 604 comments 605 decl 606 expr 607 } 608 609 // A ForClause node represents a for clause in a comprehension. 610 type ForClause struct { 611 For token.Pos 612 Key *Ident // allow pattern matching? 613 // TODO: change to Comma 614 Colon token.Pos 615 Value *Ident // allow pattern matching? 616 In token.Pos 617 Source Expr 618 619 comments 620 clause 621 } 622 623 // A IfClause node represents an if guard clause in a comprehension. 624 type IfClause struct { 625 If token.Pos 626 Condition Expr 627 628 comments 629 clause 630 } 631 632 // A LetClause node represents a let clause in a comprehension. 633 type LetClause struct { 634 Let token.Pos 635 Ident *Ident 636 Equal token.Pos 637 Expr Expr 638 639 comments 640 clause 641 decl 642 } 643 644 // A ParenExpr node represents a parenthesized expression. 645 type ParenExpr struct { 646 Lparen token.Pos // position of "(" 647 X Expr // parenthesized expression 648 Rparen token.Pos // position of ")" 649 650 comments 651 expr 652 label 653 } 654 655 // A SelectorExpr node represents an expression followed by a selector. 656 type SelectorExpr struct { 657 X Expr // expression 658 Sel Label // field selector 659 660 comments 661 expr 662 } 663 664 // NewSel creates a sequence of selectors. 665 // Useful for ASTs generated by code other than the CUE parser. 666 func NewSel(x Expr, sel ...string) Expr { 667 for _, s := range sel { 668 x = &SelectorExpr{X: x, Sel: NewIdent(s)} 669 } 670 return x 671 } 672 673 // An IndexExpr node represents an expression followed by an index. 674 type IndexExpr struct { 675 X Expr // expression 676 Lbrack token.Pos // position of "[" 677 Index Expr // index expression 678 Rbrack token.Pos // position of "]" 679 680 comments 681 expr 682 } 683 684 // An SliceExpr node represents an expression followed by slice indices. 685 type SliceExpr struct { 686 X Expr // expression 687 Lbrack token.Pos // position of "[" 688 Low Expr // begin of slice range; or nil 689 High Expr // end of slice range; or nil 690 Rbrack token.Pos // position of "]" 691 692 comments 693 expr 694 } 695 696 // A CallExpr node represents an expression followed by an argument list. 697 type CallExpr struct { 698 Fun Expr // function expression 699 Lparen token.Pos // position of "(" 700 Args []Expr // function arguments; or nil 701 Rparen token.Pos // position of ")" 702 703 comments 704 expr 705 } 706 707 // NewCall creates a new CallExpr. 708 // Useful for ASTs generated by code other than the CUE parser. 709 func NewCall(fun Expr, args ...Expr) *CallExpr { 710 return &CallExpr{Fun: fun, Args: args} 711 } 712 713 // A UnaryExpr node represents a unary expression. 714 type UnaryExpr struct { 715 OpPos token.Pos // position of Op 716 Op token.Token // operator 717 X Expr // operand 718 719 comments 720 expr 721 } 722 723 // A BinaryExpr node represents a binary expression. 724 type BinaryExpr struct { 725 X Expr // left operand 726 OpPos token.Pos // position of Op 727 Op token.Token // operator 728 Y Expr // right operand 729 730 comments 731 expr 732 } 733 734 // NewBinExpr creates for list of expressions of length 2 or greater a chained 735 // binary expression of the form (((x1 op x2) op x3) ...). For lists of length 736 // 1 it returns the expression itself. It panics for empty lists. 737 // Useful for ASTs generated by code other than the CUE parser. 738 func NewBinExpr(op token.Token, operands ...Expr) Expr { 739 if len(operands) == 0 { 740 return nil 741 } 742 expr := operands[0] 743 for _, e := range operands[1:] { 744 expr = &BinaryExpr{X: expr, Op: op, Y: e} 745 } 746 return expr 747 } 748 749 // token.Pos and End implementations for expression/type nodes. 750 751 func (x *BadExpr) Pos() token.Pos { return x.From } 752 func (x *BadExpr) pos() *token.Pos { return &x.From } 753 func (x *Ident) Pos() token.Pos { return x.NamePos } 754 func (x *Ident) pos() *token.Pos { return &x.NamePos } 755 func (x *BasicLit) Pos() token.Pos { return x.ValuePos } 756 func (x *BasicLit) pos() *token.Pos { return &x.ValuePos } 757 func (x *Interpolation) Pos() token.Pos { return x.Elts[0].Pos() } 758 func (x *Interpolation) pos() *token.Pos { return x.Elts[0].pos() } 759 func (x *Func) Pos() token.Pos { return x.Func } 760 func (x *Func) pos() *token.Pos { return &x.Func } 761 func (x *StructLit) Pos() token.Pos { return getPos(x) } 762 func (x *StructLit) pos() *token.Pos { 763 if x.Lbrace == token.NoPos && len(x.Elts) > 0 { 764 return x.Elts[0].pos() 765 } 766 return &x.Lbrace 767 } 768 769 func (x *ListLit) Pos() token.Pos { return x.Lbrack } 770 func (x *ListLit) pos() *token.Pos { return &x.Lbrack } 771 func (x *Ellipsis) Pos() token.Pos { return x.Ellipsis } 772 func (x *Ellipsis) pos() *token.Pos { return &x.Ellipsis } 773 func (x *LetClause) Pos() token.Pos { return x.Let } 774 func (x *LetClause) pos() *token.Pos { return &x.Let } 775 func (x *ForClause) Pos() token.Pos { return x.For } 776 func (x *ForClause) pos() *token.Pos { return &x.For } 777 func (x *IfClause) Pos() token.Pos { return x.If } 778 func (x *IfClause) pos() *token.Pos { return &x.If } 779 func (x *ParenExpr) Pos() token.Pos { return x.Lparen } 780 func (x *ParenExpr) pos() *token.Pos { return &x.Lparen } 781 func (x *SelectorExpr) Pos() token.Pos { return x.X.Pos() } 782 func (x *SelectorExpr) pos() *token.Pos { return x.X.pos() } 783 func (x *IndexExpr) Pos() token.Pos { return x.X.Pos() } 784 func (x *IndexExpr) pos() *token.Pos { return x.X.pos() } 785 func (x *SliceExpr) Pos() token.Pos { return x.X.Pos() } 786 func (x *SliceExpr) pos() *token.Pos { return x.X.pos() } 787 func (x *CallExpr) Pos() token.Pos { return x.Fun.Pos() } 788 func (x *CallExpr) pos() *token.Pos { return x.Fun.pos() } 789 func (x *UnaryExpr) Pos() token.Pos { return x.OpPos } 790 func (x *UnaryExpr) pos() *token.Pos { return &x.OpPos } 791 func (x *BinaryExpr) Pos() token.Pos { return x.X.Pos() } 792 func (x *BinaryExpr) pos() *token.Pos { return x.X.pos() } 793 func (x *BottomLit) Pos() token.Pos { return x.Bottom } 794 func (x *BottomLit) pos() *token.Pos { return &x.Bottom } 795 796 func (x *BadExpr) End() token.Pos { return x.To } 797 func (x *Ident) End() token.Pos { 798 return x.NamePos.Add(len(x.Name)) 799 } 800 func (x *BasicLit) End() token.Pos { return x.ValuePos.Add(len(x.Value)) } 801 802 func (x *Interpolation) End() token.Pos { return x.Elts[len(x.Elts)-1].Pos() } 803 func (x *Func) End() token.Pos { return x.Ret.End() } 804 func (x *StructLit) End() token.Pos { 805 if x.Rbrace == token.NoPos && len(x.Elts) > 0 { 806 return x.Elts[len(x.Elts)-1].End() 807 } 808 return x.Rbrace.Add(1) 809 } 810 func (x *ListLit) End() token.Pos { return x.Rbrack.Add(1) } 811 func (x *Ellipsis) End() token.Pos { 812 if x.Type != nil { 813 return x.Type.End() 814 } 815 return x.Ellipsis.Add(3) // len("...") 816 } 817 func (x *LetClause) End() token.Pos { return x.Expr.End() } 818 func (x *ForClause) End() token.Pos { return x.Source.End() } 819 func (x *IfClause) End() token.Pos { return x.Condition.End() } 820 func (x *ParenExpr) End() token.Pos { return x.Rparen.Add(1) } 821 func (x *SelectorExpr) End() token.Pos { return x.Sel.End() } 822 func (x *IndexExpr) End() token.Pos { return x.Rbrack.Add(1) } 823 func (x *SliceExpr) End() token.Pos { return x.Rbrack.Add(1) } 824 func (x *CallExpr) End() token.Pos { return x.Rparen.Add(1) } 825 func (x *UnaryExpr) End() token.Pos { return x.X.End() } 826 func (x *BinaryExpr) End() token.Pos { return x.Y.End() } 827 func (x *BottomLit) End() token.Pos { return x.Bottom.Add(1) } 828 829 // ---------------------------------------------------------------------------- 830 // Convenience functions for Idents 831 832 // NewIdent creates a new Ident without position. 833 // Useful for ASTs generated by code other than the CUE parser. 834 func NewIdent(name string) *Ident { 835 return &Ident{token.NoPos, name, nil, nil, comments{}, label{}, expr{}} 836 } 837 838 func (id *Ident) String() string { 839 if id != nil { 840 return id.Name 841 } 842 return "<nil>" 843 } 844 845 // ---------------------------------------------------------------------------- 846 // Declarations 847 848 // An ImportSpec node represents a single package import. 849 type ImportSpec struct { 850 Name *Ident // local package name (including "."); or nil 851 Path *BasicLit // import path 852 EndPos token.Pos // end of spec (overrides Path.Pos if nonzero) 853 854 comments 855 } 856 857 func (*ImportSpec) specNode() {} 858 859 func NewImport(name *Ident, importPath string) *ImportSpec { 860 importPath = literal.String.Quote(importPath) 861 path := &BasicLit{Kind: token.STRING, Value: importPath} 862 return &ImportSpec{Name: name, Path: path} 863 } 864 865 // Pos and End implementations for spec nodes. 866 867 func (s *ImportSpec) Pos() token.Pos { return getPos(s) } 868 func (s *ImportSpec) pos() *token.Pos { 869 if s.Name != nil { 870 return s.Name.pos() 871 } 872 return s.Path.pos() 873 } 874 875 // func (s *AliasSpec) Pos() token.Pos { return s.Name.Pos() } 876 // func (s *ValueSpec) Pos() token.Pos { return s.Names[0].Pos() } 877 // func (s *TypeSpec) Pos() token.Pos { return s.Name.Pos() } 878 879 func (s *ImportSpec) End() token.Pos { 880 if s.EndPos != token.NoPos { 881 return s.EndPos 882 } 883 return s.Path.End() 884 } 885 886 // A BadDecl node is a placeholder for declarations containing 887 // syntax errors for which no correct declaration nodes can be 888 // created. 889 type BadDecl struct { 890 From, To token.Pos // position range of bad declaration 891 892 comments 893 decl 894 } 895 896 // A ImportDecl node represents a series of import declarations. A valid 897 // Lparen position (Lparen.Line > 0) indicates a parenthesized declaration. 898 type ImportDecl struct { 899 Import token.Pos 900 Lparen token.Pos // position of '(', if any 901 Specs []*ImportSpec 902 Rparen token.Pos // position of ')', if any 903 904 comments 905 decl 906 } 907 908 type Spec interface { 909 Node 910 specNode() 911 } 912 913 // An EmbedDecl node represents a single expression used as a declaration. 914 // The expressions in this declaration is what will be emitted as 915 // configuration output. 916 // 917 // An EmbedDecl may only appear at the top level. 918 type EmbedDecl struct { 919 Expr Expr 920 921 comments 922 decl 923 } 924 925 // Pos and End implementations for declaration nodes. 926 927 func (d *BadDecl) Pos() token.Pos { return d.From } 928 func (d *BadDecl) pos() *token.Pos { return &d.From } 929 func (d *ImportDecl) Pos() token.Pos { return d.Import } 930 func (d *ImportDecl) pos() *token.Pos { return &d.Import } 931 func (d *EmbedDecl) Pos() token.Pos { return d.Expr.Pos() } 932 func (d *EmbedDecl) pos() *token.Pos { return d.Expr.pos() } 933 934 func (d *BadDecl) End() token.Pos { return d.To } 935 func (d *ImportDecl) End() token.Pos { 936 if d.Rparen.IsValid() { 937 return d.Rparen.Add(1) 938 } 939 if len(d.Specs) == 0 { 940 return token.NoPos 941 } 942 return d.Specs[0].End() 943 } 944 func (d *EmbedDecl) End() token.Pos { return d.Expr.End() } 945 946 // ---------------------------------------------------------------------------- 947 // Files and packages 948 949 // A File node represents a CUE source file. 950 type File struct { 951 Filename string 952 Decls []Decl // top-level declarations; or nil 953 954 Imports []*ImportSpec // imports in this file 955 Unresolved []*Ident // unresolved identifiers in this file 956 957 comments 958 } 959 960 // Preamble returns the declarations of the preamble. 961 func (f *File) Preamble() []Decl { 962 p := 0 963 outer: 964 for i, d := range f.Decls { 965 switch d.(type) { 966 default: 967 break outer 968 969 case *Package: 970 p = i + 1 971 case *CommentGroup: 972 case *Attribute: 973 case *ImportDecl: 974 p = i + 1 975 } 976 } 977 return f.Decls[:p] 978 } 979 980 func (f *File) VisitImports(fn func(d *ImportDecl)) { 981 for _, d := range f.Decls { 982 switch x := d.(type) { 983 case *CommentGroup: 984 case *Package: 985 case *Attribute: 986 case *ImportDecl: 987 fn(x) 988 default: 989 return 990 } 991 } 992 } 993 994 // PackageName returns the package name associated with this file or "" if no 995 // package is associated. 996 func (f *File) PackageName() string { 997 for _, d := range f.Decls { 998 switch x := d.(type) { 999 case *Package: 1000 if x.Name.Name == "_" { 1001 return "" 1002 } 1003 return x.Name.Name 1004 case *CommentGroup, *Attribute: 1005 default: 1006 return "" 1007 } 1008 } 1009 return "" 1010 } 1011 1012 func (f *File) Pos() token.Pos { 1013 if len(f.Decls) > 0 { 1014 return f.Decls[0].Pos() 1015 } 1016 if f.Filename != "" { 1017 // TODO. Do something more principled and efficient. 1018 return token.NewFile(f.Filename, -1, 1).Pos(0, 0) 1019 } 1020 return token.NoPos 1021 } 1022 1023 func (f *File) pos() *token.Pos { 1024 if len(f.Decls) > 0 { 1025 return f.Decls[0].pos() 1026 } 1027 if f.Filename != "" { 1028 return nil 1029 } 1030 return nil 1031 } 1032 1033 func (f *File) End() token.Pos { 1034 if n := len(f.Decls); n > 0 { 1035 return f.Decls[n-1].End() 1036 } 1037 return token.NoPos 1038 } 1039 1040 // A Package represents a package clause. 1041 type Package struct { 1042 PackagePos token.Pos // position of "package" pseudo-keyword 1043 Name *Ident // package name 1044 1045 comments 1046 decl 1047 } 1048 1049 func (p *Package) Pos() token.Pos { return getPos(p) } 1050 func (p *Package) pos() *token.Pos { 1051 if p.PackagePos != token.NoPos { 1052 return &p.PackagePos 1053 } 1054 if p.Name != nil { 1055 return p.Name.pos() 1056 } 1057 return nil 1058 } 1059 1060 func (p *Package) End() token.Pos { 1061 if p.Name != nil { 1062 return p.Name.End() 1063 } 1064 return token.NoPos 1065 }