Skip to content

Commit cc200f8

Browse files
committed
for loop variables are aliased
1 parent 15d2ee5 commit cc200f8

File tree

8 files changed

+40
-27
lines changed

8 files changed

+40
-27
lines changed

MILESTONES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@
144144
- `goto` special cases - for `Text::Balanced`.
145145
- indirect object special cases - for `GetOpt::Long`.
146146
- Here documents.
147-
- Implement aliasing in `for`.
148147
- Implement localization of regex variables.
149148
- DBI subsystem
150149
- Additional methods.
@@ -181,6 +180,7 @@
181180
- **v2.2.0**: Core modules
182181
- Perl version is now v5.40.0
183182
- `for` loop can iterate over multiple values at the same time.
183+
- `for` loop variables are aliased.
184184
- Added `DBI` module with JDBC support.
185185
- Added `URI::Escape` module.
186186
- Added `builtin` methods: `inf` `nan` `weaken` `unweaken` `is_weak` `blessed` `refaddr` `reftype` `created_as_string` `created_as_number` `stringify` `ceil` `floor` `indexed` `trim` `is_tainted`.

docs/FEATURE_MATRIX.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@
261261
- 🚧 **File test operators**: The current implementation only works with file paths, not filehandles or dirhandles.
262262
-**File test operators**: Add support for stacked file test operators.
263263
- ✔️ **Directory operators**: `readdir`, `opendir`, `closedir`, `telldir`, `seekdir`, `rewinddir`, `mkdir`, `rmdir`, `chdir`.
264-
- **`for` loop variable**: The `for` loop variable is not an alias to a list element.
264+
- ✔️ **`for` loop variable**: The `for` loop variable is aliased to list elements.
265265
- ✔️ **`for` loop variable**: Iterate over multiple values at a time is implemented.
266266
- ✔️ **loop control operators**: `next`, `last`, `redo` with labels are implemented.
267267
-**loop control operators**: `next`, `last`, `redo` with expression are not implemented.

