diff --git a/src/main/java/org/perlonjava/codegen/Dereference.java b/src/main/java/org/perlonjava/codegen/Dereference.java index 08e538a9..90f3e66f 100644 --- a/src/main/java/org/perlonjava/codegen/Dereference.java +++ b/src/main/java/org/perlonjava/codegen/Dereference.java @@ -695,7 +695,25 @@ public static void handleArrowArrayDeref(EmitterVisitor emitterVisitor, BinaryOp emitterVisitor.ctx.mv.visitVarInsn(Opcodes.ASTORE, leftSlot); ArrayLiteralNode right = (ArrayLiteralNode) node.right; - if (right.elements.size() == 1) { + + // Check if all elements are safe for single-element optimization + // (i.e., they can be evaluated in SCALAR context without needing LIST context expansion) + boolean allSafeForSingleElement = true; + for (Node elem : right.elements) { + // Ranges (.. operator) need LIST context to expand to multiple indices + if (elem instanceof BinaryOperatorNode binOp && "..".equals(binOp.operator)) { + allSafeForSingleElement = false; + break; + } + // Array slices need LIST context + if (elem instanceof OperatorNode opNode && opNode.operator.startsWith("@")) { + allSafeForSingleElement = false; + break; + } + // Most other nodes (NumberNode, StringNode, IdentifierNode, $var, $var[0], etc.) are safe + } + + if (allSafeForSingleElement && right.elements.size() == 1) { // Single index: use get/delete/exists methods Node elem = right.elements.getFirst(); elem.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); @@ -741,7 +759,7 @@ public static void handleArrowArrayDeref(EmitterVisitor emitterVisitor, BinaryOp emitterVisitor.ctx.javaClassInfo.releaseSpillSlot(); } } else { - // Multiple indices: use slice method (only for get operation) + // Multiple indices or non-literal elements: use slice method (only for get operation) if (!arrayOperation.equals("get")) { throw new PerlCompilerException(node.tokenIndex, "Array slice not supported for " + arrayOperation, emitterVisitor.ctx.errorUtil); } diff --git a/src/main/java/org/perlonjava/runtime/RuntimeArrayProxyEntry.java b/src/main/java/org/perlonjava/runtime/RuntimeArrayProxyEntry.java index 403cd551..651ec11d 100644 --- a/src/main/java/org/perlonjava/runtime/RuntimeArrayProxyEntry.java +++ b/src/main/java/org/perlonjava/runtime/RuntimeArrayProxyEntry.java @@ -17,6 +17,24 @@ public class RuntimeArrayProxyEntry extends RuntimeBaseProxy { // Index associated with this proxy in the parent array private final int key; + /** + * Gets the parent RuntimeArray. + * + * @return the parent RuntimeArray + */ + public RuntimeArray getParent() { + return parent; + } + + /** + * Gets the key (index) for this proxy entry. + * + * @return the index in the parent array + */ + public int getKey() { + return key; + } + /** * Constructs a RuntimeArrayProxyEntry for a given index in the specified parent array. * diff --git a/src/main/java/org/perlonjava/runtime/RuntimeArraySizeLvalue.java b/src/main/java/org/perlonjava/runtime/RuntimeArraySizeLvalue.java index 03d96dd7..8b747e52 100644 --- a/src/main/java/org/perlonjava/runtime/RuntimeArraySizeLvalue.java +++ b/src/main/java/org/perlonjava/runtime/RuntimeArraySizeLvalue.java @@ -35,4 +35,36 @@ public RuntimeScalar set(RuntimeScalar value) { parent.setLastElementIndex(value); return this; } + + /** + * Performs pre-decrement on the array size ($#array--). + * + * @return The updated array size after decrement. + */ + @Override + public RuntimeScalar preAutoDecrement() { + RuntimeArray parent = lvalue.arrayDeref(); + RuntimeScalar currentSize = new RuntimeScalar(parent.lastElementIndex()); + RuntimeScalar newSize = new RuntimeScalar(currentSize.getInt() - 1); + parent.setLastElementIndex(newSize); + this.value = newSize.value; + this.type = newSize.type; + return newSize; + } + + /** + * Performs post-decrement on the array size ($#array--). + * + * @return The original array size before decrement. + */ + @Override + public RuntimeScalar postAutoDecrement() { + RuntimeArray parent = lvalue.arrayDeref(); + RuntimeScalar originalSize = new RuntimeScalar(parent.lastElementIndex()); + RuntimeScalar newSize = new RuntimeScalar(originalSize.getInt() - 1); + parent.setLastElementIndex(newSize); + this.value = newSize.value; + this.type = newSize.type; + return originalSize; + } }