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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3731,12 +3731,9 @@ void compileVariableReference(OperatorNode node, String op) {
} else if (op.equals("*")) {
// Glob variable dereference: *x
if (node.operand instanceof IdentifierNode idNode) {
String varName = idNode.name;

// Add package prefix if not present
if (!varName.contains("::")) {
varName = getCurrentPackage() + "::" + varName;
}
// Use NameNormalizer to properly handle special handles (STDOUT, STDERR, STDIN, etc.)
// which must always be in the "main" package, regardless of current package.
String varName = NameNormalizer.normalizeVariableName(idNode.name, getCurrentPackage());

// Allocate register for glob
int rd = allocateOutputRegister();
Expand All @@ -3750,10 +3747,8 @@ void compileVariableReference(OperatorNode node, String op) {
lastResultReg = rd;
} else if (node.operand instanceof StringNode strNode) {
// Symbolic ref: *{'name'} or 'name'->** — load global glob by string name
String varName = strNode.value;
if (!varName.contains("::")) {
varName = getCurrentPackage() + "::" + varName;
}
// Use NameNormalizer to properly handle special handles (STDOUT, STDERR, etc.)
String varName = NameNormalizer.normalizeVariableName(strNode.value, getCurrentPackage());
int rd = allocateOutputRegister();
int nameIdx = addToStringPool(varName);
emitWithToken(Opcodes.LOAD_GLOB, node.getIndex());
Expand Down
105 changes: 14 additions & 91 deletions src/main/java/org/perlonjava/backend/bytecode/CompileAssignment.java
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ private static boolean handleLocalListAssignment(BytecodeCompiler bc, BinaryOper
}
bc.compileNode(node.right, -1, rhsContext);
int valueReg = bc.lastResultReg;
String globalVarName = bc.getCurrentPackage() + "::" + idNode.name;
String globalVarName = NameNormalizer.normalizeVariableName(idNode.name, bc.getCurrentPackage());
int nameIdx = bc.addToStringPool(globalVarName);
int localReg = bc.allocateRegister();
bc.emitWithToken(Opcodes.LOCAL_SCALAR, node.getIndex());
Expand All @@ -207,7 +207,7 @@ private static boolean handleLocalListAssignment(BytecodeCompiler bc, BinaryOper
bc.throwCompilerException("Can't localize lexical variable " + varName);
return true;
}
String globalVarName = bc.getCurrentPackage() + "::" + idNode.name;
String globalVarName = NameNormalizer.normalizeVariableName(idNode.name, bc.getCurrentPackage());
int nameIdx = bc.addToStringPool(globalVarName);
int localReg = bc.allocateRegister();
bc.emitWithToken(Opcodes.LOCAL_SCALAR, node.getIndex());
Expand Down Expand Up @@ -1522,6 +1522,8 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler,

} else if (node.left instanceof ListNode listNode) {
// List assignment: ($a, $b) = ... or () = ...
// Follow the JVM backend approach: compile LHS as a list of lvalues,
// then call setFromList() on it.
// In scalar context, returns the number of elements on RHS
// In list context, returns the RHS list
LValueVisitor.getContext(node.left);
Expand All @@ -1536,80 +1538,6 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler,
bytecodeCompiler.emitReg(rhsListReg);
bytecodeCompiler.emitReg(rhsReg);

// Resolve all LHS variables and collect their registers
List<Integer> varRegs = new ArrayList<>();
for (Node lhsElement : listNode.elements) {
if (lhsElement instanceof OperatorNode lhsOp && lhsOp.operand instanceof IdentifierNode idNode) {
String sigil = lhsOp.operator;
String varName = sigil + idNode.name;

if (sigil.equals("$")) {
if (bytecodeCompiler.hasVariable(varName)) {
int targetReg = bytecodeCompiler.getVariableRegister(varName);
if (!((bytecodeCompiler.capturedVarIndices != null && bytecodeCompiler.capturedVarIndices.containsKey(varName))
|| bytecodeCompiler.closureCapturedVarNames.contains(varName))) {
bytecodeCompiler.emit(Opcodes.LOAD_UNDEF);
bytecodeCompiler.emitReg(targetReg);
}
varRegs.add(targetReg);
} else {
if (bytecodeCompiler.shouldBlockGlobalUnderStrictVars(varName)) {
bytecodeCompiler.throwCompilerException("Global symbol \"" + varName + "\" requires explicit package name");
}
String normalizedName = NameNormalizer.normalizeVariableName(idNode.name, bytecodeCompiler.getCurrentPackage());
int nameIdx = bytecodeCompiler.addToStringPool(normalizedName);
int globalReg = bytecodeCompiler.allocateRegister();
bytecodeCompiler.emit(Opcodes.LOAD_GLOBAL_SCALAR);
bytecodeCompiler.emitReg(globalReg);
bytecodeCompiler.emit(nameIdx);
varRegs.add(globalReg);
}
} else if (sigil.equals("@")) {
int arrayReg;
if (bytecodeCompiler.currentSubroutineBeginId != 0 && bytecodeCompiler.currentSubroutineClosureVars != null
&& bytecodeCompiler.currentSubroutineClosureVars.contains(varName)) {
arrayReg = bytecodeCompiler.allocateRegister();
int nameIdx = bytecodeCompiler.addToStringPool(varName);
bytecodeCompiler.emitWithToken(Opcodes.RETRIEVE_BEGIN_ARRAY, node.getIndex());
bytecodeCompiler.emitReg(arrayReg);
bytecodeCompiler.emit(nameIdx);
bytecodeCompiler.emit(bytecodeCompiler.currentSubroutineBeginId);
} else if (bytecodeCompiler.hasVariable(varName)) {
arrayReg = bytecodeCompiler.getVariableRegister(varName);
} else {
arrayReg = bytecodeCompiler.allocateRegister();
String globalName = NameNormalizer.normalizeVariableName(idNode.name, bytecodeCompiler.getCurrentPackage());
int nameIdx = bytecodeCompiler.addToStringPool(globalName);
bytecodeCompiler.emit(Opcodes.LOAD_GLOBAL_ARRAY);
bytecodeCompiler.emitReg(arrayReg);
bytecodeCompiler.emit(nameIdx);
}
varRegs.add(arrayReg);
} else if (sigil.equals("%")) {
int hashReg;
if (bytecodeCompiler.currentSubroutineBeginId != 0 && bytecodeCompiler.currentSubroutineClosureVars != null
&& bytecodeCompiler.currentSubroutineClosureVars.contains(varName)) {
hashReg = bytecodeCompiler.allocateRegister();
int nameIdx = bytecodeCompiler.addToStringPool(varName);
bytecodeCompiler.emitWithToken(Opcodes.RETRIEVE_BEGIN_HASH, node.getIndex());
bytecodeCompiler.emitReg(hashReg);
bytecodeCompiler.emit(nameIdx);
bytecodeCompiler.emit(bytecodeCompiler.currentSubroutineBeginId);
} else if (bytecodeCompiler.hasVariable(varName)) {
hashReg = bytecodeCompiler.getVariableRegister(varName);
} else {
hashReg = bytecodeCompiler.allocateRegister();
String globalName = NameNormalizer.normalizeVariableName(idNode.name, bytecodeCompiler.getCurrentPackage());
int nameIdx = bytecodeCompiler.addToStringPool(globalName);
bytecodeCompiler.emit(Opcodes.LOAD_GLOBAL_HASH);
bytecodeCompiler.emitReg(hashReg);
bytecodeCompiler.emit(nameIdx);
}
varRegs.add(hashReg);
}
}
}

int countReg = -1;
if (outerContext == RuntimeContextType.SCALAR) {
countReg = bytecodeCompiler.allocateRegister();
Expand All @@ -1618,22 +1546,17 @@ public static void compileAssignmentOperator(BytecodeCompiler bytecodeCompiler,
bytecodeCompiler.emitReg(rhsListReg);
}

// Build LHS list and assign via SET_FROM_LIST
if (!varRegs.isEmpty()) {
int lhsListReg = bytecodeCompiler.allocateRegister();
bytecodeCompiler.emit(Opcodes.CREATE_LIST);
bytecodeCompiler.emitReg(lhsListReg);
bytecodeCompiler.emit(varRegs.size());
for (int reg : varRegs) {
bytecodeCompiler.emitReg(reg);
}
// Compile LHS ListNode in LIST context - this produces a RuntimeList of lvalues
// This follows the JVM backend approach (EmitVariable.java line 837)
bytecodeCompiler.compileNode(listNode, -1, RuntimeContextType.LIST);
int lhsListReg = bytecodeCompiler.lastResultReg;

int resultReg = bytecodeCompiler.allocateRegister();
bytecodeCompiler.emit(Opcodes.SET_FROM_LIST);
bytecodeCompiler.emitReg(resultReg);
bytecodeCompiler.emitReg(lhsListReg);
bytecodeCompiler.emitReg(rhsListReg);
}
// Call SET_FROM_LIST to assign RHS values to LHS lvalues
int resultReg = bytecodeCompiler.allocateRegister();
bytecodeCompiler.emit(Opcodes.SET_FROM_LIST);
bytecodeCompiler.emitReg(resultReg);
bytecodeCompiler.emitReg(lhsListReg);
bytecodeCompiler.emitReg(rhsListReg);

if (countReg >= 0) {
bytecodeCompiler.lastResultReg = countReg;
Expand Down
Loading