cue/parser: improve error message for misused keywords

Change-Id: Id6eb40d23e3a5ad7737933c1e188f0822d047df8
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/3963
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/parser/parser.go b/cue/parser/parser.go
index 4744ceb..7ef6ef1 100644
--- a/cue/parser/parser.go
+++ b/cue/parser/parser.go
@@ -1008,11 +1008,25 @@
 
 	case token.IF, token.FOR, token.IN, token.LET:
 		// Keywords representing clauses.
-		label = &ast.Ident{
-			NamePos: p.pos,
+		pos := p.pos
+		ident := &ast.Ident{
+			NamePos: pos,
 			Name:    p.lit,
 		}
+		c := p.openComments()
 		p.next()
+		expr = c.closeExpr(p, ident)
+
+		if p.tok != token.COLON && p.tok != token.ISA {
+			c = p.openComments()
+			p.errf(pos, "expected operand, found '%s'", ident.Name)
+			expr = &ast.BadExpr{From: pos, To: p.pos}
+			// Sync expression.
+			expr = p.parseBinaryExprTail(false, token.LowestPrec+1, expr)
+			expr = c.closeExpr(p, expr)
+			break
+		}
+		label = ident
 		ok = true
 
 	case token.LSS:
diff --git a/cue/parser/parser_test.go b/cue/parser/parser_test.go
index 4148d6e..e6f83fe 100644
--- a/cue/parser/parser_test.go
+++ b/cue/parser/parser_test.go
@@ -453,6 +453,12 @@
 			`[Y=string]: {name: Y}, ` +
 			`X1=[X2=<"d"]: {name: X2}, ` +
 			`Y1=foo: {Y2=bar: [Y1, Y2]}`,
+	}, {
+		desc: "error when keyword is used in expression",
+		in: `
+		foo: in & 2
+		`,
+		out: "foo: <*ast.BadExpr>&2\nexpected operand, found 'in'",
 	}}
 	for _, tc := range testCases {
 		t.Run(tc.desc, func(t *testing.T) {
@@ -461,10 +467,11 @@
 				mode = append(mode, ParseComments)
 			}
 			f, err := ParseFile("input", tc.in, mode...)
+			got := debugStr(f)
 			if err != nil {
-				t.Errorf("unexpected error: %v", err)
+				got += "\n" + err.Error()
 			}
-			if got := debugStr(f); got != tc.out {
+			if got != tc.out {
 				t.Errorf("\ngot  %q;\nwant %q", got, tc.out)
 			}
 		})
@@ -639,7 +646,8 @@
 func TestX(t *testing.T) {
 	t.Skip()
 
-	f, err := ParseFile("input", `a: b:: c?: <Name>: d: 1`)
+	f, err := ParseFile("input", `
+	`)
 	if err != nil {
 		t.Errorf("unexpected error: %v", err)
 	}