mirror of
https://github.com/apple/pkl.git
synced 2026-07-07 05:25:17 +02:00
Overhaul implementation of for-generators (#844)
Motivation:
* fix known bugs and limitations of for-generators
* improve code health by removing complex workarounds
Changes:
* simplify AstBuilder code related to for-generators
* track for-generators via `SymbolTable.enterForGenerator()`
* add `RestoreForBindingsNode` during initial AST construction
instead of calling `MemberNode.replaceBody()` later on
* simplify some unnecessarily complex code
* remove workarounds and band-aids such as:
* `isInIterable`
* `executeAndSetEagerly`
* adding dummy slots in `AmendFunctionNode`
* overhaul implementation of for-generators
* store keys and values of for-generator iterations in regular instead of auxiliary frame slots
* set them via `TypeNode.executeAndSet()`
* `ResolveVariableNode` no longer needs to search auxiliary slots
* `Read(Enclosing)AuxiliarySlot` is no longer needed
* at the start of each for-generator iteration, create a new `VirtualFrame`
that is a copy of the current frame (arguments + slots)
and stores the iteration key and value in additional slots.
* execute for-generator iteration with the newly created frame
* `childNode.execute(newFrame)`
* Pkl objects created during the iteration will materialize this frame
* store newly created frames in `owner.extraStorage`
if their for-generator slots may be accessed when a generated member is executed
* resolving variable names to for-generator variables at parse time would make this analysis more precise
* when a generated member is executed,
* retrieve the corresponding frame stored in `owner.extraStorage`
* copy the retrieved frame's for-generator slots into slots of the current frame
Result:
* for-generators are implemented in a correct, reasonably simple, and reasonably efficient way
* complexity is fully contained within package `generator` and `AstBuilder`
* for-generator keys and values can be accessed from all nested scopes:
* key and value expressions of generated members
* condition expressions of nested when-generators
* iterable expressions of nested for-generators
* for-generator keys and values can be accessed from within objects created by the expressions listed above
* sibling for-generators can use the same key/value variable names
* parent/child for-generators can use the same key/value variable names
* fixes https://github.com/apple/pkl/issues/741
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -17,7 +17,6 @@ package org.pkl.core.ast;
|
|||||||
|
|
||||||
import com.oracle.truffle.api.frame.FrameDescriptor;
|
import com.oracle.truffle.api.frame.FrameDescriptor;
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
import java.util.function.Function;
|
|
||||||
import org.pkl.core.ast.member.DefaultPropertyBodyNode;
|
import org.pkl.core.ast.member.DefaultPropertyBodyNode;
|
||||||
import org.pkl.core.runtime.VmExceptionBuilder;
|
import org.pkl.core.runtime.VmExceptionBuilder;
|
||||||
import org.pkl.core.runtime.VmLanguage;
|
import org.pkl.core.runtime.VmLanguage;
|
||||||
@@ -43,10 +42,6 @@ public abstract class MemberNode extends PklRootNode {
|
|||||||
return bodyNode;
|
return bodyNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void replaceBody(Function<ExpressionNode, ExpressionNode> replacer) {
|
|
||||||
bodyNode = insert(replacer.apply(bodyNode));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected final VmExceptionBuilder exceptionBuilder() {
|
protected final VmExceptionBuilder exceptionBuilder() {
|
||||||
return new VmExceptionBuilder().withSourceSection(getHeaderSection());
|
return new VmExceptionBuilder().withSourceSection(getHeaderSection());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -55,9 +55,6 @@ public final class VmModifier {
|
|||||||
|
|
||||||
public static final int GLOB = 0x1000;
|
public static final int GLOB = 0x1000;
|
||||||
|
|
||||||
// To be removed when https://github.com/apple/pkl/issues/741 is fixed
|
|
||||||
public static final int IS_IN_ITERABLE = 0x100000;
|
|
||||||
|
|
||||||
// modifier sets
|
// modifier sets
|
||||||
|
|
||||||
public static final int NONE = 0;
|
public static final int NONE = 0;
|
||||||
@@ -137,10 +134,6 @@ public final class VmModifier {
|
|||||||
return (modifiers & ENTRY) != 0;
|
return (modifiers & ENTRY) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isInIterable(int modifiers) {
|
|
||||||
return (modifiers & IS_IN_ITERABLE) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isType(int modifiers) {
|
public static boolean isType(int modifiers) {
|
||||||
return (modifiers & (CLASS | TYPE_ALIAS | IMPORT)) != 0 && (modifiers & GLOB) == 0;
|
return (modifiers & (CLASS | TYPE_ALIAS | IMPORT)) != 0 && (modifiers & GLOB) == 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -25,7 +25,6 @@ import java.io.IOException;
|
|||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.antlr.v4.runtime.ParserRuleContext;
|
import org.antlr.v4.runtime.ParserRuleContext;
|
||||||
@@ -40,7 +39,6 @@ import org.pkl.core.TypeParameter.Variance;
|
|||||||
import org.pkl.core.ast.*;
|
import org.pkl.core.ast.*;
|
||||||
import org.pkl.core.ast.builder.SymbolTable.AnnotationScope;
|
import org.pkl.core.ast.builder.SymbolTable.AnnotationScope;
|
||||||
import org.pkl.core.ast.builder.SymbolTable.ClassScope;
|
import org.pkl.core.ast.builder.SymbolTable.ClassScope;
|
||||||
import org.pkl.core.ast.builder.SymbolTable.EntryScope;
|
|
||||||
import org.pkl.core.ast.builder.SymbolTable.Scope;
|
import org.pkl.core.ast.builder.SymbolTable.Scope;
|
||||||
import org.pkl.core.ast.expression.binary.*;
|
import org.pkl.core.ast.expression.binary.*;
|
||||||
import org.pkl.core.ast.expression.generator.*;
|
import org.pkl.core.ast.expression.generator.*;
|
||||||
@@ -852,20 +850,20 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GeneratorPropertyNode visitObjectProperty(ObjectPropertyContext ctx) {
|
public GeneratorPropertyNode visitObjectProperty(ObjectPropertyContext ctx) {
|
||||||
checkHasNoForGenerator(ctx, "forGeneratorCannotGenerateProperties");
|
checkNotInsideForGenerator(ctx, "forGeneratorCannotGenerateProperties");
|
||||||
var member = doVisitObjectProperty(ctx);
|
var member = doVisitObjectProperty(ctx);
|
||||||
return GeneratorPropertyNodeGen.create(member);
|
return GeneratorPropertyNodeGen.create(member);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GeneratorMemberNode visitObjectMethod(ObjectMethodContext ctx) {
|
public GeneratorMemberNode visitObjectMethod(ObjectMethodContext ctx) {
|
||||||
checkHasNoForGenerator(ctx, "forGeneratorCannotGenerateMethods");
|
checkNotInsideForGenerator(ctx, "forGeneratorCannotGenerateMethods");
|
||||||
var member = doVisitObjectMethod(ctx);
|
var member = doVisitObjectMethod(ctx);
|
||||||
return GeneratorPropertyNodeGen.create(member);
|
return GeneratorPropertyNodeGen.create(member);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkHasNoForGenerator(ParserRuleContext ctx, String errorMessageKey) {
|
private void checkNotInsideForGenerator(ParserRuleContext ctx, String errorMessageKey) {
|
||||||
if (symbolTable.getCurrentScope().getForGeneratorVariables().isEmpty()) {
|
if (!symbolTable.getCurrentScope().isForGeneratorScope()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var forExprCtx = ctx.getParent();
|
var forExprCtx = ctx.getParent();
|
||||||
@@ -880,12 +878,19 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GeneratorMemberNode visitMemberPredicate(MemberPredicateContext ctx) {
|
public GeneratorMemberNode visitMemberPredicate(MemberPredicateContext ctx) {
|
||||||
var keyNodeAndMember = doVisitMemberPredicate(ctx);
|
if (ctx.err1 == null && ctx.err2 == null) {
|
||||||
var keyNode = keyNodeAndMember.first;
|
throw missingDelimiter("]]", ctx.k.stop.getStopIndex() + 1);
|
||||||
var member = keyNodeAndMember.second;
|
} else if (ctx.err1 != null
|
||||||
insertWriteForGeneratorVarsToFrameSlotsNode(member.getMemberNode());
|
&& (ctx.err2 == null || ctx.err1.getStartIndex() != ctx.err2.getStartIndex() - 1)) {
|
||||||
|
// There shouldn't be any whitespace between the first and second ']'.
|
||||||
|
throw wrongDelimiter("]]", "]", ctx.err1.getStartIndex());
|
||||||
|
}
|
||||||
|
|
||||||
return GeneratorPredicateMemberNodeGen.create(keyNode, member);
|
var keyNode = symbolTable.enterCustomThisScope(scope -> visitExpr(ctx.k));
|
||||||
|
var member = doVisitObjectEntryBody(createSourceSection(ctx), keyNode, ctx.v, ctx.objectBody());
|
||||||
|
var isFrameStored =
|
||||||
|
member.getMemberNode() != null && symbolTable.getCurrentScope().isForGeneratorScope();
|
||||||
|
return GeneratorPredicateMemberNodeGen.create(keyNode, member, isFrameStored);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -893,43 +898,23 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
var keyNodeAndMember = doVisitObjectEntry(ctx);
|
var keyNodeAndMember = doVisitObjectEntry(ctx);
|
||||||
var keyNode = keyNodeAndMember.first;
|
var keyNode = keyNodeAndMember.first;
|
||||||
var member = keyNodeAndMember.second;
|
var member = keyNodeAndMember.second;
|
||||||
insertWriteForGeneratorVarsToFrameSlotsNode(member.getMemberNode());
|
var isFrameStored =
|
||||||
|
member.getMemberNode() != null && symbolTable.getCurrentScope().isForGeneratorScope();
|
||||||
return GeneratorEntryNodeGen.create(keyNode, member);
|
return GeneratorEntryNodeGen.create(keyNode, member, isFrameStored);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GeneratorMemberNode visitObjectSpread(ObjectSpreadContext ctx) {
|
public GeneratorMemberNode visitObjectSpread(ObjectSpreadContext ctx) {
|
||||||
var scope = symbolTable.getCurrentScope();
|
|
||||||
var visitingIterable = scope.isVisitingIterable();
|
|
||||||
scope.setVisitingIterable(true);
|
|
||||||
var expr = visitExpr(ctx.expr());
|
var expr = visitExpr(ctx.expr());
|
||||||
scope.setVisitingIterable(visitingIterable);
|
|
||||||
return GeneratorSpreadNodeGen.create(createSourceSection(ctx), expr, ctx.QSPREAD() != null);
|
return GeneratorSpreadNodeGen.create(createSourceSection(ctx), expr, ctx.QSPREAD() != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void insertWriteForGeneratorVarsToFrameSlotsNode(@Nullable MemberNode memberNode) {
|
|
||||||
if (memberNode == null) return; // member has constant value
|
|
||||||
|
|
||||||
var descriptor = memberNode.getFrameDescriptor();
|
|
||||||
var forGeneratorVars = symbolTable.getCurrentScope().getForGeneratorVariables();
|
|
||||||
if (forGeneratorVars.isEmpty()) {
|
|
||||||
return; // node is not within a for generator
|
|
||||||
}
|
|
||||||
var slots = new int[forGeneratorVars.size()];
|
|
||||||
var i = 0;
|
|
||||||
for (var variable : forGeneratorVars) {
|
|
||||||
slots[i] = descriptor.findOrAddAuxiliarySlot(variable);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
memberNode.replaceBody((bodyNode) -> new WriteForVariablesNode(slots, bodyNode));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GeneratorElementNode visitObjectElement(ObjectElementContext ctx) {
|
public GeneratorElementNode visitObjectElement(ObjectElementContext ctx) {
|
||||||
var member = doVisitObjectElement(ctx);
|
var member = doVisitObjectElement(ctx);
|
||||||
insertWriteForGeneratorVarsToFrameSlotsNode(member.getMemberNode());
|
var isFrameStored =
|
||||||
return GeneratorElementNodeGen.create(member);
|
member.getMemberNode() != null && symbolTable.getCurrentScope().isForGeneratorScope();
|
||||||
|
return GeneratorElementNodeGen.create(member, isFrameStored);
|
||||||
}
|
}
|
||||||
|
|
||||||
private GeneratorMemberNode[] doVisitForWhenBody(ObjectBodyContext ctx) {
|
private GeneratorMemberNode[] doVisitForWhenBody(ObjectBodyContext ctx) {
|
||||||
@@ -953,18 +938,6 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
return new GeneratorWhenNode(sourceSection, visitExpr(ctx.e), thenNodes, elseNodes);
|
return new GeneratorWhenNode(sourceSection, visitExpr(ctx.e), thenNodes, elseNodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int pushForGeneratorVariableContext(ParameterContext ctx) {
|
|
||||||
var currentScope = symbolTable.getCurrentScope();
|
|
||||||
var slot = currentScope.pushForGeneratorVariableContext(ctx);
|
|
||||||
if (slot == -1) {
|
|
||||||
throw exceptionBuilder()
|
|
||||||
.evalError("duplicateDefinition", ctx.typedIdentifier().Identifier().getText())
|
|
||||||
.withSourceSection(createSourceSection(ctx))
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
return slot;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean isIgnored(@Nullable ParameterContext param) {
|
private static boolean isIgnored(@Nullable ParameterContext param) {
|
||||||
return param != null && param.UNDERSCORE() != null;
|
return param != null && param.UNDERSCORE() != null;
|
||||||
}
|
}
|
||||||
@@ -972,53 +945,68 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
@Override
|
@Override
|
||||||
public GeneratorForNode visitForGenerator(ForGeneratorContext ctx) {
|
public GeneratorForNode visitForGenerator(ForGeneratorContext ctx) {
|
||||||
checkClosingDelimiter(ctx.err, ")", ctx.e.stop);
|
checkClosingDelimiter(ctx.err, ")", ctx.e.stop);
|
||||||
var sourceSection = createSourceSection(ctx);
|
var keyParameter = ctx.t2 == null ? null : ctx.t1;
|
||||||
int keyVariableSlot;
|
var valueParameter = ctx.t2 == null ? ctx.t1 : ctx.t2;
|
||||||
int valueVariableSlot;
|
var keyTypedIdentifier = keyParameter == null ? null : keyParameter.typedIdentifier();
|
||||||
UnresolvedTypeNode unresolvedKeyTypeNode;
|
var valueTypedIdentifier = valueParameter == null ? null : valueParameter.typedIdentifier();
|
||||||
UnresolvedTypeNode unresolvedValueTypeNode;
|
var keyIdentifier =
|
||||||
|
keyTypedIdentifier == null ? null : toIdentifier(keyTypedIdentifier.Identifier());
|
||||||
|
var valueIdentifier =
|
||||||
|
valueTypedIdentifier == null ? null : toIdentifier(valueTypedIdentifier.Identifier());
|
||||||
|
if (valueIdentifier != null && valueIdentifier == keyIdentifier) {
|
||||||
|
throw exceptionBuilder()
|
||||||
|
.evalError("duplicateDefinition", valueIdentifier)
|
||||||
|
.withSourceSection(createSourceSection(valueTypedIdentifier.Identifier()))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
var currentScope = symbolTable.getCurrentScope();
|
var currentScope = symbolTable.getCurrentScope();
|
||||||
var ignoreT1 = isIgnored(ctx.t1);
|
var generatorDescriptorBuilder = currentScope.newFrameDescriptorBuilder();
|
||||||
var ignoreT2 = ctx.t2 == null ? ignoreT1 : isIgnored(ctx.t2);
|
var memberDescriptorBuilder = currentScope.newForGeneratorMemberDescriptorBuilder();
|
||||||
|
var keySlot = -1;
|
||||||
if (ctx.t2 != null) {
|
var valueSlot = -1;
|
||||||
keyVariableSlot = ignoreT1 ? -1 : pushForGeneratorVariableContext(ctx.t1);
|
if (keyIdentifier != null) {
|
||||||
valueVariableSlot = ignoreT2 ? -1 : pushForGeneratorVariableContext(ctx.t2);
|
keySlot = generatorDescriptorBuilder.addSlot(FrameSlotKind.Illegal, keyIdentifier, null);
|
||||||
unresolvedKeyTypeNode =
|
memberDescriptorBuilder.addSlot(FrameSlotKind.Illegal, keyIdentifier, null);
|
||||||
ignoreT1 ? null : visitTypeAnnotation(ctx.t1.typedIdentifier().typeAnnotation());
|
|
||||||
unresolvedValueTypeNode =
|
|
||||||
ignoreT2 ? null : visitTypeAnnotation(ctx.t2.typedIdentifier().typeAnnotation());
|
|
||||||
} else {
|
|
||||||
keyVariableSlot = -1;
|
|
||||||
valueVariableSlot = ignoreT1 ? -1 : pushForGeneratorVariableContext(ctx.t1);
|
|
||||||
unresolvedKeyTypeNode = null;
|
|
||||||
unresolvedValueTypeNode =
|
|
||||||
ignoreT1 ? null : visitTypeAnnotation(ctx.t1.typedIdentifier().typeAnnotation());
|
|
||||||
}
|
}
|
||||||
|
if (valueIdentifier != null) {
|
||||||
var scope = symbolTable.getCurrentScope();
|
valueSlot = generatorDescriptorBuilder.addSlot(FrameSlotKind.Illegal, valueIdentifier, null);
|
||||||
var visitingIterable = scope.isVisitingIterable();
|
memberDescriptorBuilder.addSlot(FrameSlotKind.Illegal, valueIdentifier, null);
|
||||||
scope.setVisitingIterable(true);
|
}
|
||||||
|
var unresolvedKeyTypeNode =
|
||||||
|
keyTypedIdentifier == null
|
||||||
|
? null
|
||||||
|
: visitTypeAnnotation(keyTypedIdentifier.typeAnnotation());
|
||||||
|
var unresolvedValueTypeNode =
|
||||||
|
valueTypedIdentifier == null
|
||||||
|
? null
|
||||||
|
: visitTypeAnnotation(valueTypedIdentifier.typeAnnotation());
|
||||||
|
// if possible, initialize immediately to avoid later insert
|
||||||
|
var keyTypeNode =
|
||||||
|
unresolvedKeyTypeNode == null && keySlot != -1
|
||||||
|
? new TypeNode.UnknownTypeNode(VmUtils.unavailableSourceSection())
|
||||||
|
.initWriteSlotNode(keySlot)
|
||||||
|
: null;
|
||||||
|
// if possible, initialize immediately to avoid later insert
|
||||||
|
var valueTypeNode =
|
||||||
|
unresolvedValueTypeNode == null && valueSlot != -1
|
||||||
|
? new TypeNode.UnknownTypeNode(VmUtils.unavailableSourceSection())
|
||||||
|
.initWriteSlotNode(valueSlot)
|
||||||
|
: null;
|
||||||
var iterableNode = visitExpr(ctx.e);
|
var iterableNode = visitExpr(ctx.e);
|
||||||
scope.setVisitingIterable(visitingIterable);
|
var memberNodes =
|
||||||
var memberNodes = doVisitForWhenBody(ctx.objectBody());
|
symbolTable.enterForGenerator(
|
||||||
if (keyVariableSlot != -1) {
|
generatorDescriptorBuilder,
|
||||||
currentScope.popForGeneratorVariable();
|
memberDescriptorBuilder,
|
||||||
}
|
scope -> doVisitForWhenBody(ctx.objectBody()));
|
||||||
if (valueVariableSlot != -1) {
|
|
||||||
currentScope.popForGeneratorVariable();
|
|
||||||
}
|
|
||||||
//noinspection ConstantConditions
|
|
||||||
return GeneratorForNodeGen.create(
|
return GeneratorForNodeGen.create(
|
||||||
sourceSection,
|
createSourceSection(ctx),
|
||||||
keyVariableSlot,
|
generatorDescriptorBuilder.build(),
|
||||||
valueVariableSlot,
|
|
||||||
iterableNode,
|
iterableNode,
|
||||||
unresolvedKeyTypeNode,
|
unresolvedKeyTypeNode,
|
||||||
unresolvedValueTypeNode,
|
unresolvedValueTypeNode,
|
||||||
memberNodes,
|
memberNodes,
|
||||||
ctx.t2 != null && !ignoreT1,
|
keyTypeNode,
|
||||||
!ignoreT2);
|
valueTypeNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkSpaceSeparatedObjectMembers(ObjectBodyContext objectBodyContext) {
|
private void checkSpaceSeparatedObjectMembers(ObjectBodyContext objectBodyContext) {
|
||||||
@@ -1200,15 +1188,13 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ObjectMember doVisitObjectElement(ObjectElementContext ctx) {
|
private ObjectMember doVisitObjectElement(ObjectElementContext ctx) {
|
||||||
|
var isForGeneratorScope = symbolTable.getCurrentScope().isForGeneratorScope();
|
||||||
return symbolTable.enterEntry(
|
return symbolTable.enterEntry(
|
||||||
null,
|
null,
|
||||||
scope -> {
|
scope -> {
|
||||||
var elementNode = visitExpr(ctx.expr());
|
var elementNode = visitExpr(ctx.expr());
|
||||||
|
|
||||||
var modifier =
|
var modifier = VmModifier.ELEMENT;
|
||||||
scope.isVisitingIterable()
|
|
||||||
? VmModifier.ELEMENT | VmModifier.IS_IN_ITERABLE
|
|
||||||
: VmModifier.ELEMENT;
|
|
||||||
var member =
|
var member =
|
||||||
new ObjectMember(
|
new ObjectMember(
|
||||||
createSourceSection(ctx),
|
createSourceSection(ctx),
|
||||||
@@ -1220,6 +1206,9 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
if (elementNode instanceof ConstantNode constantNode) {
|
if (elementNode instanceof ConstantNode constantNode) {
|
||||||
member.initConstantValue(constantNode);
|
member.initConstantValue(constantNode);
|
||||||
} else {
|
} else {
|
||||||
|
if (isForGeneratorScope) {
|
||||||
|
elementNode = new RestoreForBindingsNode(elementNode);
|
||||||
|
}
|
||||||
member.initMemberNode(
|
member.initMemberNode(
|
||||||
ElementOrEntryNodeGen.create(
|
ElementOrEntryNodeGen.create(
|
||||||
language, scope.buildFrameDescriptor(), member, elementNode));
|
language, scope.buildFrameDescriptor(), member, elementNode));
|
||||||
@@ -1229,21 +1218,6 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pair<ExpressionNode, ObjectMember> doVisitMemberPredicate(MemberPredicateContext ctx) {
|
|
||||||
if (ctx.err1 == null && ctx.err2 == null) {
|
|
||||||
throw missingDelimiter("]]", ctx.k.stop.getStopIndex() + 1);
|
|
||||||
} else if (ctx.err1 != null
|
|
||||||
&& (ctx.err2 == null || ctx.err1.getStartIndex() != ctx.err2.getStartIndex() - 1)) {
|
|
||||||
// There shouldn't be any whitespace between the first and second ']'.
|
|
||||||
throw wrongDelimiter("]]", "]", ctx.err1.getStartIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
var keyNode = symbolTable.enterCustomThisScope(scope -> visitExpr(ctx.k));
|
|
||||||
|
|
||||||
return symbolTable.enterEntry(
|
|
||||||
keyNode, objectMemberInserter(createSourceSection(ctx), keyNode, ctx.v, ctx.objectBody()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Pair<ExpressionNode, ObjectMember> doVisitObjectEntry(ObjectEntryContext ctx) {
|
private Pair<ExpressionNode, ObjectMember> doVisitObjectEntry(ObjectEntryContext ctx) {
|
||||||
checkClosingDelimiter(ctx.err1, "]", ctx.k.stop);
|
checkClosingDelimiter(ctx.err1, "]", ctx.k.stop);
|
||||||
if (ctx.err2 != null) {
|
if (ctx.err2 != null) {
|
||||||
@@ -1253,46 +1227,54 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var keyNode = visitExpr(ctx.k);
|
var keyNode = visitExpr(ctx.k);
|
||||||
|
var member = doVisitObjectEntryBody(createSourceSection(ctx), keyNode, ctx.v, ctx.objectBody());
|
||||||
return symbolTable.enterEntry(
|
return Pair.of(keyNode, member);
|
||||||
keyNode, objectMemberInserter(createSourceSection(ctx), keyNode, ctx.v, ctx.objectBody()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Function<EntryScope, Pair<ExpressionNode, ObjectMember>> objectMemberInserter(
|
private ObjectMember doVisitObjectEntryBody(
|
||||||
SourceSection sourceSection,
|
SourceSection sourceSection,
|
||||||
ExpressionNode keyNode,
|
ExpressionNode keyNode,
|
||||||
@Nullable ExprContext valueCtx,
|
@Nullable ExprContext valueCtx,
|
||||||
List<? extends ObjectBodyContext> objectBodyCtxs) {
|
List<? extends ObjectBodyContext> objectBodyCtxs) {
|
||||||
return scope -> {
|
var isForGeneratorScope = symbolTable.getCurrentScope().isForGeneratorScope();
|
||||||
var modifier =
|
return symbolTable.enterEntry(
|
||||||
scope.isVisitingIterable()
|
keyNode,
|
||||||
? VmModifier.ENTRY | VmModifier.IS_IN_ITERABLE
|
scope -> {
|
||||||
: VmModifier.ENTRY;
|
var modifier = VmModifier.ENTRY;
|
||||||
var member =
|
var member =
|
||||||
new ObjectMember(
|
new ObjectMember(
|
||||||
sourceSection, keyNode.getSourceSection(), modifier, null, scope.getQualifiedName());
|
sourceSection,
|
||||||
|
keyNode.getSourceSection(),
|
||||||
|
modifier,
|
||||||
|
null,
|
||||||
|
scope.getQualifiedName());
|
||||||
|
if (valueCtx != null) { // ["key"] = value
|
||||||
|
var valueNode = visitExpr(valueCtx);
|
||||||
|
if (valueNode instanceof ConstantNode constantNode) {
|
||||||
|
member.initConstantValue(constantNode);
|
||||||
|
} else {
|
||||||
|
if (isForGeneratorScope) {
|
||||||
|
valueNode = new RestoreForBindingsNode(valueNode);
|
||||||
|
}
|
||||||
|
member.initMemberNode(
|
||||||
|
ElementOrEntryNodeGen.create(
|
||||||
|
language, scope.buildFrameDescriptor(), member, valueNode));
|
||||||
|
}
|
||||||
|
} else { // ["key"] { ... }
|
||||||
|
var objectBody =
|
||||||
|
doVisitObjectBody(
|
||||||
|
objectBodyCtxs,
|
||||||
|
new ReadSuperEntryNode(unavailableSourceSection(), new GetMemberKeyNode()));
|
||||||
|
if (isForGeneratorScope) {
|
||||||
|
objectBody = new RestoreForBindingsNode(objectBody);
|
||||||
|
}
|
||||||
|
member.initMemberNode(
|
||||||
|
ElementOrEntryNodeGen.create(
|
||||||
|
language, scope.buildFrameDescriptor(), member, objectBody));
|
||||||
|
}
|
||||||
|
|
||||||
if (valueCtx != null) { // ["key"] = value
|
return member;
|
||||||
var valueNode = visitExpr(valueCtx);
|
});
|
||||||
if (valueNode instanceof ConstantNode constantNode) {
|
|
||||||
member.initConstantValue(constantNode);
|
|
||||||
} else {
|
|
||||||
member.initMemberNode(
|
|
||||||
ElementOrEntryNodeGen.create(
|
|
||||||
language, scope.buildFrameDescriptor(), member, valueNode));
|
|
||||||
}
|
|
||||||
} else { // ["key"] { ... }
|
|
||||||
var objectBody =
|
|
||||||
doVisitObjectBody(
|
|
||||||
objectBodyCtxs,
|
|
||||||
new ReadSuperEntryNode(unavailableSourceSection(), new GetMemberKeyNode()));
|
|
||||||
member.initMemberNode(
|
|
||||||
ElementOrEntryNodeGen.create(
|
|
||||||
language, scope.buildFrameDescriptor(), member, objectBody));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Pair.of(keyNode, member);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -1350,10 +1332,6 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
result += modifier;
|
result += modifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (symbolTable.getCurrentScope().isVisitingIterable()) {
|
|
||||||
result += VmModifier.IS_IN_ITERABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// flag modifier combinations that are never valid right away
|
// flag modifier combinations that are never valid right away
|
||||||
|
|
||||||
if (VmModifier.isExternal(result) && !ModuleKeys.isStdLibModule(moduleKey)) {
|
if (VmModifier.isExternal(result) && !ModuleKeys.isStdLibModule(moduleKey)) {
|
||||||
@@ -1986,7 +1964,6 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
visitArgumentList(argCtx),
|
visitArgumentList(argCtx),
|
||||||
MemberLookupMode.EXPLICIT_RECEIVER,
|
MemberLookupMode.EXPLICIT_RECEIVER,
|
||||||
needsConst,
|
needsConst,
|
||||||
symbolTable.getCurrentScope().isVisitingIterable(),
|
|
||||||
PropagateNullReceiverNodeGen.create(unavailableSourceSection(), receiver),
|
PropagateNullReceiverNodeGen.create(unavailableSourceSection(), receiver),
|
||||||
GetClassNodeGen.create(null)));
|
GetClassNodeGen.create(null)));
|
||||||
}
|
}
|
||||||
@@ -1999,7 +1976,6 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
visitArgumentList(argCtx),
|
visitArgumentList(argCtx),
|
||||||
MemberLookupMode.EXPLICIT_RECEIVER,
|
MemberLookupMode.EXPLICIT_RECEIVER,
|
||||||
needsConst,
|
needsConst,
|
||||||
symbolTable.getCurrentScope().isVisitingIterable(),
|
|
||||||
receiver,
|
receiver,
|
||||||
GetClassNodeGen.create(null));
|
GetClassNodeGen.create(null));
|
||||||
}
|
}
|
||||||
@@ -2074,11 +2050,7 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return InvokeSuperMethodNodeGen.create(
|
return InvokeSuperMethodNodeGen.create(
|
||||||
sourceSection,
|
sourceSection, memberName, visitArgumentList(argCtx), needsConst);
|
||||||
memberName,
|
|
||||||
symbolTable.getCurrentScope().isVisitingIterable(),
|
|
||||||
visitArgumentList(argCtx),
|
|
||||||
needsConst);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// superproperty call
|
// superproperty call
|
||||||
@@ -2136,8 +2108,7 @@ public final class AstBuilder extends AbstractAstBuilder<Object> {
|
|||||||
isBaseModule,
|
isBaseModule,
|
||||||
scope.isCustomThisScope(),
|
scope.isCustomThisScope(),
|
||||||
scope.getConstLevel(),
|
scope.getConstLevel(),
|
||||||
scope.getConstDepth(),
|
scope.getConstDepth());
|
||||||
scope.isVisitingIterable());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -17,15 +17,14 @@ package org.pkl.core.ast.builder;
|
|||||||
|
|
||||||
import com.oracle.truffle.api.frame.FrameDescriptor;
|
import com.oracle.truffle.api.frame.FrameDescriptor;
|
||||||
import com.oracle.truffle.api.frame.FrameDescriptor.Builder;
|
import com.oracle.truffle.api.frame.FrameDescriptor.Builder;
|
||||||
import com.oracle.truffle.api.frame.FrameSlotKind;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import org.pkl.core.TypeParameter;
|
import org.pkl.core.TypeParameter;
|
||||||
import org.pkl.core.ast.ConstantNode;
|
import org.pkl.core.ast.ConstantNode;
|
||||||
import org.pkl.core.ast.ExpressionNode;
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
|
import org.pkl.core.ast.expression.generator.GeneratorMemberNode;
|
||||||
import org.pkl.core.ast.member.ObjectMember;
|
import org.pkl.core.ast.member.ObjectMember;
|
||||||
import org.pkl.core.parser.Lexer;
|
import org.pkl.core.parser.Lexer;
|
||||||
import org.pkl.core.parser.antlr.PklParser.ParameterContext;
|
|
||||||
import org.pkl.core.runtime.Identifier;
|
import org.pkl.core.runtime.Identifier;
|
||||||
import org.pkl.core.runtime.ModuleInfo;
|
import org.pkl.core.runtime.ModuleInfo;
|
||||||
import org.pkl.core.runtime.VmDataSize;
|
import org.pkl.core.runtime.VmDataSize;
|
||||||
@@ -35,8 +34,6 @@ import org.pkl.core.util.Nullable;
|
|||||||
public final class SymbolTable {
|
public final class SymbolTable {
|
||||||
private Scope currentScope;
|
private Scope currentScope;
|
||||||
|
|
||||||
public static Object FOR_GENERATOR_VARIABLE = new Object();
|
|
||||||
|
|
||||||
public SymbolTable(ModuleInfo moduleInfo) {
|
public SymbolTable(ModuleInfo moduleInfo) {
|
||||||
currentScope = new ModuleScope(moduleInfo);
|
currentScope = new ModuleScope(moduleInfo);
|
||||||
}
|
}
|
||||||
@@ -99,6 +96,19 @@ public final class SymbolTable {
|
|||||||
nodeFactory);
|
nodeFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public <T> T enterForGenerator(
|
||||||
|
FrameDescriptor.Builder frameDescriptorBuilder,
|
||||||
|
FrameDescriptor.Builder memberDescriptorBuilder,
|
||||||
|
Function<ForGeneratorScope, T> nodeFactory) {
|
||||||
|
return doEnter(
|
||||||
|
new ForGeneratorScope(
|
||||||
|
currentScope,
|
||||||
|
currentScope.qualifiedName,
|
||||||
|
frameDescriptorBuilder,
|
||||||
|
memberDescriptorBuilder),
|
||||||
|
nodeFactory);
|
||||||
|
}
|
||||||
|
|
||||||
public <T> T enterLambda(
|
public <T> T enterLambda(
|
||||||
FrameDescriptor.Builder frameDescriptorBuilder, Function<LambdaScope, T> nodeFactory) {
|
FrameDescriptor.Builder frameDescriptorBuilder, Function<LambdaScope, T> nodeFactory) {
|
||||||
|
|
||||||
@@ -128,9 +138,11 @@ public final class SymbolTable {
|
|||||||
Function<EntryScope, T> nodeFactory) {
|
Function<EntryScope, T> nodeFactory) {
|
||||||
|
|
||||||
var qualifiedName = currentScope.getQualifiedName() + currentScope.getNextEntryName(keyNode);
|
var qualifiedName = currentScope.getQualifiedName() + currentScope.getNextEntryName(keyNode);
|
||||||
|
var builder =
|
||||||
return doEnter(
|
currentScope instanceof ForGeneratorScope forScope
|
||||||
new EntryScope(currentScope, qualifiedName, FrameDescriptor.newBuilder()), nodeFactory);
|
? forScope.memberDescriptorBuilder
|
||||||
|
: FrameDescriptor.newBuilder();
|
||||||
|
return doEnter(new EntryScope(currentScope, qualifiedName, builder), nodeFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> T enterCustomThisScope(Function<CustomThisScope, T> nodeFactory) {
|
public <T> T enterCustomThisScope(Function<CustomThisScope, T> nodeFactory) {
|
||||||
@@ -166,12 +178,10 @@ public final class SymbolTable {
|
|||||||
private final @Nullable Scope parent;
|
private final @Nullable Scope parent;
|
||||||
private final @Nullable Identifier name;
|
private final @Nullable Identifier name;
|
||||||
private final String qualifiedName;
|
private final String qualifiedName;
|
||||||
private final Deque<Identifier> forGeneratorVariables = new ArrayDeque<>();
|
|
||||||
private int lambdaCount = 0;
|
private int lambdaCount = 0;
|
||||||
private int entryCount = 0;
|
private int entryCount = 0;
|
||||||
private final FrameDescriptor.Builder frameDescriptorBuilder;
|
private final FrameDescriptor.Builder frameDescriptorBuilder;
|
||||||
private final ConstLevel constLevel;
|
private final ConstLevel constLevel;
|
||||||
private boolean isVisitingIterable;
|
|
||||||
|
|
||||||
private Scope(
|
private Scope(
|
||||||
@Nullable Scope parent,
|
@Nullable Scope parent,
|
||||||
@@ -188,7 +198,6 @@ public final class SymbolTable {
|
|||||||
parent != null && parent.constLevel.biggerOrEquals(constLevel)
|
parent != null && parent.constLevel.biggerOrEquals(constLevel)
|
||||||
? parent.constLevel
|
? parent.constLevel
|
||||||
: constLevel;
|
: constLevel;
|
||||||
this.isVisitingIterable = parent != null && parent.isVisitingIterable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final @Nullable Scope getParent() {
|
public final @Nullable Scope getParent() {
|
||||||
@@ -212,6 +221,30 @@ public final class SymbolTable {
|
|||||||
return frameDescriptorBuilder.build();
|
return frameDescriptorBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new descriptor builder that contains the same slots as the current scope's frame
|
||||||
|
* descriptor.
|
||||||
|
*/
|
||||||
|
public FrameDescriptor.Builder newFrameDescriptorBuilder() {
|
||||||
|
return newFrameDescriptorBuilder(buildFrameDescriptor());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a new descriptor builder for a {@link GeneratorMemberNode} in the current scope. */
|
||||||
|
public FrameDescriptor.Builder newForGeneratorMemberDescriptorBuilder() {
|
||||||
|
return this instanceof ForGeneratorScope forScope
|
||||||
|
? newFrameDescriptorBuilder(forScope.buildMemberDescriptor())
|
||||||
|
: FrameDescriptor.newBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FrameDescriptor.Builder newFrameDescriptorBuilder(FrameDescriptor descriptor) {
|
||||||
|
var builder = FrameDescriptor.newBuilder();
|
||||||
|
for (var i = 0; i < descriptor.getNumberOfSlots(); i++) {
|
||||||
|
builder.addSlot(
|
||||||
|
descriptor.getSlotKind(i), descriptor.getSlotName(i), descriptor.getSlotInfo(i));
|
||||||
|
}
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
public @Nullable TypeParameter getTypeParameter(String name) {
|
public @Nullable TypeParameter getTypeParameter(String name) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -253,35 +286,11 @@ public final class SymbolTable {
|
|||||||
return depth;
|
return depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the for generator variable to the frame descriptor.
|
|
||||||
*
|
|
||||||
* <p>Returns {@code -1} if a for-generator variable already exists with this name.
|
|
||||||
*/
|
|
||||||
public int pushForGeneratorVariableContext(ParameterContext ctx) {
|
|
||||||
var variable = Identifier.localProperty(ctx.typedIdentifier().Identifier().getText());
|
|
||||||
if (forGeneratorVariables.contains(variable)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
var slot =
|
|
||||||
frameDescriptorBuilder.addSlot(FrameSlotKind.Illegal, variable, FOR_GENERATOR_VARIABLE);
|
|
||||||
forGeneratorVariables.addLast(variable);
|
|
||||||
return slot;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void popForGeneratorVariable() {
|
|
||||||
forGeneratorVariables.removeLast();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Deque<Identifier> getForGeneratorVariables() {
|
|
||||||
return forGeneratorVariables;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getNextLambdaName() {
|
private String getNextLambdaName() {
|
||||||
return "<function#" + (++skipLambdaScopes().lambdaCount) + ">";
|
return "<function#" + (++skipLambdaScopes().lambdaCount) + ">";
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getNextEntryName(@Nullable ExpressionNode keyNode) {
|
protected String getNextEntryName(@Nullable ExpressionNode keyNode) {
|
||||||
if (keyNode instanceof ConstantNode constantNode) {
|
if (keyNode instanceof ConstantNode constantNode) {
|
||||||
var value = constantNode.getValue();
|
var value = constantNode.getValue();
|
||||||
if (value instanceof String) {
|
if (value instanceof String) {
|
||||||
@@ -336,17 +345,13 @@ public final class SymbolTable {
|
|||||||
return this instanceof LexicalScope;
|
return this instanceof LexicalScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final boolean isForGeneratorScope() {
|
||||||
|
return this instanceof ForGeneratorScope;
|
||||||
|
}
|
||||||
|
|
||||||
public ConstLevel getConstLevel() {
|
public ConstLevel getConstLevel() {
|
||||||
return constLevel;
|
return constLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setVisitingIterable(boolean isVisitingIterable) {
|
|
||||||
this.isVisitingIterable = isVisitingIterable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isVisitingIterable() {
|
|
||||||
return isVisitingIterable;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private interface LexicalScope {}
|
private interface LexicalScope {}
|
||||||
@@ -413,6 +418,30 @@ public final class SymbolTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final class ForGeneratorScope extends Scope implements LexicalScope {
|
||||||
|
private final FrameDescriptor.Builder memberDescriptorBuilder;
|
||||||
|
|
||||||
|
public ForGeneratorScope(
|
||||||
|
Scope parent,
|
||||||
|
String qualifiedName,
|
||||||
|
FrameDescriptor.Builder frameDescriptorBuilder,
|
||||||
|
FrameDescriptor.Builder memberDescriptorBuilder) {
|
||||||
|
super(parent, null, qualifiedName, ConstLevel.NONE, frameDescriptorBuilder);
|
||||||
|
this.memberDescriptorBuilder = memberDescriptorBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrameDescriptor buildMemberDescriptor() {
|
||||||
|
return memberDescriptorBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getNextEntryName(@Nullable ExpressionNode keyNode) {
|
||||||
|
var parent = getParent();
|
||||||
|
assert parent != null;
|
||||||
|
return parent.getNextEntryName(keyNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static final class PropertyScope extends Scope {
|
public static final class PropertyScope extends Scope {
|
||||||
public PropertyScope(
|
public PropertyScope(
|
||||||
Scope parent,
|
Scope parent,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -21,7 +21,6 @@ import com.oracle.truffle.api.frame.VirtualFrame;
|
|||||||
import com.oracle.truffle.api.nodes.DirectCallNode;
|
import com.oracle.truffle.api.nodes.DirectCallNode;
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
import org.pkl.core.ast.ExpressionNode;
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
import org.pkl.core.ast.builder.SymbolTable.CustomThisScope;
|
|
||||||
import org.pkl.core.ast.member.FunctionNode;
|
import org.pkl.core.ast.member.FunctionNode;
|
||||||
import org.pkl.core.ast.member.UnresolvedFunctionNode;
|
import org.pkl.core.ast.member.UnresolvedFunctionNode;
|
||||||
import org.pkl.core.runtime.VmFunction;
|
import org.pkl.core.runtime.VmFunction;
|
||||||
@@ -57,7 +56,7 @@ public final class LetExprNode extends ExpressionNode {
|
|||||||
callNode = insert(DirectCallNode.create(functionNode.getCallTarget()));
|
callNode = insert(DirectCallNode.create(functionNode.getCallTarget()));
|
||||||
if (isCustomThisScope) {
|
if (isCustomThisScope) {
|
||||||
// deferred until execution time s.t. nodes of inlined type aliases get the right frame slot
|
// deferred until execution time s.t. nodes of inlined type aliases get the right frame slot
|
||||||
customThisSlot = VmUtils.findAuxiliarySlot(frame, CustomThisScope.FRAME_SLOT_ID);
|
customThisSlot = VmUtils.findCustomThisSlot(frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,6 +70,6 @@ public final class LetExprNode extends ExpressionNode {
|
|||||||
|
|
||||||
var value = valueNode.executeGeneric(frame);
|
var value = valueNode.executeGeneric(frame);
|
||||||
|
|
||||||
return callNode.call(function.getThisValue(), function, false, value);
|
return callNode.call(function.getThisValue(), function, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-20
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -19,57 +19,50 @@ import com.oracle.truffle.api.CompilerDirectives;
|
|||||||
import com.oracle.truffle.api.dsl.Fallback;
|
import com.oracle.truffle.api.dsl.Fallback;
|
||||||
import com.oracle.truffle.api.dsl.ImportStatic;
|
import com.oracle.truffle.api.dsl.ImportStatic;
|
||||||
import com.oracle.truffle.api.dsl.Specialization;
|
import com.oracle.truffle.api.dsl.Specialization;
|
||||||
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
import org.pkl.core.ast.member.ObjectMember;
|
import org.pkl.core.ast.member.ObjectMember;
|
||||||
import org.pkl.core.runtime.BaseModule;
|
import org.pkl.core.runtime.BaseModule;
|
||||||
import org.pkl.core.runtime.VmClass;
|
import org.pkl.core.runtime.VmClass;
|
||||||
import org.pkl.core.runtime.VmDynamic;
|
import org.pkl.core.runtime.VmDynamic;
|
||||||
import org.pkl.core.runtime.VmListing;
|
import org.pkl.core.runtime.VmListing;
|
||||||
import org.pkl.core.util.EconomicMaps;
|
|
||||||
|
|
||||||
@ImportStatic(BaseModule.class)
|
@ImportStatic(BaseModule.class)
|
||||||
public abstract class GeneratorElementNode extends GeneratorMemberNode {
|
public abstract class GeneratorElementNode extends GeneratorMemberNode {
|
||||||
private final ObjectMember element;
|
private final ObjectMember element;
|
||||||
|
|
||||||
protected GeneratorElementNode(ObjectMember element) {
|
protected GeneratorElementNode(ObjectMember element, boolean isFrameStored) {
|
||||||
super(element.getSourceSection());
|
super(element.getSourceSection(), isFrameStored);
|
||||||
this.element = element;
|
this.element = element;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
protected void evalDynamic(VmDynamic parent, ObjectData data) {
|
protected void evalDynamic(VirtualFrame frame, VmDynamic parent, ObjectData data) {
|
||||||
addElement(data);
|
data.addElement(frame, element, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
protected void evalListing(VmListing parent, ObjectData data) {
|
protected void evalListing(VirtualFrame frame, VmListing parent, ObjectData data) {
|
||||||
addElement(data);
|
data.addElement(frame, element, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Specialization(guards = "parent == getDynamicClass()")
|
@Specialization(guards = "parent == getDynamicClass()")
|
||||||
protected void evalDynamicClass(VmClass parent, ObjectData data) {
|
protected void evalDynamicClass(VirtualFrame frame, VmClass parent, ObjectData data) {
|
||||||
addElement(data);
|
data.addElement(frame, element, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Specialization(guards = "parent == getListingClass()")
|
@Specialization(guards = "parent == getListingClass()")
|
||||||
protected void evalListingClass(VmClass parent, ObjectData data) {
|
protected void evalListingClass(VirtualFrame frame, VmClass parent, ObjectData data) {
|
||||||
addElement(data);
|
data.addElement(frame, element, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Fallback
|
@Fallback
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
void fallback(Object parent, ObjectData data) {
|
void fallback(VirtualFrame frame, Object parent, ObjectData data) {
|
||||||
CompilerDirectives.transferToInterpreter();
|
CompilerDirectives.transferToInterpreter();
|
||||||
throw exceptionBuilder().evalError("objectCannotHaveElement", parent).build();
|
throw exceptionBuilder().evalError("objectCannotHaveElement", parent).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addElement(ObjectData data) {
|
|
||||||
long index = data.length;
|
|
||||||
EconomicMaps.put(data.members, index, element);
|
|
||||||
data.length += 1;
|
|
||||||
data.persistForBindings(index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-15
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -25,15 +25,14 @@ import org.pkl.core.ast.ExpressionNode;
|
|||||||
import org.pkl.core.ast.member.ObjectMember;
|
import org.pkl.core.ast.member.ObjectMember;
|
||||||
import org.pkl.core.runtime.*;
|
import org.pkl.core.runtime.*;
|
||||||
import org.pkl.core.runtime.VmException.ProgramValue;
|
import org.pkl.core.runtime.VmException.ProgramValue;
|
||||||
import org.pkl.core.util.EconomicMaps;
|
|
||||||
|
|
||||||
@ImportStatic(BaseModule.class)
|
@ImportStatic(BaseModule.class)
|
||||||
public abstract class GeneratorEntryNode extends GeneratorMemberNode {
|
public abstract class GeneratorEntryNode extends GeneratorMemberNode {
|
||||||
@Child private ExpressionNode keyNode;
|
@Child private ExpressionNode keyNode;
|
||||||
private final ObjectMember member;
|
private final ObjectMember member;
|
||||||
|
|
||||||
protected GeneratorEntryNode(ExpressionNode keyNode, ObjectMember member) {
|
protected GeneratorEntryNode(ExpressionNode keyNode, ObjectMember member, boolean isFrameStored) {
|
||||||
super(member.getSourceSection());
|
super(member.getSourceSection(), isFrameStored);
|
||||||
this.keyNode = keyNode;
|
this.keyNode = keyNode;
|
||||||
this.member = member;
|
this.member = member;
|
||||||
}
|
}
|
||||||
@@ -84,7 +83,7 @@ public abstract class GeneratorEntryNode extends GeneratorMemberNode {
|
|||||||
|
|
||||||
private void addRegularEntry(VirtualFrame frame, ObjectData data) {
|
private void addRegularEntry(VirtualFrame frame, ObjectData data) {
|
||||||
var key = keyNode.executeGeneric(frame);
|
var key = keyNode.executeGeneric(frame);
|
||||||
doAdd(key, data);
|
data.addMember(frame, key, member, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addListingEntry(VirtualFrame frame, ObjectData data, int parentLength) {
|
private void addListingEntry(VirtualFrame frame, ObjectData data, int parentLength) {
|
||||||
@@ -108,15 +107,6 @@ public abstract class GeneratorEntryNode extends GeneratorMemberNode {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
doAdd(index, data);
|
data.addMember(frame, index, member, this);
|
||||||
}
|
|
||||||
|
|
||||||
private void doAdd(Object key, ObjectData data) {
|
|
||||||
if (EconomicMaps.put(data.members, key, member) != null) {
|
|
||||||
CompilerDirectives.transferToInterpreter();
|
|
||||||
throw duplicateDefinition(key, member);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.persistForBindings(key);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+70
-117
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,62 +16,51 @@
|
|||||||
package org.pkl.core.ast.expression.generator;
|
package org.pkl.core.ast.expression.generator;
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
import com.oracle.truffle.api.Truffle;
|
||||||
import com.oracle.truffle.api.dsl.Fallback;
|
import com.oracle.truffle.api.dsl.Fallback;
|
||||||
import com.oracle.truffle.api.dsl.Specialization;
|
import com.oracle.truffle.api.dsl.Specialization;
|
||||||
|
import com.oracle.truffle.api.frame.FrameDescriptor;
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
import java.util.*;
|
|
||||||
import org.pkl.core.ast.ExpressionNode;
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
import org.pkl.core.ast.type.TypeNode;
|
import org.pkl.core.ast.type.TypeNode;
|
||||||
import org.pkl.core.ast.type.UnresolvedTypeNode;
|
import org.pkl.core.ast.type.UnresolvedTypeNode;
|
||||||
import org.pkl.core.ast.type.VmTypeMismatchException;
|
|
||||||
import org.pkl.core.runtime.*;
|
import org.pkl.core.runtime.*;
|
||||||
import org.pkl.core.util.LateInit;
|
|
||||||
import org.pkl.core.util.Nullable;
|
import org.pkl.core.util.Nullable;
|
||||||
import org.pkl.core.util.Pair;
|
|
||||||
|
|
||||||
public abstract class GeneratorForNode extends GeneratorMemberNode {
|
public abstract class GeneratorForNode extends GeneratorMemberNode {
|
||||||
private final int keySlot;
|
private final FrameDescriptor generatorDescriptor;
|
||||||
private final int valueSlot;
|
|
||||||
@Child private ExpressionNode iterableNode;
|
@Child private ExpressionNode iterableNode;
|
||||||
@Child private @Nullable UnresolvedTypeNode unresolvedKeyTypeNode;
|
@Child private @Nullable UnresolvedTypeNode unresolvedKeyTypeNode;
|
||||||
@Child private @Nullable UnresolvedTypeNode unresolvedValueTypeNode;
|
@Child private @Nullable UnresolvedTypeNode unresolvedValueTypeNode;
|
||||||
@Children private final GeneratorMemberNode[] childNodes;
|
@Children private final GeneratorMemberNode[] childNodes;
|
||||||
@Child private @Nullable TypeNode keyTypeNode;
|
@Child private @Nullable TypeNode keyTypeNode;
|
||||||
@Child @LateInit private TypeNode valueTypeNode;
|
@Child private @Nullable TypeNode valueTypeNode;
|
||||||
|
|
||||||
public GeneratorForNode(
|
public GeneratorForNode(
|
||||||
SourceSection sourceSection,
|
SourceSection sourceSection,
|
||||||
int keySlot,
|
FrameDescriptor generatorDescriptor,
|
||||||
int valueSlot,
|
|
||||||
ExpressionNode iterableNode,
|
ExpressionNode iterableNode,
|
||||||
|
// null if for-generator doesn't bind key or `keyTypeNode` is passed instead of this node
|
||||||
@Nullable UnresolvedTypeNode unresolvedKeyTypeNode,
|
@Nullable UnresolvedTypeNode unresolvedKeyTypeNode,
|
||||||
|
// null if for-generator doesn't bind value or `valueTypeNode` is passed instead of this node
|
||||||
@Nullable UnresolvedTypeNode unresolvedValueTypeNode,
|
@Nullable UnresolvedTypeNode unresolvedValueTypeNode,
|
||||||
|
// If this node can be constructed at parse time,
|
||||||
|
// it should be passed instead of `unresolvedKeyTypeNode`.
|
||||||
GeneratorMemberNode[] childNodes,
|
GeneratorMemberNode[] childNodes,
|
||||||
boolean hasKeyIdentifier,
|
@Nullable TypeNode keyTypeNode,
|
||||||
boolean hasValueIdentifier) {
|
// If this node can be constructed at parse time,
|
||||||
|
// it should be passed instead of `unresolvedValueTypeNode`.
|
||||||
super(sourceSection);
|
@Nullable TypeNode valueTypeNode) {
|
||||||
this.keySlot = keySlot;
|
super(sourceSection, false);
|
||||||
this.valueSlot = valueSlot;
|
this.generatorDescriptor = generatorDescriptor;
|
||||||
this.iterableNode = iterableNode;
|
this.iterableNode = iterableNode;
|
||||||
this.unresolvedKeyTypeNode = unresolvedKeyTypeNode;
|
this.unresolvedKeyTypeNode = unresolvedKeyTypeNode;
|
||||||
this.unresolvedValueTypeNode = unresolvedValueTypeNode;
|
this.unresolvedValueTypeNode = unresolvedValueTypeNode;
|
||||||
this.childNodes = childNodes;
|
this.childNodes = childNodes;
|
||||||
|
this.keyTypeNode = keyTypeNode;
|
||||||
// initialize now if possible to save later insert()
|
this.valueTypeNode = valueTypeNode;
|
||||||
if (unresolvedKeyTypeNode == null && hasKeyIdentifier) {
|
|
||||||
keyTypeNode =
|
|
||||||
new TypeNode.UnknownTypeNode(VmUtils.unavailableSourceSection())
|
|
||||||
.initWriteSlotNode(keySlot);
|
|
||||||
}
|
|
||||||
if (unresolvedValueTypeNode == null && hasValueIdentifier) {
|
|
||||||
valueTypeNode =
|
|
||||||
new TypeNode.UnknownTypeNode(VmUtils.unavailableSourceSection())
|
|
||||||
.initWriteSlotNode(valueSlot);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void executeWithIterable(
|
protected abstract void executeWithIterable(
|
||||||
@@ -79,6 +68,7 @@ public abstract class GeneratorForNode extends GeneratorMemberNode {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void execute(VirtualFrame frame, Object parent, ObjectData data) {
|
public final void execute(VirtualFrame frame, Object parent, ObjectData data) {
|
||||||
|
initialize(frame);
|
||||||
executeWithIterable(frame, parent, data, iterableNode.executeGeneric(frame));
|
executeWithIterable(frame, parent, data, iterableNode.executeGeneric(frame));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,41 +89,33 @@ public abstract class GeneratorForNode extends GeneratorMemberNode {
|
|||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
protected void eval(VirtualFrame frame, Object parent, ObjectData data, VmList iterable) {
|
protected void eval(VirtualFrame frame, Object parent, ObjectData data, VmList iterable) {
|
||||||
initTypeNodes(frame);
|
|
||||||
long idx = 0;
|
|
||||||
for (Object element : iterable) {
|
|
||||||
executeIteration(frame, parent, data, idx++, element);
|
|
||||||
}
|
|
||||||
resetFrameSlots(frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Specialization
|
|
||||||
protected void eval(VirtualFrame frame, Object parent, ObjectData data, VmMap iterable) {
|
|
||||||
initTypeNodes(frame);
|
|
||||||
for (var entry : iterable) {
|
|
||||||
executeIteration(frame, parent, data, VmUtils.getKey(entry), VmUtils.getValue(entry));
|
|
||||||
}
|
|
||||||
resetFrameSlots(frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Specialization
|
|
||||||
protected void eval(VirtualFrame frame, Object parent, ObjectData data, VmSet iterable) {
|
|
||||||
initTypeNodes(frame);
|
|
||||||
long idx = 0;
|
long idx = 0;
|
||||||
for (var element : iterable) {
|
for (var element : iterable) {
|
||||||
executeIteration(frame, parent, data, idx++, element);
|
executeIteration(frame, parent, data, idx++, element);
|
||||||
}
|
}
|
||||||
resetFrameSlots(frame);
|
}
|
||||||
|
|
||||||
|
@Specialization
|
||||||
|
protected void eval(VirtualFrame frame, Object parent, ObjectData data, VmMap iterable) {
|
||||||
|
for (var entry : iterable) {
|
||||||
|
executeIteration(frame, parent, data, VmUtils.getKey(entry), VmUtils.getValue(entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Specialization
|
||||||
|
protected void eval(VirtualFrame frame, Object parent, ObjectData data, VmSet iterable) {
|
||||||
|
long idx = 0;
|
||||||
|
for (var element : iterable) {
|
||||||
|
executeIteration(frame, parent, data, idx++, element);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
protected void eval(VirtualFrame frame, Object parent, ObjectData data, VmIntSeq iterable) {
|
protected void eval(VirtualFrame frame, Object parent, ObjectData data, VmIntSeq iterable) {
|
||||||
initTypeNodes(frame);
|
|
||||||
var length = iterable.getLength();
|
var length = iterable.getLength();
|
||||||
for (long key = 0, value = iterable.start; key < length; key++, value += iterable.step) {
|
for (long key = 0, value = iterable.start; key < length; key++, value += iterable.step) {
|
||||||
executeIteration(frame, parent, data, key, value);
|
executeIteration(frame, parent, data, key, value);
|
||||||
}
|
}
|
||||||
resetFrameSlots(frame);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Fallback
|
@Fallback
|
||||||
@@ -147,84 +129,55 @@ public abstract class GeneratorForNode extends GeneratorMemberNode {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ForLoopReplaceableByForEach")
|
|
||||||
private void doEvalObject(VirtualFrame frame, VmObject iterable, Object parent, ObjectData data) {
|
private void doEvalObject(VirtualFrame frame, VmObject iterable, Object parent, ObjectData data) {
|
||||||
initTypeNodes(frame);
|
iterable.forceAndIterateMemberValues(
|
||||||
var members = evaluateMembers(iterable);
|
|
||||||
for (int i = 0; i < members.size(); i++) {
|
|
||||||
var member = members.get(i);
|
|
||||||
executeIteration(frame, parent, data, member.first, member.second);
|
|
||||||
}
|
|
||||||
resetFrameSlots(frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void resetFrameSlots(VirtualFrame frame) {
|
|
||||||
if (keySlot != -1) {
|
|
||||||
frame.clear(keySlot);
|
|
||||||
}
|
|
||||||
if (valueSlot != -1) {
|
|
||||||
frame.clear(valueSlot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initTypeNodes(VirtualFrame frame) {
|
|
||||||
if (unresolvedKeyTypeNode != null) {
|
|
||||||
CompilerDirectives.transferToInterpreter();
|
|
||||||
keyTypeNode = insert(unresolvedKeyTypeNode.execute(frame)).initWriteSlotNode(keySlot);
|
|
||||||
unresolvedKeyTypeNode = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unresolvedValueTypeNode != null) {
|
|
||||||
CompilerDirectives.transferToInterpreter();
|
|
||||||
valueTypeNode = insert(unresolvedValueTypeNode.execute(frame)).initWriteSlotNode(valueSlot);
|
|
||||||
unresolvedValueTypeNode = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Evaluate members upfront to make sure that `childNode.execute()` is not behind a Truffle
|
|
||||||
* boundary.
|
|
||||||
*/
|
|
||||||
@TruffleBoundary
|
|
||||||
private List<Pair<Object, Object>> evaluateMembers(VmObject object) {
|
|
||||||
var members = new ArrayList<Pair<Object, Object>>();
|
|
||||||
object.forceAndIterateMemberValues(
|
|
||||||
(key, member, value) -> {
|
(key, member, value) -> {
|
||||||
members.add(Pair.of(member.isProp() ? key.toString() : key, value));
|
var convertedKey = member.isProp() ? key.toString() : key;
|
||||||
|
// TODO: Executing iteration behind a Truffle boundary is bad for performance.
|
||||||
|
// This and similar cases will be fixed in an upcoming PR that replaces method
|
||||||
|
// `(forceAnd)iterateMemberValues` with cursor-based external iterators.
|
||||||
|
executeIteration(frame, parent, data, convertedKey, value);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
return members;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExplodeLoop
|
@ExplodeLoop
|
||||||
private void executeIteration(
|
private void executeIteration(
|
||||||
VirtualFrame frame, Object parent, ObjectData data, Object key, Object value) {
|
VirtualFrame frame, Object parent, ObjectData data, Object key, Object value) {
|
||||||
|
|
||||||
try {
|
// GraalJS uses the same implementation technique here:
|
||||||
if (keyTypeNode != null) {
|
// https://github.com/oracle/graaljs/blob/44a11ce6e87/graal-js/src/com.oracle.truffle.js/
|
||||||
keyTypeNode.executeAndSet(frame, key);
|
// src/com/oracle/truffle/js/nodes/function/IterationScopeNode.java#L86-L88
|
||||||
}
|
var newFrame =
|
||||||
if (valueTypeNode != null) {
|
Truffle.getRuntime().createVirtualFrame(frame.getArguments(), generatorDescriptor);
|
||||||
valueTypeNode.executeAndSet(frame, value);
|
// the locals in `frame` (if any) are function arguments and/or outer for-generator bindings
|
||||||
}
|
VmUtils.copyLocals(frame, 0, newFrame, 0, frame.getFrameDescriptor().getNumberOfSlots());
|
||||||
} catch (VmTypeMismatchException e) {
|
if (keyTypeNode != null) {
|
||||||
CompilerDirectives.transferToInterpreter();
|
keyTypeNode.executeAndSet(newFrame, key);
|
||||||
throw e.toVmException();
|
|
||||||
}
|
}
|
||||||
|
if (valueTypeNode != null) {
|
||||||
Object[] prevBindings = null;
|
valueTypeNode.executeAndSet(newFrame, value);
|
||||||
if (keyTypeNode != null && valueTypeNode != null) {
|
|
||||||
prevBindings = data.addForBinding(key, value);
|
|
||||||
} else if (valueTypeNode != null) {
|
|
||||||
prevBindings = data.addForBinding(value);
|
|
||||||
} else if (keyTypeNode != null) {
|
|
||||||
prevBindings = data.addForBinding(key);
|
|
||||||
}
|
}
|
||||||
|
//noinspection ForLoopReplaceableByForEach
|
||||||
for (var childNode : childNodes) {
|
for (int i = 0; i < childNodes.length; i++) {
|
||||||
childNode.execute(frame, parent, data);
|
childNodes[i].execute(newFrame, parent, data);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data.resetForBindings(prevBindings);
|
private void initialize(VirtualFrame frame) {
|
||||||
|
if (unresolvedKeyTypeNode != null) {
|
||||||
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
|
var keySlot = frame.getFrameDescriptor().getNumberOfSlots();
|
||||||
|
keyTypeNode = insert(unresolvedKeyTypeNode.execute(frame)).initWriteSlotNode(keySlot);
|
||||||
|
generatorDescriptor.setSlotKind(keySlot, keyTypeNode.getFrameSlotKind());
|
||||||
|
unresolvedKeyTypeNode = null;
|
||||||
|
}
|
||||||
|
if (unresolvedValueTypeNode != null) {
|
||||||
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
|
var valueSlot = frame.getFrameDescriptor().getNumberOfSlots() + (keyTypeNode != null ? 1 : 0);
|
||||||
|
valueTypeNode = insert(unresolvedValueTypeNode.execute(frame)).initWriteSlotNode(valueSlot);
|
||||||
|
generatorDescriptor.setSlotKind(valueSlot, valueTypeNode.getFrameSlotKind());
|
||||||
|
unresolvedValueTypeNode = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-77
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,25 +16,23 @@
|
|||||||
package org.pkl.core.ast.expression.generator;
|
package org.pkl.core.ast.expression.generator;
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives.ValueType;
|
|
||||||
import com.oracle.truffle.api.dsl.Idempotent;
|
import com.oracle.truffle.api.dsl.Idempotent;
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
import java.util.Arrays;
|
|
||||||
import org.graalvm.collections.EconomicMap;
|
|
||||||
import org.pkl.core.ast.PklNode;
|
import org.pkl.core.ast.PklNode;
|
||||||
import org.pkl.core.ast.member.ObjectMember;
|
import org.pkl.core.ast.member.ObjectMember;
|
||||||
import org.pkl.core.runtime.Identifier;
|
import org.pkl.core.runtime.Identifier;
|
||||||
import org.pkl.core.runtime.VmClass;
|
import org.pkl.core.runtime.VmClass;
|
||||||
import org.pkl.core.runtime.VmException;
|
import org.pkl.core.runtime.VmException;
|
||||||
import org.pkl.core.runtime.VmException.ProgramValue;
|
import org.pkl.core.runtime.VmException.ProgramValue;
|
||||||
import org.pkl.core.util.EconomicMaps;
|
import org.pkl.core.runtime.VmUtils;
|
||||||
import org.pkl.core.util.Nullable;
|
|
||||||
|
|
||||||
public abstract class GeneratorMemberNode extends PklNode {
|
public abstract class GeneratorMemberNode extends PklNode {
|
||||||
protected GeneratorMemberNode(SourceSection sourceSection) {
|
final boolean isFrameStored;
|
||||||
|
|
||||||
|
protected GeneratorMemberNode(SourceSection sourceSection, boolean isFrameStored) {
|
||||||
super(sourceSection);
|
super(sourceSection);
|
||||||
|
this.isFrameStored = isFrameStored;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void execute(VirtualFrame frame, Object parent, ObjectData data);
|
public abstract void execute(VirtualFrame frame, Object parent, ObjectData data);
|
||||||
@@ -54,79 +52,39 @@ public abstract class GeneratorMemberNode extends PklNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Idempotent
|
@Idempotent
|
||||||
protected boolean checkIsValidTypedProperty(VmClass clazz, ObjectMember member) {
|
@SuppressWarnings("SameReturnValue")
|
||||||
if (member.isLocal() || clazz.hasProperty(member.getName())) return true;
|
protected final boolean checkIsValidTypedProperty(VmClass clazz, ObjectMember member) {
|
||||||
|
if (member.isLocal()) return true;
|
||||||
|
var memberName = member.getName();
|
||||||
|
var classProperty = clazz.getProperty(memberName);
|
||||||
|
if (classProperty != null && !classProperty.isConstOrFixed()) return true;
|
||||||
|
|
||||||
CompilerDirectives.transferToInterpreter();
|
CompilerDirectives.transferToInterpreter();
|
||||||
throw exceptionBuilder()
|
if (classProperty == null) {
|
||||||
.cannotFindProperty(clazz.getPrototype(), member.getName(), false, false)
|
var exception =
|
||||||
.withSourceSection(member.getHeaderSection())
|
exceptionBuilder()
|
||||||
.build();
|
.cannotFindProperty(clazz.getPrototype(), memberName, false, false)
|
||||||
}
|
.build();
|
||||||
|
if (member.getHeaderSection().isAvailable()) {
|
||||||
/**
|
exception
|
||||||
* <code>
|
.getInsertedStackFrames()
|
||||||
* x = new Mapping { for (i in IntSeq(1, 3)) for (key, value in Map(4, "Pigeon", 6, "Barn Owl")) [i *
|
.put(
|
||||||
* key] = value.reverse() }
|
getRootNode().getCallTarget(),
|
||||||
* </code>
|
VmUtils.createStackFrame(member.getHeaderSection(), member.getQualifiedName()));
|
||||||
*
|
|
||||||
* <p>The above code results in - 1 MemberNode for `value.reverse()` - 1 ObjectMember for `[i *
|
|
||||||
* key] = value.reverse()` - 1 ObjectData.members map with 6 identical ObjectMember values keyed
|
|
||||||
* by `i * key` - 1 ObjectData.forBindings map with 6 distinct arrays keyed by `i * key` Each
|
|
||||||
* array contains three elements, namely the current values for `i`, `key`, and `value`. - 1
|
|
||||||
* VmMapping whose `members` field holds `ObjectData.members` and whose `extraStorage` field holds
|
|
||||||
* `ObjectData.forBindings`. - 3 `FrameSlot`s for `i`, `key`, and `value`
|
|
||||||
*/
|
|
||||||
@ValueType
|
|
||||||
public static final class ObjectData {
|
|
||||||
// member count is exact iff every for/when body has exactly one member
|
|
||||||
ObjectData(int minMemberCount, int length) {
|
|
||||||
this.members = EconomicMaps.create(minMemberCount);
|
|
||||||
this.length = length;
|
|
||||||
}
|
|
||||||
|
|
||||||
final EconomicMap<Object, ObjectMember> members;
|
|
||||||
|
|
||||||
// For-bindings keyed by object member key.
|
|
||||||
// (There is only one ObjectMember instance per lexical member definition,
|
|
||||||
// hence can't store a member's for-bindings there.)
|
|
||||||
final EconomicMap<Object, Object[]> forBindings = EconomicMap.create();
|
|
||||||
|
|
||||||
int length;
|
|
||||||
|
|
||||||
private Object @Nullable [] currentForBindings;
|
|
||||||
|
|
||||||
@TruffleBoundary
|
|
||||||
Object @Nullable [] addForBinding(Object value) {
|
|
||||||
var result = currentForBindings;
|
|
||||||
if (currentForBindings == null) {
|
|
||||||
currentForBindings = new Object[] {value};
|
|
||||||
} else {
|
|
||||||
currentForBindings = Arrays.copyOf(currentForBindings, currentForBindings.length + 1);
|
|
||||||
currentForBindings[currentForBindings.length - 1] = value;
|
|
||||||
}
|
}
|
||||||
return result;
|
throw exception;
|
||||||
}
|
}
|
||||||
|
assert classProperty.isConstOrFixed();
|
||||||
@TruffleBoundary
|
var errMsg =
|
||||||
Object @Nullable [] addForBinding(Object key, Object value) {
|
classProperty.isConst() ? "cannotAssignConstProperty" : "cannotAssignFixedProperty";
|
||||||
var result = currentForBindings;
|
var exception = exceptionBuilder().evalError(errMsg, memberName).build();
|
||||||
if (currentForBindings == null) {
|
if (member.getHeaderSection().isAvailable()) {
|
||||||
currentForBindings = new Object[] {key, value};
|
exception
|
||||||
} else {
|
.getInsertedStackFrames()
|
||||||
currentForBindings = Arrays.copyOf(currentForBindings, currentForBindings.length + 2);
|
.put(
|
||||||
currentForBindings[currentForBindings.length - 2] = key;
|
getRootNode().getCallTarget(),
|
||||||
currentForBindings[currentForBindings.length - 1] = value;
|
VmUtils.createStackFrame(member.getHeaderSection(), member.getQualifiedName()));
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void persistForBindings(Object key) {
|
|
||||||
EconomicMaps.put(forBindings, key, currentForBindings);
|
|
||||||
}
|
|
||||||
|
|
||||||
void resetForBindings(Object @Nullable [] bindings) {
|
|
||||||
currentForBindings = bindings;
|
|
||||||
}
|
}
|
||||||
|
throw exception;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+33
-44
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -27,7 +27,6 @@ import com.oracle.truffle.api.frame.VirtualFrame;
|
|||||||
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
import org.pkl.core.ast.ExpressionNode;
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
import org.pkl.core.ast.expression.generator.GeneratorMemberNode.ObjectData;
|
|
||||||
import org.pkl.core.ast.expression.literal.AmendFunctionNode;
|
import org.pkl.core.ast.expression.literal.AmendFunctionNode;
|
||||||
import org.pkl.core.ast.expression.literal.ObjectLiteralNode;
|
import org.pkl.core.ast.expression.literal.ObjectLiteralNode;
|
||||||
import org.pkl.core.ast.type.UnresolvedTypeNode;
|
import org.pkl.core.ast.type.UnresolvedTypeNode;
|
||||||
@@ -73,34 +72,31 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode {
|
|||||||
|
|
||||||
@Specialization(guards = "checkObjectCannotHaveParameters()")
|
@Specialization(guards = "checkObjectCannotHaveParameters()")
|
||||||
protected VmDynamic evalDynamic(VirtualFrame frame, VmDynamic parent) {
|
protected VmDynamic evalDynamic(VirtualFrame frame, VmDynamic parent) {
|
||||||
var data = createData(frame, parent, parent.getLength());
|
var data = executeChildren(frame, parent, parent.getLength());
|
||||||
var result = new VmDynamic(frame.materialize(), parent, data.members, data.length);
|
var result = new VmDynamic(frame.materialize(), parent, data.members(), data.length());
|
||||||
result.setExtraStorage(data.forBindings);
|
return data.storeGeneratorFrames(result);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = "checkObjectCannotHaveParameters()")
|
@Specialization(guards = "checkObjectCannotHaveParameters()")
|
||||||
protected VmTyped evalTyped(VirtualFrame frame, VmTyped parent) {
|
protected VmTyped evalTyped(VirtualFrame frame, VmTyped parent) {
|
||||||
VmUtils.checkIsInstantiable(parent.getVmClass(), getParentNode());
|
VmUtils.checkIsInstantiable(parent.getVmClass(), getParentNode());
|
||||||
var data = createData(frame, parent, 0);
|
var data = executeChildren(frame, parent, 0);
|
||||||
assert data.forBindings.isEmpty();
|
assert data.hasNoGeneratorFrames();
|
||||||
return new VmTyped(frame.materialize(), parent, parent.getVmClass(), data.members);
|
return new VmTyped(frame.materialize(), parent, parent.getVmClass(), data.members());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = "checkListingCannotHaveParameters()")
|
@Specialization(guards = "checkListingCannotHaveParameters()")
|
||||||
protected VmListing evalListing(VirtualFrame frame, VmListing parent) {
|
protected VmListing evalListing(VirtualFrame frame, VmListing parent) {
|
||||||
var data = createData(frame, parent, parent.getLength());
|
var data = executeChildren(frame, parent, parent.getLength());
|
||||||
var result = new VmListing(frame.materialize(), parent, data.members, data.length);
|
var result = new VmListing(frame.materialize(), parent, data.members(), data.length());
|
||||||
result.setExtraStorage(data.forBindings);
|
return data.storeGeneratorFrames(result);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = "checkMappingCannotHaveParameters()")
|
@Specialization(guards = "checkMappingCannotHaveParameters()")
|
||||||
protected VmMapping evalMapping(VirtualFrame frame, VmMapping parent) {
|
protected VmMapping evalMapping(VirtualFrame frame, VmMapping parent) {
|
||||||
var data = createData(frame, parent, 0);
|
var data = executeChildren(frame, parent, 0);
|
||||||
var result = new VmMapping(frame.materialize(), parent, data.members);
|
var result = new VmMapping(frame.materialize(), parent, data.members());
|
||||||
result.setExtraStorage(data.forBindings);
|
return data.storeGeneratorFrames(result);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = "checkObjectCannotHaveParameters()")
|
@Specialization(guards = "checkObjectCannotHaveParameters()")
|
||||||
@@ -110,7 +106,7 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = "checkIsValidFunctionAmendment(parent)")
|
@Specialization(guards = "checkIsValidFunctionAmendment(parent)")
|
||||||
protected Object evalFunction(
|
protected VmFunction evalFunction(
|
||||||
VirtualFrame frame,
|
VirtualFrame frame,
|
||||||
VmFunction parent,
|
VmFunction parent,
|
||||||
@Cached(value = "createAmendFunctionNode(frame)", neverDefault = true)
|
@Cached(value = "createAmendFunctionNode(frame)", neverDefault = true)
|
||||||
@@ -120,41 +116,34 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = {"parent == getDynamicClass()", "checkObjectCannotHaveParameters()"})
|
@Specialization(guards = {"parent == getDynamicClass()", "checkObjectCannotHaveParameters()"})
|
||||||
protected VmDynamic evalDynamicClass(
|
protected VmDynamic evalDynamicClass(VirtualFrame frame, VmClass parent) {
|
||||||
VirtualFrame frame, @SuppressWarnings("unused") VmClass parent) {
|
var data = executeChildren(frame, parent, 0);
|
||||||
var data = createData(frame, parent, 0);
|
|
||||||
var result =
|
var result =
|
||||||
new VmDynamic(frame.materialize(), parent.getPrototype(), data.members, data.length);
|
new VmDynamic(frame.materialize(), parent.getPrototype(), data.members(), data.length());
|
||||||
result.setExtraStorage(data.forBindings);
|
return data.storeGeneratorFrames(result);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = {"parent == getMappingClass()", "checkMappingCannotHaveParameters()"})
|
@Specialization(guards = {"parent == getMappingClass()", "checkMappingCannotHaveParameters()"})
|
||||||
protected VmMapping evalMappingClass(
|
protected VmMapping evalMappingClass(VirtualFrame frame, VmClass parent) {
|
||||||
VirtualFrame frame, @SuppressWarnings("unused") VmClass parent) {
|
var data = executeChildren(frame, parent, 0);
|
||||||
var data = createData(frame, parent, 0);
|
var result = new VmMapping(frame.materialize(), parent.getPrototype(), data.members());
|
||||||
var result = new VmMapping(frame.materialize(), parent.getPrototype(), data.members);
|
return data.storeGeneratorFrames(result);
|
||||||
result.setExtraStorage(data.forBindings);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = {"parent == getListingClass()", "checkListingCannotHaveParameters()"})
|
@Specialization(guards = {"parent == getListingClass()", "checkListingCannotHaveParameters()"})
|
||||||
protected VmListing evalListingClass(
|
protected VmListing evalListingClass(VirtualFrame frame, VmClass parent) {
|
||||||
VirtualFrame frame, @SuppressWarnings("unused") VmClass parent) {
|
var data = executeChildren(frame, parent, 0);
|
||||||
var data = createData(frame, parent, 0);
|
|
||||||
var result =
|
var result =
|
||||||
new VmListing(frame.materialize(), parent.getPrototype(), data.members, data.length);
|
new VmListing(frame.materialize(), parent.getPrototype(), data.members(), data.length());
|
||||||
result.setExtraStorage(data.forBindings);
|
return data.storeGeneratorFrames(result);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = {"isTypedObjectClass(parent)", "checkObjectCannotHaveParameters()"})
|
@Specialization(guards = {"isTypedObjectClass(parent)", "checkObjectCannotHaveParameters()"})
|
||||||
protected VmTyped evalTypedObjectClass(
|
protected VmTyped evalTypedObjectClass(VirtualFrame frame, VmClass parent) {
|
||||||
VirtualFrame frame, @SuppressWarnings("unused") VmClass parent) {
|
|
||||||
VmUtils.checkIsInstantiable(parent, getParentNode());
|
VmUtils.checkIsInstantiable(parent, getParentNode());
|
||||||
var data = createData(frame, parent, 0);
|
var data = executeChildren(frame, parent, 0);
|
||||||
assert data.forBindings.isEmpty();
|
assert data.hasNoGeneratorFrames();
|
||||||
return new VmTyped(frame.materialize(), parent.getPrototype(), parent, data.members);
|
return new VmTyped(frame.materialize(), parent.getPrototype(), parent, data.members());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Fallback
|
@Fallback
|
||||||
@@ -200,9 +189,9 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ExplodeLoop
|
@ExplodeLoop
|
||||||
private ObjectData createData(VirtualFrame frame, Object parent, int parentLength) {
|
private ObjectData executeChildren(VirtualFrame frame, Object parent, int parentLength) {
|
||||||
var data = new ObjectData(memberNodes.length, parentLength);
|
var data = new ObjectData(parentLength);
|
||||||
for (GeneratorMemberNode memberNode : memberNodes) {
|
for (var memberNode : memberNodes) {
|
||||||
memberNode.execute(frame, parent, data);
|
memberNode.execute(frame, parent, data);
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
|
|||||||
+5
-13
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -34,8 +34,9 @@ public abstract class GeneratorPredicateMemberNode extends GeneratorMemberNode {
|
|||||||
|
|
||||||
@CompilationFinal private int customThisSlot = -1;
|
@CompilationFinal private int customThisSlot = -1;
|
||||||
|
|
||||||
protected GeneratorPredicateMemberNode(ExpressionNode predicateNode, ObjectMember member) {
|
protected GeneratorPredicateMemberNode(
|
||||||
super(member.getSourceSection());
|
ExpressionNode predicateNode, ObjectMember member, boolean isFrameStored) {
|
||||||
|
super(member.getSourceSection(), isFrameStored);
|
||||||
this.predicateNode = predicateNode;
|
this.predicateNode = predicateNode;
|
||||||
this.member = member;
|
this.member = member;
|
||||||
}
|
}
|
||||||
@@ -110,7 +111,7 @@ public abstract class GeneratorPredicateMemberNode extends GeneratorMemberNode {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
var isApplicable = predicateNode.executeBoolean(frame);
|
var isApplicable = predicateNode.executeBoolean(frame);
|
||||||
if (isApplicable) doAdd(key, data);
|
if (isApplicable) data.addMember(frame, key, this.member, this);
|
||||||
} catch (UnexpectedResultException e) {
|
} catch (UnexpectedResultException e) {
|
||||||
CompilerDirectives.transferToInterpreter();
|
CompilerDirectives.transferToInterpreter();
|
||||||
throw exceptionBuilder()
|
throw exceptionBuilder()
|
||||||
@@ -134,13 +135,4 @@ public abstract class GeneratorPredicateMemberNode extends GeneratorMemberNode {
|
|||||||
frame.getFrameDescriptor().findOrAddAuxiliarySlot(CustomThisScope.FRAME_SLOT_ID);
|
frame.getFrameDescriptor().findOrAddAuxiliarySlot(CustomThisScope.FRAME_SLOT_ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doAdd(Object key, ObjectData data) {
|
|
||||||
if (EconomicMaps.put(data.members, key, member) != null) {
|
|
||||||
CompilerDirectives.transferToInterpreter();
|
|
||||||
throw duplicateDefinition(key, member);
|
|
||||||
}
|
|
||||||
|
|
||||||
data.persistForBindings(key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-26
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -20,67 +20,67 @@ import com.oracle.truffle.api.dsl.Fallback;
|
|||||||
import com.oracle.truffle.api.dsl.Idempotent;
|
import com.oracle.truffle.api.dsl.Idempotent;
|
||||||
import com.oracle.truffle.api.dsl.ImportStatic;
|
import com.oracle.truffle.api.dsl.ImportStatic;
|
||||||
import com.oracle.truffle.api.dsl.Specialization;
|
import com.oracle.truffle.api.dsl.Specialization;
|
||||||
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
import org.pkl.core.ast.member.ObjectMember;
|
import org.pkl.core.ast.member.ObjectMember;
|
||||||
import org.pkl.core.runtime.*;
|
import org.pkl.core.runtime.*;
|
||||||
import org.pkl.core.util.EconomicMaps;
|
|
||||||
|
|
||||||
@ImportStatic({BaseModule.class, GeneratorObjectLiteralNode.class})
|
@ImportStatic({BaseModule.class, GeneratorObjectLiteralNode.class})
|
||||||
public abstract class GeneratorPropertyNode extends GeneratorMemberNode {
|
public abstract class GeneratorPropertyNode extends GeneratorMemberNode {
|
||||||
protected final ObjectMember member;
|
protected final ObjectMember member;
|
||||||
|
|
||||||
protected GeneratorPropertyNode(ObjectMember member) {
|
protected GeneratorPropertyNode(ObjectMember member) {
|
||||||
super(member.getSourceSection());
|
super(member.getSourceSection(), false);
|
||||||
this.member = member;
|
this.member = member;
|
||||||
assert member.isProp();
|
assert member.isProp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
protected void evalDynamic(VmDynamic parent, ObjectData data) {
|
protected void evalDynamic(VirtualFrame frame, VmDynamic parent, ObjectData data) {
|
||||||
addProperty(data);
|
data.addProperty(frame, member, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Specialization(guards = "checkIsValidTypedProperty(parent.getVmClass(), member)")
|
@Specialization(guards = "checkIsValidTypedProperty(parent.getVmClass(), member)")
|
||||||
protected void evalTyped(VmTyped parent, ObjectData data) {
|
protected void evalTyped(VirtualFrame frame, VmTyped parent, ObjectData data) {
|
||||||
addProperty(data);
|
data.addProperty(frame, member, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Specialization(guards = "checkIsValidMappingProperty()")
|
@Specialization(guards = "checkIsValidMappingProperty()")
|
||||||
protected void evalMapping(VmMapping parent, ObjectData data) {
|
protected void evalMapping(VirtualFrame frame, VmMapping parent, ObjectData data) {
|
||||||
addProperty(data);
|
data.addProperty(frame, member, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Specialization(guards = "checkIsValidListingProperty()")
|
@Specialization(guards = "checkIsValidListingProperty()")
|
||||||
protected void evalListing(VmListing parent, ObjectData data) {
|
protected void evalListing(VirtualFrame frame, VmListing parent, ObjectData data) {
|
||||||
addProperty(data);
|
data.addProperty(frame, member, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Specialization(guards = "parent == getDynamicClass()")
|
@Specialization(guards = "parent == getDynamicClass()")
|
||||||
protected void evalDynamicClass(VmClass parent, ObjectData data) {
|
protected void evalDynamicClass(VirtualFrame frame, VmClass parent, ObjectData data) {
|
||||||
addProperty(data);
|
data.addProperty(frame, member, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Specialization(guards = {"parent == getMappingClass()", "checkIsValidMappingProperty()"})
|
@Specialization(guards = {"parent == getMappingClass()", "checkIsValidMappingProperty()"})
|
||||||
protected void evalMappingClass(VmClass parent, ObjectData data) {
|
protected void evalMappingClass(VirtualFrame frame, VmClass parent, ObjectData data) {
|
||||||
addProperty(data);
|
data.addProperty(frame, member, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Specialization(guards = {"parent == getListingClass()", "checkIsValidListingProperty()"})
|
@Specialization(guards = {"parent == getListingClass()", "checkIsValidListingProperty()"})
|
||||||
protected void evalListingClass(VmClass parent, ObjectData data) {
|
protected void evalListingClass(VirtualFrame frame, VmClass parent, ObjectData data) {
|
||||||
addProperty(data);
|
data.addProperty(frame, member, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Specialization(
|
@Specialization(
|
||||||
guards = {"isTypedObjectClass(parent)", "checkIsValidTypedProperty(parent, member)"})
|
guards = {"isTypedObjectClass(parent)", "checkIsValidTypedProperty(parent, member)"})
|
||||||
protected void evalTypedObjectClass(VmClass parent, ObjectData data) {
|
protected void evalTypedObjectClass(VirtualFrame frame, VmClass parent, ObjectData data) {
|
||||||
addProperty(data);
|
data.addProperty(frame, member, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Fallback
|
@Fallback
|
||||||
@@ -116,11 +116,4 @@ public abstract class GeneratorPropertyNode extends GeneratorMemberNode {
|
|||||||
.withSourceSection(member.getHeaderSection())
|
.withSourceSection(member.getHeaderSection())
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addProperty(ObjectData data) {
|
|
||||||
if (EconomicMaps.put(data.members, member.getName(), member) == null) return;
|
|
||||||
|
|
||||||
CompilerDirectives.transferToInterpreter();
|
|
||||||
throw duplicateDefinition(member.getName(), member);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+62
-107
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -19,7 +19,6 @@ import static org.pkl.core.runtime.BaseModule.getListingClass;
|
|||||||
import static org.pkl.core.runtime.BaseModule.getMappingClass;
|
import static org.pkl.core.runtime.BaseModule.getMappingClass;
|
||||||
|
|
||||||
import com.oracle.truffle.api.CompilerDirectives;
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
|
||||||
import com.oracle.truffle.api.dsl.Fallback;
|
import com.oracle.truffle.api.dsl.Fallback;
|
||||||
import com.oracle.truffle.api.dsl.ImportStatic;
|
import com.oracle.truffle.api.dsl.ImportStatic;
|
||||||
import com.oracle.truffle.api.dsl.Specialization;
|
import com.oracle.truffle.api.dsl.Specialization;
|
||||||
@@ -29,9 +28,11 @@ import org.pkl.core.ast.ExpressionNode;
|
|||||||
import org.pkl.core.ast.member.ObjectMember;
|
import org.pkl.core.ast.member.ObjectMember;
|
||||||
import org.pkl.core.runtime.BaseModule;
|
import org.pkl.core.runtime.BaseModule;
|
||||||
import org.pkl.core.runtime.Identifier;
|
import org.pkl.core.runtime.Identifier;
|
||||||
|
import org.pkl.core.runtime.Iterators.TruffleIterator;
|
||||||
import org.pkl.core.runtime.VmClass;
|
import org.pkl.core.runtime.VmClass;
|
||||||
import org.pkl.core.runtime.VmCollection;
|
import org.pkl.core.runtime.VmCollection;
|
||||||
import org.pkl.core.runtime.VmDynamic;
|
import org.pkl.core.runtime.VmDynamic;
|
||||||
|
import org.pkl.core.runtime.VmException;
|
||||||
import org.pkl.core.runtime.VmException.ProgramValue;
|
import org.pkl.core.runtime.VmException.ProgramValue;
|
||||||
import org.pkl.core.runtime.VmIntSeq;
|
import org.pkl.core.runtime.VmIntSeq;
|
||||||
import org.pkl.core.runtime.VmListing;
|
import org.pkl.core.runtime.VmListing;
|
||||||
@@ -41,8 +42,6 @@ import org.pkl.core.runtime.VmNull;
|
|||||||
import org.pkl.core.runtime.VmObject;
|
import org.pkl.core.runtime.VmObject;
|
||||||
import org.pkl.core.runtime.VmTyped;
|
import org.pkl.core.runtime.VmTyped;
|
||||||
import org.pkl.core.runtime.VmUtils;
|
import org.pkl.core.runtime.VmUtils;
|
||||||
import org.pkl.core.util.EconomicMaps;
|
|
||||||
import org.pkl.core.util.MutableLong;
|
|
||||||
|
|
||||||
@ImportStatic(BaseModule.class)
|
@ImportStatic(BaseModule.class)
|
||||||
public abstract class GeneratorSpreadNode extends GeneratorMemberNode {
|
public abstract class GeneratorSpreadNode extends GeneratorMemberNode {
|
||||||
@@ -51,7 +50,7 @@ public abstract class GeneratorSpreadNode extends GeneratorMemberNode {
|
|||||||
|
|
||||||
public GeneratorSpreadNode(
|
public GeneratorSpreadNode(
|
||||||
SourceSection sourceSection, ExpressionNode iterableNode, boolean nullable) {
|
SourceSection sourceSection, ExpressionNode iterableNode, boolean nullable) {
|
||||||
super(sourceSection);
|
super(sourceSection, false);
|
||||||
this.iterableNode = iterableNode;
|
this.iterableNode = iterableNode;
|
||||||
this.nullable = nullable;
|
this.nullable = nullable;
|
||||||
}
|
}
|
||||||
@@ -84,78 +83,82 @@ public abstract class GeneratorSpreadNode extends GeneratorMemberNode {
|
|||||||
|
|
||||||
@Specialization(guards = "!iterable.isTyped()")
|
@Specialization(guards = "!iterable.isTyped()")
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
protected void eval(VmDynamic parent, ObjectData data, VmObject iterable) {
|
protected void eval(VirtualFrame frame, VmDynamic parent, ObjectData data, VmObject iterable) {
|
||||||
doEvalDynamic(data, iterable);
|
doEvalDynamic(frame, data, iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = "!iterable.isTyped()")
|
@Specialization(guards = "!iterable.isTyped()")
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
protected void eval(VmListing parent, ObjectData data, VmObject iterable) {
|
protected void eval(VirtualFrame frame, VmListing parent, ObjectData data, VmObject iterable) {
|
||||||
doEvalListing(data, iterable);
|
doEvalListing(frame, data, iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = "!iterable.isTyped()")
|
@Specialization(guards = "!iterable.isTyped()")
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
protected void eval(VmMapping parent, ObjectData data, VmObject iterable) {
|
protected void eval(VirtualFrame frame, VmMapping parent, ObjectData data, VmObject iterable) {
|
||||||
doEvalMapping(data, iterable);
|
doEvalMapping(frame, data, iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = {"parent == getDynamicClass()", "!iterable.isTyped()"})
|
@Specialization(guards = {"parent == getDynamicClass()", "!iterable.isTyped()"})
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
protected void evalDynamicClass(VmClass parent, ObjectData data, VmObject iterable) {
|
protected void evalDynamicClass(
|
||||||
doEvalDynamic(data, iterable);
|
VirtualFrame frame, VmClass parent, ObjectData data, VmObject iterable) {
|
||||||
|
doEvalDynamic(frame, data, iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = {"parent == getListingClass()", "!iterable.isTyped()"})
|
@Specialization(guards = {"parent == getListingClass()", "!iterable.isTyped()"})
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
protected void evalListingClass(VmClass parent, ObjectData data, VmObject iterable) {
|
protected void evalListingClass(
|
||||||
doEvalListing(data, iterable);
|
VirtualFrame frame, VmClass parent, ObjectData data, VmObject iterable) {
|
||||||
|
doEvalListing(frame, data, iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = {"parent == getMappingClass()", "!iterable.isTyped()"})
|
@Specialization(guards = {"parent == getMappingClass()", "!iterable.isTyped()"})
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
protected void evalMappingClass(VmClass parent, ObjectData data, VmObject iterable) {
|
protected void evalMappingClass(
|
||||||
doEvalMapping(data, iterable);
|
VirtualFrame frame, VmClass parent, ObjectData data, VmObject iterable) {
|
||||||
|
doEvalMapping(frame, data, iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = {"isTypedObjectClass(parent)", "!iterable.isTyped()"})
|
@Specialization(guards = {"isTypedObjectClass(parent)", "!iterable.isTyped()"})
|
||||||
protected void evalTypedClass(VmClass parent, ObjectData data, VmObject iterable) {
|
protected void evalTypedClass(
|
||||||
doEvalTyped(parent, data, iterable);
|
VirtualFrame frame, VmClass parent, ObjectData data, VmObject iterable) {
|
||||||
|
doEvalTyped(frame, parent, data, iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(guards = {"!iterable.isTyped()"})
|
@Specialization(guards = {"!iterable.isTyped()"})
|
||||||
protected void eval(VmTyped parent, ObjectData data, VmObject iterable) {
|
protected void eval(VirtualFrame frame, VmTyped parent, ObjectData data, VmObject iterable) {
|
||||||
doEvalTyped(parent.getVmClass(), data, iterable);
|
doEvalTyped(frame, parent.getVmClass(), data, iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
protected void eval(VmObject parent, ObjectData data, VmMap iterable) {
|
protected void eval(VirtualFrame frame, VmObject parent, ObjectData data, VmMap iterable) {
|
||||||
doEvalMap(parent.getVmClass(), data, iterable);
|
doEvalMap(frame, parent.getVmClass(), data, iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
protected void eval(VmClass parent, ObjectData data, VmMap iterable) {
|
protected void eval(VirtualFrame frame, VmClass parent, ObjectData data, VmMap iterable) {
|
||||||
doEvalMap(parent, data, iterable);
|
doEvalMap(frame, parent, data, iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
protected void eval(VmObject parent, ObjectData data, VmCollection iterable) {
|
protected void eval(VirtualFrame frame, VmObject parent, ObjectData data, VmCollection iterable) {
|
||||||
doEvalCollection(parent.getVmClass(), data, iterable);
|
doEvalCollection(frame, parent.getVmClass(), data, iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
protected void eval(VmClass parent, ObjectData data, VmCollection iterable) {
|
protected void eval(VirtualFrame frame, VmClass parent, ObjectData data, VmCollection iterable) {
|
||||||
doEvalCollection(parent, data, iterable);
|
doEvalCollection(frame, parent, data, iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
protected void eval(VmObject parent, ObjectData data, VmIntSeq iterable) {
|
protected void eval(VirtualFrame frame, VmObject parent, ObjectData data, VmIntSeq iterable) {
|
||||||
doEvalIntSeq(parent.getVmClass(), data, iterable);
|
doEvalIntSeq(frame, parent.getVmClass(), data, iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization
|
@Specialization
|
||||||
protected void eval(VmClass parent, ObjectData data, VmIntSeq iterable) {
|
protected void eval(VirtualFrame frame, VmClass parent, ObjectData data, VmIntSeq iterable) {
|
||||||
doEvalIntSeq(parent, data, iterable);
|
doEvalIntSeq(frame, parent, data, iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Fallback
|
@Fallback
|
||||||
@@ -174,64 +177,55 @@ public abstract class GeneratorSpreadNode extends GeneratorMemberNode {
|
|||||||
throw builder.build();
|
throw builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void doEvalDynamic(ObjectData data, VmObject iterable) {
|
protected void doEvalDynamic(VirtualFrame frame, ObjectData data, VmObject iterable) {
|
||||||
var length = new MutableLong(data.length);
|
|
||||||
iterable.forceAndIterateMemberValues(
|
iterable.forceAndIterateMemberValues(
|
||||||
(key, member, value) -> {
|
(key, member, value) -> {
|
||||||
if (member.isElement()) {
|
if (member.isElement()) {
|
||||||
EconomicMaps.put(data.members, length.getAndIncrement(), createMember(member, value));
|
data.addElement(frame, createMember(member, value), this);
|
||||||
} else {
|
} else {
|
||||||
if (EconomicMaps.put(data.members, key, createMember(member, value)) != null) {
|
data.addMember(frame, key, createMember(member, value), this);
|
||||||
duplicateMember(key, member);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
data.length = (int) length.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doEvalMapping(ObjectData data, VmObject iterable) {
|
private void doEvalMapping(VirtualFrame frame, ObjectData data, VmObject iterable) {
|
||||||
iterable.forceAndIterateMemberValues(
|
iterable.forceAndIterateMemberValues(
|
||||||
(key, member, value) -> {
|
(key, member, value) -> {
|
||||||
if (member.isElement() || member.isProp()) {
|
if (member.isElement() || member.isProp()) {
|
||||||
cannotHaveMember(BaseModule.getMappingClass(), member);
|
cannotHaveMember(BaseModule.getMappingClass(), member);
|
||||||
}
|
}
|
||||||
if (EconomicMaps.put(data.members, key, createMember(member, value)) != null) {
|
data.addMember(frame, key, createMember(member, value), this);
|
||||||
duplicateMember(key, member);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doEvalListing(ObjectData data, VmObject iterable) {
|
private void doEvalListing(VirtualFrame frame, ObjectData data, VmObject iterable) {
|
||||||
var length = new MutableLong(data.length);
|
|
||||||
iterable.forceAndIterateMemberValues(
|
iterable.forceAndIterateMemberValues(
|
||||||
(key, member, value) -> {
|
(key, member, value) -> {
|
||||||
if (member.isEntry() || member.isProp()) {
|
if (member.isEntry() || member.isProp()) {
|
||||||
cannotHaveMember(getListingClass(), member);
|
cannotHaveMember(getListingClass(), member);
|
||||||
}
|
}
|
||||||
EconomicMaps.put(data.members, length.getAndIncrement(), createMember(member, value));
|
data.addElement(frame, createMember(member, value), this);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
data.length = (int) length.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doEvalTyped(VmClass clazz, ObjectData data, VmObject iterable) {
|
private void doEvalTyped(VirtualFrame frame, VmClass clazz, ObjectData data, VmObject iterable) {
|
||||||
iterable.forceAndIterateMemberValues(
|
iterable.forceAndIterateMemberValues(
|
||||||
(key, member, value) -> {
|
(key, member, value) -> {
|
||||||
if (member.isElement() || member.isEntry()) {
|
if (member.isElement() || member.isEntry()) {
|
||||||
cannotHaveMember(clazz, member);
|
cannotHaveMember(clazz, member);
|
||||||
}
|
}
|
||||||
checkTypedProperty(clazz, member);
|
checkIsValidTypedProperty(clazz, member);
|
||||||
if (EconomicMaps.put(data.members, key, createMember(member, value)) != null) {
|
data.addProperty(frame, createMember(member, value), this);
|
||||||
duplicateMember(key, member);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// handles both `List` and `Set`
|
// handles both `List` and `Set`
|
||||||
private void doEvalCollection(VmClass parent, ObjectData data, VmCollection iterable) {
|
private void doEvalCollection(
|
||||||
|
VirtualFrame frame, VmClass parent, ObjectData data, VmCollection iterable) {
|
||||||
if (isTypedObjectClass(parent) || parent == getMappingClass()) {
|
if (isTypedObjectClass(parent) || parent == getMappingClass()) {
|
||||||
CompilerDirectives.transferToInterpreter();
|
CompilerDirectives.transferToInterpreter();
|
||||||
throw exceptionBuilder()
|
throw exceptionBuilder()
|
||||||
@@ -241,10 +235,10 @@ public abstract class GeneratorSpreadNode extends GeneratorMemberNode {
|
|||||||
.withProgramValue("Value", iterable)
|
.withProgramValue("Value", iterable)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
spreadIterable(data, iterable);
|
spreadIterable(frame, data, iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doEvalMap(VmClass parent, ObjectData data, VmMap iterable) {
|
private void doEvalMap(VirtualFrame frame, VmClass parent, ObjectData data, VmMap iterable) {
|
||||||
if (isTypedObjectClass(parent) || parent == getListingClass()) {
|
if (isTypedObjectClass(parent) || parent == getListingClass()) {
|
||||||
CompilerDirectives.transferToInterpreter();
|
CompilerDirectives.transferToInterpreter();
|
||||||
throw exceptionBuilder()
|
throw exceptionBuilder()
|
||||||
@@ -255,13 +249,12 @@ public abstract class GeneratorSpreadNode extends GeneratorMemberNode {
|
|||||||
}
|
}
|
||||||
for (var entry : iterable) {
|
for (var entry : iterable) {
|
||||||
var member = VmUtils.createSyntheticObjectEntry("", VmUtils.getValue(entry));
|
var member = VmUtils.createSyntheticObjectEntry("", VmUtils.getValue(entry));
|
||||||
if (EconomicMaps.put(data.members, VmUtils.getKey(entry), member) != null) {
|
data.addMember(frame, VmUtils.getKey(entry), member, this);
|
||||||
duplicateMember(VmUtils.getKey(entry), member);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doEvalIntSeq(VmClass parent, ObjectData data, VmIntSeq iterable) {
|
private void doEvalIntSeq(
|
||||||
|
VirtualFrame frame, VmClass parent, ObjectData data, VmIntSeq iterable) {
|
||||||
if (isTypedObjectClass(parent) || parent == getMappingClass()) {
|
if (isTypedObjectClass(parent) || parent == getMappingClass()) {
|
||||||
CompilerDirectives.transferToInterpreter();
|
CompilerDirectives.transferToInterpreter();
|
||||||
throw exceptionBuilder()
|
throw exceptionBuilder()
|
||||||
@@ -270,7 +263,7 @@ public abstract class GeneratorSpreadNode extends GeneratorMemberNode {
|
|||||||
.withProgramValue("Value", iterable)
|
.withProgramValue("Value", iterable)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
spreadIterable(data, iterable);
|
spreadIterable(frame, data, iterable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cannotHaveMember(VmClass clazz, ObjectMember member) {
|
private void cannotHaveMember(VmClass clazz, ObjectMember member) {
|
||||||
@@ -295,7 +288,8 @@ public abstract class GeneratorSpreadNode extends GeneratorMemberNode {
|
|||||||
throw exception;
|
throw exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void duplicateMember(Object key, ObjectMember member) {
|
@Override
|
||||||
|
protected VmException duplicateDefinition(Object key, ObjectMember member) {
|
||||||
CompilerDirectives.transferToInterpreter();
|
CompilerDirectives.transferToInterpreter();
|
||||||
var exception =
|
var exception =
|
||||||
exceptionBuilder()
|
exceptionBuilder()
|
||||||
@@ -331,51 +325,12 @@ public abstract class GeneratorSpreadNode extends GeneratorMemberNode {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@TruffleBoundary
|
private void spreadIterable(VirtualFrame frame, ObjectData data, Iterable<?> iterable) {
|
||||||
private void spreadIterable(ObjectData data, Iterable<?> iterable) {
|
var iterator = new TruffleIterator<>(iterable);
|
||||||
var length = data.length;
|
while (iterator.hasNext()) {
|
||||||
for (var elem : iterable) {
|
var elem = iterator.next();
|
||||||
var index = length++;
|
var member = VmUtils.createSyntheticObjectElement(String.valueOf(data.length()), elem);
|
||||||
var member = VmUtils.createSyntheticObjectElement(String.valueOf(index), elem);
|
data.addElement(frame, member, this);
|
||||||
EconomicMaps.put(data.members, (long) index, member);
|
|
||||||
}
|
|
||||||
data.length = length;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void checkTypedProperty(VmClass clazz, ObjectMember member) {
|
|
||||||
if (member.isLocal()) return;
|
|
||||||
|
|
||||||
var memberName = member.getName();
|
|
||||||
var classProperty = clazz.getProperty(memberName);
|
|
||||||
if (classProperty == null) {
|
|
||||||
CompilerDirectives.transferToInterpreter();
|
|
||||||
var exception =
|
|
||||||
exceptionBuilder()
|
|
||||||
.cannotFindProperty(clazz.getPrototype(), memberName, false, false)
|
|
||||||
.build();
|
|
||||||
if (member.getHeaderSection().isAvailable()) {
|
|
||||||
exception
|
|
||||||
.getInsertedStackFrames()
|
|
||||||
.put(
|
|
||||||
getRootNode().getCallTarget(),
|
|
||||||
VmUtils.createStackFrame(member.getHeaderSection(), member.getQualifiedName()));
|
|
||||||
}
|
|
||||||
throw exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (classProperty.isConstOrFixed()) {
|
|
||||||
CompilerDirectives.transferToInterpreter();
|
|
||||||
var errMsg =
|
|
||||||
classProperty.isConst() ? "cannotAssignConstProperty" : "cannotAssignFixedProperty";
|
|
||||||
var exception = exceptionBuilder().evalError(errMsg, memberName).build();
|
|
||||||
if (member.getHeaderSection().isAvailable()) {
|
|
||||||
exception
|
|
||||||
.getInsertedStackFrames()
|
|
||||||
.put(
|
|
||||||
getRootNode().getCallTarget(),
|
|
||||||
VmUtils.createStackFrame(member.getHeaderSection(), member.getQualifiedName()));
|
|
||||||
}
|
|
||||||
throw exception;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -34,7 +34,7 @@ public final class GeneratorWhenNode extends GeneratorMemberNode {
|
|||||||
GeneratorMemberNode[] thenNodes,
|
GeneratorMemberNode[] thenNodes,
|
||||||
GeneratorMemberNode[] elseNodes) {
|
GeneratorMemberNode[] elseNodes) {
|
||||||
|
|
||||||
super(sourceSection);
|
super(sourceSection, false);
|
||||||
this.conditionNode = conditionNode;
|
this.conditionNode = conditionNode;
|
||||||
this.thenNodes = thenNodes;
|
this.thenNodes = thenNodes;
|
||||||
this.elseNodes = elseNodes;
|
this.elseNodes = elseNodes;
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* 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.ast.expression.generator;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.CompilerDirectives;
|
||||||
|
import com.oracle.truffle.api.frame.MaterializedFrame;
|
||||||
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
|
import org.graalvm.collections.EconomicMap;
|
||||||
|
import org.graalvm.collections.UnmodifiableEconomicMap;
|
||||||
|
import org.pkl.core.ast.member.ObjectMember;
|
||||||
|
import org.pkl.core.runtime.VmObject;
|
||||||
|
import org.pkl.core.runtime.VmUtils;
|
||||||
|
import org.pkl.core.util.EconomicMaps;
|
||||||
|
|
||||||
|
/** Data collected by {@link GeneratorObjectLiteralNode} to generate a `VmObject`. */
|
||||||
|
public final class ObjectData {
|
||||||
|
/** The object's members. */
|
||||||
|
private final EconomicMap<Object, ObjectMember> members;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The frames that were active when `members` were generated. Only a subset of members have their
|
||||||
|
* frames stored ({@link GeneratorMemberNode#isFrameStored}). Frames are stored in
|
||||||
|
* `owner.extraStorage` and retrieved by `RestoreForBindingsNode` when members are executed
|
||||||
|
*/
|
||||||
|
private final EconomicMap<Object, MaterializedFrame> generatorFrames;
|
||||||
|
|
||||||
|
/** The object's number of elements. */
|
||||||
|
private int length;
|
||||||
|
|
||||||
|
ObjectData(int parentLength) {
|
||||||
|
// optimize for memory usage by not estimating minimum size
|
||||||
|
members = EconomicMaps.create();
|
||||||
|
generatorFrames = EconomicMaps.create();
|
||||||
|
length = parentLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
UnmodifiableEconomicMap<Object, ObjectMember> members() {
|
||||||
|
return members;
|
||||||
|
}
|
||||||
|
|
||||||
|
int length() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasNoGeneratorFrames() {
|
||||||
|
return generatorFrames.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void addElement(VirtualFrame frame, ObjectMember member, GeneratorMemberNode node) {
|
||||||
|
addMember(frame, (long) length, member, node);
|
||||||
|
length += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addProperty(VirtualFrame frame, ObjectMember member, GeneratorMemberNode node) {
|
||||||
|
addMember(frame, member.getName(), member, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void addMember(VirtualFrame frame, Object key, ObjectMember member, GeneratorMemberNode node) {
|
||||||
|
if (EconomicMaps.put(members, key, member) != null) {
|
||||||
|
CompilerDirectives.transferToInterpreter();
|
||||||
|
throw node.duplicateDefinition(key, member);
|
||||||
|
}
|
||||||
|
if (node.isFrameStored) {
|
||||||
|
EconomicMaps.put(generatorFrames, key, frame.materialize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<T extends VmObject> T storeGeneratorFrames(T object) {
|
||||||
|
object.setExtraStorage(generatorFrames);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MaterializedFrame getGeneratorFrame(VirtualFrame frame) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
var map = (EconomicMap<Object, MaterializedFrame>) VmUtils.getOwner(frame).getExtraStorage();
|
||||||
|
var result = EconomicMaps.get(map, VmUtils.getMemberKey(frame));
|
||||||
|
assert result != null;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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.ast.expression.generator;
|
||||||
|
|
||||||
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
|
import org.pkl.core.runtime.VmUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores for-generator variable bindings when a member generated by a for-generator is executed.
|
||||||
|
*/
|
||||||
|
public final class RestoreForBindingsNode extends ExpressionNode {
|
||||||
|
private @Child ExpressionNode child;
|
||||||
|
|
||||||
|
public RestoreForBindingsNode(ExpressionNode child) {
|
||||||
|
super(child.getSourceSection());
|
||||||
|
this.child = child;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object executeGeneric(VirtualFrame frame) {
|
||||||
|
var generatorFrame = ObjectData.getGeneratorFrame(frame);
|
||||||
|
var numSlots = frame.getFrameDescriptor().getNumberOfSlots();
|
||||||
|
// This value is constant and could be a constructor argument.
|
||||||
|
var startSlot = generatorFrame.getFrameDescriptor().getNumberOfSlots() - numSlots;
|
||||||
|
assert startSlot >= 0;
|
||||||
|
// Copy locals that are for-generator variables into this frame.
|
||||||
|
// Slots before `startSlot` (if any) are function arguments
|
||||||
|
// and must not be copied to preserve scoping rules.
|
||||||
|
VmUtils.copyLocals(generatorFrame, startSlot, frame, 0, numSlots);
|
||||||
|
return child.executeGeneric(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
-52
@@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2024 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.ast.expression.generator;
|
|
||||||
|
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
|
||||||
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
|
||||||
import org.graalvm.collections.UnmodifiableEconomicMap;
|
|
||||||
import org.pkl.core.ast.ExpressionNode;
|
|
||||||
import org.pkl.core.runtime.VmUtils;
|
|
||||||
import org.pkl.core.util.EconomicMaps;
|
|
||||||
|
|
||||||
public final class WriteForVariablesNode extends ExpressionNode {
|
|
||||||
private final int[] auxiliarySlots;
|
|
||||||
@Child private ExpressionNode childNode;
|
|
||||||
|
|
||||||
public WriteForVariablesNode(int[] auxiliarySlots, ExpressionNode childNode) {
|
|
||||||
this.auxiliarySlots = auxiliarySlots;
|
|
||||||
this.childNode = childNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@ExplodeLoop
|
|
||||||
public Object executeGeneric(VirtualFrame frame) {
|
|
||||||
var extraStorage = VmUtils.getOwner(frame).getExtraStorage();
|
|
||||||
assert extraStorage instanceof UnmodifiableEconomicMap;
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
var forBindings = (UnmodifiableEconomicMap<Object, Object[]>) extraStorage;
|
|
||||||
var bindings = EconomicMaps.get(forBindings, VmUtils.getMemberKey(frame));
|
|
||||||
assert bindings != null;
|
|
||||||
assert bindings.length == auxiliarySlots.length;
|
|
||||||
|
|
||||||
for (var i = 0; i < auxiliarySlots.length; i++) {
|
|
||||||
frame.setAuxiliarySlot(auxiliarySlots[i], bindings[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return childNode.executeGeneric(frame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -26,8 +26,6 @@ import org.pkl.core.ast.ExpressionNode;
|
|||||||
import org.pkl.core.ast.PklNode;
|
import org.pkl.core.ast.PklNode;
|
||||||
import org.pkl.core.ast.PklRootNode;
|
import org.pkl.core.ast.PklRootNode;
|
||||||
import org.pkl.core.ast.SimpleRootNode;
|
import org.pkl.core.ast.SimpleRootNode;
|
||||||
import org.pkl.core.ast.builder.SymbolTable;
|
|
||||||
import org.pkl.core.ast.builder.SymbolTable.CustomThisScope;
|
|
||||||
import org.pkl.core.ast.frame.ReadFrameSlotNodeGen;
|
import org.pkl.core.ast.frame.ReadFrameSlotNodeGen;
|
||||||
import org.pkl.core.ast.member.FunctionNode;
|
import org.pkl.core.ast.member.FunctionNode;
|
||||||
import org.pkl.core.ast.member.Lambda;
|
import org.pkl.core.ast.member.Lambda;
|
||||||
@@ -40,10 +38,7 @@ public final class AmendFunctionNode extends PklNode {
|
|||||||
private final PklRootNode initialFunctionRootNode;
|
private final PklRootNode initialFunctionRootNode;
|
||||||
@CompilationFinal private int customThisSlot = -1;
|
@CompilationFinal private int customThisSlot = -1;
|
||||||
|
|
||||||
public AmendFunctionNode(
|
public AmendFunctionNode(ObjectLiteralNode hostNode, TypeNode[] parameterTypeNodes) {
|
||||||
ObjectLiteralNode hostNode,
|
|
||||||
TypeNode[] parameterTypeNodes,
|
|
||||||
FrameDescriptor hostFrameDescriptor) {
|
|
||||||
super(hostNode.getSourceSection());
|
super(hostNode.getSourceSection());
|
||||||
|
|
||||||
isCustomThisScope = hostNode.isCustomThisScope;
|
isCustomThisScope = hostNode.isCustomThisScope;
|
||||||
@@ -61,39 +56,7 @@ public final class AmendFunctionNode extends PklNode {
|
|||||||
} else {
|
} else {
|
||||||
parameterSlots = new int[0];
|
parameterSlots = new int[0];
|
||||||
}
|
}
|
||||||
var hasForGenVars = false;
|
var objectToAmendSlot = builder.addSlot(FrameSlotKind.Object, null, null);
|
||||||
for (var i = 0; i < hostFrameDescriptor.getNumberOfSlots(); i++) {
|
|
||||||
var slotInfo = hostFrameDescriptor.getSlotInfo(i);
|
|
||||||
// Copy for-generator variables from the outer frame descriptor into inner lambda.
|
|
||||||
//
|
|
||||||
// We need to do this because at parse time within AstBuilder, we inject for-generator
|
|
||||||
// variables into the frame descriptor of the containing root node.
|
|
||||||
// The expectation is that when GeneratorForNode executes, it writes for-generator variables
|
|
||||||
// into these slots.
|
|
||||||
//
|
|
||||||
// In the case of an amend function node, AstBuilder can't determine out that there is another
|
|
||||||
// frame (e.g. with `new Mixin { ... }` syntax), so it injects for-generator vars into the
|
|
||||||
// wrong frame.
|
|
||||||
//
|
|
||||||
// As a remedy, we simply copy outer variables into this frame if there are any for generator
|
|
||||||
// variables.
|
|
||||||
//
|
|
||||||
// We need to preserve the frame slot index, so we insert dummy identifiers
|
|
||||||
// for other slots that aren't for generator variables.
|
|
||||||
if (slotInfo != null && slotInfo.equals(SymbolTable.FOR_GENERATOR_VARIABLE)) {
|
|
||||||
if (!hasForGenVars) {
|
|
||||||
hasForGenVars = true;
|
|
||||||
for (var j = 0; j < i; j++) {
|
|
||||||
builder.addSlot(FrameSlotKind.Illegal, Identifier.DUMMY, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
builder.addSlot(
|
|
||||||
hostFrameDescriptor.getSlotKind(i), hostFrameDescriptor.getSlotName(i), null);
|
|
||||||
} else if (hasForGenVars) {
|
|
||||||
builder.addSlot(FrameSlotKind.Illegal, Identifier.DUMMY, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var objectToAmendSlot = builder.addSlot(FrameSlotKind.Object, new Object(), null);
|
|
||||||
var frameDescriptor = builder.build();
|
var frameDescriptor = builder.build();
|
||||||
|
|
||||||
var subsequentFunctionRootNode =
|
var subsequentFunctionRootNode =
|
||||||
@@ -138,7 +101,7 @@ public final class AmendFunctionNode extends PklNode {
|
|||||||
public VmFunction execute(VirtualFrame frame, VmFunction functionToAmend) {
|
public VmFunction execute(VirtualFrame frame, VmFunction functionToAmend) {
|
||||||
if (isCustomThisScope && customThisSlot == -1) {
|
if (isCustomThisScope && customThisSlot == -1) {
|
||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
customThisSlot = VmUtils.findAuxiliarySlot(frame, CustomThisScope.FRAME_SLOT_ID);
|
customThisSlot = VmUtils.findCustomThisSlot(frame);
|
||||||
}
|
}
|
||||||
return new VmFunction(
|
return new VmFunction(
|
||||||
frame.materialize(),
|
frame.materialize(),
|
||||||
@@ -184,8 +147,7 @@ public final class AmendFunctionNode extends PklNode {
|
|||||||
var arguments = new Object[frameArguments.length];
|
var arguments = new Object[frameArguments.length];
|
||||||
arguments[0] = functionToAmend.getThisValue();
|
arguments[0] = functionToAmend.getThisValue();
|
||||||
arguments[1] = functionToAmend;
|
arguments[1] = functionToAmend;
|
||||||
arguments[2] = false;
|
System.arraycopy(frameArguments, 2, arguments, 2, frameArguments.length - 2);
|
||||||
System.arraycopy(frameArguments, 3, arguments, 3, frameArguments.length - 3);
|
|
||||||
|
|
||||||
var valueToAmend = callNode.call(functionToAmend.getCallTarget(), arguments);
|
var valueToAmend = callNode.call(functionToAmend.getCallTarget(), arguments);
|
||||||
if (!(valueToAmend instanceof VmFunction newFunctionToAmend)) {
|
if (!(valueToAmend instanceof VmFunction newFunctionToAmend)) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -20,7 +20,6 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
|
|||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
import com.oracle.truffle.api.frame.VirtualFrame;
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
import org.pkl.core.ast.ExpressionNode;
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
import org.pkl.core.ast.builder.SymbolTable.CustomThisScope;
|
|
||||||
import org.pkl.core.ast.member.FunctionNode;
|
import org.pkl.core.ast.member.FunctionNode;
|
||||||
import org.pkl.core.ast.member.UnresolvedFunctionNode;
|
import org.pkl.core.ast.member.UnresolvedFunctionNode;
|
||||||
import org.pkl.core.runtime.VmFunction;
|
import org.pkl.core.runtime.VmFunction;
|
||||||
@@ -48,7 +47,7 @@ public final class FunctionLiteralNode extends ExpressionNode {
|
|||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
functionNode = unresolvedFunctionNode.execute(frame);
|
functionNode = unresolvedFunctionNode.execute(frame);
|
||||||
if (isCustomThisScope) {
|
if (isCustomThisScope) {
|
||||||
customThisSlot = VmUtils.findAuxiliarySlot(frame, CustomThisScope.FRAME_SLOT_ID);
|
customThisSlot = VmUtils.findCustomThisSlot(frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -66,7 +66,7 @@ public abstract class ObjectLiteralNode extends ExpressionNode {
|
|||||||
parametersDescriptor == null
|
parametersDescriptor == null
|
||||||
? new TypeNode[0]
|
? new TypeNode[0]
|
||||||
: VmUtils.resolveParameterTypes(frame, parametersDescriptor, parameterTypes);
|
: VmUtils.resolveParameterTypes(frame, parametersDescriptor, parameterTypes);
|
||||||
return new AmendFunctionNode(this, resolvedParameterTypes, frame.getFrameDescriptor());
|
return new AmendFunctionNode(this, resolvedParameterTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Idempotent
|
@Idempotent
|
||||||
|
|||||||
+4
-8
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -28,7 +28,6 @@ public final class InvokeMethodDirectNode extends ExpressionNode {
|
|||||||
private final VmObjectLike owner;
|
private final VmObjectLike owner;
|
||||||
@Child private ExpressionNode receiverNode;
|
@Child private ExpressionNode receiverNode;
|
||||||
@Children private final ExpressionNode[] argumentNodes;
|
@Children private final ExpressionNode[] argumentNodes;
|
||||||
private final boolean isInIterable;
|
|
||||||
|
|
||||||
@Child private DirectCallNode callNode;
|
@Child private DirectCallNode callNode;
|
||||||
|
|
||||||
@@ -36,14 +35,12 @@ public final class InvokeMethodDirectNode extends ExpressionNode {
|
|||||||
SourceSection sourceSection,
|
SourceSection sourceSection,
|
||||||
ClassMethod method,
|
ClassMethod method,
|
||||||
ExpressionNode receiverNode,
|
ExpressionNode receiverNode,
|
||||||
ExpressionNode[] argumentNodes,
|
ExpressionNode[] argumentNodes) {
|
||||||
boolean isInIterable) {
|
|
||||||
|
|
||||||
super(sourceSection);
|
super(sourceSection);
|
||||||
this.owner = method.getOwner();
|
this.owner = method.getOwner();
|
||||||
this.receiverNode = receiverNode;
|
this.receiverNode = receiverNode;
|
||||||
this.argumentNodes = argumentNodes;
|
this.argumentNodes = argumentNodes;
|
||||||
this.isInIterable = isInIterable;
|
|
||||||
|
|
||||||
callNode = DirectCallNode.create(method.getCallTarget(sourceSection));
|
callNode = DirectCallNode.create(method.getCallTarget(sourceSection));
|
||||||
}
|
}
|
||||||
@@ -51,12 +48,11 @@ public final class InvokeMethodDirectNode extends ExpressionNode {
|
|||||||
@Override
|
@Override
|
||||||
@ExplodeLoop
|
@ExplodeLoop
|
||||||
public Object executeGeneric(VirtualFrame frame) {
|
public Object executeGeneric(VirtualFrame frame) {
|
||||||
var args = new Object[3 + argumentNodes.length];
|
var args = new Object[2 + argumentNodes.length];
|
||||||
args[0] = receiverNode.executeGeneric(frame);
|
args[0] = receiverNode.executeGeneric(frame);
|
||||||
args[1] = owner;
|
args[1] = owner;
|
||||||
args[2] = isInIterable;
|
|
||||||
for (var i = 0; i < argumentNodes.length; i++) {
|
for (var i = 0; i < argumentNodes.length; i++) {
|
||||||
args[3 + i] = argumentNodes[i].executeGeneric(frame);
|
args[2 + i] = argumentNodes[i].executeGeneric(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
return callNode.call(args);
|
return callNode.call(args);
|
||||||
|
|||||||
+4
-8
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -33,33 +33,29 @@ public final class InvokeMethodLexicalNode extends ExpressionNode {
|
|||||||
private final int levelsUp;
|
private final int levelsUp;
|
||||||
|
|
||||||
@Child private DirectCallNode callNode;
|
@Child private DirectCallNode callNode;
|
||||||
private final boolean isInIterable;
|
|
||||||
|
|
||||||
InvokeMethodLexicalNode(
|
InvokeMethodLexicalNode(
|
||||||
SourceSection sourceSection,
|
SourceSection sourceSection,
|
||||||
CallTarget callTarget,
|
CallTarget callTarget,
|
||||||
int levelsUp,
|
int levelsUp,
|
||||||
ExpressionNode[] argumentNodes,
|
ExpressionNode[] argumentNodes) {
|
||||||
boolean isInIterable) {
|
|
||||||
|
|
||||||
super(sourceSection);
|
super(sourceSection);
|
||||||
this.levelsUp = levelsUp;
|
this.levelsUp = levelsUp;
|
||||||
this.argumentNodes = argumentNodes;
|
this.argumentNodes = argumentNodes;
|
||||||
|
|
||||||
callNode = DirectCallNode.create(callTarget);
|
callNode = DirectCallNode.create(callTarget);
|
||||||
this.isInIterable = isInIterable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ExplodeLoop
|
@ExplodeLoop
|
||||||
public Object executeGeneric(VirtualFrame frame) {
|
public Object executeGeneric(VirtualFrame frame) {
|
||||||
var args = new Object[3 + argumentNodes.length];
|
var args = new Object[2 + argumentNodes.length];
|
||||||
var enclosingFrame = getEnclosingFrame(frame);
|
var enclosingFrame = getEnclosingFrame(frame);
|
||||||
args[0] = VmUtils.getReceiver(enclosingFrame);
|
args[0] = VmUtils.getReceiver(enclosingFrame);
|
||||||
args[1] = VmUtils.getOwner(enclosingFrame);
|
args[1] = VmUtils.getOwner(enclosingFrame);
|
||||||
args[2] = isInIterable;
|
|
||||||
for (var i = 0; i < argumentNodes.length; i++) {
|
for (var i = 0; i < argumentNodes.length; i++) {
|
||||||
args[3 + i] = argumentNodes[i].executeGeneric(frame);
|
args[2 + i] = argumentNodes[i].executeGeneric(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
return callNode.call(args);
|
return callNode.call(args);
|
||||||
|
|||||||
+12
-20
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -45,31 +45,27 @@ public abstract class InvokeMethodVirtualNode extends ExpressionNode {
|
|||||||
@Children private final ExpressionNode[] argumentNodes;
|
@Children private final ExpressionNode[] argumentNodes;
|
||||||
private final MemberLookupMode lookupMode;
|
private final MemberLookupMode lookupMode;
|
||||||
private final boolean needsConst;
|
private final boolean needsConst;
|
||||||
private final boolean isInIterable;
|
|
||||||
|
|
||||||
protected InvokeMethodVirtualNode(
|
protected InvokeMethodVirtualNode(
|
||||||
SourceSection sourceSection,
|
SourceSection sourceSection,
|
||||||
Identifier methodName,
|
Identifier methodName,
|
||||||
ExpressionNode[] argumentNodes,
|
ExpressionNode[] argumentNodes,
|
||||||
MemberLookupMode lookupMode,
|
MemberLookupMode lookupMode,
|
||||||
boolean needsConst,
|
boolean needsConst) {
|
||||||
boolean isInIterable) {
|
|
||||||
|
|
||||||
super(sourceSection);
|
super(sourceSection);
|
||||||
this.methodName = methodName;
|
this.methodName = methodName;
|
||||||
this.argumentNodes = argumentNodes;
|
this.argumentNodes = argumentNodes;
|
||||||
this.lookupMode = lookupMode;
|
this.lookupMode = lookupMode;
|
||||||
this.needsConst = needsConst;
|
this.needsConst = needsConst;
|
||||||
this.isInIterable = isInIterable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected InvokeMethodVirtualNode(
|
protected InvokeMethodVirtualNode(
|
||||||
SourceSection sourceSection,
|
SourceSection sourceSection,
|
||||||
Identifier methodName,
|
Identifier methodName,
|
||||||
ExpressionNode[] argumentNodes,
|
ExpressionNode[] argumentNodes,
|
||||||
MemberLookupMode lookupMode,
|
MemberLookupMode lookupMode) {
|
||||||
boolean isInIterable) {
|
this(sourceSection, methodName, argumentNodes, lookupMode, false);
|
||||||
this(sourceSection, methodName, argumentNodes, lookupMode, false, isInIterable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,12 +85,11 @@ public abstract class InvokeMethodVirtualNode extends ExpressionNode {
|
|||||||
RootCallTarget cachedCallTarget,
|
RootCallTarget cachedCallTarget,
|
||||||
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
|
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
|
||||||
|
|
||||||
var args = new Object[3 + argumentNodes.length];
|
var args = new Object[2 + argumentNodes.length];
|
||||||
args[0] = receiver.getThisValue();
|
args[0] = receiver.getThisValue();
|
||||||
args[1] = receiver;
|
args[1] = receiver;
|
||||||
args[2] = isInIterable;
|
|
||||||
for (var i = 0; i < argumentNodes.length; i++) {
|
for (var i = 0; i < argumentNodes.length; i++) {
|
||||||
args[3 + i] = argumentNodes[i].executeGeneric(frame);
|
args[2 + i] = argumentNodes[i].executeGeneric(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
return callNode.call(args);
|
return callNode.call(args);
|
||||||
@@ -109,12 +104,11 @@ public abstract class InvokeMethodVirtualNode extends ExpressionNode {
|
|||||||
@SuppressWarnings("unused") VmClass receiverClass,
|
@SuppressWarnings("unused") VmClass receiverClass,
|
||||||
@Exclusive @Cached("create()") IndirectCallNode callNode) {
|
@Exclusive @Cached("create()") IndirectCallNode callNode) {
|
||||||
|
|
||||||
var args = new Object[3 + argumentNodes.length];
|
var args = new Object[2 + argumentNodes.length];
|
||||||
args[0] = receiver.getThisValue();
|
args[0] = receiver.getThisValue();
|
||||||
args[1] = receiver;
|
args[1] = receiver;
|
||||||
args[2] = isInIterable;
|
|
||||||
for (var i = 0; i < argumentNodes.length; i++) {
|
for (var i = 0; i < argumentNodes.length; i++) {
|
||||||
args[3 + i] = argumentNodes[i].executeGeneric(frame);
|
args[2 + i] = argumentNodes[i].executeGeneric(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
return callNode.call(receiver.getCallTarget(), args);
|
return callNode.call(receiver.getCallTarget(), args);
|
||||||
@@ -130,12 +124,11 @@ public abstract class InvokeMethodVirtualNode extends ExpressionNode {
|
|||||||
@Cached("resolveMethod(receiverClass)") ClassMethod method,
|
@Cached("resolveMethod(receiverClass)") ClassMethod method,
|
||||||
@Cached("create(method.getCallTarget(sourceSection))") DirectCallNode callNode) {
|
@Cached("create(method.getCallTarget(sourceSection))") DirectCallNode callNode) {
|
||||||
|
|
||||||
var args = new Object[3 + argumentNodes.length];
|
var args = new Object[2 + argumentNodes.length];
|
||||||
args[0] = receiver;
|
args[0] = receiver;
|
||||||
args[1] = method.getOwner();
|
args[1] = method.getOwner();
|
||||||
args[2] = isInIterable;
|
|
||||||
for (var i = 0; i < argumentNodes.length; i++) {
|
for (var i = 0; i < argumentNodes.length; i++) {
|
||||||
args[3 + i] = argumentNodes[i].executeGeneric(frame);
|
args[2 + i] = argumentNodes[i].executeGeneric(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
return callNode.call(args);
|
return callNode.call(args);
|
||||||
@@ -150,12 +143,11 @@ public abstract class InvokeMethodVirtualNode extends ExpressionNode {
|
|||||||
@Exclusive @Cached("create()") IndirectCallNode callNode) {
|
@Exclusive @Cached("create()") IndirectCallNode callNode) {
|
||||||
|
|
||||||
var method = resolveMethod(receiverClass);
|
var method = resolveMethod(receiverClass);
|
||||||
var args = new Object[3 + argumentNodes.length];
|
var args = new Object[2 + argumentNodes.length];
|
||||||
args[0] = receiver;
|
args[0] = receiver;
|
||||||
args[1] = method.getOwner();
|
args[1] = method.getOwner();
|
||||||
args[2] = isInIterable;
|
|
||||||
for (var i = 0; i < argumentNodes.length; i++) {
|
for (var i = 0; i < argumentNodes.length; i++) {
|
||||||
args[3 + i] = argumentNodes[i].executeGeneric(frame);
|
args[2 + i] = argumentNodes[i].executeGeneric(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecation should not report here (getCallTarget(sourceSection)), as this happens for each
|
// Deprecation should not report here (getCallTarget(sourceSection)), as this happens for each
|
||||||
|
|||||||
+3
-7
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -30,18 +30,15 @@ import org.pkl.core.runtime.VmUtils;
|
|||||||
public abstract class InvokeSuperMethodNode extends ExpressionNode {
|
public abstract class InvokeSuperMethodNode extends ExpressionNode {
|
||||||
private final Identifier methodName;
|
private final Identifier methodName;
|
||||||
@Children private final ExpressionNode[] argumentNodes;
|
@Children private final ExpressionNode[] argumentNodes;
|
||||||
private final boolean isInIterable;
|
|
||||||
private final boolean needsConst;
|
private final boolean needsConst;
|
||||||
|
|
||||||
protected InvokeSuperMethodNode(
|
protected InvokeSuperMethodNode(
|
||||||
SourceSection sourceSection,
|
SourceSection sourceSection,
|
||||||
Identifier methodName,
|
Identifier methodName,
|
||||||
boolean isInIterable,
|
|
||||||
ExpressionNode[] argumentNodes,
|
ExpressionNode[] argumentNodes,
|
||||||
boolean needsConst) {
|
boolean needsConst) {
|
||||||
|
|
||||||
super(sourceSection);
|
super(sourceSection);
|
||||||
this.isInIterable = isInIterable;
|
|
||||||
this.needsConst = needsConst;
|
this.needsConst = needsConst;
|
||||||
|
|
||||||
assert !methodName.isLocalMethod();
|
assert !methodName.isLocalMethod();
|
||||||
@@ -57,12 +54,11 @@ public abstract class InvokeSuperMethodNode extends ExpressionNode {
|
|||||||
@Cached(value = "findSupermethod(frame)", neverDefault = true) ClassMethod supermethod,
|
@Cached(value = "findSupermethod(frame)", neverDefault = true) ClassMethod supermethod,
|
||||||
@Cached("create(supermethod.getCallTarget(sourceSection))") DirectCallNode callNode) {
|
@Cached("create(supermethod.getCallTarget(sourceSection))") DirectCallNode callNode) {
|
||||||
|
|
||||||
var args = new Object[3 + argumentNodes.length];
|
var args = new Object[2 + argumentNodes.length];
|
||||||
args[0] = VmUtils.getReceiverOrNull(frame);
|
args[0] = VmUtils.getReceiverOrNull(frame);
|
||||||
args[1] = supermethod.getOwner();
|
args[1] = supermethod.getOwner();
|
||||||
args[2] = isInIterable;
|
|
||||||
for (int i = 0; i < argumentNodes.length; i++) {
|
for (int i = 0; i < argumentNodes.length; i++) {
|
||||||
args[3 + i] = argumentNodes[i].executeGeneric(frame);
|
args[2 + i] = argumentNodes[i].executeGeneric(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
return callNode.call(args);
|
return callNode.call(args);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -50,7 +50,6 @@ public final class ResolveMethodNode extends ExpressionNode {
|
|||||||
private final boolean isCustomThisScope;
|
private final boolean isCustomThisScope;
|
||||||
private final ConstLevel constLevel;
|
private final ConstLevel constLevel;
|
||||||
private final int constDepth;
|
private final int constDepth;
|
||||||
private final boolean isInIterable;
|
|
||||||
|
|
||||||
public ResolveMethodNode(
|
public ResolveMethodNode(
|
||||||
SourceSection sourceSection,
|
SourceSection sourceSection,
|
||||||
@@ -59,8 +58,7 @@ public final class ResolveMethodNode extends ExpressionNode {
|
|||||||
boolean isBaseModule,
|
boolean isBaseModule,
|
||||||
boolean isCustomThisScope,
|
boolean isCustomThisScope,
|
||||||
ConstLevel constLevel,
|
ConstLevel constLevel,
|
||||||
int constDepth,
|
int constDepth) {
|
||||||
boolean isInIterable) {
|
|
||||||
|
|
||||||
super(sourceSection);
|
super(sourceSection);
|
||||||
|
|
||||||
@@ -70,7 +68,6 @@ public final class ResolveMethodNode extends ExpressionNode {
|
|||||||
this.isCustomThisScope = isCustomThisScope;
|
this.isCustomThisScope = isCustomThisScope;
|
||||||
this.constLevel = constLevel;
|
this.constLevel = constLevel;
|
||||||
this.constDepth = constDepth;
|
this.constDepth = constDepth;
|
||||||
this.isInIterable = isInIterable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -94,11 +91,7 @@ public final class ResolveMethodNode extends ExpressionNode {
|
|||||||
assert localMethod.isLocal();
|
assert localMethod.isLocal();
|
||||||
checkConst(currOwner, localMethod, levelsUp);
|
checkConst(currOwner, localMethod, levelsUp);
|
||||||
return new InvokeMethodLexicalNode(
|
return new InvokeMethodLexicalNode(
|
||||||
sourceSection,
|
sourceSection, localMethod.getCallTarget(sourceSection), levelsUp, argumentNodes);
|
||||||
localMethod.getCallTarget(sourceSection),
|
|
||||||
levelsUp,
|
|
||||||
argumentNodes,
|
|
||||||
isInIterable);
|
|
||||||
}
|
}
|
||||||
var method = currOwner.getVmClass().getDeclaredMethod(methodName);
|
var method = currOwner.getVmClass().getDeclaredMethod(methodName);
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
@@ -106,11 +99,7 @@ public final class ResolveMethodNode extends ExpressionNode {
|
|||||||
checkConst(currOwner, method, levelsUp);
|
checkConst(currOwner, method, levelsUp);
|
||||||
if (method.getDeclaringClass().isClosed()) {
|
if (method.getDeclaringClass().isClosed()) {
|
||||||
return new InvokeMethodLexicalNode(
|
return new InvokeMethodLexicalNode(
|
||||||
sourceSection,
|
sourceSection, method.getCallTarget(sourceSection), levelsUp, argumentNodes);
|
||||||
method.getCallTarget(sourceSection),
|
|
||||||
levelsUp,
|
|
||||||
argumentNodes,
|
|
||||||
isInIterable);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//noinspection ConstantConditions
|
//noinspection ConstantConditions
|
||||||
@@ -119,7 +108,6 @@ public final class ResolveMethodNode extends ExpressionNode {
|
|||||||
methodName,
|
methodName,
|
||||||
argumentNodes,
|
argumentNodes,
|
||||||
MemberLookupMode.IMPLICIT_LEXICAL,
|
MemberLookupMode.IMPLICIT_LEXICAL,
|
||||||
isInIterable,
|
|
||||||
levelsUp == 0 ? new GetReceiverNode() : new GetEnclosingReceiverNode(levelsUp),
|
levelsUp == 0 ? new GetReceiverNode() : new GetEnclosingReceiverNode(levelsUp),
|
||||||
GetClassNodeGen.create(null));
|
GetClassNodeGen.create(null));
|
||||||
}
|
}
|
||||||
@@ -134,7 +122,7 @@ public final class ResolveMethodNode extends ExpressionNode {
|
|||||||
(CallTarget) localMethod.getCallTarget().call(currOwner, currOwner);
|
(CallTarget) localMethod.getCallTarget().call(currOwner, currOwner);
|
||||||
|
|
||||||
return new InvokeMethodLexicalNode(
|
return new InvokeMethodLexicalNode(
|
||||||
sourceSection, methodCallTarget, levelsUp, argumentNodes, isInIterable);
|
sourceSection, methodCallTarget, levelsUp, argumentNodes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +138,7 @@ public final class ResolveMethodNode extends ExpressionNode {
|
|||||||
if (method != null) {
|
if (method != null) {
|
||||||
assert !method.isLocal();
|
assert !method.isLocal();
|
||||||
return new InvokeMethodDirectNode(
|
return new InvokeMethodDirectNode(
|
||||||
sourceSection, method, new ConstantValueNode(baseModule), argumentNodes, isInIterable);
|
sourceSection, method, new ConstantValueNode(baseModule), argumentNodes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +158,6 @@ public final class ResolveMethodNode extends ExpressionNode {
|
|||||||
argumentNodes,
|
argumentNodes,
|
||||||
MemberLookupMode.IMPLICIT_THIS,
|
MemberLookupMode.IMPLICIT_THIS,
|
||||||
needsConst,
|
needsConst,
|
||||||
isInIterable,
|
|
||||||
VmUtils.createThisNode(VmUtils.unavailableSourceSection(), isCustomThisScope),
|
VmUtils.createThisNode(VmUtils.unavailableSourceSection(), isCustomThisScope),
|
||||||
GetClassNodeGen.create(null));
|
GetClassNodeGen.create(null));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -21,7 +21,6 @@ import com.oracle.truffle.api.frame.VirtualFrame;
|
|||||||
import com.oracle.truffle.api.nodes.NodeInfo;
|
import com.oracle.truffle.api.nodes.NodeInfo;
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
import org.pkl.core.ast.ExpressionNode;
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
import org.pkl.core.ast.builder.SymbolTable.CustomThisScope;
|
|
||||||
import org.pkl.core.runtime.VmUtils;
|
import org.pkl.core.runtime.VmUtils;
|
||||||
|
|
||||||
/** `this` inside `CustomThisScope` (type constraint, object member predicate). */
|
/** `this` inside `CustomThisScope` (type constraint, object member predicate). */
|
||||||
@@ -38,7 +37,7 @@ public final class CustomThisNode extends ExpressionNode {
|
|||||||
if (customThisSlot == -1) {
|
if (customThisSlot == -1) {
|
||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
// deferred until execution time s.t. nodes of inlined type aliases get the right frame slot
|
// deferred until execution time s.t. nodes of inlined type aliases get the right frame slot
|
||||||
customThisSlot = VmUtils.findAuxiliarySlot(frame, CustomThisScope.FRAME_SLOT_ID);
|
customThisSlot = VmUtils.findCustomThisSlot(frame);
|
||||||
}
|
}
|
||||||
return frame.getAuxiliarySlot(customThisSlot);
|
return frame.getAuxiliarySlot(customThisSlot);
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-46
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -24,8 +24,6 @@ import org.pkl.core.ast.MemberLookupMode;
|
|||||||
import org.pkl.core.ast.builder.ConstLevel;
|
import org.pkl.core.ast.builder.ConstLevel;
|
||||||
import org.pkl.core.ast.expression.member.ReadLocalPropertyNode;
|
import org.pkl.core.ast.expression.member.ReadLocalPropertyNode;
|
||||||
import org.pkl.core.ast.expression.member.ReadPropertyNodeGen;
|
import org.pkl.core.ast.expression.member.ReadPropertyNodeGen;
|
||||||
import org.pkl.core.ast.frame.ReadAuxiliarySlotNode;
|
|
||||||
import org.pkl.core.ast.frame.ReadEnclosingAuxiliarySlotNode;
|
|
||||||
import org.pkl.core.ast.frame.ReadEnclosingFrameSlotNodeGen;
|
import org.pkl.core.ast.frame.ReadEnclosingFrameSlotNodeGen;
|
||||||
import org.pkl.core.ast.frame.ReadFrameSlotNodeGen;
|
import org.pkl.core.ast.frame.ReadFrameSlotNodeGen;
|
||||||
import org.pkl.core.ast.member.Member;
|
import org.pkl.core.ast.member.Member;
|
||||||
@@ -34,14 +32,23 @@ import org.pkl.core.runtime.*;
|
|||||||
/**
|
/**
|
||||||
* Resolves a variable name, for example `foo` in `x = foo`.
|
* Resolves a variable name, for example `foo` in `x = foo`.
|
||||||
*
|
*
|
||||||
* <p>A variable name can refer to any of the following: - a (potentially `local`) property in the
|
* <p>A variable name can refer to any of the following:
|
||||||
* lexical scope - a method or lambda parameter in the lexical scope - a base module property - a
|
*
|
||||||
* property accessible through `this`
|
* <ul>
|
||||||
|
* <li>a method/lambda parameter or for-generator/let-expression variable in the lexical scope
|
||||||
|
* <li>a (potentially `local`) property in the lexical scope
|
||||||
|
* <li>a `pkl.base` module property
|
||||||
|
* <li>a property accessible through `this`
|
||||||
|
* </ul>
|
||||||
*
|
*
|
||||||
* <p>This node's task is to make a one-time decision between these alternatives for the call site
|
* <p>This node's task is to make a one-time decision between these alternatives for the call site
|
||||||
* it represents.
|
* it represents.
|
||||||
*/
|
*/
|
||||||
// TODO: Move this to parse time (required for supporting local variables, more efficient)
|
// TODO: Move this to parse time
|
||||||
|
// * more capable because more information is available
|
||||||
|
// and AST customization beyond replacing this node is possible
|
||||||
|
// * useful for runtime AST transformations, for example to implement property-based testing
|
||||||
|
// * more efficient
|
||||||
//
|
//
|
||||||
// TODO: In REPL, undo replace if environment changes to make the following work.
|
// TODO: In REPL, undo replace if environment changes to make the following work.
|
||||||
// Perhaps instrumenting this node in REPL would be a good solution.
|
// Perhaps instrumenting this node in REPL would be a good solution.
|
||||||
@@ -82,49 +89,18 @@ public final class ResolveVariableNode extends ExpressionNode {
|
|||||||
CompilerDirectives.transferToInterpreter();
|
CompilerDirectives.transferToInterpreter();
|
||||||
|
|
||||||
var localPropertyName = variableName.toLocalProperty();
|
var localPropertyName = variableName.toLocalProperty();
|
||||||
|
|
||||||
// search the frame for auxiliary slots carrying this variable (placed by
|
|
||||||
// `WriteForVariablesNode`)
|
|
||||||
var variableSlot = VmUtils.findAuxiliarySlot(frame, localPropertyName);
|
|
||||||
if (variableSlot == -1) {
|
|
||||||
variableSlot = VmUtils.findAuxiliarySlot(frame, variableName);
|
|
||||||
}
|
|
||||||
if (variableSlot != -1) {
|
|
||||||
return new ReadAuxiliarySlotNode(getSourceSection(), variableSlot);
|
|
||||||
}
|
|
||||||
// search the frame for slots carrying this variable
|
|
||||||
variableSlot = VmUtils.findSlot(frame, localPropertyName);
|
|
||||||
if (variableSlot == -1) {
|
|
||||||
variableSlot = VmUtils.findSlot(frame, variableName);
|
|
||||||
}
|
|
||||||
if (variableSlot != -1) {
|
|
||||||
return ReadFrameSlotNodeGen.create(getSourceSection(), variableSlot);
|
|
||||||
}
|
|
||||||
|
|
||||||
var currFrame = frame;
|
var currFrame = frame;
|
||||||
var currOwner = VmUtils.getOwner(currFrame);
|
var currOwner = VmUtils.getOwner(currFrame);
|
||||||
var levelsUp = 0;
|
var levelsUp = 0;
|
||||||
|
|
||||||
// Search lexical scope for a matching method/lambda parameter, `for` generator variable, or
|
// Search lexical scope for a matching function parameter, for-generator variable, or object
|
||||||
// object property.
|
// property.
|
||||||
do {
|
do {
|
||||||
var parameterSlot = VmUtils.findSlot(currFrame, variableName);
|
var slot = findFrameSlot(currFrame, variableName, localPropertyName);
|
||||||
if (parameterSlot == -1) {
|
if (slot != -1) {
|
||||||
parameterSlot = VmUtils.findSlot(currFrame, localPropertyName);
|
|
||||||
}
|
|
||||||
if (parameterSlot != -1) {
|
|
||||||
return levelsUp == 0
|
return levelsUp == 0
|
||||||
? ReadFrameSlotNodeGen.create(getSourceSection(), parameterSlot)
|
? ReadFrameSlotNodeGen.create(getSourceSection(), slot)
|
||||||
: ReadEnclosingFrameSlotNodeGen.create(getSourceSection(), parameterSlot, levelsUp);
|
: ReadEnclosingFrameSlotNodeGen.create(getSourceSection(), slot, levelsUp);
|
||||||
}
|
|
||||||
var auxiliarySlot = VmUtils.findAuxiliarySlot(currFrame, variableName);
|
|
||||||
if (auxiliarySlot == -1) {
|
|
||||||
auxiliarySlot = VmUtils.findAuxiliarySlot(currFrame, localPropertyName);
|
|
||||||
}
|
|
||||||
if (auxiliarySlot != -1) {
|
|
||||||
return levelsUp == 0
|
|
||||||
? new ReadAuxiliarySlotNode(getSourceSection(), auxiliarySlot)
|
|
||||||
: new ReadEnclosingAuxiliarySlotNode(getSourceSection(), auxiliarySlot, levelsUp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var localMember = currOwner.getMember(localPropertyName);
|
var localMember = currOwner.getMember(localPropertyName);
|
||||||
@@ -136,8 +112,8 @@ public final class ResolveVariableNode extends ExpressionNode {
|
|||||||
var value = localMember.getConstantValue();
|
var value = localMember.getConstantValue();
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
// This is the only code path that resolves local constant properties.
|
// This is the only code path that resolves local constant properties.
|
||||||
// Since this code path doesn't use ObjectMember.getCachedValue(),
|
// Since this code path doesn't call VmObject.getCachedValue(),
|
||||||
// there is no point in calling localMember.setCachedValue() either.
|
// there is no point in calling VmObject.setCachedValue() either.
|
||||||
return new ConstantValueNode(sourceSection, value);
|
return new ConstantValueNode(sourceSection, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,4 +212,17 @@ public final class ResolveVariableNode extends ExpressionNode {
|
|||||||
throw exceptionBuilder().evalError("propertyMustBeConst", variableName.toString()).build();
|
throw exceptionBuilder().evalError("propertyMustBeConst", variableName.toString()).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int findFrameSlot(VirtualFrame frame, Object identifier1, Object identifier2) {
|
||||||
|
var descriptor = frame.getFrameDescriptor();
|
||||||
|
// Search backwards. The for-generator implementation exploits this
|
||||||
|
// to shadow a slot by appending a slot with the same name.
|
||||||
|
for (var i = descriptor.getNumberOfSlots() - 1; i >= 0; i--) {
|
||||||
|
var slotName = descriptor.getSlotName(i);
|
||||||
|
if (slotName == identifier1 || slotName == identifier2) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2024 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.ast.frame;
|
|
||||||
|
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
|
||||||
import org.pkl.core.ast.ExpressionNode;
|
|
||||||
|
|
||||||
public class ReadAuxiliarySlotNode extends ExpressionNode {
|
|
||||||
private final int slot;
|
|
||||||
|
|
||||||
public ReadAuxiliarySlotNode(SourceSection sourceSection, int slot) {
|
|
||||||
super(sourceSection);
|
|
||||||
this.slot = slot;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object executeGeneric(VirtualFrame frame) {
|
|
||||||
return frame.getAuxiliarySlot(slot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright © 2024 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.ast.frame;
|
|
||||||
|
|
||||||
import com.oracle.truffle.api.frame.MaterializedFrame;
|
|
||||||
import com.oracle.truffle.api.frame.VirtualFrame;
|
|
||||||
import com.oracle.truffle.api.nodes.ExplodeLoop;
|
|
||||||
import com.oracle.truffle.api.source.SourceSection;
|
|
||||||
import org.pkl.core.ast.ExpressionNode;
|
|
||||||
import org.pkl.core.runtime.VmUtils;
|
|
||||||
|
|
||||||
public class ReadEnclosingAuxiliarySlotNode extends ExpressionNode {
|
|
||||||
private final int slot;
|
|
||||||
private final int levelsUp;
|
|
||||||
|
|
||||||
public ReadEnclosingAuxiliarySlotNode(SourceSection sourceSection, int slot, int levelsUp) {
|
|
||||||
super(sourceSection);
|
|
||||||
this.slot = slot;
|
|
||||||
this.levelsUp = levelsUp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// could be factored out into a separate node s.t. it
|
|
||||||
// won't be repeated in case of FrameSlotTypeException
|
|
||||||
@ExplodeLoop
|
|
||||||
protected final MaterializedFrame getCapturedFrame(VirtualFrame frame) {
|
|
||||||
var owner = VmUtils.getOwner(frame);
|
|
||||||
for (var i = 0; i < levelsUp - 1; i++) {
|
|
||||||
owner = owner.getEnclosingOwner();
|
|
||||||
assert owner != null; // guaranteed by AstBuilder
|
|
||||||
}
|
|
||||||
return owner.getEnclosingFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object executeGeneric(VirtualFrame frame) {
|
|
||||||
return getCapturedFrame(frame).getAuxiliarySlot(slot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -80,7 +80,6 @@ public abstract class ToStringNode extends UnaryExpressionNode {
|
|||||||
Identifier.TO_STRING,
|
Identifier.TO_STRING,
|
||||||
new ExpressionNode[] {},
|
new ExpressionNode[] {},
|
||||||
MemberLookupMode.EXPLICIT_RECEIVER,
|
MemberLookupMode.EXPLICIT_RECEIVER,
|
||||||
false,
|
|
||||||
null,
|
null,
|
||||||
null);
|
null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -33,12 +33,12 @@ public abstract class ApplyVmFunction0Node extends PklNode {
|
|||||||
RootCallTarget cachedCallTarget,
|
RootCallTarget cachedCallTarget,
|
||||||
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
|
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
|
||||||
|
|
||||||
return callNode.call(function.getThisValue(), function, false);
|
return callNode.call(function.getThisValue(), function);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(replaces = "evalDirect")
|
@Specialization(replaces = "evalDirect")
|
||||||
protected Object eval(VmFunction function, @Cached("create()") IndirectCallNode callNode) {
|
protected Object eval(VmFunction function, @Cached("create()") IndirectCallNode callNode) {
|
||||||
|
|
||||||
return callNode.call(function.getCallTarget(), function.getThisValue(), function, false);
|
return callNode.call(function.getCallTarget(), function.getThisValue(), function);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -77,13 +77,13 @@ public abstract class ApplyVmFunction1Node extends ExpressionNode {
|
|||||||
RootCallTarget cachedCallTarget,
|
RootCallTarget cachedCallTarget,
|
||||||
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
|
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
|
||||||
|
|
||||||
return callNode.call(function.getThisValue(), function, false, arg1);
|
return callNode.call(function.getThisValue(), function, arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(replaces = "evalDirect")
|
@Specialization(replaces = "evalDirect")
|
||||||
protected Object eval(
|
protected Object eval(
|
||||||
VmFunction function, Object arg1, @Cached("create()") IndirectCallNode callNode) {
|
VmFunction function, Object arg1, @Cached("create()") IndirectCallNode callNode) {
|
||||||
|
|
||||||
return callNode.call(function.getCallTarget(), function.getThisValue(), function, false, arg1);
|
return callNode.call(function.getCallTarget(), function.getThisValue(), function, arg1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -76,7 +76,7 @@ public abstract class ApplyVmFunction2Node extends PklNode {
|
|||||||
RootCallTarget cachedCallTarget,
|
RootCallTarget cachedCallTarget,
|
||||||
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
|
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
|
||||||
|
|
||||||
return callNode.call(function.getThisValue(), function, false, arg1, arg2);
|
return callNode.call(function.getThisValue(), function, arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(replaces = "evalDirect")
|
@Specialization(replaces = "evalDirect")
|
||||||
@@ -86,7 +86,6 @@ public abstract class ApplyVmFunction2Node extends PklNode {
|
|||||||
Object arg2,
|
Object arg2,
|
||||||
@Cached("create()") IndirectCallNode callNode) {
|
@Cached("create()") IndirectCallNode callNode) {
|
||||||
|
|
||||||
return callNode.call(
|
return callNode.call(function.getCallTarget(), function.getThisValue(), function, arg1, arg2);
|
||||||
function.getCallTarget(), function.getThisValue(), function, false, arg1, arg2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -36,7 +36,7 @@ public abstract class ApplyVmFunction3Node extends PklNode {
|
|||||||
RootCallTarget cachedCallTarget,
|
RootCallTarget cachedCallTarget,
|
||||||
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
|
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
|
||||||
|
|
||||||
return callNode.call(function.getThisValue(), function, false, arg1, arg2, arg3);
|
return callNode.call(function.getThisValue(), function, arg1, arg2, arg3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(replaces = "evalDirect")
|
@Specialization(replaces = "evalDirect")
|
||||||
@@ -48,6 +48,6 @@ public abstract class ApplyVmFunction3Node extends PklNode {
|
|||||||
@Cached("create()") IndirectCallNode callNode) {
|
@Cached("create()") IndirectCallNode callNode) {
|
||||||
|
|
||||||
return callNode.call(
|
return callNode.call(
|
||||||
function.getCallTarget(), function.getThisValue(), function, false, arg1, arg2, arg3);
|
function.getCallTarget(), function.getThisValue(), function, arg1, arg2, arg3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -38,7 +38,7 @@ public abstract class ApplyVmFunction4Node extends PklNode {
|
|||||||
RootCallTarget cachedCallTarget,
|
RootCallTarget cachedCallTarget,
|
||||||
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
|
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
|
||||||
|
|
||||||
return callNode.call(function.getThisValue(), function, false, arg1, arg2, arg3, arg4);
|
return callNode.call(function.getThisValue(), function, arg1, arg2, arg3, arg4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(replaces = "evalDirect")
|
@Specialization(replaces = "evalDirect")
|
||||||
@@ -51,6 +51,6 @@ public abstract class ApplyVmFunction4Node extends PklNode {
|
|||||||
@Cached("create()") IndirectCallNode callNode) {
|
@Cached("create()") IndirectCallNode callNode) {
|
||||||
|
|
||||||
return callNode.call(
|
return callNode.call(
|
||||||
function.getCallTarget(), function.getThisValue(), function, false, arg1, arg2, arg3, arg4);
|
function.getCallTarget(), function.getThisValue(), function, arg1, arg2, arg3, arg4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -39,7 +39,7 @@ public abstract class ApplyVmFunction5Node extends PklNode {
|
|||||||
RootCallTarget cachedCallTarget,
|
RootCallTarget cachedCallTarget,
|
||||||
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
|
@Cached("create(cachedCallTarget)") DirectCallNode callNode) {
|
||||||
|
|
||||||
return callNode.call(function.getThisValue(), function, false, arg1, arg2, arg3, arg4, arg5);
|
return callNode.call(function.getThisValue(), function, arg1, arg2, arg3, arg4, arg5);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Specialization(replaces = "evalDirect")
|
@Specialization(replaces = "evalDirect")
|
||||||
@@ -53,14 +53,6 @@ public abstract class ApplyVmFunction5Node extends PklNode {
|
|||||||
@Cached("create()") IndirectCallNode callNode) {
|
@Cached("create()") IndirectCallNode callNode) {
|
||||||
|
|
||||||
return callNode.call(
|
return callNode.call(
|
||||||
function.getCallTarget(),
|
function.getCallTarget(), function.getThisValue(), function, arg1, arg2, arg3, arg4, arg5);
|
||||||
function.getThisValue(),
|
|
||||||
function,
|
|
||||||
false,
|
|
||||||
arg1,
|
|
||||||
arg2,
|
|
||||||
arg3,
|
|
||||||
arg4,
|
|
||||||
arg5);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -43,11 +43,7 @@ public final class FunctionNode extends RegularMemberNode {
|
|||||||
// For VmObject receivers, the owner is the same as or an ancestor of the receiver.
|
// For VmObject receivers, the owner is the same as or an ancestor of the receiver.
|
||||||
// For other receivers, the owner is the prototype of the receiver's class.
|
// For other receivers, the owner is the prototype of the receiver's class.
|
||||||
// The chain of enclosing owners forms a function/property's lexical scope.
|
// The chain of enclosing owners forms a function/property's lexical scope.
|
||||||
//
|
private static final int IMPLICIT_PARAM_COUNT = 2;
|
||||||
// For function calls only, a third implicit argument is passed; whether the call came from within
|
|
||||||
// an iterable node or not.
|
|
||||||
// This is a mitigation for an existing bug (https://github.com/apple/pkl/issues/741).
|
|
||||||
private static final int IMPLICIT_PARAM_COUNT = 3;
|
|
||||||
|
|
||||||
private final int paramCount;
|
private final int paramCount;
|
||||||
private final int totalParamCount;
|
private final int totalParamCount;
|
||||||
@@ -112,15 +108,9 @@ public final class FunctionNode extends RegularMemberNode {
|
|||||||
throw wrongArgumentCount(totalArgCount - IMPLICIT_PARAM_COUNT);
|
throw wrongArgumentCount(totalArgCount - IMPLICIT_PARAM_COUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
var isInIterable = (boolean) frame.getArguments()[2];
|
|
||||||
|
|
||||||
for (var i = 0; i < parameterTypeNodes.length; i++) {
|
for (var i = 0; i < parameterTypeNodes.length; i++) {
|
||||||
var argument = frame.getArguments()[IMPLICIT_PARAM_COUNT + i];
|
var argument = frame.getArguments()[IMPLICIT_PARAM_COUNT + i];
|
||||||
if (isInIterable) {
|
parameterTypeNodes[i].executeAndSet(frame, argument);
|
||||||
parameterTypeNodes[i].executeEagerlyAndSet(frame, argument);
|
|
||||||
} else {
|
|
||||||
parameterTypeNodes[i].executeAndSet(frame, argument);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = bodyNode.executeGeneric(frame);
|
var result = bodyNode.executeGeneric(frame);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -130,20 +130,4 @@ public abstract class Member {
|
|||||||
public final boolean isLocalOrExternalOrAbstract() {
|
public final boolean isLocalOrExternalOrAbstract() {
|
||||||
return VmModifier.isLocalOrExternalOrAbstract(modifiers);
|
return VmModifier.isLocalOrExternalOrAbstract(modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells if this member is declared inside the iterable of a for-generator, or an object spread.
|
|
||||||
*
|
|
||||||
* <p>This is {@code true} for {@code new {}} within:
|
|
||||||
*
|
|
||||||
* <pre>{@code
|
|
||||||
* for (x in new Listing { new {} }) {
|
|
||||||
* ^^^^^^
|
|
||||||
* // etc
|
|
||||||
* }
|
|
||||||
* }</pre>
|
|
||||||
*/
|
|
||||||
public boolean isInIterable() {
|
|
||||||
return VmModifier.isInIterable(modifiers);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -59,24 +59,8 @@ public final class PropertyTypeNode extends PklRootNode {
|
|||||||
return qualifiedPropertyName;
|
return qualifiedPropertyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isInIterable(VirtualFrame frame) {
|
|
||||||
var args = frame.getArguments();
|
|
||||||
return args.length >= 4 && args[3] instanceof Boolean b && b;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Object executeImpl(VirtualFrame frame) {
|
protected Object executeImpl(VirtualFrame frame) {
|
||||||
if (isInIterable(frame)) {
|
|
||||||
// There is currently a bug around resolving variables within the iterable of a for
|
|
||||||
// generator or spread syntax (https://github.com/apple/pkl/issues/741)
|
|
||||||
//
|
|
||||||
// Normally, mappings/listings are type-checked lazily. However, this results in said
|
|
||||||
// bug getting widened, for any object members declared in the iterable.
|
|
||||||
//
|
|
||||||
// As a workaround for now, prevent the bug from being any worse by ensuring that these
|
|
||||||
// object members are eagerly typechecked.
|
|
||||||
return typeNode.executeEagerly(frame, frame.getArguments()[2]);
|
|
||||||
}
|
|
||||||
return typeNode.execute(frame, frame.getArguments()[2]);
|
return typeNode.execute(frame, frame.getArguments()[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -55,8 +55,7 @@ public abstract class TypeCheckedPropertyNode extends RegularMemberNode {
|
|||||||
|
|
||||||
// TODO: propagate SUPER_CALL_MARKER to disable constraint (but not type) check
|
// TODO: propagate SUPER_CALL_MARKER to disable constraint (but not type) check
|
||||||
if (callNode != null && VmUtils.shouldRunTypeCheck(frame)) {
|
if (callNode != null && VmUtils.shouldRunTypeCheck(frame)) {
|
||||||
return callNode.call(
|
return callNode.call(VmUtils.getReceiverOrNull(frame), property.getOwner(), result);
|
||||||
VmUtils.getReceiverOrNull(frame), property.getOwner(), result, member.isInIterable());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -76,8 +75,7 @@ public abstract class TypeCheckedPropertyNode extends RegularMemberNode {
|
|||||||
typeAnnNode.getCallTarget(),
|
typeAnnNode.getCallTarget(),
|
||||||
VmUtils.getReceiverOrNull(frame),
|
VmUtils.getReceiverOrNull(frame),
|
||||||
property.getOwner(),
|
property.getOwner(),
|
||||||
result,
|
result);
|
||||||
member.isInIterable());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -47,10 +47,7 @@ public final class TypedPropertyNode extends RegularMemberNode {
|
|||||||
var propertyValue = bodyNode.executeGeneric(frame);
|
var propertyValue = bodyNode.executeGeneric(frame);
|
||||||
if (VmUtils.shouldRunTypeCheck(frame)) {
|
if (VmUtils.shouldRunTypeCheck(frame)) {
|
||||||
return typeCheckCallNode.call(
|
return typeCheckCallNode.call(
|
||||||
VmUtils.getReceiver(frame),
|
VmUtils.getReceiver(frame), VmUtils.getOwner(frame), propertyValue);
|
||||||
VmUtils.getOwner(frame),
|
|
||||||
propertyValue,
|
|
||||||
member.isInIterable());
|
|
||||||
}
|
}
|
||||||
return propertyValue;
|
return propertyValue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -54,14 +54,14 @@ public final class IdentityMixinNode extends PklRootNode {
|
|||||||
@Override
|
@Override
|
||||||
protected Object executeImpl(VirtualFrame frame) {
|
protected Object executeImpl(VirtualFrame frame) {
|
||||||
var arguments = frame.getArguments();
|
var arguments = frame.getArguments();
|
||||||
if (arguments.length != 4) {
|
if (arguments.length != 3) {
|
||||||
CompilerDirectives.transferToInterpreter();
|
CompilerDirectives.transferToInterpreter();
|
||||||
throw exceptionBuilder()
|
throw exceptionBuilder()
|
||||||
.evalError("wrongFunctionArgumentCount", 1, arguments.length - 3)
|
.evalError("wrongFunctionArgumentCount", 1, arguments.length - 2)
|
||||||
.withSourceSection(sourceSection)
|
.withSourceSection(sourceSection)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
var argument = arguments[3];
|
var argument = arguments[2];
|
||||||
if (argumentTypeNode != null) {
|
if (argumentTypeNode != null) {
|
||||||
return argumentTypeNode.execute(frame, argument);
|
return argumentTypeNode.execute(frame, argument);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -25,7 +25,6 @@ import com.oracle.truffle.api.frame.VirtualFrame;
|
|||||||
import com.oracle.truffle.api.source.SourceSection;
|
import com.oracle.truffle.api.source.SourceSection;
|
||||||
import org.pkl.core.ast.ExpressionNode;
|
import org.pkl.core.ast.ExpressionNode;
|
||||||
import org.pkl.core.ast.PklNode;
|
import org.pkl.core.ast.PklNode;
|
||||||
import org.pkl.core.ast.builder.SymbolTable.CustomThisScope;
|
|
||||||
import org.pkl.core.ast.lambda.ApplyVmFunction1Node;
|
import org.pkl.core.ast.lambda.ApplyVmFunction1Node;
|
||||||
import org.pkl.core.runtime.BaseModule;
|
import org.pkl.core.runtime.BaseModule;
|
||||||
import org.pkl.core.runtime.VmFunction;
|
import org.pkl.core.runtime.VmFunction;
|
||||||
@@ -87,7 +86,7 @@ public abstract class TypeConstraintNode extends PklNode {
|
|||||||
if (customThisSlot == -1) {
|
if (customThisSlot == -1) {
|
||||||
CompilerDirectives.transferToInterpreterAndInvalidate();
|
CompilerDirectives.transferToInterpreterAndInvalidate();
|
||||||
// deferred until execution time s.t. nodes of inlined type aliases get the right frame slot
|
// deferred until execution time s.t. nodes of inlined type aliases get the right frame slot
|
||||||
customThisSlot = VmUtils.findAuxiliarySlot(frame, CustomThisScope.FRAME_SLOT_ID);
|
customThisSlot = VmUtils.findCustomThisSlot(frame);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -95,14 +95,6 @@ public abstract class TypeNode extends PklNode {
|
|||||||
return execute(frame, value);
|
return execute(frame, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if {@code value} conforms to this type.
|
|
||||||
*
|
|
||||||
* <p>If {@code value} is conforming, sets {@code slot} to {@code value}. Otherwise, throws a
|
|
||||||
* {@link VmTypeMismatchException}.
|
|
||||||
*/
|
|
||||||
public abstract Object executeEagerlyAndSet(VirtualFrame frame, Object value);
|
|
||||||
|
|
||||||
// method arguments are used when default value contains a root node
|
// method arguments are used when default value contains a root node
|
||||||
public @Nullable Object createDefaultValue(
|
public @Nullable Object createDefaultValue(
|
||||||
VmLanguage language,
|
VmLanguage language,
|
||||||
@@ -226,11 +218,6 @@ public abstract class TypeNode extends PklNode {
|
|||||||
frame.setLong(slot, (long) value);
|
frame.setLong(slot, (long) value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
|
|
||||||
return executeAndSet(frame, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract static class ObjectSlotTypeNode extends FrameSlotTypeNode {
|
public abstract static class ObjectSlotTypeNode extends FrameSlotTypeNode {
|
||||||
@@ -248,13 +235,6 @@ public abstract class TypeNode extends PklNode {
|
|||||||
frame.setObject(slot, result);
|
frame.setObject(slot, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public final Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
|
|
||||||
var result = executeEagerly(frame, value);
|
|
||||||
frame.setObject(slot, result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -288,13 +268,6 @@ public abstract class TypeNode extends PklNode {
|
|||||||
writeSlotNode.executeWithValue(frame, result);
|
writeSlotNode.executeWithValue(frame, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
|
|
||||||
var result = executeEagerly(frame, value);
|
|
||||||
writeSlotNode.executeWithValue(frame, result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The `unknown` type. */
|
/** The `unknown` type. */
|
||||||
@@ -360,11 +333,6 @@ public abstract class TypeNode extends PklNode {
|
|||||||
throw PklBugException.unreachableCode();
|
throw PklBugException.unreachableCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
|
|
||||||
return executeAndSet(frame, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FrameSlotKind getFrameSlotKind() {
|
public FrameSlotKind getFrameSlotKind() {
|
||||||
return FrameSlotKind.Illegal;
|
return FrameSlotKind.Illegal;
|
||||||
@@ -2435,22 +2403,6 @@ public abstract class TypeNode extends PklNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** See docstring on {@link TypeAliasTypeNode#execute}. */
|
|
||||||
@Override
|
|
||||||
public Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
|
|
||||||
var prevOwner = VmUtils.getOwner(frame);
|
|
||||||
var prevReceiver = VmUtils.getReceiver(frame);
|
|
||||||
setOwner(frame, VmUtils.getOwner(typeAlias.getEnclosingFrame()));
|
|
||||||
setReceiver(frame, VmUtils.getReceiver(typeAlias.getEnclosingFrame()));
|
|
||||||
|
|
||||||
try {
|
|
||||||
return aliasedTypeNode.executeEagerlyAndSet(frame, value);
|
|
||||||
} finally {
|
|
||||||
setOwner(frame, prevOwner);
|
|
||||||
setReceiver(frame, prevReceiver);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
public @Nullable Object createDefaultValue(
|
public @Nullable Object createDefaultValue(
|
||||||
@@ -2586,13 +2538,6 @@ public abstract class TypeNode extends PklNode {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
|
|
||||||
var ret = executeEagerly(frame, value);
|
|
||||||
childNode.executeEagerlyAndSet(frame, ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @Nullable Object createDefaultValue(
|
public @Nullable Object createDefaultValue(
|
||||||
VmLanguage language, SourceSection headerSection, String qualifiedName) {
|
VmLanguage language, SourceSection headerSection, String qualifiedName) {
|
||||||
@@ -2740,11 +2685,6 @@ public abstract class TypeNode extends PklNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
|
|
||||||
return executeAndSet(frame, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VmClass getVmClass() {
|
public VmClass getVmClass() {
|
||||||
return BaseModule.getNumberClass();
|
return BaseModule.getNumberClass();
|
||||||
@@ -2813,11 +2753,6 @@ public abstract class TypeNode extends PklNode {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
|
|
||||||
return executeAndSet(frame, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VmClass getVmClass() {
|
public VmClass getVmClass() {
|
||||||
return BaseModule.getFloatClass();
|
return BaseModule.getFloatClass();
|
||||||
@@ -2858,11 +2793,6 @@ public abstract class TypeNode extends PklNode {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object executeEagerlyAndSet(VirtualFrame frame, Object value) {
|
|
||||||
return executeAndSet(frame, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public VmClass getVmClass() {
|
public VmClass getVmClass() {
|
||||||
return BaseModule.getBooleanClass();
|
return BaseModule.getBooleanClass();
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -141,9 +141,6 @@ public final class Identifier implements Comparable<Identifier> {
|
|||||||
// common in lambdas etc
|
// common in lambdas etc
|
||||||
public static final Identifier IT = get("it");
|
public static final Identifier IT = get("it");
|
||||||
|
|
||||||
// dummy, unrepresentable identifier
|
|
||||||
public static final Identifier DUMMY = get("`#_");
|
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
private Identifier(String name) {
|
private Identifier(String name) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -55,7 +55,7 @@ public final class VmFunction extends VmObjectLike {
|
|||||||
// if call site is a node, use ApplyVmFunction1Node.execute() or DirectCallNode.call() instead of
|
// if call site is a node, use ApplyVmFunction1Node.execute() or DirectCallNode.call() instead of
|
||||||
// this method
|
// this method
|
||||||
public Object apply(Object arg1) {
|
public Object apply(Object arg1) {
|
||||||
return getCallTarget().call(thisValue, this, false, arg1);
|
return getCallTarget().call(thisValue, this, arg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String applyString(Object arg1) {
|
public String applyString(Object arg1) {
|
||||||
@@ -69,7 +69,7 @@ public final class VmFunction extends VmObjectLike {
|
|||||||
// if call site is a node, use ApplyVmFunction2Node.execute() or DirectCallNode.call() instead of
|
// if call site is a node, use ApplyVmFunction2Node.execute() or DirectCallNode.call() instead of
|
||||||
// this method
|
// this method
|
||||||
public Object apply(Object arg1, Object arg2) {
|
public Object apply(Object arg1, Object arg2) {
|
||||||
return getCallTarget().call(thisValue, this, false, arg1, arg2);
|
return getCallTarget().call(thisValue, this, arg1, arg2);
|
||||||
}
|
}
|
||||||
|
|
||||||
public VmFunction copy(
|
public VmFunction copy(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -23,8 +23,8 @@ import org.pkl.core.ast.member.ObjectMember;
|
|||||||
import org.pkl.core.util.Nullable;
|
import org.pkl.core.util.Nullable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Corresponds to `pkl.base#Object|pkl.base#Function`. The lexical scope is a hierarchy of
|
* Corresponds to `pkl.base#Object|pkl.base#Function`. The lexical scope is a chain of
|
||||||
* `VmOwner`s.
|
* `VmObjectLike` instances.
|
||||||
*/
|
*/
|
||||||
public abstract class VmObjectLike extends VmValue {
|
public abstract class VmObjectLike extends VmValue {
|
||||||
/** The frame that was active when this object was instantiated. * */
|
/** The frame that was active when this object was instantiated. * */
|
||||||
@@ -66,8 +66,8 @@ public abstract class VmObjectLike extends VmValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the parent object in the prototype chain. For each concrete subclass X of VmOwner, the
|
* Returns the parent object in the prototype chain. For each concrete subclass X of VmObjectLike,
|
||||||
* exact return type of this method is `X|VmTyped`.
|
* the exact return type of this method is `X|VmTyped`.
|
||||||
*/
|
*/
|
||||||
public abstract @Nullable VmObjectLike getParent();
|
public abstract @Nullable VmObjectLike getParent();
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -47,6 +47,7 @@ import org.pkl.core.ast.ExpressionNode;
|
|||||||
import org.pkl.core.ast.SimpleRootNode;
|
import org.pkl.core.ast.SimpleRootNode;
|
||||||
import org.pkl.core.ast.VmModifier;
|
import org.pkl.core.ast.VmModifier;
|
||||||
import org.pkl.core.ast.builder.AstBuilder;
|
import org.pkl.core.ast.builder.AstBuilder;
|
||||||
|
import org.pkl.core.ast.builder.SymbolTable.CustomThisScope;
|
||||||
import org.pkl.core.ast.expression.primary.CustomThisNode;
|
import org.pkl.core.ast.expression.primary.CustomThisNode;
|
||||||
import org.pkl.core.ast.expression.primary.ThisNode;
|
import org.pkl.core.ast.expression.primary.ThisNode;
|
||||||
import org.pkl.core.ast.member.*;
|
import org.pkl.core.ast.member.*;
|
||||||
@@ -300,6 +301,59 @@ public final class VmUtils {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies {@code numberOfLocalsToCopy} locals from {@code sourceFrame}, starting at {@code
|
||||||
|
* firstSourceSlot}, to {@code firstSourceSlot}, starting at {@code firstTargetSlot}.
|
||||||
|
*/
|
||||||
|
public static void copyLocals(
|
||||||
|
VirtualFrame sourceFrame,
|
||||||
|
int firstSourceSlot,
|
||||||
|
VirtualFrame targetFrame,
|
||||||
|
int firstTargetSlot,
|
||||||
|
int numberOfLocalsToCopy) {
|
||||||
|
var sourceDescriptor = sourceFrame.getFrameDescriptor();
|
||||||
|
var targetDescriptor = targetFrame.getFrameDescriptor();
|
||||||
|
// Alternatively, locals could be copied with `numberOfLocalsToCopy`
|
||||||
|
// `ReadFrameSlotNode/WriteFrameSlotNode`'s.
|
||||||
|
for (int i = 0; i < numberOfLocalsToCopy; i++) {
|
||||||
|
var sourceSlot = firstSourceSlot + i;
|
||||||
|
var targetSlot = firstTargetSlot + i;
|
||||||
|
// If, for a particular call site of this method,
|
||||||
|
// slot kinds of `sourceDescriptor` will reach a steady state,
|
||||||
|
// then slot kinds of `targetDescriptor` will too.
|
||||||
|
var slotKind = sourceDescriptor.getSlotKind(sourceSlot);
|
||||||
|
switch (slotKind) {
|
||||||
|
case Boolean -> {
|
||||||
|
targetDescriptor.setSlotKind(targetSlot, FrameSlotKind.Boolean);
|
||||||
|
targetFrame.setBoolean(targetSlot, sourceFrame.getBoolean(sourceSlot));
|
||||||
|
}
|
||||||
|
case Long -> {
|
||||||
|
targetDescriptor.setSlotKind(targetSlot, FrameSlotKind.Long);
|
||||||
|
targetFrame.setLong(targetSlot, sourceFrame.getLong(sourceSlot));
|
||||||
|
}
|
||||||
|
case Double -> {
|
||||||
|
targetDescriptor.setSlotKind(targetSlot, FrameSlotKind.Double);
|
||||||
|
targetFrame.setDouble(targetSlot, sourceFrame.getDouble(sourceSlot));
|
||||||
|
}
|
||||||
|
case Object -> {
|
||||||
|
targetDescriptor.setSlotKind(targetSlot, FrameSlotKind.Object);
|
||||||
|
targetFrame.setObject(
|
||||||
|
targetSlot,
|
||||||
|
sourceFrame instanceof MaterializedFrame
|
||||||
|
// Even though sourceDescriptor.getSlotKind is now Object,
|
||||||
|
// it may have been a primitive kind when `sourceFrame`'s local was written.
|
||||||
|
// Hence we need to read the local with getValue() instead of getObject().
|
||||||
|
? sourceFrame.getValue(sourceSlot)
|
||||||
|
: sourceFrame.getObject(sourceSlot));
|
||||||
|
}
|
||||||
|
default -> {
|
||||||
|
CompilerDirectives.transferToInterpreter();
|
||||||
|
throw new VmExceptionBuilder().bug("Unexpected FrameSlotKind: " + slotKind).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A failed property type check looks as follows in the stack trace:
|
// A failed property type check looks as follows in the stack trace:
|
||||||
// x: Int(isPositive)
|
// x: Int(isPositive)
|
||||||
// at ...
|
// at ...
|
||||||
@@ -687,9 +741,7 @@ public final class VmUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static TypeNode[] resolveParameterTypes(
|
public static TypeNode[] resolveParameterTypes(
|
||||||
VirtualFrame frame,
|
VirtualFrame frame, FrameDescriptor descriptor, UnresolvedTypeNode[] parameterTypeNodes) {
|
||||||
FrameDescriptor descriptor,
|
|
||||||
@Nullable UnresolvedTypeNode[] parameterTypeNodes) {
|
|
||||||
|
|
||||||
var resolvedNodes = new TypeNode[parameterTypeNodes.length];
|
var resolvedNodes = new TypeNode[parameterTypeNodes.length];
|
||||||
|
|
||||||
@@ -836,25 +888,11 @@ public final class VmUtils {
|
|||||||
return callNode.call(rootNode.getCallTarget(), module, module);
|
return callNode.call(rootNode.getCallTarget(), module, module);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int findSlot(VirtualFrame frame, Object identifier) {
|
public static int findCustomThisSlot(VirtualFrame frame) {
|
||||||
var descriptor = frame.getFrameDescriptor();
|
return frame
|
||||||
for (int i = 0; i < descriptor.getNumberOfSlots(); i++) {
|
.getFrameDescriptor()
|
||||||
if (descriptor.getSlotName(i) == identifier
|
.getAuxiliarySlots()
|
||||||
&& frame.getTag(i) != FrameSlotKind.Illegal.tag
|
.getOrDefault(CustomThisScope.FRAME_SLOT_ID, -1);
|
||||||
// Truffle initializes all frame tags as `FrameSlotKind.Object`, instead of
|
|
||||||
// `FrameSlotKind.Illegal`. Unevaluated (in a `when` with `false` condition) `for`
|
|
||||||
// generators, therefore, leave their bound variables tagged as `Object`, but `null`. If
|
|
||||||
// another `for` generator in the same scope binds variables with the same names, they
|
|
||||||
// resolve the wrong slot number.
|
|
||||||
&& (frame.getTag(i) != FrameSlotKind.Object.tag || frame.getObject(i) != null)) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int findAuxiliarySlot(VirtualFrame frame, Object identifier) {
|
|
||||||
return frame.getFrameDescriptor().getAuxiliarySlots().getOrDefault(identifier, -1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TruffleBoundary
|
@TruffleBoundary
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -31,12 +31,11 @@ public final class FunctionNodes {
|
|||||||
protected Object eval(VmFunction self, VmList argList) {
|
protected Object eval(VmFunction self, VmList argList) {
|
||||||
var argCount = argList.getLength();
|
var argCount = argList.getLength();
|
||||||
|
|
||||||
var args = new Object[3 + argCount];
|
var args = new Object[2 + argCount];
|
||||||
args[0] = self.getThisValue();
|
args[0] = self.getThisValue();
|
||||||
args[1] = self;
|
args[1] = self;
|
||||||
args[2] = false;
|
|
||||||
|
|
||||||
var i = 3;
|
var i = 2;
|
||||||
for (var arg : argList) {
|
for (var arg : argList) {
|
||||||
args[i++] = arg;
|
args[i++] = arg;
|
||||||
}
|
}
|
||||||
|
|||||||
-11
@@ -1,11 +0,0 @@
|
|||||||
a = List(1, 2, 3, 4)
|
|
||||||
|
|
||||||
b = List("a", "b", "c", "d")
|
|
||||||
|
|
||||||
foo {
|
|
||||||
for (_dup, i in a) {
|
|
||||||
for (_dup, j in b) {
|
|
||||||
i + j
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
+18
@@ -0,0 +1,18 @@
|
|||||||
|
function myMethod(arg) = new {
|
||||||
|
arg = "property" // same name as method arg
|
||||||
|
for (key, value in List("one", "two", arg)) { // `arg` resolves to method arg
|
||||||
|
[Pair(arg, key)] = // `arg` resolves to method arg
|
||||||
|
Pair(arg, value) // `arg` resolves to object property
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
local myLambda = (arg) -> new Dynamic {
|
||||||
|
arg = "property" // same name as lambda arg
|
||||||
|
for (key, value in List("one", "two", arg)) { // `arg` resolves to lambda arg
|
||||||
|
[Pair(arg, key)] = // `arg` resolves to lambda arg
|
||||||
|
Pair(arg, value) // `arg` resolves to object property
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res1 = myMethod("three")
|
||||||
|
res2 = myLambda.apply("three")
|
||||||
Vendored
+25
@@ -0,0 +1,25 @@
|
|||||||
|
// https://github.com/apple/pkl/issues/741
|
||||||
|
|
||||||
|
bar = new {}
|
||||||
|
|
||||||
|
res1 {
|
||||||
|
for (i in List(1)) {
|
||||||
|
...(bar) {
|
||||||
|
baz {
|
||||||
|
new { i }
|
||||||
|
}
|
||||||
|
}.baz
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res2 {
|
||||||
|
for (i in List(1)) {
|
||||||
|
for (elem in (bar) {
|
||||||
|
baz {
|
||||||
|
new { i }
|
||||||
|
}
|
||||||
|
}.baz) {
|
||||||
|
elem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+33
@@ -0,0 +1,33 @@
|
|||||||
|
examples {
|
||||||
|
local a = List("1", "2", "3", "4")
|
||||||
|
local b = List("a", "b", "c", "d")
|
||||||
|
|
||||||
|
["shadow key variable"] {
|
||||||
|
new {
|
||||||
|
for (key, outerValue in a) {
|
||||||
|
for (key, innerValue in b) {
|
||||||
|
List(outerValue, key, innerValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
["shadow value variable"] {
|
||||||
|
new {
|
||||||
|
for (outerKey, value in a) {
|
||||||
|
for (innerKey, value in b) {
|
||||||
|
List(outerKey, value, innerKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
["sibling for-generators can use same variable names"] {
|
||||||
|
new {
|
||||||
|
for (key, value in a) {
|
||||||
|
List(key, value)
|
||||||
|
}
|
||||||
|
for (key, value in b) {
|
||||||
|
List(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
-6
@@ -1,6 +0,0 @@
|
|||||||
–– Pkl Error ––
|
|
||||||
Duplicate definition of member `_dup`.
|
|
||||||
|
|
||||||
x | for (_dup, j in b) {
|
|
||||||
^^^^
|
|
||||||
at forGeneratorDuplicateParams2#foo (file:///$snippetsDir/input/errors/forGeneratorDuplicateParams2.pkl)
|
|
||||||
Vendored
+12
@@ -0,0 +1,12 @@
|
|||||||
|
res1 {
|
||||||
|
arg = "property"
|
||||||
|
[Pair("three", 0)] = Pair("property", "one")
|
||||||
|
[Pair("three", 1)] = Pair("property", "two")
|
||||||
|
[Pair("three", 2)] = Pair("property", "three")
|
||||||
|
}
|
||||||
|
res2 {
|
||||||
|
arg = "property"
|
||||||
|
[Pair("three", 0)] = Pair("property", "one")
|
||||||
|
[Pair("three", 1)] = Pair("property", "two")
|
||||||
|
[Pair("three", 2)] = Pair("property", "three")
|
||||||
|
}
|
||||||
Vendored
+11
@@ -0,0 +1,11 @@
|
|||||||
|
bar {}
|
||||||
|
res1 {
|
||||||
|
new {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res2 {
|
||||||
|
new {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
+54
@@ -0,0 +1,54 @@
|
|||||||
|
examples {
|
||||||
|
["shadow key variable"] {
|
||||||
|
new {
|
||||||
|
List("1", 0, "a")
|
||||||
|
List("1", 1, "b")
|
||||||
|
List("1", 2, "c")
|
||||||
|
List("1", 3, "d")
|
||||||
|
List("2", 0, "a")
|
||||||
|
List("2", 1, "b")
|
||||||
|
List("2", 2, "c")
|
||||||
|
List("2", 3, "d")
|
||||||
|
List("3", 0, "a")
|
||||||
|
List("3", 1, "b")
|
||||||
|
List("3", 2, "c")
|
||||||
|
List("3", 3, "d")
|
||||||
|
List("4", 0, "a")
|
||||||
|
List("4", 1, "b")
|
||||||
|
List("4", 2, "c")
|
||||||
|
List("4", 3, "d")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
["shadow value variable"] {
|
||||||
|
new {
|
||||||
|
List(0, "a", 0)
|
||||||
|
List(0, "b", 1)
|
||||||
|
List(0, "c", 2)
|
||||||
|
List(0, "d", 3)
|
||||||
|
List(1, "a", 0)
|
||||||
|
List(1, "b", 1)
|
||||||
|
List(1, "c", 2)
|
||||||
|
List(1, "d", 3)
|
||||||
|
List(2, "a", 0)
|
||||||
|
List(2, "b", 1)
|
||||||
|
List(2, "c", 2)
|
||||||
|
List(2, "d", 3)
|
||||||
|
List(3, "a", 0)
|
||||||
|
List(3, "b", 1)
|
||||||
|
List(3, "c", 2)
|
||||||
|
List(3, "d", 3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
["sibling for-generators can use same variable names"] {
|
||||||
|
new {
|
||||||
|
List(0, "1")
|
||||||
|
List(1, "2")
|
||||||
|
List(2, "3")
|
||||||
|
List(3, "4")
|
||||||
|
List(0, "a")
|
||||||
|
List(1, "b")
|
||||||
|
List(2, "c")
|
||||||
|
List(3, "d")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user