cuelang.org/go@v0.10.1/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 Optional token.Pos // Deprecated 306 Constraint token.Token // token.ILLEGAL, token.OPTION, or token.NOT 307 308 // No TokenPos: Value must be an StructLit with one field. 309 TokenPos token.Pos 310 Token token.Token // Deprecated: always token.COLON 311 312 Value Expr // the value associated with this field. 313 314 Attrs []*Attribute 315 316 comments 317 decl 318 } 319 320 func (d *Field) Pos() token.Pos { return d.Label.Pos() } 321 func (d *Field) pos() *token.Pos { return d.Label.pos() } 322 func (d *Field) End() token.Pos { 323 if len(d.Attrs) > 0 { 324 return d.Attrs[len(d.Attrs)-1].End() 325 } 326 return d.Value.End() 327 } 328 329 // TODO: make Alias a type of Field. This is possible now we have different 330 // separator types. 331 332 // An Alias binds another field to the alias name in the current struct. 333 type Alias struct { 334 Ident *Ident // field name, always an Ident 335 Equal token.Pos // position of "=" 336 Expr Expr // An Ident or SelectorExpr 337 338 comments 339 clause 340 decl 341 expr 342 label 343 } 344 345 func (a *Alias) Pos() token.Pos { return a.Ident.Pos() } 346 func (a *Alias) pos() *token.Pos { return a.Ident.pos() } 347 func (a *Alias) End() token.Pos { return a.Expr.End() } 348 349 // A Comprehension node represents a comprehension declaration. 350 type Comprehension struct { 351 Clauses []Clause // There must be at least one clause. 352 Value Expr // Must be a struct TODO: change to Struct 353 354 comments 355 decl 356 expr // TODO: only allow Comprehension in "Embedding" productions. 357 } 358 359 func (x *Comprehension) Pos() token.Pos { return getPos(x) } 360 func (x *Comprehension) pos() *token.Pos { return x.Clauses[0].pos() } 361 func (x *Comprehension) End() token.Pos { 362 return x.Value.End() 363 } 364 365 // ---------------------------------------------------------------------------- 366 // Expressions and types 367 // 368 // An expression is represented by a tree consisting of one 369 // or more of the following concrete expression nodes. 370 371 // A BadExpr node is a placeholder for expressions containing 372 // syntax errors for which no correct expression nodes can be 373 // created. This is different from an ErrorExpr which represents 374 // an explicitly marked error in the source. 375 type BadExpr struct { 376 From, To token.Pos // position range of bad expression 377 378 comments 379 expr 380 } 381 382 // A BottomLit indicates an error. 383 type BottomLit struct { 384 Bottom token.Pos 385 386 comments 387 expr 388 } 389 390 // An Ident node represents a left-hand side identifier, 391 // including the underscore "_" identifier to represent top. 392 type Ident struct { 393 NamePos token.Pos // identifier position 394 395 // This LHS path element may be an identifier. Possible forms: 396 // foo: a normal identifier 397 // "foo": JSON compatible 398 Name string 399 400 Scope Node // scope in which node was found or nil if referring directly 401 Node Node 402 403 comments 404 label 405 expr 406 } 407 408 // A BasicLit node represents a literal of basic type. 409 type BasicLit struct { 410 ValuePos token.Pos // literal position 411 Kind token.Token // INT, FLOAT, DURATION, or STRING 412 Value string // literal string; e.g. 42, 0x7f, 3.14, 1_234_567, 1e-9, 2.4i, 'a', '\x7f', "foo", or '\m\n\o' 413 414 comments 415 expr 416 label 417 } 418 419 // TODO: introduce and use NewLabel and NewBytes and perhaps NewText (in the 420 // later case NewString would return a string or bytes type) to distinguish from 421 // NewString. Consider how to pass indentation information. 422 423 // NewString creates a new BasicLit with a string value without position. 424 // It quotes the given string. 425 // Useful for ASTs generated by code other than the CUE parser. 426 func NewString(str string) *BasicLit { 427 str = literal.String.Quote(str) 428 return &BasicLit{Kind: token.STRING, ValuePos: token.NoPos, Value: str} 429 } 430 431 // NewNull creates a new BasicLit configured to be a null value. 432 // Useful for ASTs generated by code other than the CUE parser. 433 func NewNull() *BasicLit { 434 return &BasicLit{Kind: token.NULL, Value: "null"} 435 } 436 437 // NewLit creates a new BasicLit with from a token type and string without 438 // position. 439 // Useful for ASTs generated by code other than the CUE parser. 440 func NewLit(tok token.Token, s string) *BasicLit { 441 return &BasicLit{Kind: tok, Value: s} 442 } 443 444 // NewBool creates a new BasicLit with a bool value without position. 445 // Useful for ASTs generated by code other than the CUE parser. 446 func NewBool(b bool) *BasicLit { 447 x := &BasicLit{} 448 if b { 449 x.Kind = token.TRUE 450 x.Value = "true" 451 } else { 452 x.Kind = token.FALSE 453 x.Value = "false" 454 } 455 return x 456 } 457 458 // TODO: 459 // - use CUE-specific quoting (hoist functionality in export) 460 // - NewBytes 461 462 // A Interpolation node represents a string or bytes interpolation. 463 type Interpolation struct { 464 Elts []Expr // interleaving of strings and expressions. 465 466 comments 467 expr 468 label 469 } 470 471 // A Func node represents a function type. 472 // 473 // This is an experimental type and the contents will change without notice. 474 type Func struct { 475 Func token.Pos // position of "func" 476 Args []Expr // list of elements; or nil 477 Ret Expr // return type, must not be nil 478 479 comments 480 expr 481 } 482 483 // A StructLit node represents a literal struct. 484 type StructLit struct { 485 Lbrace token.Pos // position of "{" 486 Elts []Decl // list of elements; or nil 487 Rbrace token.Pos // position of "}" 488 489 comments 490 expr 491 } 492 493 // NewStruct creates a struct from the given fields. 494 // 495 // A field is either a *Field, an *Ellipsis, *LetClause, a *CommentGroup, or a 496 // Label, optionally followed by a token.OPTION or token.NOT to indicate the 497 // field is optional or required, followed by an expression for the field value. 498 // 499 // It will panic if a values not matching these patterns are given. Useful for 500 // ASTs generated by code other than the CUE parser. 501 func NewStruct(fields ...interface{}) *StructLit { 502 s := &StructLit{ 503 // Set default positions so that comment attachment is as expected. 504 Lbrace: token.NoSpace.Pos(), 505 } 506 for i := 0; i < len(fields); i++ { 507 var ( 508 label Label 509 optional = token.NoPos 510 constraint = token.ILLEGAL 511 expr Expr 512 ) 513 514 switch x := fields[i].(type) { 515 case *Field: 516 s.Elts = append(s.Elts, x) 517 continue 518 case *CommentGroup: 519 s.Elts = append(s.Elts, x) 520 continue 521 case *Ellipsis: 522 s.Elts = append(s.Elts, x) 523 continue 524 case *LetClause: 525 s.Elts = append(s.Elts, x) 526 continue 527 case *embedding: 528 s.Elts = append(s.Elts, (*EmbedDecl)(x)) 529 continue 530 case Label: 531 label = x 532 case string: 533 label = NewString(x) 534 default: 535 panic(fmt.Sprintf("unsupported label type %T", x)) 536 } 537 538 inner: 539 for i++; i < len(fields); i++ { 540 switch x := (fields[i]).(type) { 541 case Expr: 542 expr = x 543 break inner 544 case token.Token: 545 switch x { 546 case token.OPTION: 547 constraint = x 548 optional = token.Blank.Pos() 549 case token.NOT: 550 constraint = x 551 case token.COLON, token.ILLEGAL: 552 default: 553 panic(fmt.Sprintf("invalid token %s", x)) 554 } 555 default: 556 panic(fmt.Sprintf("unsupported expression type %T", x)) 557 } 558 } 559 if expr == nil { 560 panic("label not matched with expression") 561 } 562 s.Elts = append(s.Elts, &Field{ 563 Label: label, 564 Optional: optional, 565 Constraint: constraint, 566 Value: expr, 567 }) 568 } 569 return s 570 } 571 572 // Embed can be used in conjunction with NewStruct to embed values. 573 func Embed(x Expr) *embedding { 574 return (*embedding)(&EmbedDecl{Expr: x}) 575 } 576 577 type embedding EmbedDecl 578 579 // A ListLit node represents a literal list. 580 type ListLit struct { 581 Lbrack token.Pos // position of "[" 582 583 // TODO: change to embedding or similar. 584 Elts []Expr // list of composite elements; or nil 585 Rbrack token.Pos // position of "]" 586 587 comments 588 expr 589 label 590 } 591 592 // NewList creates a list of Expressions. 593 // Useful for ASTs generated by code other than the CUE parser. 594 func NewList(exprs ...Expr) *ListLit { 595 return &ListLit{Elts: exprs} 596 } 597 598 type Ellipsis struct { 599 Ellipsis token.Pos // open list if set 600 Type Expr // type for the remaining elements 601 602 comments 603 decl 604 expr 605 } 606 607 // A ForClause node represents a for clause in a comprehension. 608 type ForClause struct { 609 For token.Pos 610 Key *Ident // allow pattern matching? 611 // TODO: change to Comma 612 Colon token.Pos 613 Value *Ident // allow pattern matching? 614 In token.Pos 615 Source Expr 616 617 comments 618 clause 619 } 620 621 // A IfClause node represents an if guard clause in a comprehension. 622 type IfClause struct { 623 If token.Pos 624 Condition Expr 625 626 comments 627 clause 628 } 629 630 // A LetClause node represents a let clause in a comprehension. 631 type LetClause struct { 632 Let token.Pos 633 Ident *Ident 634 Equal token.Pos 635 Expr Expr 636 637 comments 638 clause 639 decl 640 } 641 642 // A ParenExpr node represents a parenthesized expression. 643 type ParenExpr struct { 644 Lparen token.Pos // position of "(" 645 X Expr // parenthesized expression 646 Rparen token.Pos // position of ")" 647 648 comments 649 expr 650 label 651 } 652 653 // A SelectorExpr node represents an expression followed by a selector. 654 type SelectorExpr struct { 655 X Expr // expression 656 Sel Label // field selector 657 658 comments 659 expr 660 } 661 662 // NewSel creates a sequence of selectors. 663 // Useful for ASTs generated by code other than the CUE parser. 664 func NewSel(x Expr, sel ...string) Expr { 665 for _, s := range sel { 666 x = &SelectorExpr{X: x, Sel: NewIdent(s)} 667 } 668 return x 669 } 670 671 // An IndexExpr node represents an expression followed by an index. 672 type IndexExpr struct { 673 X Expr // expression 674 Lbrack token.Pos // position of "[" 675 Index Expr // index expression 676 Rbrack token.Pos // position of "]" 677 678 comments 679 expr 680 } 681 682 // An SliceExpr node represents an expression followed by slice indices. 683 type SliceExpr struct { 684 X Expr // expression 685 Lbrack token.Pos // position of "[" 686 Low Expr // begin of slice range; or nil 687 High Expr // end of slice range; or nil 688 Rbrack token.Pos // position of "]" 689 690 comments 691 expr 692 } 693 694 // A CallExpr node represents an expression followed by an argument list. 695 type CallExpr struct { 696 Fun Expr // function expression 697 Lparen token.Pos // position of "(" 698 Args []Expr // function arguments; or nil 699 Rparen token.Pos // position of ")" 700 701 comments 702 expr 703 } 704 705 // NewCall creates a new CallExpr. 706 // Useful for ASTs generated by code other than the CUE parser. 707 func NewCall(fun Expr, args ...Expr) *CallExpr { 708 return &CallExpr{Fun: fun, Args: args} 709 } 710 711 // A UnaryExpr node represents a unary expression. 712 type UnaryExpr struct { 713 OpPos token.Pos // position of Op 714 Op token.Token // operator 715 X Expr // operand 716 717 comments 718 expr 719 } 720 721 // A BinaryExpr node represents a binary expression. 722 type BinaryExpr struct { 723 X Expr // left operand 724 OpPos token.Pos // position of Op 725 Op token.Token // operator 726 Y Expr // right operand 727 728 comments 729 expr 730 } 731 732 // NewBinExpr creates for list of expressions of length 2 or greater a chained 733 // binary expression of the form (((x1 op x2) op x3) ...). For lists of length 734 // 1 it returns the expression itself. It panics for empty lists. 735 // Useful for ASTs generated by code other than the CUE parser. 736 func NewBinExpr(op token.Token, operands ...Expr) Expr { 737 if len(operands) == 0 { 738 return nil 739 } 740 expr := operands[0] 741 for _, e := range operands[1:] { 742 expr = &BinaryExpr{X: expr, Op: op, Y: e} 743 } 744 return expr 745 } 746 747 // token.Pos and End implementations for expression/type nodes. 748 749 func (x *BadExpr) Pos() token.Pos { return x.From } 750 func (x *BadExpr) pos() *token.Pos { return &x.From } 751 func (x *Ident) Pos() token.Pos { return x.NamePos } 752 func (x *Ident) pos() *token.Pos { return &x.NamePos } 753 func (x *BasicLit) Pos() token.Pos { return x.ValuePos } 754 func (x *BasicLit) pos() *token.Pos { return &x.ValuePos } 755 func (x *Interpolation) Pos() token.Pos { return x.Elts[0].Pos() } 756 func (x *Interpolation) pos() *token.Pos { return x.Elts[0].pos() } 757 func (x *Func) Pos() token.Pos { return x.Func } 758 func (x *Func) pos() *token.Pos { return &x.Func } 759 func (x *StructLit) Pos() token.Pos { return getPos(x) } 760 func (x *StructLit) pos() *token.Pos { 761 if x.Lbrace == token.NoPos && len(x.Elts) > 0 { 762 return x.Elts[0].pos() 763 } 764 return &x.Lbrace 765 } 766 767 func (x *ListLit) Pos() token.Pos { return x.Lbrack } 768 func (x *ListLit) pos() *token.Pos { return &x.Lbrack } 769 func (x *Ellipsis) Pos() token.Pos { return x.Ellipsis } 770 func (x *Ellipsis) pos() *token.Pos { return &x.Ellipsis } 771 func (x *LetClause) Pos() token.Pos { return x.Let } 772 func (x *LetClause) pos() *token.Pos { return &x.Let } 773 func (x *ForClause) Pos() token.Pos { return x.For } 774 func (x *ForClause) pos() *token.Pos { return &x.For } 775 func (x *IfClause) Pos() token.Pos { return x.If } 776 func (x *IfClause) pos() *token.Pos { return &x.If } 777 func (x *ParenExpr) Pos() token.Pos { return x.Lparen } 778 func (x *ParenExpr) pos() *token.Pos { return &x.Lparen } 779 func (x *SelectorExpr) Pos() token.Pos { return x.X.Pos() } 780 func (x *SelectorExpr) pos() *token.Pos { return x.X.pos() } 781 func (x *IndexExpr) Pos() token.Pos { return x.X.Pos() } 782 func (x *IndexExpr) pos() *token.Pos { return x.X.pos() } 783 func (x *SliceExpr) Pos() token.Pos { return x.X.Pos() } 784 func (x *SliceExpr) pos() *token.Pos { return x.X.pos() } 785 func (x *CallExpr) Pos() token.Pos { return x.Fun.Pos() } 786 func (x *CallExpr) pos() *token.Pos { return x.Fun.pos() } 787 func (x *UnaryExpr) Pos() token.Pos { return x.OpPos } 788 func (x *UnaryExpr) pos() *token.Pos { return &x.OpPos } 789 func (x *BinaryExpr) Pos() token.Pos { return x.X.Pos() } 790 func (x *BinaryExpr) pos() *token.Pos { return x.X.pos() } 791 func (x *BottomLit) Pos() token.Pos { return x.Bottom } 792 func (x *BottomLit) pos() *token.Pos { return &x.Bottom } 793 794 func (x *BadExpr) End() token.Pos { return x.To } 795 func (x *Ident) End() token.Pos { 796 return x.NamePos.Add(len(x.Name)) 797 } 798 func (x *BasicLit) End() token.Pos { return x.ValuePos.Add(len(x.Value)) } 799 800 func (x *Interpolation) End() token.Pos { return x.Elts[len(x.Elts)-1].Pos() } 801 func (x *Func) End() token.Pos { return x.Ret.End() } 802 func (x *StructLit) End() token.Pos { 803 if x.Rbrace == token.NoPos && len(x.Elts) > 0 { 804 return x.Elts[len(x.Elts)-1].End() 805 } 806 return x.Rbrace.Add(1) 807 } 808 func (x *ListLit) End() token.Pos { return x.Rbrack.Add(1) } 809 func (x *Ellipsis) End() token.Pos { 810 if x.Type != nil { 811 return x.Type.End() 812 } 813 return x.Ellipsis.Add(3) // len("...") 814 } 815 func (x *LetClause) End() token.Pos { return x.Expr.End() } 816 func (x *ForClause) End() token.Pos { return x.Source.End() } 817 func (x *IfClause) End() token.Pos { return x.Condition.End() } 818 func (x *ParenExpr) End() token.Pos { return x.Rparen.Add(1) } 819 func (x *SelectorExpr) End() token.Pos { return x.Sel.End() } 820 func (x *IndexExpr) End() token.Pos { return x.Rbrack.Add(1) } 821 func (x *SliceExpr) End() token.Pos { return x.Rbrack.Add(1) } 822 func (x *CallExpr) End() token.Pos { return x.Rparen.Add(1) } 823 func (x *UnaryExpr) End() token.Pos { return x.X.End() } 824 func (x *BinaryExpr) End() token.Pos { return x.Y.End() } 825 func (x *BottomLit) End() token.Pos { return x.Bottom.Add(1) } 826 827 // ---------------------------------------------------------------------------- 828 // Convenience functions for Idents 829 830 // NewIdent creates a new Ident without position. 831 // Useful for ASTs generated by code other than the CUE parser. 832 func NewIdent(name string) *Ident { 833 return &Ident{token.NoPos, name, nil, nil, comments{}, label{}, expr{}} 834 } 835 836 func (id *Ident) String() string { 837 if id != nil { 838 return id.Name 839 } 840 return "<nil>" 841 } 842 843 // ---------------------------------------------------------------------------- 844 // Declarations 845 846 // An ImportSpec node represents a single package import. 847 type ImportSpec struct { 848 Name *Ident // local package name (including "."); or nil 849 Path *BasicLit // import path 850 EndPos token.Pos // end of spec (overrides Path.Pos if nonzero) 851 852 comments 853 } 854 855 func (*ImportSpec) specNode() {} 856 857 func NewImport(name *Ident, importPath string) *ImportSpec { 858 importPath = literal.String.Quote(importPath) 859 path := &BasicLit{Kind: token.STRING, Value: importPath} 860 return &ImportSpec{Name: name, Path: path} 861 } 862 863 // Pos and End implementations for spec nodes. 864 865 func (s *ImportSpec) Pos() token.Pos { return getPos(s) } 866 func (s *ImportSpec) pos() *token.Pos { 867 if s.Name != nil { 868 return s.Name.pos() 869 } 870 return s.Path.pos() 871 } 872 873 // func (s *AliasSpec) Pos() token.Pos { return s.Name.Pos() } 874 // func (s *ValueSpec) Pos() token.Pos { return s.Names[0].Pos() } 875 // func (s *TypeSpec) Pos() token.Pos { return s.Name.Pos() } 876 877 func (s *ImportSpec) End() token.Pos { 878 if s.EndPos != token.NoPos { 879 return s.EndPos 880 } 881 return s.Path.End() 882 } 883 884 // A BadDecl node is a placeholder for declarations containing 885 // syntax errors for which no correct declaration nodes can be 886 // created. 887 type BadDecl struct { 888 From, To token.Pos // position range of bad declaration 889 890 comments 891 decl 892 } 893 894 // A ImportDecl node represents a series of import declarations. A valid 895 // Lparen position (Lparen.Line > 0) indicates a parenthesized declaration. 896 type ImportDecl struct { 897 Import token.Pos 898 Lparen token.Pos // position of '(', if any 899 Specs []*ImportSpec 900 Rparen token.Pos // position of ')', if any 901 902 comments 903 decl 904 } 905 906 type Spec interface { 907 Node 908 specNode() 909 } 910 911 // An EmbedDecl node represents a single expression used as a declaration. 912 // The expressions in this declaration is what will be emitted as 913 // configuration output. 914 // 915 // An EmbedDecl may only appear at the top level. 916 type EmbedDecl struct { 917 Expr Expr 918 919 comments 920 decl 921 } 922 923 // Pos and End implementations for declaration nodes. 924 925 func (d *BadDecl) Pos() token.Pos { return d.From } 926 func (d *BadDecl) pos() *token.Pos { return &d.From } 927 func (d *ImportDecl) Pos() token.Pos { return d.Import } 928 func (d *ImportDecl) pos() *token.Pos { return &d.Import } 929 func (d *EmbedDecl) Pos() token.Pos { return d.Expr.Pos() } 930 func (d *EmbedDecl) pos() *token.Pos { return d.Expr.pos() } 931 932 func (d *BadDecl) End() token.Pos { return d.To } 933 func (d *ImportDecl) End() token.Pos { 934 if d.Rparen.IsValid() { 935 return d.Rparen.Add(1) 936 } 937 if len(d.Specs) == 0 { 938 return token.NoPos 939 } 940 return d.Specs[0].End() 941 } 942 func (d *EmbedDecl) End() token.Pos { return d.Expr.End() } 943 944 // ---------------------------------------------------------------------------- 945 // Files and packages 946 947 // A File node represents a CUE source file. 948 // 949 // The Comments list contains all comments in the source file in order of 950 // appearance, including the comments that are pointed to from other nodes 951 // via Doc and Comment fields. 952 type File struct { 953 Filename string 954 Decls []Decl // top-level declarations; or nil 955 956 Imports []*ImportSpec // imports in this file 957 Unresolved []*Ident // unresolved identifiers in this file 958 959 comments 960 } 961 962 // Preamble returns the declarations of the preamble. 963 func (f *File) Preamble() []Decl { 964 p := 0 965 outer: 966 for i, d := range f.Decls { 967 switch d.(type) { 968 default: 969 break outer 970 971 case *Package: 972 p = i + 1 973 case *CommentGroup: 974 case *Attribute: 975 case *ImportDecl: 976 p = i + 1 977 } 978 } 979 return f.Decls[:p] 980 } 981 982 func (f *File) VisitImports(fn func(d *ImportDecl)) { 983 for _, d := range f.Decls { 984 switch x := d.(type) { 985 case *CommentGroup: 986 case *Package: 987 case *Attribute: 988 case *ImportDecl: 989 fn(x) 990 default: 991 return 992 } 993 } 994 } 995 996 // PackageName returns the package name associated with this file or "" if no 997 // package is associated. 998 func (f *File) PackageName() string { 999 for _, d := range f.Decls { 1000 switch x := d.(type) { 1001 case *Package: 1002 if x.Name.Name == "_" { 1003 return "" 1004 } 1005 return x.Name.Name 1006 case *CommentGroup, *Attribute: 1007 default: 1008 return "" 1009 } 1010 } 1011 return "" 1012 } 1013 1014 func (f *File) Pos() token.Pos { 1015 if len(f.Decls) > 0 { 1016 return f.Decls[0].Pos() 1017 } 1018 if f.Filename != "" { 1019 // TODO. Do something more principled and efficient. 1020 return token.NewFile(f.Filename, -1, 1).Pos(0, 0) 1021 } 1022 return token.NoPos 1023 } 1024 1025 func (f *File) pos() *token.Pos { 1026 if len(f.Decls) > 0 { 1027 return f.Decls[0].pos() 1028 } 1029 if f.Filename != "" { 1030 return nil 1031 } 1032 return nil 1033 } 1034 1035 func (f *File) End() token.Pos { 1036 if n := len(f.Decls); n > 0 { 1037 return f.Decls[n-1].End() 1038 } 1039 return token.NoPos 1040 } 1041 1042 // A Package represents a package clause. 1043 type Package struct { 1044 PackagePos token.Pos // position of "package" pseudo-keyword 1045 Name *Ident // package name 1046 1047 comments 1048 decl 1049 } 1050 1051 func (p *Package) Pos() token.Pos { return getPos(p) } 1052 func (p *Package) pos() *token.Pos { 1053 if p.PackagePos != token.NoPos { 1054 return &p.PackagePos 1055 } 1056 if p.Name != nil { 1057 return p.Name.pos() 1058 } 1059 return nil 1060 } 1061 1062 func (p *Package) End() token.Pos { 1063 if p.Name != nil { 1064 return p.Name.End() 1065 } 1066 return token.NoPos 1067 }