Skip to content

Commit 2b4f066

Browse files
committed
Add implicit property name converter annotations for built-in renderers
1 parent 9435666 commit 2b4f066

28 files changed

+421
-27
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.pkl.core.runtime;
17+
18+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
19+
import java.net.URI;
20+
21+
public final class JsonModule extends StdLibModule {
22+
private static final VmTyped instance = VmUtils.createEmptyModule();
23+
24+
static {
25+
loadModule(URI.create("pkl:json"), instance);
26+
}
27+
28+
public static VmTyped getModule() {
29+
return instance;
30+
}
31+
32+
public static VmClass getPropertyClass() {
33+
return PropertyClass.instance;
34+
}
35+
36+
private static final class PropertyClass {
37+
static final VmClass instance = loadClass("Property");
38+
}
39+
40+
@TruffleBoundary
41+
private static VmClass loadClass(String className) {
42+
var theModule = getModule();
43+
return (VmClass) VmUtils.readMember(theModule, Identifier.get(className));
44+
}
45+
}

pkl-core/src/main/java/org/pkl/core/runtime/JsonnetModule.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
2+
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -29,6 +29,10 @@ public static VmTyped getModule() {
2929
return instance;
3030
}
3131

32+
public static VmClass getPropertyClass() {
33+
return PropertyClass.instance;
34+
}
35+
3236
public static VmClass getImportStrClass() {
3337
return ImportStrClass.instance;
3438
}
@@ -37,6 +41,10 @@ public static VmClass getExtVarClass() {
3741
return ExtVarClass.instance;
3842
}
3943

44+
private static final class PropertyClass {
45+
static final VmClass instance = loadClass("Property");
46+
}
47+
4048
private static final class ImportStrClass {
4149
static final VmClass instance = loadClass("ImportStr");
4250
}

