Skip to content

Commit 489f273

Browse files
committed
add "local *typeglob"
1 parent 6a6db37 commit 489f273

File tree

7 files changed

+65
-24
lines changed

7 files changed

+65
-24
lines changed

FEATURE_MATRIX.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,14 @@
6565
- ✔️ **References**: References to variables and data structures are supported.
6666
- ✔️ **Autovivification**: Autovivification is implemented.
6767
- ✔️ **File handles**: Support for file handles is implemented.
68+
- ✔️ **`local` special cases**: `local` works for typeglobs and filehandles.
6869
-**Tied Scalars**: Support for tying scalars to classes is missing.
6970
-**Overload**: overloading Perl operations is missing.
7071
- ✔️ **Cached string/numeric conversions; dualvars**: Caching is implemented, but it doesn't use the Perl "dual variable" implementation.
7172
-**Unicode**: Support for non-Unicode strings is not implemented.
7273
-**Taint checks**: Support for taint checks is not implemented.
73-
-**`local` special cases**: `local` is missing for typeglobs and filehandles. Localization in for-loops is also missing.
74+
-**`local` special cases**: Variable localization in for-loops is missing.
75+
-**`local` special cases**: `local *HANDLE = *HANDLE` doesn't create a new typeglob.
7476

7577
## Objects
7678
- ✔️ **Objects**: Creating classes, method call syntax works.

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

