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