cue: uniform handling of definitions

This mostly affects spacing, which will be tested in followup CLs.

Change-Id: I5308aca574308131d737173d6b9d344317a34356
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/5941
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cue/export.go b/cue/export.go
index 6fe9f2b..251e0e9 100644
--- a/cue/export.go
+++ b/cue/export.go
@@ -874,7 +874,7 @@
 			if p.mode.omitDefinitions || p.mode.concrete {
 				continue
 			}
-			if !isDef(f) {
+			if !internal.IsDefinition(f.Label) {
 				f.Token = token.ISA
 			}
 		}
@@ -914,7 +914,7 @@
 					opt = token.NoSpace.Pos() // anything but token.NoPos
 				}
 				tok := token.COLON
-				if c.def {
+				if c.def && !internal.IsDefinition(label) {
 					tok = token.ISA
 				}
 				f := &ast.Field{
diff --git a/cue/format/node.go b/cue/format/node.go
index 9cdd869..0bd8525 100644
--- a/cue/format/node.go
+++ b/cue/format/node.go
@@ -120,7 +120,7 @@
 			if hasDocComments(x) {
 				switch x := list[i-1].(type) {
 				case *ast.Field:
-					if x.Token == token.ISA {
+					if x.Token == token.ISA || internal.IsDefinition(x.Label) {
 						f.print(newsection)
 					}
 
diff --git a/internal/encoding/encoding.go b/internal/encoding/encoding.go
index 03fc7ab..a828a1b 100644
--- a/internal/encoding/encoding.go
+++ b/internal/encoding/encoding.go
@@ -367,8 +367,9 @@
 		check(n, i.Imports, "imports", true)
 
 	case *ast.Field:
-		check(n, i.Definitions, "definitions", x.Token == token.ISA)
-		check(n, i.Data, "regular fields", x.Token != token.ISA)
+		check(n, i.Definitions, "definitions",
+			x.Token == token.ISA || internal.IsDefinition(x.Label))
+		check(n, i.Data, "regular fields", internal.IsRegularField(x))
 		check(n, constraints, "optional fields", x.Optional != token.NoPos)
 
 		_, _, err := ast.LabelName(x.Label)
diff --git a/internal/internal.go b/internal/internal.go
index a2cd8c7..ffc8e66 100644
--- a/internal/internal.go
+++ b/internal/internal.go
@@ -280,6 +280,38 @@
 	return false
 }
 
+func IsDefinition(label ast.Label) bool {
+	switch x := label.(type) {
+	case *ast.Alias:
+		if ident, ok := x.Expr.(*ast.Ident); ok {
+			return strings.HasPrefix(ident.Name, "#")
+		}
+	case *ast.Ident:
+		return strings.HasPrefix(x.Name, "#")
+	}
+	return false
+}
+
+func IsRegularField(f *ast.Field) bool {
+	if f.Token == token.ISA {
+		return false
+	}
+	var ident *ast.Ident
+	switch x := f.Label.(type) {
+	case *ast.Alias:
+		ident, _ = x.Expr.(*ast.Ident)
+	case *ast.Ident:
+		ident = x
+	}
+	if ident == nil {
+		return true
+	}
+	if strings.HasPrefix(ident.Name, "#") || strings.HasPrefix(ident.Name, "_") {
+		return false
+	}
+	return true
+}
+
 func EmbedStruct(s *ast.StructLit) *ast.EmbedDecl {
 	e := &ast.EmbedDecl{Expr: s}
 	if len(s.Elts) == 1 {