Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions pkl-core/src/main/java/org/pkl/core/ast/member/ClassProperty.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@ public ClassProperty(
this.initializer = initializer;
}

public List<VmTyped> getAllAnnotations() {
var annotations = new ArrayList<VmTyped>();
for (var klazz = getDeclaringClass(); klazz != null; klazz = klazz.getSuperclass()) {
var p = klazz.getDeclaredProperty(getName());
if (p != null) {
annotations.addAll(p.getAnnotations());
}
}
return annotations;
}

public @Nullable PropertyTypeNode getTypeNode() {
return typeNode;
}
Expand All @@ -70,11 +81,9 @@ public String getCallSignature() {

public static final class Mirror {
private final ClassProperty prop;
private final VmClass clazz;

Mirror(ClassProperty prop, VmClass clazz) {
Mirror(ClassProperty prop) {
this.prop = prop;
this.clazz = clazz;
}

public ClassProperty getProperty() {
Expand All @@ -83,7 +92,7 @@ public ClassProperty getProperty() {

public List<VmTyped> getAllAnnotations() {
var annotations = new ArrayList<VmTyped>();
for (var klazz = clazz; klazz != null; klazz = klazz.getSuperclass()) {
for (var klazz = prop.getDeclaringClass(); klazz != null; klazz = klazz.getSuperclass()) {
var p = klazz.getDeclaredProperty(prop.getName());
if (p != null) {
annotations.addAll(p.getAnnotations());
Expand All @@ -94,7 +103,7 @@ public List<VmTyped> getAllAnnotations() {

public VmSet getAllModifierMirrors() {
var mods = 0;
for (var klazz = clazz; klazz != null; klazz = klazz.getSuperclass()) {
for (var klazz = prop.getDeclaringClass(); klazz != null; klazz = klazz.getSuperclass()) {
var parent = klazz.getDeclaredProperty(prop.getName());
if (parent != null) {
mods |= parent.getModifiers();
Expand All @@ -104,8 +113,8 @@ public VmSet getAllModifierMirrors() {
}
}

public VmTyped getMirror(VmClass clazz) {
return MirrorFactories.propertyFactory.create(new Mirror(this, clazz));
public VmTyped getMirror() {
return MirrorFactories.propertyFactory.create(new Mirror(this));
}

public VmSet getModifierMirrors() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public final class Identifier implements Comparable<Identifier> {
public static final Identifier ROOT_ELEMENT_NAME = get("rootElementName");
public static final Identifier ROOT_ELEMENT_ATTRIBUTES = get("rootElementAttributes");
public static final Identifier CONVERTERS = get("converters");
public static final Identifier ANNOTATION_CONVERTERS = get("annotationConverters");
public static final Identifier USE_MAPPING = get("useMapping");

// members of pkl.base#RegexMatch
Expand Down
4 changes: 2 additions & 2 deletions pkl-core/src/main/java/org/pkl/core/runtime/TestRunner.java
Original file line number Diff line number Diff line change
@@ -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");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -42,7 +42,7 @@

/** Runs test results examples and facts. */
public final class TestRunner {
private static final PklConverter converter = new PklConverter(VmMapping.empty());
private static final PklConverter converter = PklConverter.NOOP;
private final BufferedLogger logger;
private final StackFrameTransformer stackFrameTransformer;
private final boolean overwrite;
Expand Down
4 changes: 2 additions & 2 deletions pkl-core/src/main/java/org/pkl/core/runtime/VmClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -575,7 +575,7 @@ public VmMap getPropertyMirrors() {
var builder = VmMap.builder();
for (var property : declaredProperties.getValues()) {
if (property.isLocal()) continue;
builder.add(property.getName().toString(), property.getMirror(this));
builder.add(property.getName().toString(), property.getMirror());
}
return builder.build();
}
Expand All @@ -584,7 +584,7 @@ public VmMap getAllPropertyMirrors() {
var builder = VmMap.builder();
for (var property : getAllProperties().getValues()) {
if (property.isLocal()) continue;
builder.add(property.getName().toString(), property.getMirror(this));
builder.add(property.getName().toString(), property.getMirror());
}
return builder.build();
}
Expand Down
6 changes: 6 additions & 0 deletions pkl-core/src/main/java/org/pkl/core/runtime/VmFunction.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ public Object apply(Object arg1, Object arg2) {
return getCallTarget().call(thisValue, this, arg1, arg2);
}

// if call site is a node, use ApplyVmFunction3Node.execute() or DirectCallNode.call() instead of
// this method
public Object apply(Object arg1, Object arg2, Object arg3) {
return getCallTarget().call(thisValue, this, arg1, arg2, arg3);
}

public VmFunction copy(
int newParamCount, @Nullable PklRootNode newRootNode, @Nullable Object newExtraStorage) {
return new VmFunction(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public VmPklBinaryEncoder(MessageBufferPacker packer, PklConverter converter) {
}

public VmPklBinaryEncoder(MessageBufferPacker packer) {
this(packer, new PklConverter(VmMapping.empty()));
this(packer, PklConverter.NOOP);
}

private void packCode(PklBinaryCode code) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
*/
package org.pkl.core.runtime;

import org.pkl.core.ast.member.ClassProperty;
import org.pkl.core.util.Pair;

public interface VmValueConverter<T> {
Object WILDCARD_PROPERTY =
new Object() {
Expand Down Expand Up @@ -82,6 +85,8 @@ public String toString() {

T convertFunction(VmFunction value, Iterable<Object> path);

Pair<Identifier, T> convertProperty(ClassProperty property, Object value, Iterable<Object> path);

default T convert(Object value, Iterable<Object> path) {
if (value instanceof VmValue vmValue) {
return vmValue.accept(this, path);
Expand Down
21 changes: 18 additions & 3 deletions pkl-core/src/main/java/org/pkl/core/stdlib/AbstractRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import org.pkl.core.ast.member.ClassProperty;
import org.pkl.core.runtime.BaseModule;
import org.pkl.core.runtime.Identifier;
import org.pkl.core.runtime.VmClass;
Expand Down Expand Up @@ -195,7 +196,12 @@ public void visitTyped(VmTyped value) {
(memberKey, member, memberValue) -> {
if (member.isClass() || member.isTypeAlias()) return true;
assert member.isProp();
doVisitProperty((Identifier) memberKey, memberValue, member.getSourceSection(), isFirst);
doVisitProperty(
(Identifier) memberKey,
memberValue,
value.getVmClass().getProperty((Identifier) memberKey),
member.getSourceSection(),
isFirst);
return true;
});

Expand All @@ -218,7 +224,7 @@ public final void visitDynamic(VmDynamic value) {
var sourceSection = member.getSourceSection();
if (member.isProp()) {
if (!canRenderPropertyOrEntry) cannotRenderObjectWithElementsAndOtherMembers(value);
doVisitProperty((Identifier) memberKey, memberValue, sourceSection, isFirst);
doVisitProperty((Identifier) memberKey, memberValue, null, sourceSection, isFirst);
} else if (member.isEntry()) {
if (!canRenderPropertyOrEntry) cannotRenderObjectWithElementsAndOtherMembers(value);
doVisitEntry(memberKey, memberValue, sourceSection, isFirst);
Expand Down Expand Up @@ -327,10 +333,19 @@ public final void visitMap(VmMap value) {
}

private void doVisitProperty(
Identifier name, Object value, SourceSection sourceSection, MutableBoolean isFirst) {
Identifier name,
Object value,
@Nullable ClassProperty property,
SourceSection sourceSection,
MutableBoolean isFirst) {
var prevSourceSection = currSourceSection;
currSourceSection = sourceSection;
currPath.push(name);
if (property != null) {
var propVal = converter.convertProperty(property, value, currPath);
name = propVal.getFirst();
value = propVal.getSecond();
}
var convertedValue = converter.convert(value, currPath);
if (!(skipNullProperties && convertedValue instanceof VmNull)) {
visitProperty(name, convertedValue, isFirst.getAndSetFalse());
Expand Down
58 changes: 56 additions & 2 deletions pkl-core/src/main/java/org/pkl/core/stdlib/PklConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@
package org.pkl.core.stdlib;

import java.util.*;
import org.pkl.core.ast.member.ClassProperty;
import org.pkl.core.runtime.*;
import org.pkl.core.util.Nullable;
import org.pkl.core.util.Pair;

public final class PklConverter implements VmValueConverter<Object> {
private final Map<VmClass, VmFunction> typeConverters;
private final Map<VmClass, VmFunction> annotationConverters;
private final Pair<Object[], VmFunction>[] pathConverters;

private final @Nullable VmFunction stringConverter;
Expand All @@ -44,11 +46,13 @@ public final class PklConverter implements VmValueConverter<Object> {
private final @Nullable VmFunction classConverter;
private final @Nullable VmFunction typeAliasConverter;

public PklConverter(VmMapping converters) {
public PklConverter(VmMapping converters, VmMapping annotationConverters) {
// As of 0.18, `converters` is forced by the mapping type check,
// but let's not rely on this implementation detail.
converters.force(false, false);
annotationConverters.force(false, false);
typeConverters = createTypeConverters(converters);
this.annotationConverters = createAnnotationConverters(annotationConverters);
pathConverters = createPathConverters(converters);

stringConverter = typeConverters.get(BaseModule.getStringClass());
Expand All @@ -72,6 +76,20 @@ public PklConverter(VmMapping converters) {
typeAliasConverter = typeConverters.get(BaseModule.getTypeAliasClass());
}

public static final PklConverter NOOP = new PklConverter(VmMapping.empty(), VmMapping.empty());

public static PklConverter fromRenderer(VmTyped renderer) {
var converters = (VmMapping) VmUtils.readMember(renderer, Identifier.CONVERTERS);
var annotationConverters =
(VmMapping) VmUtils.readMember(renderer, Identifier.ANNOTATION_CONVERTERS);
return new PklConverter(converters, annotationConverters);
}

public static PklConverter fromParser(VmTyped parser) {
var converters = (VmMapping) VmUtils.readMember(parser, Identifier.CONVERTERS);
return new PklConverter(converters, VmMapping.empty()); // no annotation converters in parsers
}

@Override
public Object convertString(String value, Iterable<Object> path) {
return doConvert(value, path, stringConverter);
Expand Down Expand Up @@ -177,6 +195,23 @@ public Object convertNull(VmNull value, Iterable<Object> path) {
return doConvert(value, path, nullConverter);
}

@Override
public Pair<Identifier, Object> convertProperty(
ClassProperty property, Object value, Iterable<Object> path) {
var name = property.getName();
for (var annotation : property.getAllAnnotations()) {
var converter = findAnnotationConverter(annotation.getVmClass());
if (converter == null) {
continue;
}
var nameVal = (VmPair) converter.apply(name.toString(), annotation, value);
name = Identifier.get((String) nameVal.getFirst());
value = nameVal.getSecond();
}

return Pair.of(name, value);
}

private Map<VmClass, VmFunction> createTypeConverters(VmMapping converters) {
var result = new HashMap<VmClass, VmFunction>();
converters.iterateMemberValues(
Expand All @@ -190,6 +225,17 @@ private Map<VmClass, VmFunction> createTypeConverters(VmMapping converters) {
return result;
}

private Map<VmClass, VmFunction> createAnnotationConverters(VmMapping annotationConverters) {
var result = new HashMap<VmClass, VmFunction>();
annotationConverters.iterateMemberValues(
(key, member, value) -> {
assert value != null; // forced in ctor
result.put((VmClass) key, (VmFunction) value);
return true;
});
return result;
}

@SuppressWarnings("unchecked")
private Pair<Object[], VmFunction>[] createPathConverters(VmMapping converters) {
var result = new ArrayList<Pair<Object[], VmFunction>>();
Expand Down Expand Up @@ -221,8 +267,16 @@ private Pair<Object[], VmFunction>[] createPathConverters(VmMapping converters)
* method will return the most specific converter for a type.
*/
private @Nullable VmFunction findTypeConverter(VmClass clazz) {
return findConverterByType(typeConverters, clazz);
}

private @Nullable VmFunction findAnnotationConverter(VmClass clazz) {
return findConverterByType(annotationConverters, clazz);
}

private @Nullable VmFunction findConverterByType(Map<VmClass, VmFunction> bag, VmClass clazz) {
for (var current = clazz; current != null; current = current.getSuperclass()) {
var found = typeConverters.get(current);
var found = bag.get(current);
if (found != null) return found;
}
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ protected String eval(VmTyped self, Object value) {
private static JsonRenderer createRenderer(VmTyped self, StringBuilder builder) {
var indent = (String) VmUtils.readMember(self, Identifier.INDENT);
var omitNullProperties = (boolean) VmUtils.readMember(self, Identifier.OMIT_NULL_PROPERTIES);
var converters = (VmMapping) VmUtils.readMember(self, Identifier.CONVERTERS);
var converter = new PklConverter(converters);
return new JsonRenderer(builder, indent, converter, omitNullProperties);
return new JsonRenderer(builder, indent, PklConverter.fromRenderer(self), omitNullProperties);
}

private static final class JsonRenderer extends AbstractStringRenderer {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,7 @@ protected String eval(VmTyped self, Object value) {

private static PListRenderer createRenderer(VmTyped self, StringBuilder builder) {
var indent = (String) VmUtils.readMember(self, Identifier.INDENT);
var converters = (VmMapping) VmUtils.readMember(self, Identifier.CONVERTERS);
var converter = new PklConverter(converters);
return new PListRenderer(builder, indent, converter);
return new PListRenderer(builder, indent, PklConverter.fromRenderer(self));
}

// keep in sync with org.pkl.core.PListRenderer
Expand Down
Original file line number Diff line number Diff line change
@@ -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");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -46,12 +46,14 @@ protected String eval(VmTyped self, Object value) {

private static PcfRenderer createRenderer(VmTyped self, StringBuilder builder) {
var indent = (String) VmUtils.readMember(self, Identifier.INDENT);
var converters = (VmMapping) VmUtils.readMember(self, Identifier.CONVERTERS);
var omitNullProperties = (boolean) VmUtils.readMember(self, Identifier.OMIT_NULL_PROPERTIES);
var useCustomStringDelimiters =
(boolean) VmUtils.readMember(self, Identifier.USE_CUSTOM_STRING_DELIMITERS);
var converter = new PklConverter(converters);
return new PcfRenderer(
builder, indent, converter, omitNullProperties, useCustomStringDelimiters);
builder,
indent,
PklConverter.fromRenderer(self),
omitNullProperties,
useCustomStringDelimiters);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,8 @@ protected String eval(VmTyped self, Object value) {
private static PropertiesRenderer createRenderer(VmTyped self, StringBuilder builder) {
var omitNullProperties = (boolean) VmUtils.readMember(self, Identifier.OMIT_NULL_PROPERTIES);
var restrictCharset = (boolean) VmUtils.readMember(self, Identifier.RESTRICT_CHARSET);
var converters = (VmMapping) VmUtils.readMember(self, Identifier.CONVERTERS);
var PklConverter = new PklConverter(converters);
return new PropertiesRenderer(builder, omitNullProperties, restrictCharset, PklConverter);
return new PropertiesRenderer(
builder, omitNullProperties, restrictCharset, PklConverter.fromRenderer(self));
}

private static final class PropertiesRenderer extends AbstractStringRenderer {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,13 @@ private static YamlRenderer createRenderer(VmTyped self, StringBuilder builder)
var indentWidth = ((Long) VmUtils.readMember(self, Identifier.INDENT_WIDTH)).intValue();
var omitNullProperties = (boolean) VmUtils.readMember(self, Identifier.OMIT_NULL_PROPERTIES);
var isStream = (boolean) VmUtils.readMember(self, Identifier.IS_STREAM);
var converters = (VmMapping) VmUtils.readMember(self, Identifier.CONVERTERS);
var converter = new PklConverter(converters);
return new YamlRenderer(
builder, " ".repeat(indentWidth), converter, omitNullProperties, mode, isStream);
builder,
" ".repeat(indentWidth),
PklConverter.fromRenderer(self),
omitNullProperties,
mode,
isStream);
}

private static final class YamlRenderer extends AbstractStringRenderer {
Expand Down
Loading