YamlRenderer: allow all primitive scalar types as map keys (#879)

This commit is contained in:
Josh B
2025-01-13 16:22:52 -08:00
committed by GitHub
parent 267de3c789
commit 160e4a5636
6 changed files with 101 additions and 10 deletions
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -415,6 +415,16 @@ public abstract class AbstractRenderer implements VmValueVisitor {
.build(); .build();
} }
protected void cannotRenderNonScalarKey(Object key) {
assert enclosingValue != null;
var isMap = enclosingValue instanceof VmMap;
throw new VmExceptionBuilder()
.evalError(isMap ? "cannotRenderNonScalarMap" : "cannotRenderObjectWithNonScalarKey", name)
.withProgramValue(isMap ? "Map" : "Object", enclosingValue)
.withProgramValue("Key", key)
.build();
}
protected void increaseIndent() { protected void increaseIndent() {
currIndent.append(indent); currIndent.append(indent);
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -278,8 +278,24 @@ public final class YamlRendererNodes {
startNewLine(); startNewLine();
} }
if (key instanceof String string) { if (key instanceof String stringKey) {
emitter.emit(string, currIndent, true); emitter.emit(stringKey, currIndent, true);
builder.append(':');
return;
} else if (key instanceof Long longKey) {
emitter.emit(longKey);
builder.append(':');
return;
} else if (key instanceof Double doubleKey) {
emitter.emit(doubleKey);
builder.append(':');
return;
} else if (key instanceof Boolean booleanKey) {
emitter.emit(booleanKey);
builder.append(':');
return;
} else if (key instanceof VmNull) {
emitter.emitNull();
builder.append(':'); builder.append(':');
return; return;
} }
@@ -290,7 +306,7 @@ public final class YamlRendererNodes {
return; return;
} }
cannotRenderNonStringKey(key); cannotRenderNonScalarKey(key);
} }
@Override @Override
@@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved. * Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -310,7 +310,7 @@ public final class RendererNodes {
isDirective || key instanceof Long || key instanceof Boolean || key instanceof String; isDirective || key instanceof Long || key instanceof Boolean || key instanceof String;
if (!isValidKey) { if (!isValidKey) {
throw new VmExceptionBuilder() throw new VmExceptionBuilder()
.evalError("cannotRenderNonScalarMapKey") .evalError("cannotRenderProtobufMapKey")
.withProgramValue("Key", key) .withProgramValue("Key", key)
.build(); .build();
} }
@@ -583,7 +583,7 @@ public final class RendererNodes {
|| keyType instanceof StringTypeNode || keyType instanceof StringTypeNode
|| keyType instanceof BooleanTypeNode)) { || keyType instanceof BooleanTypeNode)) {
throw new VmExceptionBuilder() throw new VmExceptionBuilder()
.evalError("cannotRenderNonScalarMapKeyType") .evalError("cannotRenderProtobufMapKeyType")
.withSourceSection(type.getSourceSection()) .withSourceSection(type.getSourceSection())
.build(); .build();
} }
@@ -608,10 +608,16 @@ Cannot render map with non-string key as {0}.
cannotRenderObjectWithNonStringKey=\ cannotRenderObjectWithNonStringKey=\
Cannot render object with non-string key as {0}. Cannot render object with non-string key as {0}.
cannotRenderNonScalarMapKey=\ cannotRenderNonScalarMap=\
Cannot render map with non-scalar key as {0}.
cannotRenderObjectWithNonScalarKey=\
Cannot render object with non-scalar key as {0}.
cannotRenderProtobufMapKey=\
Cannot render map with a non-scalar, floating point or byte array key. Cannot render map with a non-scalar, floating point or byte array key.
cannotRenderNonScalarMapKeyType=\ cannotRenderProtobufMapKeyType=\
Cannot render map with a non-scalar, floating point or byte array key type. Cannot render map with a non-scalar, floating point or byte array key type.
cannotRenderObjectWithElementsAndOtherMembers=\ cannotRenderObjectWithElementsAndOtherMembers=\
@@ -0,0 +1,33 @@
// Test that non-String scalars can be rendered as YAML map keys.
mappingInt = new Mapping {
[5] = "abc"
[10] = "def"
[20] = "ghi"
}
mapInt = mappingInt.toMap()
mappingFloat = new Mapping {
[5.0] = "abc"
[10.5] = "def"
[20.999999990] = "ghi"
}
mapFloat = mappingFloat.toMap()
mappingBool = new Mapping {
[true] = "abc"
[false] = "def"
}
mapBool = mappingBool.toMap()
mappingNull = new Mapping {
[null] = "abc"
}
mapNull = mappingNull.toMap()
output {
renderer = new YamlRenderer {}
}
@@ -0,0 +1,26 @@
mappingInt:
5: abc
10: def
20: ghi
mapInt:
5: abc
10: def
20: ghi
mappingFloat:
5.0: abc
10.5: def
20.99999999: ghi
mapFloat:
5.0: abc
10.5: def
20.99999999: ghi
mappingBool:
true: abc
false: def
mapBool:
true: abc
false: def
mappingNull:
null: abc
mapNull:
null: abc