cue/parser: allow full expressions for embeddings

This completes the implementation of the spec
allowing expressions for embeddings.

It also lifts the restriction in the spec.

Futher relaxing would be possible, but requires
lookahead.

Not that this is not unlike the Go ambiguity:
if foo == myStruct{} {
}
where parenthesis are required around the struct
literal.

Closes #106.

Change-Id: I629fc6e7a65612bbe754863ffd79a36b39a50dfe
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/3300
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/parser/parser.go b/cue/parser/parser.go
index 5cc3c69..c65a762 100644
--- a/cue/parser/parser.go
+++ b/cue/parser/parser.go
@@ -749,7 +749,7 @@
 
 		if !ok {
 			if expr == nil {
-				expr = p.parseExpr()
+				expr = p.parseRHS()
 			}
 			e := &ast.EmbedDecl{Expr: expr}
 			if p.atComma("struct literal", token.RBRACE) {
@@ -887,7 +887,7 @@
 	switch tok {
 	case token.IDENT, token.STRING, token.INTERPOLATION,
 		token.NULL, token.TRUE, token.FALSE:
-		expr = p.parsePrimaryExpr()
+		expr = p.parseExpr(true)
 
 		switch x := expr.(type) {
 		case *ast.BasicLit:
@@ -1002,7 +1002,7 @@
 				Colon:  colon,
 				Value:  value,
 				In:     p.expect(token.IN),
-				Source: p.parseExpr(),
+				Source: p.parseRHS(),
 			}))
 
 		case token.IF:
@@ -1017,7 +1017,7 @@
 
 			clauses = append(clauses, c.closeClause(p, &ast.IfClause{
 				If:        ifPos,
-				Condition: p.parseExpr(),
+				Condition: p.parseRHS(),
 			}))
 
 		// case token.LET:
@@ -1242,7 +1242,7 @@
 }
 
 // If lhs is set and the result is an identifier, it is not resolved.
-func (p *parser) parseBinaryExpr(prec1 int) ast.Expr {
+func (p *parser) parseBinaryExpr(lhs bool, prec1 int) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "BinaryExpr"))
 	}
@@ -1253,6 +1253,12 @@
 
 	for {
 		op, prec := p.tokPrec()
+		if lhs && op == token.LSS {
+			// Eagerly interpret this as a template label.
+			if _, ok := x.(ast.Label); ok {
+				return x
+			}
+		}
 		if prec < prec1 {
 			return x
 		}
@@ -1263,7 +1269,8 @@
 			X:     p.checkExpr(x),
 			OpPos: pos,
 			Op:    op,
-			Y:     p.checkExpr(p.parseBinaryExpr(prec + 1))})
+			// Treat nested expressions as RHS.
+			Y: p.checkExpr(p.parseBinaryExpr(false, prec+1))})
 	}
 }
 
@@ -1287,7 +1294,7 @@
 		p.expect(token.LPAREN)
 		cc.closeExpr(p, last)
 
-		exprs = append(exprs, p.parseExpr())
+		exprs = append(exprs, p.parseRHS())
 
 		cc = p.openComments()
 		if p.tok != token.RPAREN {
@@ -1308,16 +1315,16 @@
 }
 
 // Callers must check the result (using checkExpr), depending on context.
-func (p *parser) parseExpr() ast.Expr {
+func (p *parser) parseExpr(lhs bool) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "Expression"))
 	}
 
-	return p.parseBinaryExpr(token.LowestPrec + 1)
+	return p.parseBinaryExpr(lhs, token.LowestPrec+1)
 }
 
 func (p *parser) parseRHS() ast.Expr {
-	x := p.checkExpr(p.parseExpr())
+	x := p.checkExpr(p.parseExpr(false))
 	return x
 }
 
diff --git a/cue/parser/parser_test.go b/cue/parser/parser_test.go
index 6907865..6bf83f0 100644
--- a/cue/parser/parser_test.go
+++ b/cue/parser/parser_test.go
@@ -96,13 +96,15 @@
 		`{ V1, V2 }`,
 		`{V1, V2}`,
 	}, {
-		"selector embedding",
+		"expression embedding",
 		`Def :: {
 			a.b.c
+			a > b < c
+			-1<2
 
 			foo: 2
 		}`,
-		`Def :: {a.b.c, foo: 2}`,
+		`Def :: {a.b.c, a>b<c, -1<2, foo: 2}`,
 	}, {
 		"ellipsis in structs",
 		`Def :: {
diff --git a/doc/ref/spec.md b/doc/ref/spec.md
index d8849be..0f6744d 100644
--- a/doc/ref/spec.md
+++ b/doc/ref/spec.md
@@ -1295,8 +1295,8 @@
 A struct resulting from such a unification is closed if either of the involved
 structs were closed.
 
-Syntactically, embeddings may be any expression except that it only
-allows binary expressions with operators `&` or `|`.
+Syntactically, embeddings may be any expression, except that `<`
+is eagerly interpreted as a bind label.
 
 ```
 S1: {