...

Source file src/cuelang.org/go/cue/ast/ast.go

Documentation: cuelang.org/go/cue/ast

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

View as plain text