cue/parser: allow let clause in comprehension
Closes #284
Change-Id: Ie051eb90f98f8e3cdf85d2aa3177ca6355619c9b
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7303
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cue/ast/astutil/resolve.go b/cue/ast/astutil/resolve.go
index 9ddd8f7..00f33c9 100644
--- a/cue/ast/astutil/resolve.go
+++ b/cue/ast/astutil/resolve.go
@@ -413,20 +413,30 @@
func scopeClauses(s *scope, clauses []ast.Clause) *scope {
for _, c := range clauses {
- if f, ok := c.(*ast.ForClause); ok { // TODO(let): support let clause
- walk(s, f.Source)
- s = newScope(s.file, s, f, nil)
- if f.Key != nil {
- name, err := ast.ParseIdent(f.Key)
+ switch x := c.(type) {
+ case *ast.ForClause:
+ walk(s, x.Source)
+ s = newScope(s.file, s, x, nil)
+ if x.Key != nil {
+ name, err := ast.ParseIdent(x.Key)
if err == nil {
- s.insert(name, f.Key, f)
+ s.insert(name, x.Key, x)
}
}
- name, err := ast.ParseIdent(f.Value)
+ name, err := ast.ParseIdent(x.Value)
if err == nil {
- s.insert(name, f.Value, f)
+ s.insert(name, x.Value, x)
}
- } else {
+
+ case *ast.LetClause:
+ walk(s, x.Expr)
+ s = newScope(s.file, s, x, nil)
+ name, err := ast.ParseIdent(x.Ident)
+ if err == nil {
+ s.insert(name, x.Ident, x)
+ }
+
+ default:
walk(s, c)
}
}
diff --git a/cue/parser/parser.go b/cue/parser/parser.go
index 92143f1..b0b1431 100644
--- a/cue/parser/parser.go
+++ b/cue/parser/parser.go
@@ -1123,11 +1123,20 @@
Condition: p.parseRHS(),
}))
- // TODO:
- // case token.LET:
- // c := p.openComments()
- // p.expect(token.LET)
- // return nil, c
+ case token.LET:
+ c := p.openComments()
+ letPos := p.expect(token.LET)
+
+ ident := p.parseIdent()
+ assign := p.expect(token.BIND)
+ expr := p.parseRHS()
+
+ clauses = append(clauses, c.closeClause(p, &ast.LetClause{
+ Let: letPos,
+ Ident: ident,
+ Equal: assign,
+ Expr: expr,
+ }))
default:
return clauses, nil
diff --git a/cue/parser/parser_test.go b/cue/parser/parser_test.go
index 15b1646..a829192 100644
--- a/cue/parser/parser_test.go
+++ b/cue/parser/parser_test.go
@@ -280,6 +280,17 @@
}`,
`{y: {a: 1, b: 2}, a: {for k: v in y if v>2 {"\(k)": v}}}`,
}, {
+ "nested comprehensions",
+ `{
+ y: { a: 1, b: 2}
+ a: {
+ for k, v in y let x = v+2 if x > 2 {
+ "\(k)": v
+ }
+ }
+ }`,
+ `{y: {a: 1, b: 2}, a: {for k: v in y let x=v+2 if x>2 {"\(k)": v}}}`,
+ }, {
"let declaration",
`{
let X = 42
diff --git a/cue/testdata/eval/comprehensions.txtar b/cue/testdata/eval/comprehensions.txtar
index 09152da..a0da3af 100644
--- a/cue/testdata/eval/comprehensions.txtar
+++ b/cue/testdata/eval/comprehensions.txtar
@@ -13,6 +13,12 @@
l: 40
}
}
+
+c: {
+ for k, v in a let y = v+10 if y > 50 {
+ "\(k)": y
+ }
+}
-- out/eval --
(struct){
a: (struct){
@@ -26,6 +32,10 @@
z: (int){ 50 }
l: (int){ 40 }
}
+ c: (struct){
+ y: (int){ 110 }
+ z: (int){ 60 }
+ }
}
-- out/compile --
--- in.cue
@@ -48,4 +58,9 @@
l: 40
}
}
+ c: {
+ for k, v in 〈1;a〉 let y = (〈0;v〉 + 10) if (〈0;y〉 > 50) {
+ "\(〈2;k〉)": 〈1;y〉
+ }
+ }
}
diff --git a/internal/core/subsume/structural.go b/internal/core/subsume/structural.go
index bc581cb..7f1725d 100644
--- a/internal/core/subsume/structural.go
+++ b/internal/core/subsume/structural.go
@@ -275,6 +275,8 @@
c.yielders = append(c.yielders, x)
case *adt.LetClause:
+ c.yielders = append(c.yielders, x)
+
case *adt.ValueClause:
}
}