From a1fb1f3cdf0509c8fc358ed79e69ed4b3b2165f9 Mon Sep 17 00:00:00 2001 From: "Flavio S. Glock" Date: Mon, 21 Oct 2024 15:19:05 +0200 Subject: [PATCH] fix code references with `&` --- FEATURE_MATRIX.md | 2 +- .../perlonjava/codegen/EmitterVisitor.java | 19 +++++++++++++++---- .../org/perlonjava/runtime/RuntimeScalar.java | 7 +++++++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/FEATURE_MATRIX.md b/FEATURE_MATRIX.md index 9965efd..de8b749 100644 --- a/FEATURE_MATRIX.md +++ b/FEATURE_MATRIX.md @@ -168,7 +168,7 @@ - ✔️ **Compound assignment operators**: Compound assignment operators are implemented. - ✔️ **`package` declaration**: `package BLOCK` is also supported. - ✔️ **Typeglob operations**: Operations like `*x = sub {}` are supported. -- ✔️ **Code references**: Code references like `&subr` are implemented. +- ✔️ **Code references**: Code references like `\&subr`, `\&$subname`, `\&{$subname}`, are implemented. - ✔️ **Special literals**: `__PACKAGE__`, `__FILE__`, `__LINE__` - ✔️ **`die` related operators**: `die`, `warn`, `exit` are supported. - ❌ **`die` related features**: `$SIG{__DIE__}`, `$SIG{__WARN__}`, `PROPAGATE` are not yet supported. diff --git a/src/main/java/org/perlonjava/codegen/EmitterVisitor.java b/src/main/java/org/perlonjava/codegen/EmitterVisitor.java index c226879..3bafd3c 100644 --- a/src/main/java/org/perlonjava/codegen/EmitterVisitor.java +++ b/src/main/java/org/perlonjava/codegen/EmitterVisitor.java @@ -886,10 +886,21 @@ private void handleCreateReference(OperatorNode node) { mv.visitInsn(Opcodes.POP); } } else { - if (node.operand instanceof OperatorNode && ((OperatorNode) node.operand).operator.equals("&")) { - // System.out.println("handleCreateReference of &var"); - // &var is already a reference - node.operand.accept(this.with(RuntimeContextType.LIST)); + if (node.operand instanceof OperatorNode operatorNode && operatorNode.operator.equals("&")) { + ctx.logDebug("Handle \\& " + operatorNode.operand); + if (operatorNode.operand instanceof OperatorNode || operatorNode.operand instanceof BlockNode) { + // \&$a or \&{$a} + operatorNode.operand.accept(this.with(RuntimeContextType.SCALAR)); + ctx.mv.visitLdcInsn(ctx.symbolTable.getCurrentPackage()); + ctx.mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, + "org/perlonjava/runtime/RuntimeScalar", + "createCodeReference", + "(Ljava/lang/String;)Lorg/perlonjava/runtime/RuntimeScalar;", + false); + } else { + // assume \&var, which is already a reference + node.operand.accept(this.with(RuntimeContextType.LIST)); + } } else { node.operand.accept(this.with(RuntimeContextType.LIST)); ctx.mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "org/perlonjava/runtime/RuntimeDataProvider", "createReference", "()Lorg/perlonjava/runtime/RuntimeScalar;", true); diff --git a/src/main/java/org/perlonjava/runtime/RuntimeScalar.java b/src/main/java/org/perlonjava/runtime/RuntimeScalar.java index 0161e5e..dd857b0 100644 --- a/src/main/java/org/perlonjava/runtime/RuntimeScalar.java +++ b/src/main/java/org/perlonjava/runtime/RuntimeScalar.java @@ -898,6 +898,13 @@ public RuntimeScalar createReference() { return result; } + // Return a reference to the subroutine with this name: \&$a + public RuntimeScalar createCodeReference(String packageName) { + String name = NameNormalizer.normalizeVariableName(this.toString(), packageName); + System.out.println("Creating code reference: " + name + " got: " + GlobalContext.getGlobalCodeRef(name)); + return GlobalContext.getGlobalCodeRef(name); + } + public RuntimeScalar undefine() { this.type = RuntimeScalarType.UNDEF; return this;