From 2506450b6e054cf0f07b7c03c79a180856f4f6a9 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Sun, 18 Jun 2017 08:45:45 -0700 Subject: [PATCH] zclsyntax: correct evaluation of the for expression "group" mode This further alters the object-construction mode so that rather than producing a flat object it instead produces an object of tuples. All items that produce the same key are grouped together under the same key in the result, allowing projections that flip the orientation of a key/value sequence where the new keys are not necessarily unique. --- zcl/zclsyntax/expression.go | 23 +++++++++++++++++++++-- zcl/zclsyntax/expression_test.go | 20 ++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/zcl/zclsyntax/expression.go b/zcl/zclsyntax/expression.go index 65a038b..bad6fbe 100644 --- a/zcl/zclsyntax/expression.go +++ b/zcl/zclsyntax/expression.go @@ -697,7 +697,13 @@ func (e *ForExpr) Value(ctx *zcl.EvalContext) (cty.Value, zcl.Diagnostics) { if e.KeyExpr != nil { // Producing an object - vals := map[string]cty.Value{} + var vals map[string]cty.Value + var groupVals map[string][]cty.Value + if e.Group { + groupVals = map[string][]cty.Value{} + } else { + vals = map[string]cty.Value{} + } it := collVal.ElementIterator() @@ -791,13 +797,26 @@ func (e *ForExpr) Value(ctx *zcl.EvalContext) (cty.Value, zcl.Diagnostics) { val, valDiags := e.ValExpr.Value(childCtx) diags = append(diags, valDiags...) - vals[key.AsString()] = val + + if e.Group { + k := key.AsString() + groupVals[k] = append(groupVals[k], val) + } else { + vals[key.AsString()] = val + } } if !known { return cty.DynamicVal, diags } + if e.Group { + vals = map[string]cty.Value{} + for k, gvs := range groupVals { + vals[k] = cty.TupleVal(gvs) + } + } + return cty.ObjectVal(vals), diags } else { diff --git a/zcl/zclsyntax/expression_test.go b/zcl/zclsyntax/expression_test.go index b3b59cb..73a4149 100644 --- a/zcl/zclsyntax/expression_test.go +++ b/zcl/zclsyntax/expression_test.go @@ -509,6 +509,26 @@ upper( }), 1, // must have a key expr when producing a map }, + { + `{for i, v in ["a", "b", "c", "b", "d"]: v => i...}`, + nil, + cty.ObjectVal(map[string]cty.Value{ + "a": cty.TupleVal([]cty.Value{ + cty.NumberIntVal(0), + }), + "b": cty.TupleVal([]cty.Value{ + cty.NumberIntVal(1), + cty.NumberIntVal(3), + }), + "c": cty.TupleVal([]cty.Value{ + cty.NumberIntVal(2), + }), + "d": cty.TupleVal([]cty.Value{ + cty.NumberIntVal(4), + }), + }), + 0, + }, { `[for v in {hello: "world"}: v...]`, nil,