Skip to content

Commit a6fff27

Browse files
OmriSteinermvdan
authored andcommitted
internal/encoding/yaml: support alias to scalars as map keys
This makes the decoder follow aliases in YAML map keys. Before this commit the decoder would outright reject these keys as non-scalar keys. This commit adds support specifically for keys which are aliases to scalar values. YAML also permits non-scalar keys such as maps / sequences, but there's no equivalent for those in CUE, so we error out. Note that this used to work in CUE v0.8.2, before we transitioned from our own older fork of go-yaml to yaml.v3. The minor regression in behavior was unintentional and went unnoticed as we lacked test cases. Fixes #3821. Closes #3822 as merged as of commit b6c33cd. Signed-off-by: Omri Steiner <[email protected]> Change-Id: I53bfc09a40ab0a1bbfabde63db1690dbb9222584 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1213252 TryBot-Result: CUEcueckoo <[email protected]> Unity-Result: CUE porcuepine <[email protected]> Reviewed-by: Roger Peppe <[email protected]>
1 parent 52d9689 commit a6fff27

File tree

2 files changed

+28
-7
lines changed

2 files changed

+28
-7
lines changed

internal/encoding/yaml/decode.go

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -390,9 +390,6 @@ outer:
390390
}
391391
continue
392392
}
393-
if yk.Kind != yaml.ScalarNode {
394-
return d.posErrorf(yn, "invalid map key: %v", yk.ShortTag())
395-
}
396393

397394
field := &ast.Field{}
398395
label, err := d.label(yk)
@@ -450,17 +447,33 @@ func (d *decoder) merge(yn *yaml.Node, m *ast.StructLit, multiline bool) error {
450447
func (d *decoder) label(yn *yaml.Node) (ast.Label, error) {
451448
pos := d.pos(yn)
452449

453-
expr, err := d.scalar(yn)
450+
var expr ast.Expr
451+
var err error
452+
var value string
453+
switch yn.Kind {
454+
case yaml.ScalarNode:
455+
expr, err = d.scalar(yn)
456+
value = yn.Value
457+
case yaml.AliasNode:
458+
if yn.Alias.Kind != yaml.ScalarNode {
459+
return nil, d.posErrorf(yn, "invalid map key: %v", yn.Alias.ShortTag())
460+
}
461+
expr, err = d.alias(yn)
462+
value = yn.Alias.Value
463+
default:
464+
return nil, d.posErrorf(yn, "invalid map key: %v", yn.ShortTag())
465+
}
454466
if err != nil {
455467
return nil, err
456468
}
469+
457470
switch expr := expr.(type) {
458471
case *ast.BasicLit:
459472
if expr.Kind == token.STRING {
460-
if ast.IsValidIdent(yn.Value) && !internal.IsDefOrHidden(yn.Value) {
473+
if ast.IsValidIdent(value) && !internal.IsDefOrHidden(value) {
461474
return &ast.Ident{
462475
NamePos: pos,
463-
Name: yn.Value,
476+
Name: value,
464477
}, nil
465478
}
466479
ast.SetPos(expr, pos)
@@ -474,7 +487,7 @@ func (d *decoder) label(yn *yaml.Node) (ast.Label, error) {
474487
}, nil
475488

476489
default:
477-
return nil, d.posErrorf(yn, "invalid label "+yn.Value)
490+
return nil, d.posErrorf(yn, "invalid label "+value)
478491
}
479492
}
480493

internal/encoding/yaml/decode_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,12 @@ b: {
488488
"a: &a [1, 2]\nb: *a",
489489
"a: [1, 2]\nb: [1, 2]", // TODO: a: [1, 2], b: a
490490
},
491+
{
492+
`a: &a "b"
493+
*a : "c"`,
494+
`a: "b"
495+
b: "c"`,
496+
},
491497

492498
{
493499
"foo: ''",
@@ -921,6 +927,8 @@ var unmarshalErrorTests = []struct {
921927
{"a:\n- b: *,", "test.yaml:2: did not find expected alphabetic or numeric character"},
922928
{"a: *b\n", "test.yaml: unknown anchor 'b' referenced"},
923929
{"a: &a\n b: *a\n", `test.yaml:2: anchor "a" value contains itself`},
930+
{"a: &a { b: c }\n*a : foo", "test.yaml:2: invalid map key: !!map"},
931+
{"a: &a [b]\n*a : foo", "test.yaml:2: invalid map key: !!seq"},
924932
{"value: -", "test.yaml: block sequence entries are not allowed in this context"},
925933
{"a: !!binary ==", "test.yaml:1: !!binary value contains invalid base64 data"},
926934
{"{[.]}", `test.yaml:1: invalid map key: !!seq`},

0 commit comments

Comments
 (0)