pkl-core/src/main/java/org/pkl/core/runtime/ModuleCache.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,20 @@ public synchronized VmTyped getOrLoad(
9292
return BaseModule.getModule();
9393
case "Benchmark":
9494
return BenchmarkModule.getModule();
95-
case "pklbinary":
96-
return PklBinaryModule.getModule();
95+
case "json":
96+
return JsonModule.getModule();
9797
case "jsonnet":
9898
return JsonnetModule.getModule();
9999
case "math":
100100
return MathModule.getModule();
101+
case "pklbinary":
102+
return PklBinaryModule.getModule();
101103
case "platform":
102104
return PlatformModule.getModule();
103105
case "project":
104106
return ProjectModule.getModule();
107+
case "protobuf":
108+
return ProtobufModule.getModule();
105109
case "reflect":
106110
return ReflectModule.getModule();
107111
case "release":
@@ -115,6 +119,8 @@ public synchronized VmTyped getOrLoad(
115119
return TestModule.getModule();
116120
case "xml":
117121
return XmlModule.getModule();
122+
case "yaml":
123+
return YamlModule.getModule();
118124
default:
119125
if (!STDLIB_MODULE_URIS.contains(moduleKey.getUri())) {
120126
var stdlibModules = String.join("\n", Release.current().standardLibrary().modules());
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.pkl.core.runtime;
17+
18+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
19+
import java.net.URI;
20+
21+
public final class ProtobufModule extends StdLibModule {
22+
private static final VmTyped instance = VmUtils.createEmptyModule();
23+
24+
static {
25+
loadModule(URI.create("pkl:protobuf"), instance);
26+
}
27+
28+
public static VmTyped getModule() {
29+
return instance;
30+
}
31+
32+
public static VmClass getPropertyClass() {
33+
return PropertyClass.instance;
34+
}
35+
36+
private static final class PropertyClass {
37+
static final VmClass instance = loadClass("Property");
38+
}
39+
40+
@TruffleBoundary
41+
private static VmClass loadClass(String className) {
42+
var theModule = getModule();
43+
return (VmClass) VmUtils.readMember(theModule, Identifier.get(className));
44+
}
45+
}

pkl-core/src/main/java/org/pkl/core/runtime/XmlModule.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
2+
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -29,6 +29,10 @@ public static VmTyped getModule() {
2929
return instance;
3030
}
3131

32+
public static VmClass getPropertyClass() {
33+
return PropertyClass.instance;
34+
}
35+
3236
public static VmClass getInlineClass() {
3337
return InlineClass.instance;
3438
}
@@ -41,6 +45,10 @@ public static VmClass getCDataClass() {
4145
return CDataClass.instance;
4246
}
4347

48+
private static final class PropertyClass {
49+
static final VmClass instance = loadClass("Property");
50+
}
51+
4452
private static final class InlineClass {
4553
static final VmClass instance = loadClass("Inline");
4654
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.pkl.core.runtime;
17+
18+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
19+
import java.net.URI;
20+
21+
public final class YamlModule extends StdLibModule {
22+
private static final VmTyped instance = VmUtils.createEmptyModule();
23+
24+
static {
25+
loadModule(URI.create("pkl:yaml"), instance);
26+
}
27+
28+
public static VmTyped getModule() {
29+
return instance;
30+
}
31+
32+
public static VmClass getPropertyClass() {
33+
return PropertyClass.instance;
34+
}
35+
36+
private static final class PropertyClass {
37+
static final VmClass instance = loadClass("Property");
38+
}
39+
40+
@TruffleBoundary
41+
private static VmClass loadClass(String className) {
42+
var theModule = getModule();
43+
return (VmClass) VmUtils.readMember(theModule, Identifier.get(className));
44+
}
45+
}

pkl-core/src/main/java/org/pkl/core/stdlib/PklConverter.java

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@
2222
import org.pkl.core.util.Pair;
2323

2424
public final class PklConverter implements VmValueConverter<Object> {
25+
private interface AnnotationConverter {
26+
VmPair convert(String property, VmTyped annotation, Object value);
27+
}
28+
2529
private final Map<VmClass, VmFunction> typeConverters;
26-
private final Map<VmClass, VmFunction> annotationConverters;
30+
private final Map<VmClass, AnnotationConverter> annotationConverters;
2731
private final Pair<Object[], VmFunction>[] pathConverters;
2832

2933
private final @Nullable VmFunction stringConverter;
@@ -46,13 +50,17 @@ public final class PklConverter implements VmValueConverter<Object> {
4650
private final @Nullable VmFunction classConverter;
4751
private final @Nullable VmFunction typeAliasConverter;
4852

49-
public PklConverter(VmMapping converters, VmMapping annotationConverters) {
53+
private PklConverter(
54+
VmMapping converters,
55+
VmMapping annotationConverters,
56+
@Nullable VmClass propertyNameAnnotation) {
5057
// As of 0.18, `converters` is forced by the mapping type check,
5158
// but let's not rely on this implementation detail.
5259
converters.force(false, false);
5360
annotationConverters.force(false, false);
5461
typeConverters = createTypeConverters(converters);
55-
this.annotationConverters = createAnnotationConverters(annotationConverters);
62+
this.annotationConverters =
63+
createAnnotationConverters(annotationConverters, propertyNameAnnotation);
5664
pathConverters = createPathConverters(converters);
5765

5866
stringConverter = typeConverters.get(BaseModule.getStringClass());
@@ -76,18 +84,27 @@ public PklConverter(VmMapping converters, VmMapping annotationConverters) {
7684
typeAliasConverter = typeConverters.get(BaseModule.getTypeAliasClass());
7785
}
7886

79-
public static final PklConverter NOOP = new PklConverter(VmMapping.empty(), VmMapping.empty());
87+
public static final PklConverter NOOP =
88+
new PklConverter(VmMapping.empty(), VmMapping.empty(), null);
89+
90+
public static PklConverter fromRenderer(VmTyped renderer, VmClass propertyNameAnnotation) {
91+
var converters = (VmMapping) VmUtils.readMember(renderer, Identifier.CONVERTERS);
92+
var annotationConverters =
93+
(VmMapping) VmUtils.readMember(renderer, Identifier.ANNOTATION_CONVERTERS);
94+
return new PklConverter(converters, annotationConverters, propertyNameAnnotation);
95+
}
8096

8197
public static PklConverter fromRenderer(VmTyped renderer) {
8298
var converters = (VmMapping) VmUtils.readMember(renderer, Identifier.CONVERTERS);
8399
var annotationConverters =
84100
(VmMapping) VmUtils.readMember(renderer, Identifier.ANNOTATION_CONVERTERS);
85-
return new PklConverter(converters, annotationConverters);
101+
return new PklConverter(converters, annotationConverters, null);
86102
}
87103

88104
public static PklConverter fromParser(VmTyped parser) {
89105
var converters = (VmMapping) VmUtils.readMember(parser, Identifier.CONVERTERS);
90-
return new PklConverter(converters, VmMapping.empty()); // no annotation converters in parsers
106+
return new PklConverter(
107+
converters, VmMapping.empty(), null); // no annotation converters in parsers
91108
}
92109

93110
@Override
@@ -204,7 +221,7 @@ public Pair<Identifier, Object> convertProperty(
204221
if (converter == null) {
205222
continue;
206223
}
207-
var nameVal = (VmPair) converter.apply(name.toString(), annotation, value);
224+
var nameVal = converter.convert(name.toString(), annotation, value);
208225
name = Identifier.get((String) nameVal.getFirst());
209226
value = nameVal.getSecond();
210227
}
@@ -225,14 +242,26 @@ private Map<VmClass, VmFunction> createTypeConverters(VmMapping converters) {
225242
return result;
226243
}
227244

228-
private Map<VmClass, VmFunction> createAnnotationConverters(VmMapping annotationConverters) {
229-
var result = new HashMap<VmClass, VmFunction>();
245+
private Map<VmClass, AnnotationConverter> createAnnotationConverters(
246+
VmMapping annotationConverters, @Nullable VmClass propertyNameAnnotation) {
247+
var result = new HashMap<VmClass, AnnotationConverter>();
230248
annotationConverters.iterateMemberValues(
231249
(key, member, value) -> {
232250
assert value != null; // forced in ctor
233-
result.put((VmClass) key, (VmFunction) value);
251+
result.put(
252+
(VmClass) key,
253+
(name, annotation, val) ->
254+
(VmPair) ((VmFunction) value).apply(name, annotation, val));
234255
return true;
235256
});
257+
258+
if (propertyNameAnnotation != null && !result.containsKey(propertyNameAnnotation)) {
259+
result.put(
260+
propertyNameAnnotation,
261+
(name, annotation, val) ->
262+
new VmPair(VmUtils.readMember(annotation, Identifier.NAME), val));
263+
}
264+
236265
return result;
237266
}
238267

@@ -270,11 +299,11 @@ private Pair<Object[], VmFunction>[] createPathConverters(VmMapping converters)
270299
return findConverterByType(typeConverters, clazz);
271300
}
272301

273-
private @Nullable VmFunction findAnnotationConverter(VmClass clazz) {
302+
private @Nullable AnnotationConverter findAnnotationConverter(VmClass clazz) {
274303
return findConverterByType(annotationConverters, clazz);
275304
}
276305

277-
private @Nullable VmFunction findConverterByType(Map<VmClass, VmFunction> bag, VmClass clazz) {
306+
private <T> @Nullable T findConverterByType(Map<VmClass, T> bag, VmClass clazz) {
278307
for (var current = clazz; current != null; current = current.getSuperclass()) {
279308
var found = bag.get(current);
280309
if (found != null) return found;

pkl-core/src/main/java/org/pkl/core/stdlib/base/JsonRendererNodes.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,11 @@ protected String eval(VmTyped self, Object value) {
5252
private static JsonRenderer createRenderer(VmTyped self, StringBuilder builder) {
5353
var indent = (String) VmUtils.readMember(self, Identifier.INDENT);
5454
var omitNullProperties = (boolean) VmUtils.readMember(self, Identifier.OMIT_NULL_PROPERTIES);
55-
return new JsonRenderer(builder, indent, PklConverter.fromRenderer(self), omitNullProperties);
55+
return new JsonRenderer(
56+
builder,
57+
indent,
58+
PklConverter.fromRenderer(self, JsonModule.getPropertyClass()),
59+
omitNullProperties);
5660
}
5761

5862
private static final class JsonRenderer extends AbstractStringRenderer {

pkl-core/src/main/java/org/pkl/core/stdlib/base/YamlRendererNodes.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.pkl.core.runtime.VmSet;
3636
import org.pkl.core.runtime.VmTyped;
3737
import org.pkl.core.runtime.VmUtils;
38+
import org.pkl.core.runtime.YamlModule;
3839
import org.pkl.core.stdlib.AbstractStringRenderer;
3940
import org.pkl.core.stdlib.ExternalMethod1Node;
4041
import org.pkl.core.stdlib.PklConverter;
@@ -72,7 +73,7 @@ private static YamlRenderer createRenderer(VmTyped self, StringBuilder builder)
7273
return new YamlRenderer(
7374
builder,
7475
" ".repeat(indentWidth),
75-
PklConverter.fromRenderer(self),
76+
PklConverter.fromRenderer(self, YamlModule.getPropertyClass()),
7677
omitNullProperties,
7778
mode,
7879
isStream);

pkl-core/src/main/java/org/pkl/core/stdlib/jsonnet/RendererNodes.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ private static Renderer createRenderer(VmTyped self, StringBuilder builder) {
4747
var indent = (String) VmNull.unwrap(VmUtils.readMember(self, Identifier.INDENT));
4848
if (indent == null) indent = "";
4949
var omitNullProperties = (boolean) VmUtils.readMember(self, Identifier.OMIT_NULL_PROPERTIES);
50-
return new Renderer(builder, indent, omitNullProperties, PklConverter.fromRenderer(self));
50+
return new Renderer(
51+
builder,
52+
indent,
53+
omitNullProperties,
54+
PklConverter.fromRenderer(self, JsonnetModule.getPropertyClass()));
5155
}
5256

5357
public abstract static class renderDocument extends ExternalMethod1Node {

0 commit comments

Comments
 (0)