+11-1
Original file line numberDiff line numberDiff line change
@@ -622,8 +622,18 @@ static void handleLocal(EmitterVisitor emitterVisitor, OperatorNode node) {
622622
// emit the lvalue
623623
int lvalueContext = LValueVisitor.getContext(node.operand);
624624
node.operand.accept(emitterVisitor.with(lvalueContext));
625+
boolean isTypeglob = false;
626+
if (node.operand instanceof OperatorNode operatorNode && operatorNode.operator.equals("*")) {
627+
isTypeglob = true;
628+
}
625629
// save the old value
626-
if (lvalueContext == RuntimeContextType.LIST) {
630+
if (isTypeglob) {
631+
emitterVisitor.ctx.mv.visitMethodInsn(Opcodes.INVOKESTATIC,
632+
"org/perlonjava/runtime/DynamicVariableManager",
633+
"pushLocalVariable",
634+
"(Lorg/perlonjava/runtime/RuntimeGlob;)Lorg/perlonjava/runtime/RuntimeGlob;",
635+
false);
636+
} else if (lvalueContext == RuntimeContextType.LIST) {
627637
emitterVisitor.ctx.mv.visitMethodInsn(Opcodes.INVOKESTATIC,
628638
"org/perlonjava/runtime/DynamicVariableManager",
629639
"pushLocalVariable",

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,17 @@ static void handleAssignOperator(EmitterVisitor emitterVisitor, BinaryOperatorNo
180180
node.right.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); // emit the value
181181
node.left.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); // emit the variable
182182

183+
OperatorNode nodeLeft = null;
184+
if (node.left instanceof OperatorNode operatorNode) {
185+
nodeLeft = operatorNode;
186+
if (nodeLeft.operator.equals("local") && nodeLeft.operand instanceof OperatorNode localNode) {
187+
nodeLeft = localNode; // local *var = ...
188+
}
189+
}
190+
183191
boolean isGlob = false;
184192
String leftDescriptor = "org/perlonjava/runtime/RuntimeScalar";
185-
if (node.left instanceof OperatorNode && ((OperatorNode) node.left).operator.equals("*")) {
193+
if (nodeLeft != null && nodeLeft.operator.equals("*")) {
186194
leftDescriptor = "org/perlonjava/runtime/RuntimeGlob";
187195
isGlob = true;
188196
}

src/main/java/org/perlonjava/operators/Operator.java

+17-6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import static org.perlonjava.runtime.GlobalVariable.getGlobalVariable;
1313
import static org.perlonjava.runtime.RuntimeScalarCache.getScalarBoolean;
14+
import static org.perlonjava.runtime.RuntimeScalarCache.scalarFalse;
1415

1516
public class Operator {
1617

@@ -223,9 +224,14 @@ public static RuntimeScalar print(RuntimeList runtimeList, RuntimeScalar fileHan
223224
// Append the newline character
224225
sb.append(newline);
225226

226-
// Write the content to the file handle
227-
RuntimeIO fh = fileHandle.getRuntimeIO();
228-
return fh.write(sb.toString());
227+
try {
228+
// Write the content to the file handle
229+
RuntimeIO fh = fileHandle.getRuntimeIO();
230+
return fh.write(sb.toString());
231+
} catch (Exception e) {
232+
getGlobalVariable("main::!").set("File operation failed: " + e.getMessage());
233+
return scalarFalse;
234+
}
229235
}
230236

231237
/**
@@ -252,9 +258,14 @@ public static RuntimeScalar say(RuntimeList runtimeList, RuntimeScalar fileHandl
252258
// Append the newline character
253259
sb.append("\n");
254260

255-
// Write the content to the file handle
256-
RuntimeIO fh = fileHandle.getRuntimeIO();
257-
return fh.write(sb.toString());
261+
try {
262+
// Write the content to the file handle
263+
RuntimeIO fh = fileHandle.getRuntimeIO();
264+
return fh.write(sb.toString());
265+
} catch (Exception e) {
266+
getGlobalVariable("main::!").set("File operation failed: " + e.getMessage());
267+
return scalarFalse;
268+
}
258269
}
259270

260271
public static RuntimeScalar eof(RuntimeList runtimeList, RuntimeScalar fileHandle) {

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

+7
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ public static RuntimeScalar pushLocalVariable(RuntimeScalar variable) {
4242
return variable;
4343
}
4444

45+
public static RuntimeGlob pushLocalVariable(RuntimeGlob variable) {
46+
// Save the current state of the variable and push it onto the stack.
47+
variable.dynamicSaveState();
48+
variableStack.push(variable);
49+
return variable;
50+
}
51+
4552
/**
4653
* Pops dynamic variables from the stack until the stack size matches the specified target local level.
4754
* This is useful for restoring the stack to a previous state by removing any variables added after that state.

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

+13-15
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,7 @@ public boolean getDefinedBoolean() {
173173
* @return A RuntimeScalar representing the typeglob.
174174
*/
175175
public RuntimeScalar scalar() {
176-
RuntimeScalar ret = new RuntimeScalar();
177-
ret.type = RuntimeScalarType.GLOB;
178-
ret.value = this;
179-
return ret;
176+
return new RuntimeScalar(this);
180177
}
181178

182179
/**
@@ -321,25 +318,26 @@ public RuntimeGlob undefine() {
321318
}
322319

323320
/**
324-
* Saves the current state of the instance.
325-
*
326-
* <p>This method creates a snapshot of the current value,
327-
* and pushes it onto a static stack for later restoration. After saving, it clears
328-
* the current elements and resets the value.
321+
* Saves the current state of the typeglob.
329322
*/
330323
@Override
331324
public void dynamicSaveState() {
332-
throw new PerlCompilerException("not implemented: local GLOB");
325+
GlobalVariable.getGlobalCodeRef(this.globName).dynamicSaveState();
326+
GlobalVariable.getGlobalArray(this.globName).dynamicSaveState();
327+
GlobalVariable.getGlobalHash(this.globName).dynamicSaveState();
328+
GlobalVariable.getGlobalVariable(this.globName).dynamicSaveState();
329+
GlobalVariable.getGlobalIO(this.globName).dynamicSaveState();
333330
}
334331

335332
/**
336-
* Restores the most recently saved state of the instance.
337-
*
338-
* <p>This method pops the most recent state from the static stack and restores
339-
* the value. If no state is saved, it does nothing.
333+
* Restores the most recently saved state of the typeglob.
340334
*/
341335
@Override
342336
public void dynamicRestoreState() {
343-
throw new PerlCompilerException("not implemented: local GLOB");
337+
GlobalVariable.getGlobalIO(this.globName).dynamicRestoreState();
338+
GlobalVariable.getGlobalVariable(this.globName).dynamicRestoreState();
339+
GlobalVariable.getGlobalHash(this.globName).dynamicRestoreState();
340+
GlobalVariable.getGlobalArray(this.globName).dynamicRestoreState();
341+
GlobalVariable.getGlobalCodeRef(this.globName).dynamicRestoreState();
344342
}
345343
}

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

+5
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ public RuntimeScalar(RuntimeIO value) {
114114
this.value = value;
115115
}
116116

117+
public RuntimeScalar (RuntimeGlob value) {
118+
this.type = RuntimeScalarType.GLOB;
119+
this.value = value;
120+
}
121+
117122
public static RuntimeScalar undef() {
118123
return scalarUndef;
119124
}

0 commit comments

Comments
 (0)