Implement Pkl binary renderer and parser (#1203)

Implements a binary renderer for Pkl values, which is a lossless capturing of Pkl data.

This follows the pkl binary format that is already used with `pkl server` calls, and is
made available as a Java API and also an in-language API.

Also, introduces a binary parser into the corresponding `PObject` types in Java.
This commit is contained in:
Jen Basch
2025-10-20 09:10:22 -07:00
committed by GitHub
parent c602dbb84c
commit 6c036bf82a
298 changed files with 4236 additions and 2581 deletions

View File

@@ -172,6 +172,15 @@ public interface Evaluator extends AutoCloseable {
*/
Object evaluateExpression(ModuleSource moduleSource, String expression);
/**
* Evaluates the Pkl expression represented as {@code expression}, returning a byte array of the
* <code>pkl-binary</code>-encoded representation of the result.
*
* @throws PklException if an error occurs during evaluation
* @throws IllegalStateException if this evaluator has already been closed
*/
byte[] evaluateExpressionPklBinary(ModuleSource moduleSource, String expression);
/**
* Evaluates the Pkl expression, returning the stringified result.
*

View File

@@ -28,6 +28,8 @@ import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;
import org.graalvm.polyglot.Context;
import org.msgpack.core.MessageBufferPacker;
import org.msgpack.core.MessagePack;
import org.pkl.core.ast.ConstantValueNode;
import org.pkl.core.ast.internal.ToStringNodeGen;
import org.pkl.core.evaluatorSettings.TraceMode;
@@ -48,6 +50,7 @@ import org.pkl.core.runtime.VmExceptionBuilder;
import org.pkl.core.runtime.VmLanguage;
import org.pkl.core.runtime.VmMapping;
import org.pkl.core.runtime.VmNull;
import org.pkl.core.runtime.VmPklBinaryEncoder;
import org.pkl.core.runtime.VmStackOverflowException;
import org.pkl.core.runtime.VmTyped;
import org.pkl.core.runtime.VmUtils;
@@ -56,17 +59,18 @@ import org.pkl.core.runtime.VmValueRenderer;
import org.pkl.core.util.ErrorMessages;
import org.pkl.core.util.Nullable;
public class EvaluatorImpl implements Evaluator {
protected final StackFrameTransformer frameTransformer;
protected final boolean color;
protected final ModuleResolver moduleResolver;
protected final Context polyglotContext;
protected final @Nullable Duration timeout;
protected final @Nullable ScheduledExecutorService timeoutExecutor;
protected final SecurityManager securityManager;
protected final BufferedLogger logger;
protected final PackageResolver packageResolver;
public final class EvaluatorImpl implements Evaluator {
private final StackFrameTransformer frameTransformer;
private final boolean color;
private final ModuleResolver moduleResolver;
private final Context polyglotContext;
private final @Nullable Duration timeout;
private final @Nullable ScheduledExecutorService timeoutExecutor;
private final SecurityManager securityManager;
private final BufferedLogger logger;
private final PackageResolver packageResolver;
private final VmValueRenderer vmValueRenderer = VmValueRenderer.singleLine(1000);
private @Nullable MessageBufferPacker messagePacker;
public EvaluatorImpl(
StackFrameTransformer transformer,
@@ -217,6 +221,37 @@ public class EvaluatorImpl implements Evaluator {
};
}
private MessageBufferPacker getMessagePacker() {
if (messagePacker == null) {
messagePacker = MessagePack.newDefaultBufferPacker();
}
messagePacker.clear();
return messagePacker;
}
@Override
public byte[] evaluateExpressionPklBinary(ModuleSource moduleSource, String expression) {
return doEvaluate(
moduleSource,
(module) -> {
var expressionResult =
switch (expression) {
case "module" -> module;
case "output.text" -> VmUtils.readTextProperty(readModuleOutput(module));
case "output.value" ->
VmUtils.readMember(readModuleOutput(module), Identifier.VALUE);
case "output.bytes" -> VmUtils.readBytesProperty(readModuleOutput(module));
default ->
VmUtils.evaluateExpression(module, expression, securityManager, moduleResolver);
};
VmValue.force(expressionResult, false);
var packer = getMessagePacker();
new VmPklBinaryEncoder(packer).renderDocument(expressionResult);
return packer.toByteArray();
});
}
@Override
public String evaluateExpressionString(ModuleSource moduleSource, String expression) {
// optimization: if the expression is `output.text` (the common case), read members
@@ -363,7 +398,7 @@ public class EvaluatorImpl implements Evaluator {
return evalResult;
}
protected <T> T doEvaluate(ModuleSource moduleSource, Function<VmTyped, T> doEvaluate) {
private <T> T doEvaluate(ModuleSource moduleSource, Function<VmTyped, T> doEvaluate) {
return doEvaluate(
() -> {
var moduleKey = moduleResolver.resolve(moduleSource);

View File

@@ -0,0 +1,184 @@
/*
* Copyright © 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.core;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.msgpack.core.MessagePack;
import org.msgpack.core.MessageUnpacker;
import org.pkl.core.runtime.BaseModule;
import org.pkl.core.util.CollectionUtils;
import org.pkl.core.util.pklbinary.AbstractPklBinaryDecoder;
/**
* A decoder/parser for <code>pkl-binary</code>.
*
* <p>For how pkl-binary turns Java, see {@link Value}.
*/
public class PklBinaryDecoder extends AbstractPklBinaryDecoder {
private PklBinaryDecoder(MessageUnpacker unpacker) {
super(unpacker);
}
/** Decode a value from the supplied byte array. */
public static Object decode(byte[] bytes) {
return new PklBinaryDecoder(MessagePack.newDefaultUnpacker(bytes)).decode();
}
/** Decode a value from the supplied {@link InputStream}. */
public static Object decode(InputStream inputStream) {
return new PklBinaryDecoder(MessagePack.newDefaultUnpacker(inputStream)).decode();
}
@Override
protected RuntimeException doFail(Exception cause, long offset, List<String> path) {
return new RuntimeException(
String.format(
"Exception while decoding binary data at offset %d, path [%s]",
offset, String.join(", ", path)),
cause);
}
@Override
protected RuntimeException doIOFail(IOException cause) {
return new UncheckedIOException("IO exception during decoding", cause);
}
@Override
protected Object doDecodeNull() {
return PNull.getInstance();
}
@Override
protected Object doDecodeDuration(double value, DurationUnit unit) {
return new Duration(value, unit);
}
@Override
protected Object doDecodeObject(
String className, URI moduleUri, DecodeIterator<DecodedObjectMember> iter) {
var properties = CollectionUtils.<String, Object>newLinkedHashMap(iter.getSize());
while (iter.hasNext()) {
var member = iter.next();
properties.put(member.key().toString(), member.value());
}
if (moduleUri.equals(PClassInfo.pklBaseUri)) {
// dynamic
if (className.equals(BaseModule.getDynamicClass().getDisplayName())) {
return new PObject(PClassInfo.Dynamic, properties);
}
// pkl:base typed
if (!className.equals(BaseModule.getModule().getVmClass().getDisplayName())) {
return new PObject(PClassInfo.get("pkl.base", className, moduleUri), properties);
}
// fall through to module case
}
// module
var hashIndex = className.lastIndexOf("#");
if (hashIndex < 0) {
return new PModule(
moduleUri, className, PClassInfo.get(className, "ModuleClass", moduleUri), properties);
}
// non-pkl:base class
return new PObject(
PClassInfo.get(
className.substring(0, hashIndex), className.substring(hashIndex + 1), moduleUri),
properties);
}
@Override
protected Object doDecodeMap(MapDecodeIterator iter) {
var map = CollectionUtils.newLinkedHashMap(iter.getSize());
while (iter.hasNext()) {
var entry = iter.next();
map.put(entry.getFirst(), entry.getSecond());
}
return map;
}
@Override
protected Object doDecodeMapping(MapDecodeIterator iter) {
return doDecodeMap(iter); // same exported result!
}
@Override
protected Object doDecodeList(CollectionDecodeIterator iter) {
var listing = new ArrayList<>(iter.getSize());
while (iter.hasNext()) {
listing.add(iter.next());
}
return listing;
}
@Override
protected Object doDecodeListing(CollectionDecodeIterator iter) {
return doDecodeList(iter); // same exported result!
}
@Override
protected Object doDecodeSet(CollectionDecodeIterator iter) {
var set = CollectionUtils.newLinkedHashSet(iter.getSize());
while (iter.hasNext()) {
set.add(iter.next());
}
return set;
}
@Override
protected Object doDecodeDataSize(double value, DataSizeUnit unit) {
return new DataSize(value, unit);
}
@Override
protected Object doDecodePair(Object first, Object second) {
return new Pair<>(first, second);
}
@Override
protected Object doDecodeIntSeq(long start, long end, long step) {
throw new DecodeException("Cannot decode IntSeq value");
}
@Override
protected Object doDecodeRegex(Pattern pattern) {
return pattern;
}
@Override
protected Object doDecodeClass(String qualifiedName, URI moduleUri) {
throw new DecodeException("Cannot decode Class value");
}
@Override
protected Object doDecodeTypeAlias(String qualifiedName, URI moduleUri) {
throw new DecodeException("Cannot decode TypeAlias value");
}
@Override
protected Object doDecodeBytes(byte[] bytes) {
return bytes;
}
}

View File

@@ -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.
@@ -53,7 +53,7 @@ public final class TypeAlias extends Member implements Value {
/**
* Returns the name of the module that this type alias is declared in. Note that a module name is
* not guaranteed to be unique, especially if it not declared but inferred from the module URI.
* not guaranteed to be unique, especially if it is not declared but inferred from the module URI.
*/
public String getModuleName() {
return moduleName;

View File

@@ -143,6 +143,9 @@ public final class Identifier implements Comparable<Identifier> {
// members of pkl.yaml
public static final Identifier MAX_COLLECTION_ALIASES = get("maxCollectionAliases");
// members of pkl.encoding
public static final Identifier IMPORTS = get("imports");
// common in lambdas etc
public static final Identifier IT = get("it");

View File

@@ -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.
@@ -92,6 +92,8 @@ public final class ModuleCache {
return BaseModule.getModule();
case "Benchmark":
return BenchmarkModule.getModule();
case "pklbinary":
return PklBinaryModule.getModule();
case "jsonnet":
return JsonnetModule.getModule();
case "math":

View File

@@ -0,0 +1,30 @@
/*
* Copyright © 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.core.runtime;
import java.net.URI;
public class PklBinaryModule extends StdLibModule {
private static final VmTyped instance = VmUtils.createEmptyModule();
static {
loadModule(URI.create("pkl:pklbinary"), instance);
}
public static VmTyped getModule() {
return instance;
}
}

View File

@@ -0,0 +1,376 @@
/*
* Copyright © 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.core.runtime;
import java.io.IOException;
import java.util.Deque;
import org.msgpack.core.MessageBufferPacker;
import org.pkl.core.PklBugException;
import org.pkl.core.stdlib.AbstractRenderer;
import org.pkl.core.stdlib.PklConverter;
import org.pkl.core.util.pklbinary.PklBinaryCode;
/** An encoder/renderer for <code>pkl-binary</code></a> encoding. */
public class VmPklBinaryEncoder extends AbstractRenderer {
// this type explicitly works with MessageBufferPacker:
// * assumes no I/O during packing (in-memory writes only)
// * IOExceptions are caught and assumed unreachable
private final MessageBufferPacker packer;
public VmPklBinaryEncoder(MessageBufferPacker packer, PklConverter converter) {
super("pkl-binary", converter, false, false);
this.packer = packer;
}
public VmPklBinaryEncoder(MessageBufferPacker packer) {
this(packer, new PklConverter(VmMapping.empty()));
}
private void packCode(PklBinaryCode code) throws IOException {
packer.packByte(code.getCode());
}
@Override
public void visitString(String value) {
try {
packer.packString(value);
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
@Override
public void visitBoolean(Boolean value) {
try {
packer.packBoolean(value);
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
@Override
public void visitInt(Long value) {
try {
packer.packLong(value);
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
@Override
public void visitFloat(Double value) {
try {
packer.packDouble(value);
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
@Override
public void visitDuration(VmDuration value) {
try {
packer.packArrayHeader(3);
packCode(PklBinaryCode.DURATION);
packer.packDouble(value.getValue());
packer.packString(value.getUnit().toString());
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
@Override
public void visitDataSize(VmDataSize value) {
try {
packer.packArrayHeader(3);
packCode(PklBinaryCode.DATASIZE);
packer.packDouble(value.getValue());
packer.packString(value.getUnit().toString());
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
@Override
public void visitBytes(VmBytes value) {
try {
packer.packArrayHeader(2);
packCode(PklBinaryCode.BYTES);
packer.packBinaryHeader(value.getBytes().length);
packer.addPayload(value.getBytes());
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
@Override
public void visitIntSeq(VmIntSeq value) {
try {
packer.packArrayHeader(4);
packCode(PklBinaryCode.INTSEQ);
packer.packLong(value.start);
packer.packLong(value.end);
packer.packLong(value.step);
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
@Override
protected void visitDocument(Object value) {
visit(value);
}
@Override
protected void visitTopLevelValue(Object value) {
visit(value);
}
@Override
protected void visitRenderDirective(VmTyped value) {
try {
packer.writePayload(VmUtils.readBytesProperty(value).getBytes());
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
@Override
protected void startDynamic(VmDynamic value) {
startObject(value, value.getRegularMemberCount());
}
@Override
protected void startTyped(VmTyped value) {
startObject(value, value.getVmClass().getAllRegularPropertyNames().size());
}
private void startObject(VmObjectLike value, int memberCount) {
try {
packer.packArrayHeader(4);
packCode(PklBinaryCode.OBJECT);
packer.packString(value.getVmClass().getDisplayName());
packer.packString(
value.getVmClass().getModule().getModuleInfo().getModuleKey().getUri().toString());
packer.packArrayHeader(memberCount);
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
private void startList(PklBinaryCode code, int length) {
try {
packer.packArrayHeader(2);
packCode(code);
packer.packArrayHeader(length);
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
private void startMap(PklBinaryCode code, int length) {
try {
packer.packArrayHeader(2);
packCode(code);
packer.packMapHeader(length);
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
@Override
protected void startListing(VmListing value) {
startList(PklBinaryCode.LISTING, value.getLength());
}
@Override
protected void startMapping(VmMapping value) {
startMap(PklBinaryCode.MAPPING, (int) value.getLength());
}
@Override
protected void startList(VmList value) {
startList(PklBinaryCode.LIST, value.getLength());
}
@Override
protected void startSet(VmSet value) {
startList(PklBinaryCode.SET, value.getLength());
}
@Override
protected void startMap(VmMap value) {
startMap(PklBinaryCode.MAP, value.getLength());
}
@Override
protected void visitEntryKeyValue(
Object key, boolean isFirst, Deque<Object> valuePath, Object value) {
if (enclosingValue instanceof VmDynamic) {
try {
packer.packArrayHeader(3);
packCode(PklBinaryCode.ENTRY);
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
super.visitEntryKeyValue(key, isFirst, valuePath, value);
}
@Override
protected void visitElement(long index, Object value, boolean isFirst) {
if (enclosingValue instanceof VmDynamic) {
try {
packer.packArrayHeader(3);
packCode(PklBinaryCode.ELEMENT);
packer.packLong(index);
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
visit(value);
}
@Override
protected void visitProperty(Identifier name, Object value, boolean isFirst) {
try {
packer.packArrayHeader(3);
packCode(PklBinaryCode.PROPERTY);
packer.packString(name.toString());
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
visit(value);
}
@Override
public void visitClass(VmClass value) {
try {
packer.packArrayHeader(3);
packCode(PklBinaryCode.CLASS);
packer.packString(value.getDisplayName());
packer.packString(value.getModule().getModuleInfo().getModuleKey().getUri().toString());
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
@Override
public void visitTypeAlias(VmTypeAlias value) {
try {
packer.packArrayHeader(3);
packCode(PklBinaryCode.TYPEALIAS);
packer.packString(value.getDisplayName());
packer.packString(value.getModuleUri().toString());
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
@Override
public void visitPair(VmPair value) {
try {
packer.packArrayHeader(3);
packCode(PklBinaryCode.PAIR);
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
visit(value.getFirst());
visit(value.getSecond());
}
@Override
public void visitRegex(VmRegex value) {
try {
packer.packArrayHeader(2);
packCode(PklBinaryCode.REGEX);
packer.packString(value.getPattern().pattern());
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
@Override
public void visitNull(VmNull value) {
try {
packer.packNil();
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
@Override
public void visitFunction(VmFunction value) {
try {
packer.packArrayHeader(1);
packCode(PklBinaryCode.FUNCTION);
} catch (IOException e) {
throw PklBugException.unreachableCode();
}
}
@Override
protected void visitEntryKey(Object key, boolean isFirst) {
visit(key);
}
@Override
protected void visitEntryValue(Object value) {
visit(value);
}
@Override
protected void endDynamic(VmDynamic value, boolean isEmpty) {
// noop
}
@Override
protected void endTyped(VmTyped value, boolean isEmpty) {
// noop
}
@Override
protected void endListing(VmListing value, boolean isEmpty) {
// noop
}
@Override
protected void endMapping(VmMapping value, boolean isEmpty) {
// noop
}
@Override
protected void endList(VmList value) {
// noop
}
@Override
protected void endSet(VmSet value) {
// noop
}
@Override
protected void endMap(VmMap value) {
// noop
}
@Override
protected boolean canRenderPropertyOrEntryOf(VmDynamic object) {
return true;
}
}

View File

@@ -19,10 +19,12 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.frame.Frame;
import com.oracle.truffle.api.frame.MaterializedFrame;
import com.oracle.truffle.api.source.SourceSection;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.concurrent.GuardedBy;
import org.pkl.core.Member.SourceLocation;
import org.pkl.core.PClassInfo;
import org.pkl.core.PObject;
import org.pkl.core.TypeAlias;
import org.pkl.core.TypeParameter;
@@ -140,6 +142,10 @@ public final class VmTypeAlias extends VmValue {
return module.getVmClass().getModuleName();
}
public URI getModuleUri() {
return module.getVmClass().getPClassInfo().getModuleUri();
}
public VmTyped getModuleMirror() {
return module.getModuleInfo().getMirror(module);
}
@@ -152,6 +158,12 @@ public final class VmTypeAlias extends VmValue {
return qualifiedName;
}
public String getDisplayName() {
// display `UInt` rather than `pkl.base#UInt`, etc.
// based on PClassInfo.getDisplayName
return getModuleUri().equals(PClassInfo.pklBaseUri) ? simpleName : qualifiedName;
}
public int getTypeParameterCount() {
return typeParameters.size();
}

View File

@@ -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.

View File

@@ -406,14 +406,6 @@ public final class VmUtils {
return isCustomThisScope ? new CustomThisNode(sourceSection) : new ThisNode(sourceSection);
}
public static boolean isRenderDirective(VmValue value) {
return value.getVmClass() == BaseModule.getRenderDirectiveClass();
}
public static boolean isRenderDirective(Object value) {
return value instanceof VmTyped typed && isRenderDirective(typed);
}
public static boolean isPcfRenderDirective(Object value) {
return value instanceof VmTyped typed
&& typed.getVmClass().getPClassInfo() == PClassInfo.PcfRenderDirective;

View File

@@ -19,6 +19,7 @@ import com.oracle.truffle.api.source.SourceSection;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import org.pkl.core.runtime.BaseModule;
import org.pkl.core.runtime.Identifier;
import org.pkl.core.runtime.VmClass;
import org.pkl.core.runtime.VmCollection;
@@ -35,7 +36,6 @@ import org.pkl.core.runtime.VmSet;
import org.pkl.core.runtime.VmTypeAlias;
import org.pkl.core.runtime.VmTyped;
import org.pkl.core.runtime.VmUndefinedValueException;
import org.pkl.core.runtime.VmUtils;
import org.pkl.core.runtime.VmValue;
import org.pkl.core.runtime.VmValueConverter;
import org.pkl.core.runtime.VmValueVisitor;
@@ -43,18 +43,11 @@ import org.pkl.core.util.LateInit;
import org.pkl.core.util.MutableBoolean;
import org.pkl.core.util.Nullable;
/** Base class for renderers that are part of the standard library. */
public abstract class AbstractRenderer implements VmValueVisitor {
protected static final char LINE_BREAK = '\n';
/** The name of this renderer. */
protected final String name;
protected final StringBuilder builder;
/** The indent to be used. */
protected final String indent;
protected final PklConverter converter;
/** Whether to skip visiting properties with null value (after conversion). */
@@ -65,33 +58,31 @@ public abstract class AbstractRenderer implements VmValueVisitor {
@LateInit protected Deque<Object> currPath;
/** The value directly enclosing the currently visited value, if any. */
protected @Nullable VmValue enclosingValue;
/** The value passed to either {@link #renderDocument(Object)} or {@link #renderValue(Object)}. */
@LateInit private Object topLevelValue;
/** The current indent. Modified by {@link #increaseIndent()} and {@link #decreaseIndent()}. */
protected final StringBuilder currIndent = new StringBuilder();
/** The value directly enclosing the currently visited value, if any. */
protected @Nullable VmValue enclosingValue;
/** The (closest) {@link SourceSection} of the value being visited, for better error messages. */
protected @Nullable SourceSection currSourceSection = null;
public AbstractRenderer(
String name,
StringBuilder builder,
String indent,
PklConverter converter,
boolean skipNullProperties,
boolean skipNullEntries) {
protected AbstractRenderer(
String name, PklConverter converter, boolean skipNullProperties, boolean skipNullEntries) {
this.name = name;
this.builder = builder;
this.indent = indent;
this.converter = converter;
this.skipNullProperties = skipNullProperties;
this.skipNullEntries = skipNullEntries;
}
protected boolean isRenderDirective(VmValue value) {
return value.getVmClass() == BaseModule.getRenderDirectiveClass();
}
protected boolean isRenderDirective(Object value) {
return value instanceof VmTyped typed && isRenderDirective(typed);
}
public final void renderDocument(Object value) {
currPath = new ArrayDeque<>();
currPath.push(VmValueConverter.TOP_LEVEL_VALUE);
@@ -185,71 +176,22 @@ public abstract class AbstractRenderer implements VmValueVisitor {
protected abstract void endMap(VmMap value);
private void doVisitProperty(
Identifier name, Object value, SourceSection sourceSection, MutableBoolean isFirst) {
var prevSourceSection = currSourceSection;
currSourceSection = sourceSection;
currPath.push(name);
var convertedValue = converter.convert(value, currPath);
if (!(skipNullProperties && convertedValue instanceof VmNull)) {
visitProperty(name, convertedValue, isFirst.getAndSetFalse());
}
currPath.pop();
currSourceSection = prevSourceSection;
}
private void doVisitEntry(
Object key, Object value, @Nullable SourceSection sourceSection, MutableBoolean isFirst) {
var prevSourceSection = currSourceSection;
if (sourceSection != null) {
currSourceSection = sourceSection;
}
var valuePath = currPath;
try {
var convertedKey = converter.convert(key, List.of());
valuePath.push(convertedKey);
var convertedValue = converter.convert(value, valuePath);
if (skipNullEntries && (convertedValue instanceof VmNull)) {
return;
}
currPath = new ArrayDeque<>();
visitEntryKey(convertedKey, isFirst.getAndSetFalse());
currPath = valuePath;
visitEntryValue(convertedValue);
} finally {
valuePath.pop();
currSourceSection = prevSourceSection;
}
}
private void doVisitElement(
long index, Object value, @Nullable SourceSection sourceSection, boolean isFirst) {
var prevSourceSection = currSourceSection;
if (sourceSection != null) {
currSourceSection = sourceSection;
}
currPath.push(index);
var convertedValue = converter.convert(value, currPath);
visitElement(index, convertedValue, isFirst);
currPath.pop();
currSourceSection = prevSourceSection;
}
@Override
public void visitTyped(VmTyped value) {
// value.getParent().getMember(value);
if (VmUtils.isRenderDirective(value)) {
if (isRenderDirective(value)) {
visitRenderDirective(value);
return;
}
value.force(false, false);
startTyped(value);
var prevEnclosingValue = enclosingValue;
enclosingValue = value;
var isFirst = new MutableBoolean(true);
value.forceAndIterateMemberValues(
value.iterateAlreadyForcedMemberValues(
(memberKey, member, memberValue) -> {
if (member.isClass() || member.isTypeAlias()) return true;
assert member.isProp();
@@ -263,6 +205,7 @@ public abstract class AbstractRenderer implements VmValueVisitor {
@Override
public final void visitDynamic(VmDynamic value) {
value.force(false, false);
startDynamic(value);
var prevEnclosingValue = enclosingValue;
@@ -270,7 +213,7 @@ public abstract class AbstractRenderer implements VmValueVisitor {
var isFirst = new MutableBoolean(true);
var canRenderPropertyOrEntry = canRenderPropertyOrEntryOf(value);
value.forceAndIterateMemberValues(
value.iterateAlreadyForcedMemberValues(
(memberKey, member, memberValue) -> {
var sourceSection = member.getSourceSection();
if (member.isProp()) {
@@ -302,12 +245,14 @@ public abstract class AbstractRenderer implements VmValueVisitor {
@Override
public final void visitListing(VmListing value) {
value.force(false, false);
startListing(value);
var prevEnclosingValue = enclosingValue;
enclosingValue = value;
var isFirst = new MutableBoolean(true);
value.forceAndIterateMemberValues(
value.iterateAlreadyForcedMemberValues(
(memberKey, member, memberValue) -> {
assert member.isElement();
doVisitElement(
@@ -321,12 +266,14 @@ public abstract class AbstractRenderer implements VmValueVisitor {
@Override
public final void visitMapping(VmMapping value) {
value.force(false, false);
startMapping(value);
var prevEnclosingValue = enclosingValue;
enclosingValue = value;
var isFirst = new MutableBoolean(true);
value.forceAndIterateMemberValues(
value.iterateAlreadyForcedMemberValues(
(memberKey, member, memberValue) -> {
assert member.isEntry();
doVisitEntry(memberKey, memberValue, member.getSourceSection(), isFirst);
@@ -379,19 +326,60 @@ public abstract class AbstractRenderer implements VmValueVisitor {
endMap(value);
}
@Override
public final void visitTypeAlias(VmTypeAlias value) {
cannotRenderTypeAddConverter(value);
private void doVisitProperty(
Identifier name, Object value, SourceSection sourceSection, MutableBoolean isFirst) {
var prevSourceSection = currSourceSection;
currSourceSection = sourceSection;
currPath.push(name);
var convertedValue = converter.convert(value, currPath);
if (!(skipNullProperties && convertedValue instanceof VmNull)) {
visitProperty(name, convertedValue, isFirst.getAndSetFalse());
}
currPath.pop();
currSourceSection = prevSourceSection;
}
@Override
public final void visitClass(VmClass value) {
cannotRenderTypeAddConverter(value);
private void doVisitEntry(
Object key, Object value, @Nullable SourceSection sourceSection, MutableBoolean isFirst) {
var prevSourceSection = currSourceSection;
if (sourceSection != null) {
currSourceSection = sourceSection;
}
var valuePath = currPath;
try {
var convertedKey = converter.convert(key, List.of());
valuePath.push(convertedKey);
var convertedValue = converter.convert(value, valuePath);
if (skipNullEntries && (convertedValue instanceof VmNull)) {
return;
}
visitEntryKeyValue(convertedKey, isFirst.getAndSetFalse(), valuePath, convertedValue);
} finally {
valuePath.pop();
currSourceSection = prevSourceSection;
}
}
@Override
public final void visitFunction(VmFunction value) {
cannotRenderTypeAddConverter(value);
protected void visitEntryKeyValue(
Object key, boolean isFirst, Deque<Object> valuePath, Object value) {
currPath = new ArrayDeque<>();
visitEntryKey(key, isFirst);
currPath = valuePath;
visitEntryValue(value);
}
private void doVisitElement(
long index, Object value, @Nullable SourceSection sourceSection, boolean isFirst) {
var prevSourceSection = currSourceSection;
if (sourceSection != null) {
currSourceSection = sourceSection;
}
currPath.push(index);
var convertedValue = converter.convert(value, currPath);
visitElement(index, convertedValue, isFirst);
currPath.pop();
currSourceSection = prevSourceSection;
}
protected void cannotRenderTypeAddConverter(VmValue value) {
@@ -405,6 +393,21 @@ public abstract class AbstractRenderer implements VmValueVisitor {
throw builder.build();
}
@Override
public void visitTypeAlias(VmTypeAlias value) {
cannotRenderTypeAddConverter(value);
}
@Override
public void visitClass(VmClass value) {
cannotRenderTypeAddConverter(value);
}
@Override
public void visitFunction(VmFunction value) {
cannotRenderTypeAddConverter(value);
}
protected void cannotRenderNonStringKey(Object key) {
assert enclosingValue != null;
var isMap = enclosingValue instanceof VmMap;
@@ -424,12 +427,4 @@ public abstract class AbstractRenderer implements VmValueVisitor {
.withProgramValue("Key", key)
.build();
}
protected void increaseIndent() {
currIndent.append(indent);
}
protected void decreaseIndent() {
currIndent.setLength(currIndent.length() - indent.length());
}
}

View File

@@ -0,0 +1,70 @@
/*
* 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.core.stdlib;
import org.pkl.core.runtime.VmClass;
import org.pkl.core.runtime.VmFunction;
import org.pkl.core.runtime.VmTypeAlias;
/** Base class for renderers that are part of the standard library. */
public abstract class AbstractStringRenderer extends AbstractRenderer {
protected static final char LINE_BREAK = '\n';
protected final StringBuilder builder;
/** The indent to be used. */
protected final String indent;
/** The current indent. Modified by {@link #increaseIndent()} and {@link #decreaseIndent()}. */
protected final StringBuilder currIndent = new StringBuilder();
public AbstractStringRenderer(
String name,
StringBuilder builder,
String indent,
PklConverter converter,
boolean skipNullProperties,
boolean skipNullEntries) {
super(name, converter, skipNullProperties, skipNullEntries);
this.builder = builder;
this.indent = indent;
}
protected void increaseIndent() {
currIndent.append(indent);
}
protected void decreaseIndent() {
currIndent.setLength(currIndent.length() - indent.length());
}
// override these to mark them final
@Override
public final void visitTypeAlias(VmTypeAlias value) {
super.visitTypeAlias(value);
}
@Override
public final void visitClass(VmClass value) {
super.visitClass(value);
}
@Override
public final void visitFunction(VmFunction value) {
super.visitFunction(value);
}
}

View File

@@ -18,7 +18,7 @@ package org.pkl.core.stdlib.base;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import org.pkl.core.runtime.*;
import org.pkl.core.stdlib.AbstractRenderer;
import org.pkl.core.stdlib.AbstractStringRenderer;
import org.pkl.core.stdlib.ExternalMethod1Node;
import org.pkl.core.stdlib.PklConverter;
import org.pkl.core.util.json.JsonEscaper;
@@ -57,7 +57,7 @@ public final class JsonRendererNodes {
return new JsonRenderer(builder, indent, converter, omitNullProperties);
}
private static final class JsonRenderer extends AbstractRenderer {
private static final class JsonRenderer extends AbstractStringRenderer {
private final String separator;
private final JsonEscaper escaper = new JsonEscaper(false);
@@ -212,7 +212,7 @@ public final class JsonRendererNodes {
return;
}
if (VmUtils.isRenderDirective(key)) {
if (isRenderDirective(key)) {
visitRenderDirective((VmTyped) key);
builder.append(separator);
return;

View File

@@ -18,7 +18,7 @@ package org.pkl.core.stdlib.base;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import org.pkl.core.runtime.*;
import org.pkl.core.stdlib.AbstractRenderer;
import org.pkl.core.stdlib.AbstractStringRenderer;
import org.pkl.core.stdlib.ExternalMethod1Node;
import org.pkl.core.stdlib.PklConverter;
import org.pkl.core.util.ArrayCharEscaper;
@@ -54,7 +54,7 @@ public final class PListRendererNodes {
}
// keep in sync with org.pkl.core.PListRenderer
private static final class PListRenderer extends AbstractRenderer {
private static final class PListRenderer extends AbstractStringRenderer {
// it's safe (though not required) to escape all the following characters in XML text nodes
private static final ArrayCharEscaper charEscaper =
@@ -241,7 +241,7 @@ public final class PListRendererNodes {
builder.append("<dict>").append(LINE_BREAK);
}
if (VmUtils.isRenderDirective(key)) {
if (isRenderDirective(key)) {
key = VmUtils.readTextProperty(key);
}

View File

@@ -34,12 +34,12 @@ import org.pkl.core.runtime.VmRegex;
import org.pkl.core.runtime.VmSet;
import org.pkl.core.runtime.VmTyped;
import org.pkl.core.runtime.VmUtils;
import org.pkl.core.stdlib.AbstractRenderer;
import org.pkl.core.stdlib.AbstractStringRenderer;
import org.pkl.core.stdlib.PklConverter;
import org.pkl.core.util.LateInit;
import org.pkl.parser.Lexer;
public final class PcfRenderer extends AbstractRenderer {
public final class PcfRenderer extends AbstractStringRenderer {
private final ValueFormatter valueFormatter;
private boolean isDocument;
@@ -227,7 +227,7 @@ public final class PcfRenderer extends AbstractRenderer {
}
private void visitStandaloneValue(Object value) {
if (value instanceof VmObjectLike && !VmUtils.isRenderDirective(value)) {
if (value instanceof VmObjectLike && !isRenderDirective(value)) {
builder.append("new ");
}
visit(value);

View File

@@ -36,7 +36,7 @@ import org.pkl.core.runtime.VmTyped;
import org.pkl.core.runtime.VmUtils;
import org.pkl.core.runtime.VmValue;
import org.pkl.core.runtime.VmValueConverter;
import org.pkl.core.stdlib.AbstractRenderer;
import org.pkl.core.stdlib.AbstractStringRenderer;
import org.pkl.core.stdlib.ExternalMethod1Node;
import org.pkl.core.stdlib.PklConverter;
import org.pkl.core.util.EconomicMaps;
@@ -74,7 +74,7 @@ public final class PropertiesRendererNodes {
return new PropertiesRenderer(builder, omitNullProperties, restrictCharset, PklConverter);
}
private static final class PropertiesRenderer extends AbstractRenderer {
private static final class PropertiesRenderer extends AbstractStringRenderer {
private final boolean restrictCharset;
private boolean isDocument;
@@ -158,7 +158,7 @@ public final class PropertiesRendererNodes {
.withProgramValue("Value", value)
.build();
}
if (!VmUtils.isRenderDirective(value)) {
if (!isRenderDirective(value)) {
isDocument = true;
}
visit(value);
@@ -170,7 +170,7 @@ public final class PropertiesRendererNodes {
|| value instanceof VmTyped
|| value instanceof VmMapping
|| value instanceof VmDynamic)
&& !VmUtils.isRenderDirective(value)) {
&& !isRenderDirective(value)) {
cannotRenderTypeAddConverter((VmValue) value);
}
isDocument = false;
@@ -303,7 +303,7 @@ public final class PropertiesRendererNodes {
if (isFollowing.get()) {
builder.append('.');
}
if (VmUtils.isRenderDirective(path)) {
if (isRenderDirective(path)) {
builder.append(VmUtils.readTextProperty(path));
} else {
builder.append(

View File

@@ -35,7 +35,7 @@ import org.pkl.core.runtime.VmRegex;
import org.pkl.core.runtime.VmSet;
import org.pkl.core.runtime.VmTyped;
import org.pkl.core.runtime.VmUtils;
import org.pkl.core.stdlib.AbstractRenderer;
import org.pkl.core.stdlib.AbstractStringRenderer;
import org.pkl.core.stdlib.ExternalMethod1Node;
import org.pkl.core.stdlib.PklConverter;
import org.pkl.core.util.MutableBoolean;
@@ -75,7 +75,7 @@ public final class YamlRendererNodes {
builder, " ".repeat(indentWidth), converter, omitNullProperties, mode, isStream);
}
private static final class YamlRenderer extends AbstractRenderer {
private static final class YamlRenderer extends AbstractStringRenderer {
private final boolean isStream;
private final YamlEmitter emitter;
private final String elementIndent;
@@ -306,7 +306,7 @@ public final class YamlRendererNodes {
return;
}
if (VmUtils.isRenderDirective(key)) {
if (isRenderDirective(key)) {
visitRenderDirective((VmTyped) key);
builder.append(':');
return;

View File

@@ -36,7 +36,7 @@ import org.pkl.core.runtime.VmRegex;
import org.pkl.core.runtime.VmSet;
import org.pkl.core.runtime.VmTyped;
import org.pkl.core.runtime.VmUtils;
import org.pkl.core.stdlib.AbstractRenderer;
import org.pkl.core.stdlib.AbstractStringRenderer;
import org.pkl.core.stdlib.ExternalMethod1Node;
import org.pkl.core.stdlib.PklConverter;
import org.pkl.core.util.ArrayCharEscaper;
@@ -72,7 +72,7 @@ public final class RendererNodes {
}
}
private static final class Renderer extends AbstractRenderer {
private static final class Renderer extends AbstractStringRenderer {
// Pattern for object fields that we can render without any quotes.
// From: https://jsonnet.org/ref/spec.html#lexing
private static final Pattern ID_PATTERN = Pattern.compile("[_a-zA-Z][_a-zA-Z0-9]*");
@@ -288,7 +288,7 @@ public final class RendererNodes {
builder.append(memberSeparator).append(currIndent);
if (key instanceof String string) {
renderAsFieldName(string);
} else if (VmUtils.isRenderDirective(key)) {
} else if (isRenderDirective(key)) {
visitRenderDirective((VmTyped) key);
builder.append(": ");
} else {

View File

@@ -0,0 +1,71 @@
/*
* Copyright © 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.core.stdlib.pklbinary;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import org.msgpack.core.MessageBufferPacker;
import org.msgpack.core.MessagePack;
import org.pkl.core.runtime.Identifier;
import org.pkl.core.runtime.VmBytes;
import org.pkl.core.runtime.VmMapping;
import org.pkl.core.runtime.VmPklBinaryEncoder;
import org.pkl.core.runtime.VmTyped;
import org.pkl.core.runtime.VmUtils;
import org.pkl.core.stdlib.ExternalMethod1Node;
import org.pkl.core.stdlib.PklConverter;
import org.pkl.core.util.Nullable;
public final class RendererNodes {
private abstract static class RenderMethod extends ExternalMethod1Node {
private @Nullable MessageBufferPacker messagePacker;
protected MessageBufferPacker getMessagePacker() {
if (messagePacker == null) {
messagePacker = MessagePack.newDefaultBufferPacker();
}
messagePacker.clear();
return messagePacker;
}
}
public abstract static class renderDocument extends RenderMethod {
@Specialization
@TruffleBoundary
protected VmBytes eval(VmTyped self, Object value) {
var packer = getMessagePacker();
createRenderer(self, packer).renderDocument(value);
return new VmBytes(packer.toByteArray());
}
}
public abstract static class renderValue extends RenderMethod {
@Specialization
@TruffleBoundary
protected VmBytes eval(VmTyped self, Object value) {
var packer = getMessagePacker();
createRenderer(self, packer).renderValue(value);
return new VmBytes(packer.toByteArray());
}
}
private static VmPklBinaryEncoder createRenderer(VmTyped self, MessageBufferPacker packer) {
var converters = (VmMapping) VmUtils.readMember(self, Identifier.CONVERTERS);
var converter = new PklConverter(converters);
return new VmPklBinaryEncoder(packer, converter);
}
}

View File

@@ -0,0 +1,4 @@
@NonnullByDefault
package org.pkl.core.stdlib.pklbinary;
import org.pkl.core.util.NonnullByDefault;

View File

@@ -63,7 +63,7 @@ import org.pkl.core.runtime.VmSet;
import org.pkl.core.runtime.VmTyped;
import org.pkl.core.runtime.VmUtils;
import org.pkl.core.runtime.VmValue;
import org.pkl.core.stdlib.AbstractRenderer;
import org.pkl.core.stdlib.AbstractStringRenderer;
import org.pkl.core.stdlib.ExternalMethod1Node;
import org.pkl.core.stdlib.PklConverter;
import org.pkl.core.util.ArrayCharEscaper;
@@ -140,7 +140,7 @@ public final class RendererNodes {
return new ProtobufRenderer(builder, indent, new PklConverter(converters));
}
private static final class ProtobufRenderer extends AbstractRenderer {
private static final class ProtobufRenderer extends AbstractStringRenderer {
private final Deque<Identifier> propertyPath = new ArrayDeque<>();
private final Deque<Boolean> wrapperRequirement = new ArrayDeque<>();
private final JsonEscaper jsonEscaper = new JsonEscaper(false);
@@ -306,7 +306,7 @@ public final class RendererNodes {
@Override
protected void visitEntryKey(Object key, boolean isFirst) {
var isDirective = VmUtils.isRenderDirective(key);
var isDirective = isRenderDirective(key);
var isValidKey =
isDirective || key instanceof Long || key instanceof Boolean || key instanceof String;
if (!isValidKey) {

View File

@@ -18,7 +18,7 @@ package org.pkl.core.stdlib.xml;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Specialization;
import org.pkl.core.runtime.*;
import org.pkl.core.stdlib.AbstractRenderer;
import org.pkl.core.stdlib.AbstractStringRenderer;
import org.pkl.core.stdlib.ExternalMethod1Node;
import org.pkl.core.stdlib.PklConverter;
import org.pkl.core.util.ArrayCharEscaper;
@@ -60,7 +60,7 @@ public final class RendererNodes {
}
}
public static final class Renderer extends AbstractRenderer {
public static final class Renderer extends AbstractStringRenderer {
// it's safe (though not required) to escape all the following characters in text nodes and
// attribute values
private static final ArrayCharEscaper stringEscaper =
@@ -266,7 +266,7 @@ public final class RendererNodes {
renderXmlInline((VmTyped) value);
} else if (isContent(value)) {
visit(value);
} else if (VmUtils.isRenderDirective(value)) {
} else if (isRenderDirective(value)) {
builder.append(VmUtils.readTextProperty(value));
} else {
writeXmlElement(VmUtils.getClass(value).getSimpleName(), null, value, true, true);
@@ -293,7 +293,7 @@ public final class RendererNodes {
} else {
assert deferredKey != null;
assert enclosingValue != null;
if (VmUtils.isRenderDirective(deferredKey)) {
if (isRenderDirective(deferredKey)) {
writeXmlElement(VmUtils.readTextProperty(deferredKey), null, value, true, false);
} else if (deferredKey instanceof String string) {
writeXmlElement(string, null, value, true, true);

View File

@@ -0,0 +1,468 @@
/*
* Copyright © 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.core.util.pklbinary;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.Formatter;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
import org.msgpack.core.MessageInsufficientBufferException;
import org.msgpack.core.MessagePackException;
import org.msgpack.core.MessageUnpacker;
import org.pkl.core.DataSizeUnit;
import org.pkl.core.DurationUnit;
import org.pkl.core.Pair;
import org.pkl.core.util.LateInit;
/**
* Base class for implementing a decoder/parser for the <a
* href="https://pkl-lang.org/main/current/bindings-specification/binary-encoding.html"><code>
* pkl-binary</code></a> encoding.
*/
public abstract class AbstractPklBinaryDecoder {
private final MessageUnpacker unpacker;
@LateInit protected Deque<Object> currPath;
protected AbstractPklBinaryDecoder(MessageUnpacker unpacker) {
this.unpacker = unpacker;
}
protected static class DecodeException extends RuntimeException {
public DecodeException(String msg, Object... args) {
super(new Formatter().format(msg, args).toString());
}
}
protected final Object decode() {
currPath = new ArrayDeque<>();
try {
try {
return doDecode();
} catch (MessageInsufficientBufferException e) {
throw new DecodeException("Unexpected EOF", e);
}
} catch (IOException e) {
throw doIOFail(e);
} catch (MessagePackException | DecodeException e) {
var path = new ArrayList<String>(currPath.size());
for (var iter = currPath.descendingIterator(); iter.hasNext(); ) {
path.add(iter.next().toString());
}
Collections.reverse(path);
throw doFail(e, unpacker.getTotalReadBytes(), path);
}
}
private void assertLength(PklBinaryCode type, int len, int expected) {
if (len < expected) {
throw new DecodeException(
"Expected %s structure to have at least %d slots, found %d", type, expected + 1, len);
}
}
protected record DecodedObjectMember(PklBinaryCode type, Object key, Object value) {}
protected abstract RuntimeException doFail(Exception cause, long offset, List<String> path);
protected abstract RuntimeException doIOFail(IOException cause);
protected abstract Object doDecodeNull();
protected abstract Object doDecodeObject(
String className, URI moduleUri, DecodeIterator<DecodedObjectMember> iter);
protected abstract Object doDecodeMap(MapDecodeIterator iter);
protected abstract Object doDecodeMapping(MapDecodeIterator iter);
protected abstract Object doDecodeList(CollectionDecodeIterator iter);
protected abstract Object doDecodeListing(CollectionDecodeIterator iter);
protected abstract Object doDecodeSet(CollectionDecodeIterator iter);
protected abstract Object doDecodeDuration(double value, DurationUnit unit);
protected abstract Object doDecodeDataSize(double value, DataSizeUnit unit);
protected abstract Object doDecodePair(Object first, Object second);
protected abstract Object doDecodeIntSeq(long start, long end, long step);
protected abstract Object doDecodeRegex(Pattern pattern);
protected abstract Object doDecodeClass(String qualifiedName, URI moduleUri);
protected abstract Object doDecodeTypeAlias(String qualifiedName, URI moduleUri);
protected Object doDecodeFunction() {
throw new DecodeException("Cannot decode Function value");
}
protected abstract Object doDecodeBytes(byte[] bytes);
private Object doDecode() throws IOException {
if (!unpacker.hasNext()) {
throw new DecodeException("Unexpected EOF");
}
return switch (unpacker.getNextFormat().getValueType()) {
// primitives
case NIL -> {
unpacker.unpackNil();
yield doDecodeNull();
}
case STRING -> unpacker.unpackString();
case INTEGER -> unpacker.unpackLong();
case BOOLEAN -> unpacker.unpackBoolean();
case FLOAT -> unpacker.unpackDouble();
// non-primitive
case ARRAY -> decodeNonPrimitive();
// things we should never see outside a non-primitive
case BINARY -> throw new DecodeException("Unexpected msgpack bin value");
case MAP -> throw new DecodeException("Unexpected msgpack map value");
case EXTENSION -> throw new DecodeException("Unexpected msgpack ext value");
};
}
private Object decodeNonPrimitive() throws IOException {
var len = unpacker.unpackArrayHeader();
if (len < 1) {
throw new DecodeException("Unexpected empty object array value");
}
var codeInt = unpacker.unpackInt();
var code = PklBinaryCode.fromInt(codeInt);
if (code == null) {
throw new DecodeException("Unrecognized code 0x%x", (byte) codeInt);
}
return switch (code) {
case OBJECT -> decodeObject(len);
case MAP -> decodeMap(len);
case MAPPING -> decodeMapping(len);
case LIST -> decodeList(len);
case LISTING -> decodeListing(len);
case SET -> decodeSet(len);
case DURATION -> decodeDuration(len);
case DATASIZE -> decodeDataSize(len);
case PAIR -> decodePair(len);
case INTSEQ -> decodeIntSeq(len);
case REGEX -> decodeRegex(len);
case CLASS -> decodeClass(len);
case TYPEALIAS -> decodeTypeAlias(len);
case FUNCTION -> decodeFunction(len);
case BYTES -> decodeBytes(len);
default -> throw new DecodeException("Unrecognized object code %s", code);
};
}
private Object decodeObject(int len) throws IOException {
assertLength(PklBinaryCode.OBJECT, len, 3);
currPath.push("'object");
var className = unpacker.unpackString();
if (className.isBlank()) {
throw new DecodeException("Unexpected blank object class name");
}
var classModuleUriString = unpacker.unpackString();
if (classModuleUriString.isBlank()) {
throw new DecodeException("Unexpected blank object module URI");
}
var classModuleUri = URI.create(classModuleUriString);
var result =
doDecodeObject(
className, classModuleUri, new ObjectDecodeIterator(unpacker.unpackArrayHeader()));
unpacker.skipValue(len - 4);
currPath.pop();
return result;
}
private Object decodeMap(int len) throws IOException {
assertLength(PklBinaryCode.MAP, len, 1);
currPath.push("'map");
var result = doDecodeMap(new MapDecodeIterator(unpacker.unpackMapHeader()));
unpacker.skipValue(len - 2);
currPath.pop();
return result;
}
private Object decodeMapping(int len) throws IOException {
assertLength(PklBinaryCode.MAPPING, len, 1);
currPath.push("'mapping");
var result = doDecodeMapping(new MapDecodeIterator(unpacker.unpackMapHeader()));
unpacker.skipValue(len - 2);
currPath.pop();
return result;
}
private Object decodeList(int len) throws IOException {
assertLength(PklBinaryCode.LIST, len, 1);
currPath.push("'list");
var result = doDecodeList(new CollectionDecodeIterator(unpacker.unpackArrayHeader()));
unpacker.skipValue(len - 2);
currPath.pop();
return result;
}
private Object decodeListing(int len) throws IOException {
assertLength(PklBinaryCode.LISTING, len, 1);
currPath.push("'listing");
var result = doDecodeListing(new CollectionDecodeIterator(unpacker.unpackArrayHeader()));
unpacker.skipValue(len - 2);
currPath.pop();
return result;
}
private Object decodeSet(int len) throws IOException {
assertLength(PklBinaryCode.SET, len, 1);
currPath.push("'set");
var result = doDecodeSet(new CollectionDecodeIterator(unpacker.unpackArrayHeader()));
currPath.pop();
unpacker.skipValue(len - 2);
return result;
}
private Object decodeDuration(int len) throws IOException {
assertLength(PklBinaryCode.DURATION, len, 2);
currPath.push("'duration");
var durationValue = unpacker.unpackDouble();
var rawDurationUnit = unpacker.unpackString();
var durationUnit = DurationUnit.parse(rawDurationUnit);
if (durationUnit == null) {
throw new DecodeException("Invalid Duration unit `%s`", rawDurationUnit);
}
var result = doDecodeDuration(durationValue, durationUnit);
unpacker.skipValue(len - 3);
currPath.pop();
return result;
}
private Object decodeDataSize(int len) throws IOException {
assertLength(PklBinaryCode.DATASIZE, len, 2);
currPath.push("'datasize");
var dataSizeValue = unpacker.unpackDouble();
var rawDataSizeUnit = unpacker.unpackString();
var dataSizeUnit = DataSizeUnit.parse(rawDataSizeUnit);
if (dataSizeUnit == null) {
throw new DecodeException("Invalid DataSize unit `%s`", rawDataSizeUnit);
}
var result = doDecodeDataSize(dataSizeValue, dataSizeUnit);
unpacker.skipValue(len - 3);
currPath.pop();
return result;
}
private Object decodePair(int len) throws IOException {
assertLength(PklBinaryCode.PAIR, len, 2);
currPath.push("'pair");
currPath.push("'first");
var first = doDecode();
currPath.pop();
currPath.push("'second");
var second = doDecode();
currPath.pop();
var result = doDecodePair(first, second);
unpacker.skipValue(len - 3);
currPath.pop();
return result;
}
private Object decodeIntSeq(int len) throws IOException {
assertLength(PklBinaryCode.INTSEQ, len, 3);
currPath.push("'intseq");
var start = unpacker.unpackLong();
var end = unpacker.unpackLong();
var step = unpacker.unpackLong();
var result = doDecodeIntSeq(start, end, step);
unpacker.skipValue(len - 4);
currPath.pop();
return result;
}
private Object decodeRegex(int len) throws IOException {
assertLength(PklBinaryCode.REGEX, len, 1);
currPath.push("'regex");
var result = doDecodeRegex(Pattern.compile(unpacker.unpackString()));
unpacker.skipValue(len - 2);
currPath.pop();
return result;
}
private Object decodeClass(int len) throws IOException {
assertLength(PklBinaryCode.CLASS, len, 2);
currPath.push("'class");
var name = unpacker.unpackString();
if (name.isBlank()) {
throw new DecodeException("Unexpected blank class name");
}
var moduleUriString = unpacker.unpackString();
if (moduleUriString.isBlank()) {
throw new DecodeException("Unexpected blank class module URI");
}
var moduleUri = URI.create(moduleUriString);
var result = doDecodeClass(name, moduleUri);
unpacker.skipValue(len - 3);
currPath.pop();
return result;
}
private Object decodeTypeAlias(int len) throws IOException {
assertLength(PklBinaryCode.TYPEALIAS, len, 2);
currPath.push("'typealias");
var name = unpacker.unpackString();
if (name.isBlank()) {
throw new DecodeException("Unexpected blank typealias name");
}
var moduleUriString = unpacker.unpackString();
if (moduleUriString.isBlank()) {
throw new DecodeException("Unexpected blank typealias module URI");
}
var moduleUri = URI.create(moduleUriString);
var result = doDecodeTypeAlias(name, moduleUri);
unpacker.skipValue(len - 3);
currPath.pop();
return result;
}
private Object decodeFunction(int len) throws IOException {
assertLength(PklBinaryCode.FUNCTION, len, 0);
currPath.push("'function");
var result = doDecodeFunction();
unpacker.skipValue(len - 1);
currPath.pop();
return result;
}
private Object decodeBytes(int len) throws IOException {
assertLength(PklBinaryCode.BYTES, len, 1);
currPath.push("'bytes");
var result = doDecodeBytes(unpacker.readPayload(unpacker.unpackBinaryHeader()));
unpacker.skipValue(len - 2);
currPath.pop();
return result;
}
// some silly iterator classes because next() needs to handle IOException
protected abstract class DecodeIterator<T> implements Iterator<T> {
private final int size;
private int idx = 0;
DecodeIterator(int size) {
this.size = size;
}
public int getSize() {
return size;
}
public boolean hasNext() {
return idx < size;
}
public T next() {
currPath.push(idx);
try {
return getNext();
} catch (IOException e) {
throw doIOFail(e);
} finally {
currPath.pop();
idx++;
}
}
abstract T getNext() throws IOException;
}
protected class ObjectDecodeIterator extends DecodeIterator<DecodedObjectMember> {
ObjectDecodeIterator(int size) {
super(size);
}
@Override
DecodedObjectMember getNext() throws IOException {
var memberLen = unpacker.unpackArrayHeader();
if (memberLen != 3) {
throw new DecodeException("Expected 3 fields in object member, found %d", memberLen);
}
var memberCodeInt = unpacker.unpackInt();
var memberCode = PklBinaryCode.fromInt(memberCodeInt);
if (memberCode == null) {
throw new DecodeException("Unrecognized code 0x%x", (byte) memberCodeInt);
}
DecodedObjectMember member;
switch (memberCode) {
case PROPERTY -> {
var propertyName = unpacker.unpackString();
currPath.push(propertyName);
member = new DecodedObjectMember(memberCode, propertyName, doDecode());
}
case ENTRY -> {
var entryKey = doDecode();
currPath.push(entryKey);
member = new DecodedObjectMember(memberCode, entryKey, doDecode());
}
case ELEMENT -> {
var elementIndex = unpacker.unpackLong();
currPath.push(elementIndex);
member = new DecodedObjectMember(memberCode, elementIndex, doDecode());
}
default -> throw new DecodeException("Unrecognized member code %s", memberCode);
}
currPath.pop();
return member;
}
}
protected class CollectionDecodeIterator extends DecodeIterator<Object> {
CollectionDecodeIterator(int size) {
super(size);
}
@Override
Object getNext() throws IOException {
return doDecode();
}
}
protected class MapDecodeIterator extends DecodeIterator<Pair<Object, Object>> {
MapDecodeIterator(int size) {
super(size);
}
@Override
Pair<Object, Object> getNext() throws IOException {
var key = doDecode();
currPath.push(key);
var val = doDecode();
currPath.pop();
return new Pair<>(key, val);
}
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright © 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.core.util.pklbinary;
import org.pkl.core.util.Nullable;
public enum PklBinaryCode {
OBJECT((byte) 0x01),
MAP((byte) 0x02),
MAPPING((byte) 0x03),
LIST((byte) 0x04),
LISTING((byte) 0x05),
SET((byte) 0x06),
DURATION((byte) 0x07),
DATASIZE((byte) 0x08),
PAIR((byte) 0x09),
INTSEQ((byte) 0x0A),
REGEX((byte) 0x0B),
CLASS((byte) 0x0C),
TYPEALIAS((byte) 0x0D),
FUNCTION((byte) 0x0E),
BYTES((byte) 0x0F),
PROPERTY((byte) 0x10),
ENTRY((byte) 0x11),
ELEMENT((byte) 0x12);
private final byte code;
PklBinaryCode(byte code) {
this.code = code;
}
public byte getCode() {
return code;
}
public static @Nullable PklBinaryCode fromInt(int value) {
return switch (value) {
case 0x01 -> PklBinaryCode.OBJECT;
case 0x02 -> PklBinaryCode.MAP;
case 0x03 -> PklBinaryCode.MAPPING;
case 0x04 -> PklBinaryCode.LIST;
case 0x05 -> PklBinaryCode.LISTING;
case 0x06 -> PklBinaryCode.SET;
case 0x07 -> PklBinaryCode.DURATION;
case 0x08 -> PklBinaryCode.DATASIZE;
case 0x09 -> PklBinaryCode.PAIR;
case 0x0A -> PklBinaryCode.INTSEQ;
case 0x0B -> PklBinaryCode.REGEX;
case 0x0C -> PklBinaryCode.CLASS;
case 0x0D -> PklBinaryCode.TYPEALIAS;
case 0x0E -> PklBinaryCode.FUNCTION;
case 0x0F -> PklBinaryCode.BYTES;
case 0x10 -> PklBinaryCode.PROPERTY;
case 0x11 -> PklBinaryCode.ENTRY;
case 0x12 -> PklBinaryCode.ELEMENT;
default -> null;
};
}
}

View File

@@ -0,0 +1,4 @@
@NonnullByDefault
package org.pkl.core.util.pklbinary;
import org.pkl.core.util.NonnullByDefault;

View File

@@ -0,0 +1,48 @@
open module encoding1
import "pkl:pklbinary"
import "pkl:base"
class Foo {
dynamic: Dynamic = new {
hello = "world"
["hello"] = "world"
"hello world"
}
string: String = "foo"
map = Map("foo", "bar")
mapping: Mapping = new { ["foo"] = "bar" }
list = List("foo", "bar")
listing: Listing = new { "foo"; 0 }
set = Set("foo", "bar")
duration = 123.h
dataSize = 123.gib
pair = Pair("foo", "bar")
intSeq = IntSeq(123, 456)
regex = Regex("foo.*")
func: ((String, Int) -> Boolean)? =
(a, b) -> a.sha256Int + b % 2 == 0
bytes = Bytes(0x01, 0x02, 0x03)
moduleClass: Class
baseModuleClass: Class = base.getClass()
pklbinaryModuleClass: Class = pklbinary.getClass()
stdlibClass: Class = PcfRenderer
someClass: Class = Foo
stdlibTypealias: TypeAlias = UInt
someTypealias: TypeAlias = Bar
something: Any = new PcfRenderer {} // a non-external class from pkl:base
}
typealias Bar = Mapping<String, String>
classInstance: Foo = new {
moduleClass = Map(true, module.getClass())[true]
}
hidden noFunc: Foo = (classInstance) { func = null }
hidden encoded: Bytes = new pklbinary.Renderer {}.renderValue(noFunc)
output {
bytes = encoded
}

View File

@@ -0,0 +1,9 @@
extends ".../pklbinaryTest.pkl"
res1 = "bar"
res2 = ""
res3 = 1
res4 = 2.3
res5 = true
res6 = false
res7 = null

View File

@@ -0,0 +1,27 @@
module com.foo.bar.MyModule
extends ".../pklbinaryTest.pkl"
class Person {
firstName: String
lastName: String
age: Int
}
barnOwl: Person = new {
firstName = "Barn Owl"
lastName = "Bird"
age = 38
}
pigeon: Person = new {
firstName = "Pigeon"
lastName = "Bird"
age = 41
}
typealias MyPerson = Person
personClass = Person
personTypeAlias = MyPerson

View File

@@ -0,0 +1,13 @@
extends ".../pklbinaryTest.pkl"
res1: DataSize = 1.b
res2: DataSize = 2.kb
res3: DataSize = 3.kib
res4: DataSize = 4.mb
res5: DataSize = 5.mib
res6: DataSize = 6.gb
res7: DataSize = 7.gib
res8: DataSize = 8.tb
res9: DataSize = 9.tib
res10: DataSize = 10.pb
res11: DataSize = 11.pib

View File

@@ -0,0 +1,9 @@
extends ".../pklbinaryTest.pkl"
res1 = 1.ns
res2 = 2.us
res3 = 3.ms
res4 = 4.s
res5 = 5.min
res6 = 6.h
res7 = 7.d

View File

@@ -0,0 +1,4 @@
extends ".../pklbinaryTest.pkl"
res1 = IntSeq(1, 3)
res2 = IntSeq(1, 4).step(5)

View File

@@ -0,0 +1,8 @@
extends ".../pklbinaryTest.pkl"
res1: List<Int> = List(1, 3, 5, 7)
res2: Listing<Int> = new { 2; 4; 6; 8 }
res3: List<Int> = List()
res4: Listing<Int> = new {}
res5: List<List<Int>> = List(List(1, 2))
res6: Listing<Listing<Int>> = new { new { 1; 2 } }

View File

@@ -0,0 +1,23 @@
extends ".../pklbinaryTest.pkl"
res1: Map = Map("foo", 1, "bar", 2)
res2: Mapping = new {
["foo"] = 1
["bar"] = 2
}
res3: Mapping = new {
["childMap"] = new Mapping {
["childFoo"] = 3
}
}
res4: Mapping = new {
[Map("foo", 1)] = new Mapping {
["bar"] = 2
}
}
// https://github.com/apple/pkl/issues/1151
res5: Mapping = new {
local self = this
["foo"] = new Dynamic { name = "foo" }
["bar"] = new Dynamic { name = self["foo"].name + "bar" }
}

View File

@@ -0,0 +1,4 @@
extends ".../pklbinaryTest.pkl"
res1 = Pair(1, 2)
res2 = Pair("foo", "bar")

View File

@@ -0,0 +1,5 @@
extends ".../pklbinaryTest.pkl"
res1 = Regex("abc")
res2 = Regex("")
res3 = Regex("(?m)^abc$")

View File

@@ -0,0 +1,5 @@
extends ".../pklbinaryTest.pkl"
res1: Set<Int> = Set(1, 3, 5, 7)
res2: Set<Int> = Set()
res3: Set<Any> = Set(1, true, "", null)

View File

@@ -0,0 +1,13 @@
open module pklbinaryTest
import "pkl:pklbinary"
output {
// ensure no output file written for this specific module, only children that add properties
when (module.toMap().isEmpty) {
text = ""
} else {
value = if (module.toMap().isEmpty) "" else module
renderer = new pklbinary.Renderer {}
}
}

View File

@@ -8,10 +8,10 @@ at pkl.base#JsonRenderer.renderDocument (file:///$snippetsDir/input/api/jsonRend
Consider adding a converter to `output.converters`.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -8,10 +8,10 @@ at pkl.jsonnet#Renderer.renderDocument (file:///$snippetsDir/input/api/jsonnetRe
Consider adding a converter to `output.converters`.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -8,10 +8,10 @@ at pkl.base#PListRenderer.renderDocument (file:///$snippetsDir/input/api/pListRe
Consider adding a converter to `output.converters`.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -8,10 +8,10 @@ at pkl.base#PcfRenderer.renderDocument (file:///$snippetsDir/input/api/pcfRender
Consider adding a converter to `output.converters`.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -0,0 +1,190 @@
- 1
- 'encoding1#Foo'
- 'file:///$snippetsDir/input/api/pklbinary1.msgpack.yaml.pkl'
-
-
- 16
- 'dynamic'
-
- 1
- 'Dynamic'
- 'pkl:base'
-
-
- 16
- 'hello'
- 'world'
-
- 17
- 'hello'
- 'world'
-
- 18
- 0
- 'hello world'
-
- 16
- 'string'
- 'foo'
-
- 16
- 'map'
-
- 2
-
'foo': 'bar'
-
- 16
- 'mapping'
-
- 3
-
'foo': 'bar'
-
- 16
- 'list'
-
- 4
-
- 'foo'
- 'bar'
-
- 16
- 'listing'
-
- 5
-
- 'foo'
- 0
-
- 16
- 'set'
-
- 6
-
- 'foo'
- 'bar'
-
- 16
- 'duration'
-
- 7
- 123.0
- 'h'
-
- 16
- 'dataSize'
-
- 8
- 123.0
- 'gib'
-
- 16
- 'pair'
-
- 9
- 'foo'
- 'bar'
-
- 16
- 'intSeq'
-
- 10
- 123
- 456
- 1
-
- 16
- 'regex'
-
- 11
- 'foo.*'
-
- 16
- 'func'
- null
-
- 16
- 'bytes'
-
- 15
- !!binary 'AQID'
-
- 16
- 'moduleClass'
-
- 12
- 'encoding1'
- 'file:///$snippetsDir/input/api/pklbinary1.msgpack.yaml.pkl'
-
- 16
- 'baseModuleClass'
-
- 12
- 'ModuleClass'
- 'pkl:base'
-
- 16
- 'pklbinaryModuleClass'
-
- 12
- 'pkl.pklbinary'
- 'pkl:pklbinary'
-
- 16
- 'stdlibClass'
-
- 12
- 'PcfRenderer'
- 'pkl:base'
-
- 16
- 'someClass'
-
- 12
- 'encoding1#Foo'
- 'file:///$snippetsDir/input/api/pklbinary1.msgpack.yaml.pkl'
-
- 16
- 'stdlibTypealias'
-
- 13
- 'UInt'
- 'pkl:base'
-
- 16
- 'someTypealias'
-
- 13
- 'encoding1#Bar'
- 'file:///$snippetsDir/input/api/pklbinary1.msgpack.yaml.pkl'
-
- 16
- 'something'
-
- 1
- 'PcfRenderer'
- 'pkl:base'
-
-
- 16
- 'converters'
-
- 3
- {}
-
- 16
- 'extension'
- 'pcf'
-
- 16
- 'indent'
- ' '
-
- 16
- 'omitNullProperties'
- false
-
- 16
- 'useCustomStringDelimiters'
- false

View File

@@ -8,10 +8,10 @@ at propertiesRenderer10.properties#foo (file:///$snippetsDir/input/api/propertie
Consider adding a converter to `output.converters`.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -8,10 +8,10 @@ at pkl.base#PropertiesRenderer.renderDocument (file:///$snippetsDir/input/api/pr
Consider adding a converter to `output.converters`.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -8,7 +8,7 @@ res7 = "Cannot render value of type `DataSize` as Properties. Value: 1.mb"
res8 = "Cannot render value of type `List` as Properties. Value: List(\"pigeon\", \"parrot\")"
res9 = "Cannot render value of type `Set` as Properties. Value: Set(\"pigeon\", \"parrot\")"
res10 = "Cannot render value of type `Map` as Properties. Value: Map(\"name\", \"pigeon\", \"age\", 42)"
res11 = "Cannot render value of type `Listing` as Properties. Value: new Listing { ?; ? }"
res11 = "Cannot render value of type `Listing` as Properties. Value: new Listing { \"pigeon\"; \"parrot\" }"
res12 = "Cannot render value of type `Mapping` as Properties. Value: new Mapping { [\"name\"] = ?; [\"age\"] = ? }"
res13 = "Cannot render value of type `Dynamic` as Properties. Value: new Dynamic { name = ?; age = ? }"
res14 = "Cannot render value of type `propertiesRenderer4#Person` as Properties. Value: new Person { name = ?; age = ? }"

View File

@@ -8,10 +8,10 @@ at pkl.xml#Renderer.renderDocument (file:///$snippetsDir/input/api/xmlRenderer8.
Consider adding a converter to `output.converters`.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -4,6 +4,6 @@
<name>Pigeon</name>
<age>42</age>
</pigeon2>
<res2>`xml.Element` is not supported here. Value: new Dynamic { _isXmlElement = true; name = ?; attributes = ?; isBlockFormat =...</res2>
<res3>`xml.Inline` is not supported here. Value: new Inline { value = ? }</res3>
<res2>`xml.Element` is not supported here. Value: new Dynamic { _isXmlElement = true; name = &quot;pigeon2&quot;; attributes {}; isBlockF...</res2>
<res3>`xml.Inline` is not supported here. Value: new Inline { value { name = ?; age = ? } }</res3>
</root>

View File

@@ -8,10 +8,10 @@ at pkl.base#YamlRenderer.renderDocument (file:///$snippetsDir/input/api/yamlRend
Consider adding a converter to `output.converters`.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -5,10 +5,10 @@ x | bar = throw("Something went wrong")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at exceptions#foo.bar (file:///$snippetsDir/input/basic/exceptions.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -8,10 +8,10 @@ at class3#person (file:///$snippetsDir/input/classes/class3.pkl)
Did you mean any of the following?
address
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -10,10 +10,10 @@ xx | max = 3
^
at constraints5#res2.max (file:///$snippetsDir/input/classes/constraints5.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -8,10 +8,10 @@ at inheritanceError1#Derived (file:///$snippetsDir/input/classes/inheritanceErro
By default, classes are closed for extension.
To make a class extensible, add an `open` modifier: `open class MyClass { ... }`
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -10,10 +10,10 @@ Examples:
* `123` uses literal syntax to create an instance of class `Int`.
* `Pair(1, 2)` uses the `Pair()` constructor method to create an instance of class `Pair`.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -8,10 +8,10 @@ at invalidInstantiation2#res1 (file:///$snippetsDir/input/classes/invalidInstant
Abstract classes cannot be instantiated.
Instead, instantiate a concrete subclass.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ xx | a = "other"
^^^^^^^
at unionTypesErrorAlias#res1.a (file:///$snippetsDir/input/classes/unionTypesErrorAlias.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -14,10 +14,10 @@ x | a = List(1, 3.14, 2)
^^^^^^^^^^^^^^^^
at unionTypesErrorDifferent1#res1.a (file:///$snippetsDir/input/classes/unionTypesErrorDifferent1.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -14,10 +14,10 @@ x | a = List(1, 2, 3)
^^^^^^^^^^^^^
at unionTypesErrorDifferent2#res1.a (file:///$snippetsDir/input/classes/unionTypesErrorDifferent2.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -18,10 +18,10 @@ x | res1: Alias1|Alias2 = new Dynamic { }
^^^^^^^^^^^^^^^
at unionTypesErrorMultipleAliases#res1 (file:///$snippetsDir/input/classes/unionTypesErrorMultipleAliases.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -18,10 +18,10 @@ x | a = Map(
^^^^
at unionTypesErrorNested#res1.a (file:///$snippetsDir/input/classes/unionTypesErrorNested.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -10,10 +10,10 @@ x | a = 42
^^
at unionTypesErrorSimple#res1.a (file:///$snippetsDir/input/classes/unionTypesErrorSimple.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ x | a = "foox"
^^^^^^
at unionTypesErrorString1#res1.a (file:///$snippetsDir/input/classes/unionTypesErrorString1.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ xx | a = "other"
^^^^^^^
at unionTypesErrorString2#res1.a (file:///$snippetsDir/input/classes/unionTypesErrorString2.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -10,10 +10,10 @@ x | name = 42
^^
at wrongType1#pigeon.name (file:///$snippetsDir/input/classes/wrongType1.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -10,10 +10,10 @@ x | age = "42"
^^^^
at wrongType2#pigeon.age (file:///$snippetsDir/input/classes/wrongType2.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -10,10 +10,10 @@ xx | address = "Howdy St."
^^^^^^^^^^^
at wrongType3#person.address (file:///$snippetsDir/input/classes/wrongType3.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -10,10 +10,10 @@ xx | street = 4.gb
^^^^
at wrongType4#person.address.street (file:///$snippetsDir/input/classes/wrongType4.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -10,10 +10,10 @@ x | names: List<String>(!isEmpty)
^^^^^
at wrongType6#Person.names (file:///$snippetsDir/input/classes/wrongType6.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ x | res = analyze.importGraph(Set(reflect.Module(cannotFindModule).uri))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at analyzeImportsCannotFindModule#res (file:///$snippetsDir/input/errors/analyzeImportsCannotFindModule.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ x | res = analyze.importGraph(Set(reflect.Module(invalidGlob).uri))
^^^^^^^^^^^
at analyzeImportsInvalidGlob#res (file:///$snippetsDir/input/errors/analyzeImportsInvalidGlob.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -7,10 +7,10 @@ at analyzeInvalidModuleUri#result (file:///$snippetsDir/input/errors/analyzeInva
Illegal character in path at index 3: foo <>
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -5,10 +5,10 @@ x | result = analyze.importGraph(Set("foo.pkl"))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at analyzeRelativeModuleUri#result (file:///$snippetsDir/input/errors/analyzeRelativeModuleUri.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -2,12 +2,12 @@
The top-level value of a Pcf document must have type `Typed` or `Dynamic`, but got type `String`.
Value: "anyConverterError"
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
This value was converted during rendering. Previous: new ModuleClass {}. After: "anyConverterError".
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -5,10 +5,10 @@ xx | bird {
^^^^
at cannotAmendFixedProperty1#n (file:///$snippetsDir/input/errors/cannotAmendFixedProperty1.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -5,10 +5,10 @@ x | name = _name
^^^^
at cannotAssignFixedProperty1#p (file:///$snippetsDir/input/errors/cannotAssignFixedProperty1.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ x | ...new Dynamic { name = "Osprey" }
^^^^
at cannotAssignFixedProperty3#p.name (file:///$snippetsDir/input/errors/cannotAssignFixedProperty3.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -12,10 +12,10 @@ x | value: nothing = "foo"
^^^^^
at cannotAssignToNothing#value (file:///$snippetsDir/input/errors/cannotAssignToNothing.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -7,10 +7,10 @@ at cannotChangeFixed1#Dog (file:///$snippetsDir/input/errors/cannotChangeFixed1.
Property `name` must be declared fixed, because it overrides a fixed property on parent class `cannotChangeFixed1#Animal`.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -7,10 +7,10 @@ at cannotChangeFixed2#Dog (file:///$snippetsDir/input/errors/cannotChangeFixed2.
Property `name` cannot be declared fixed, because it overrides a non-fixed property on parent class `cannotChangeFixed2#Animal`.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -10,10 +10,10 @@ Did you mean any of the following?
"foyo"
"xfoo"
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -15,6 +15,7 @@ pkl:EvaluatorSettings
pkl:json
pkl:jsonnet
pkl:math
pkl:pklbinary
pkl:platform
pkl:Project
pkl:protobuf
@@ -31,10 +32,10 @@ x | res1 = nonExisting.bar
^^^^^^^^^^^
at cannotFindStdLibModule#res1 (file:///$snippetsDir/input/errors/cannotFindStdLibModule.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -8,10 +8,10 @@ at cannotInstantiateAbstractModule#res1 (file:///$snippetsDir/input/errors/canno
Abstract classes cannot be instantiated.
Instead, instantiate a concrete subclass.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -8,10 +8,10 @@ at pkl.base#PcfRenderer.renderDocument (file:///$snippetsDir/input/errors/cannot
Consider adding a converter to `output.converters`.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ To fix, do either of:
1. Add modifier `const` to method `f1`
2. Self-import this module, and reference this method from the import.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ To fix, do either of:
1. Add modifier `const` to property `top`
2. Self-import this module, and reference this property from the import.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ To fix, do either of:
1. Add modifier `const` to property `notConst`
2. Self-import this module, and reference this property from the import.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ To fix, do either of:
1. Add modifier `const` to property `a`
2. Self-import this module, and reference this property from the import.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ To fix, do either of:
1. Add modifier `const` to method `a`
2. Self-import this module, and reference this method from the import.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -13,10 +13,10 @@ x | res = constFunctionCallingNonConst().apply("prefix")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at constFunctionCallingNonConst#res (file:///$snippetsDir/input/errors/const/constFunctionCallingNonConst.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ To fix, do either of:
1. Add modifier `const` to property `a`
2. Self-import this module, and reference this property from the import.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ To fix, do either of:
1. Add modifier `const` to method `a`
2. Self-import this module, and reference this method from the import.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ To fix, do either of:
1. Add modifier `const` to property `bar`
2. Self-import this module, and reference this property from the import.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -13,10 +13,10 @@ x | res = foo()
^^^^^
at constLocalMethod#obj.res (file:///$snippetsDir/input/errors/const/constLocalMethod.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -13,10 +13,10 @@ x | res2 = qux
^^^
at constLocalProperty#foo.res2 (file:///$snippetsDir/input/errors/const/constLocalProperty.pkl)
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ To fix, do either of:
1. Add modifier `const` to method `fun`
2. Self-import this module, and reference this method from the import.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ To fix, do either of:
1. Add modifier `const` to method `bar`
2. Self-import this module, and reference this method from the import.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ To fix, do either of:
1. Add modifier `const` to property `notConst`
2. Self-import this module, and reference this property from the import.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ To fix, do either of:
1. Add modifier `const` to property `notConst`
2. Self-import this module, and reference this property from the import.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

View File

@@ -9,10 +9,10 @@ To fix, do either of:
1. Add modifier `const` to property `name`
2. Self-import this module, and reference this property from the import.
xxx | text = renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
xxx | renderer.renderDocument(value)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
at pkl.base#Module.output.text (pkl:base)
xxx | bytes = text.encodeToBytes("UTF-8")
^^^^
xxx | if (renderer is BytesRenderer) renderer.renderDocument(value) else text.encodeToBytes("UTF-8")
^^^^
at pkl.base#Module.output.bytes (pkl:base)

Some files were not shown because too many files have changed in this diff Show More