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  }