cue: generate error node rather than panic on faulty output.

Issue #593

Change-Id: Icf1690e0ea631ee650a5b3962e7777608a0229c6
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7722
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/format/format_test.go b/cue/format/format_test.go
index b0da92e..47a0b6a 100644
--- a/cue/format/format_test.go
+++ b/cue/format/format_test.go
@@ -286,7 +286,7 @@
 // Verify that the printer doesn't crash if the AST contains BadXXX nodes.
 func TestBadNodes(t *testing.T) {
 	const src = "package p\n("
-	const res = "package p\n\n(BadExpr)\n"
+	const res = "package p\n\n(_|_)\n"
 	f, err := parser.ParseFile("", src, parser.ParseComments)
 	if err == nil {
 		t.Error("expected illegal program") // error in test
diff --git a/cue/format/node.go b/cue/format/node.go
index ebbb64f..8e9192f 100644
--- a/cue/format/node.go
+++ b/cue/format/node.go
@@ -532,7 +532,7 @@
 
 	switch x := expr.(type) {
 	case *ast.BadExpr:
-		f.print(x.From, "BadExpr")
+		f.print(x.From, "_|_")
 
 	case *ast.BottomLit:
 		f.print(x.Bottom, token.BOTTOM)
diff --git a/cue/types.go b/cue/types.go
index fdb2643..d9aa414 100644
--- a/cue/types.go
+++ b/cue/types.go
@@ -939,6 +939,29 @@
 
 	pkgID := v.instance().ID()
 
+	bad := func(name string, err error) ast.Node {
+		const format = `"%s: internal error
+Error: %s
+
+Profile:
+%#v
+
+Value:
+%v
+
+You could file a bug with the above information at:
+    https://github.com/cuelang/cue/issues/new?assignees=&labels=NeedsInvestigation&template=bug_report.md&title=.
+`
+		cg := &ast.CommentGroup{Doc: true}
+		msg := fmt.Sprintf(format, name, err, p, v)
+		for _, line := range strings.Split(msg, "\n") {
+			cg.List = append(cg.List, &ast.Comment{Text: "// " + line})
+		}
+		x := &ast.BadExpr{}
+		ast.AddComment(x, cg)
+		return x
+	}
+
 	// var expr ast.Expr
 	var err error
 	var f *ast.File
@@ -947,19 +970,19 @@
 		var expr ast.Expr
 		expr, err = p.Value(v.idx.Runtime, pkgID, v.v)
 		if err != nil {
-			return nil
+			return bad(`"cuelang.org/go/internal/core/export".Value`, err)
 		}
 
 		// This introduces gratuitous unshadowing!
 		f, err = astutil.ToFile(expr)
 		if err != nil {
-			return nil
+			return bad(`"cuelang.org/go/ast/astutil".ToFile`, err)
 		}
 		// return expr
 	} else {
 		f, err = p.Def(v.idx.Runtime, pkgID, v.v)
 		if err != nil {
-			panic(err)
+			return bad(`"cuelang.org/go/internal/core/export".Def`, err)
 		}
 	}