cue/ast: reorganization of node types

Change-Id: Ib61eb58bb35c301898a67460bde783a7ead7cd70
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/3484
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/ast/ast.go b/cue/ast/ast.go
index 5d0dce4..864fe2f 100644
--- a/cue/ast/ast.go
+++ b/cue/ast/ast.go
@@ -90,24 +90,9 @@
 	exprNode()
 }
 
-func (*BadExpr) exprNode()       {}
-func (*Ident) exprNode()         {}
-func (*BasicLit) exprNode()      {}
-func (*Interpolation) exprNode() {}
-func (*StructLit) exprNode()     {}
-func (*ListLit) exprNode()       {}
-func (*Ellipsis) exprNode()      {}
+type expr struct{}
 
-// func (*Comprehension) exprNode() {}
-func (*ListComprehension) exprNode() {}
-func (*ParenExpr) exprNode()         {}
-func (*SelectorExpr) exprNode()      {}
-func (*IndexExpr) exprNode()         {}
-func (*SliceExpr) exprNode()         {}
-func (*CallExpr) exprNode()          {}
-func (*UnaryExpr) exprNode()         {}
-func (*BinaryExpr) exprNode()        {}
-func (*BottomLit) exprNode()         {}
+func (expr) exprNode() {}
 
 // A Decl node is implemented by all declarations.
 type Decl interface {
@@ -115,17 +100,9 @@
 	declNode()
 }
 
-func (*Field) declNode()         {}
-func (*Comprehension) declNode() {}
-func (*ImportDecl) declNode()    {}
-func (*BadDecl) declNode()       {}
-func (*EmbedDecl) declNode()     {}
-func (*Alias) declNode()         {}
-func (*Ellipsis) declNode()      {}
+type decl struct{}
 
-// Not technically declarations, but appearing at the same level.
-func (*Package) declNode()      {}
-func (*CommentGroup) declNode() {}
+func (decl) declNode() {}
 
 // A Label is any production that can be used as a LHS label.
 type Label interface {
@@ -143,6 +120,10 @@
 	clauseNode()
 }
 
+type clause struct{}
+
+func (clause) clauseNode() {}
+
 func (x *ForClause) clauseNode() {}
 func (x *IfClause) clauseNode()  {}
 func (x *Alias) clauseNode()     {}
@@ -213,6 +194,8 @@
 	//    <0> Label <1> ":" <2> Expr <3> "," <4>
 	Position int8
 	List     []*Comment // len(List) > 0
+
+	decl
 }
 
 func (g *CommentGroup) Pos() token.Pos  { return getPos(g) }
@@ -294,9 +277,10 @@
 
 // An Attribute provides meta data about a field.
 type Attribute struct {
-	comments
 	At   token.Pos
 	Text string // must be a valid attribute format.
+
+	comments
 }
 
 func (a *Attribute) Pos() token.Pos  { return a.At }
@@ -305,7 +289,6 @@
 
 // A Field represents a field declaration in a struct.
 type Field struct {
-	comments
 	Label    Label // must have at least one element.
 	Optional token.Pos
 
@@ -316,6 +299,9 @@
 	Value Expr // the value associated with this field.
 
 	Attrs []*Attribute
+
+	comments
+	decl
 }
 
 func (d *Field) Pos() token.Pos  { return d.Label.Pos() }
@@ -332,10 +318,12 @@
 
 // An Alias binds another field to the alias name in the current struct.
 type Alias struct {
-	comments
 	Ident *Ident    // field name, always an Ident
 	Equal token.Pos // position of "="
 	Expr  Expr      // An Ident or SelectorExpr
+
+	comments
+	decl
 }
 
 func (a *Alias) Pos() token.Pos  { return a.Ident.Pos() }
@@ -344,9 +332,11 @@
 
 // A Comprehension node represents a comprehension declaration.
 type Comprehension struct {
-	comments
 	Clauses []Clause // There must be at least one clause.
 	Value   Expr     // Must be a struct
+
+	comments
+	decl
 }
 
 func (x *Comprehension) Pos() token.Pos  { return getPos(x) }