src/main/java/org/perlonjava/astnode/For1Node.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ public class For1Node extends AbstractNode {
1212
* This loop creates a new variable scope
1313
*/
1414
public final boolean useNewScope;
15-
/**
16-
* The list part of the for loop.
17-
*/
18-
public Node variable;
1915
/**
2016
* The variable part of the for loop.
2117
*/
@@ -25,6 +21,10 @@ public class For1Node extends AbstractNode {
2521
*/
2622
public final Node body;
2723
public final Node continueBlock;
24+
/**
25+
* The list part of the for loop.
26+
*/
27+
public Node variable;
2828
/**
2929
* the label name for this loop
3030
*/

src/main/java/org/perlonjava/codegen/EmitForeach.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import org.objectweb.asm.MethodVisitor;
55
import org.objectweb.asm.Opcodes;
66
import org.perlonjava.astnode.*;
7+
import org.perlonjava.perlmodule.Warnings;
78
import org.perlonjava.runtime.RuntimeContextType;
89

910
public class EmitForeach {
@@ -24,17 +25,26 @@ static void emitFor1(EmitterVisitor emitterVisitor, For1Node node) {
2425
opNode.operator.equals("$") &&
2526
opNode.operand instanceof IdentifierNode idNode &&
2627
idNode.name.equals("_")) {
27-
int varIndex = emitterVisitor.ctx.symbolTable.getVariableIndex("$_");
28-
if (varIndex == -1) {
29-
node.variable = new OperatorNode("our", node.variable, node.variable.getIndex());
30-
}
28+
node.variable = new OperatorNode("our", node.variable, node.variable.getIndex());
3129
}
3230

3331
// First declare the variables if it's a my/our operator
3432
if (node.variable instanceof OperatorNode opNode &&
3533
(opNode.operator.equals("my") || opNode.operator.equals("our"))) {
34+
boolean isWarningEnabled = Warnings.warningManager.isWarningEnabled("redefine");
35+
if (isWarningEnabled) {
36+
// turn off "masks earlier declaration" warning
37+
Warnings.warningManager.setWarningState("redefine", false);
38+
}
39+
// emit the variable declarations
3640
node.variable.accept(emitterVisitor.with(RuntimeContextType.VOID));
37-
node.variable = ((OperatorNode) node.variable).operand;
41+
// rewrite the variable node without the declaration
42+
node.variable = opNode.operand;
43+
44+
if (isWarningEnabled) {
45+
// restore warnings
46+
Warnings.warningManager.setWarningState("redefine", true);
47+
}
3848
}
3949

4050
// Obtain the iterator for the list
@@ -78,7 +88,7 @@ static void emitFor1(EmitterVisitor emitterVisitor, For1Node node) {
7888
// Assign to variable
7989
Node varNode = varList.elements.get(i);
8090
if (varNode instanceof OperatorNode operatorNode) {
81-
String varName = operatorNode.operator + ((IdentifierNode)operatorNode.operand).name;
91+
String varName = operatorNode.operator + ((IdentifierNode) operatorNode.operand).name;
8292
int varIndex = emitterVisitor.ctx.symbolTable.getVariableIndex(varName);
8393
emitterVisitor.ctx.logDebug("FOR1 multi var name:" + varName + " index:" + varIndex);
8494
mv.visitVarInsn(Opcodes.ASTORE, varIndex);
@@ -91,7 +101,7 @@ static void emitFor1(EmitterVisitor emitterVisitor, For1Node node) {
91101
mv.visitTypeInsn(Opcodes.CHECKCAST, "org/perlonjava/runtime/RuntimeScalar");
92102

93103
if (node.variable instanceof OperatorNode operatorNode) {
94-
String varName = operatorNode.operator + ((IdentifierNode)operatorNode.operand).name;
104+
String varName = operatorNode.operator + ((IdentifierNode) operatorNode.operand).name;
95105
int varIndex = emitterVisitor.ctx.symbolTable.getVariableIndex(varName);
96106
emitterVisitor.ctx.logDebug("FOR1 single var name:" + varName + " index:" + varIndex);
97107
mv.visitVarInsn(Opcodes.ASTORE, varIndex);

src/main/java/org/perlonjava/codegen/EmitVariable.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import org.objectweb.asm.MethodVisitor;
44
import org.objectweb.asm.Opcodes;
55
import org.perlonjava.astnode.*;
6+
import org.perlonjava.perlmodule.Warnings;
67
import org.perlonjava.runtime.*;
78

89
import java.util.ArrayList;
@@ -347,11 +348,13 @@ static void handleMyOperator(EmitterVisitor emitterVisitor, OperatorNode node) {
347348
String var = sigil + name;
348349
emitterVisitor.ctx.logDebug("MY " + operator + " " + sigil + name);
349350
if (emitterVisitor.ctx.symbolTable.getVariableIndexInCurrentScope(var) != -1) {
350-
System.err.println(
351-
emitterVisitor.ctx.errorUtil.errorMessage(node.getIndex(),
352-
"Warning: \"" + operator + "\" variable "
353-
+ var
354-
+ " masks earlier declaration in same ctx.symbolTable"));
351+
if (Warnings.warningManager.isWarningEnabled("redefine")) {
352+
System.err.println(
353+
emitterVisitor.ctx.errorUtil.errorMessage(node.getIndex(),
354+
"Warning: \"" + operator + "\" variable "
355+
+ var
356+
+ " masks earlier declaration in same ctx.symbolTable"));
357+
}
355358
}
356359
int varIndex = emitterVisitor.ctx.symbolTable.addVariable(var, operator, sigilNode);
357360
// TODO optimization - SETVAR+MY can be combined

src/main/java/org/perlonjava/perlmodule/Exporter.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,14 @@ public static RuntimeList importSymbols(RuntimeArray args, int ctx) {
6060
RuntimeArray exportOk = GlobalVariable.getGlobalArray(packageScalar + "::EXPORT_OK");
6161
RuntimeHash exportTags = GlobalVariable.getGlobalHash(packageScalar + "::EXPORT_TAGS");
6262

63-
// If no specific symbols are requested, default to exporting all symbols in @EXPORT
64-
if (args.size() == 0) {
65-
if (export != null && export.elements != null) {
66-
args = export;
67-
} else {
68-
args = new RuntimeArray();
69-
}
63+
// If no specific symbols are requested, default to exporting all symbols in @EXPORT
64+
if (args.size() == 0) {
65+
if (export != null && export.elements != null) {
66+
args = export;
67+
} else {
68+
args = new RuntimeArray();
7069
}
70+
}
7171

7272
String exportLevel = GlobalVariable.getGlobalVariable("Exporter::ExportLevel").toString();
7373

src/main/java/org/perlonjava/perlmodule/Warnings.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*/
1111
public class Warnings extends PerlModuleBase {
1212

13-
private static final WarningFlags warningManager = new WarningFlags();
13+
public static final WarningFlags warningManager = new WarningFlags();
1414

1515
/**
1616
* Constructor for Warnings.

src/main/java/org/perlonjava/runtime/WarningFlags.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public void disableWarning(String category) {
9696
* @param category The name of the warning category.
9797
* @param state The state to set (true for enabled, false for disabled).
9898
*/
99-
private void setWarningState(String category, boolean state) {
99+
public void setWarningState(String category, boolean state) {
100100
ScopedSymbolTable symbolTable = getCurrentScope();
101101
if (state) {
102102
symbolTable.enableWarningCategory(category);

0 commit comments

Comments
 (0)