@@ -366,20 +356,22 @@
 // created. This is different from an ErrorExpr which represents
 // an explicitly marked error in the source.
 type BadExpr struct {
-	comments
 	From, To token.Pos // position range of bad expression
+
+	comments
+	expr
 }
 
 // A BottomLit indicates an error.
 type BottomLit struct {
-	comments
 	Bottom token.Pos
+
+	comments
+	expr
 }
 
 // An Ident node represents an left-hand side identifier.
 type Ident struct {
-	label
-	comments
 	NamePos token.Pos // identifier position
 
 	// This LHS path element may be an identifier. Possible forms:
@@ -390,24 +382,31 @@
 
 	Scope Node // scope in which node was found or nil if referring directly
 	Node  Node
+
+	comments
+	label
+	expr
 }
 
 // A TemplateLabel represents a field template declaration in a struct.
 type TemplateLabel struct {
-	label
-	comments
 	Langle token.Pos
 	Ident  *Ident
 	Rangle token.Pos
+
+	comments
+	label
 }
 
 // A BasicLit node represents a literal of basic type.
 type BasicLit struct {
-	label
-	comments
 	ValuePos token.Pos   // literal position
 	Kind     token.Token // INT, FLOAT, DURATION, or STRING
 	Value    string      // literal string; e.g. 42, 0x7f, 3.14, 1_234_567, 1e-9, 2.4i, 'a', '\x7f', "foo", or '\m\n\o'
+
+	comments
+	expr
+	label
 }
 
 // NewString creates a new BasicLit with a string value without position.
@@ -425,45 +424,55 @@
 
 // A Interpolation node represents a string or bytes interpolation.
 type Interpolation struct {
-	label
-	comments
 	Elts []Expr // interleaving of strings and expressions.
+
+	comments
+	expr
+	label
 }
 
 // A StructLit node represents a literal struct.
 type StructLit struct {
-	comments
 	Lbrace token.Pos // position of "{"
 	Elts   []Decl    // list of elements; or nil
 	Rbrace token.Pos // position of "}"
+
+	comments
+	expr
 }
 
 // A ListLit node represents a literal list.
 type ListLit struct {
-	comments
 	Lbrack token.Pos // position of "["
 	Elts   []Expr    // list of composite elements; or nil
 	Rbrack token.Pos // position of "]"
+
+	comments
+	expr
 }
 
 type Ellipsis struct {
-	comments
 	Ellipsis token.Pos // open list if set
 	Type     Expr      // type for the remaining elements
+
+	comments
+	decl
+	expr
 }
 
 // A ListComprehension node represents as list comprehension.
 type ListComprehension struct {
-	comments
 	Lbrack  token.Pos // position of "["
 	Expr    Expr
 	Clauses []Clause  // Feed or Guard (TODO let)
 	Rbrack  token.Pos // position of "]"
+
+	comments
+	expr
 }
 
 // A ForClause node represents a for clause in a comprehension.
 type ForClause struct {
-	comments
 	For token.Pos
 	Key *Ident // allow pattern matching?
 	// TODO: change to Comma
@@ -471,28 +480,37 @@
 	Value  *Ident // allow pattern matching?
 	In     token.Pos
 	Source Expr
+
+	comments
+	clause
 }
 
 // A IfClause node represents an if guard clause in a comprehension.
 type IfClause struct {
-	comments
 	If        token.Pos
 	Condition Expr
+
+	comments
+	clause
 }
 
 // A ParenExpr node represents a parenthesized expression.
 type ParenExpr struct {
-	comments
 	Lparen token.Pos // position of "("
 	X      Expr      // parenthesized expression
 	Rparen token.Pos // position of ")"
+
+	comments
+	expr
 }
 
 // A SelectorExpr node represents an expression followed by a selector.
 type SelectorExpr struct {
-	comments
 	X   Expr   // expression
 	Sel *Ident // field selector
+
+	comments
+	expr
 }
 
 // NewSel creates a sequence of selectors.
@@ -506,30 +524,36 @@
 
 // An IndexExpr node represents an expression followed by an index.
 type IndexExpr struct {
-	comments
 	X      Expr      // expression
 	Lbrack token.Pos // position of "["
 	Index  Expr      // index expression
 	Rbrack token.Pos // position of "]"
+
+	comments
+	expr
 }
 
 // An SliceExpr node represents an expression followed by slice indices.
 type SliceExpr struct {
-	comments
 	X      Expr      // expression
 	Lbrack token.Pos // position of "["
 	Low    Expr      // begin of slice range; or nil
 	High   Expr      // end of slice range; or nil
 	Rbrack token.Pos // position of "]"
+
+	comments
+	expr
 }
 
 // A CallExpr node represents an expression followed by an argument list.
 type CallExpr struct {
-	comments
 	Fun    Expr      // function expression
 	Lparen token.Pos // position of "("
 	Args   []Expr    // function arguments; or nil
 	Rparen token.Pos // position of ")"
+
+	comments
+	expr
 }
 
 // NewCall creates a new CallExpr.
@@ -540,19 +564,23 @@
 
 // A UnaryExpr node represents a unary expression.
 type UnaryExpr struct {
-	comments
 	OpPos token.Pos   // position of Op
 	Op    token.Token // operator
 	X     Expr        // operand
+
+	comments
+	expr
 }
 
 // A BinaryExpr node represents a binary expression.
 type BinaryExpr struct {
-	comments
 	X     Expr        // left operand
 	OpPos token.Pos   // position of Op
 	Op    token.Token // operator
 	Y     Expr        // right operand
+
+	comments
+	expr
 }
 
 // token.Pos and End implementations for expression/type nodes.
@@ -641,7 +669,7 @@
 // NewIdent creates a new Ident without position.
 // Useful for ASTs generated by code other than the Go
 func NewIdent(name string) *Ident {
-	return &Ident{label{}, comments{}, token.NoPos, name, nil, nil}
+	return &Ident{token.NoPos, name, nil, nil, comments{}, label{}, expr{}}
 }
 
 func (id *Ident) String() string {
@@ -656,12 +684,15 @@
 
 // An ImportSpec node represents a single package import.
 type ImportSpec struct {
-	comments
 	Name   *Ident    // local package name (including "."); or nil
 	Path   *BasicLit // import path
 	EndPos token.Pos // end of spec (overrides Path.Pos if nonzero)
+
+	comments
 }
 
+func (*ImportSpec) specNode() {}
+
 func NewImport(name *Ident, importPath string) *ImportSpec {
 	importPath = strconv.Quote(importPath)
 	path := &BasicLit{Kind: token.STRING, Value: importPath}
@@ -693,18 +724,22 @@
 // syntax errors for which no correct declaration nodes can be
 // created.
 type BadDecl struct {
-	comments
 	From, To token.Pos // position range of bad declaration
+
+	comments
+	decl
 }
 
 // A ImportDecl node represents a series of import declarations. A valid
 // Lparen position (Lparen.Line > 0) indicates a parenthesized declaration.
 type ImportDecl struct {
-	comments
 	Import token.Pos
 	Lparen token.Pos // position of '(', if any
 	Specs  []*ImportSpec
 	Rparen token.Pos // position of ')', if any
+
+	comments
+	decl
 }
 
 type Spec interface {
@@ -712,18 +747,16 @@
 	specNode()
 }
 
-func (*ImportSpec) specNode() {}
-
-func (*Package) specNode() {}
-
 // An EmbedDecl node represents a single expression used as a declaration.
 // The expressions in this declaration is what will be emitted as
 // configuration output.
 //
 // An EmbedDecl may only appear at the top level.
 type EmbedDecl struct {
-	comments
 	Expr Expr
+
+	comments
+	decl
 }
 
 // Pos and End implementations for declaration nodes.
@@ -757,11 +790,12 @@
 // via Doc and Comment fields.
 type File struct {
 	Filename string
-	comments
-	Decls []Decl // top-level declarations; or nil
+	Decls    []Decl // top-level declarations; or nil
 
 	Imports    []*ImportSpec // imports in this file
 	Unresolved []*Ident      // unresolved identifiers in this file
+
+	comments
 }
 
 func (f *File) Pos() token.Pos {
@@ -794,9 +828,11 @@
 
 // A Package represents a package clause.
 type Package struct {
-	comments
 	PackagePos token.Pos // position of "package" pseudo-keyword
 	Name       *Ident    // package name
+
+	comments
+	decl
 }
 
 func (p *Package) Pos() token.Pos { return getPos(p) }
diff --git a/cue/parser/parser_test.go b/cue/parser/parser_test.go
index 6bf83f0..79bf9a8 100644
--- a/cue/parser/parser_test.go
+++ b/cue/parser/parser_test.go
@@ -544,7 +544,7 @@
 			if sel == nil {
 				t.Fatalf("found no *SelectorExpr: %#v %s", f.Decls[0], debugStr(f))
 			}
-			const wantSel = "&{{<nil>} fmt _}"
+			const wantSel = "&{fmt _ {<nil>} {}}"
 			if fmt.Sprint(sel) != wantSel {
 				t.Fatalf("found selector %v, want %s", sel, wantSel)
 			}