Interpreter: fix package BLOCK scoping and compound assignment on globals#228
Merged
Interpreter: fix package BLOCK scoping and compound assignment on globals#228
Conversation
…bals
Five fixes:
1. BytecodeCompiler: strip sigil before normalizeVariableName in compound
assignment path. varName was "$main::c" but normalize expects "main::c".
This caused LOAD/STORE_GLOBAL_SCALAR to use wrong global slot.
2. BytecodeCompiler/CompileOperator: emit PUSH_PACKAGE for scoped package
blocks (package Foo { }) so InterpreterState.currentPackage is saved.
Use nextPackageIsScoped flag set by visit(BlockNode). Emit POP_PACKAGE
at block exit to restore the runtime package via DynamicVariableManager.
3. EvalStringHandler: use InterpreterState.currentPackage (runtime) instead
of currentCode.compilePackage (compile-time) so that eval STRING inside
a package BLOCK sees the correct package for __PACKAGE__.
4. EvalStringHandler: substitute undef for null captured registers instead
of capturing null — null registers crash when the eval reads them as
the eval string operand.
5. BytecodeCompiler visit(BlockNode): when the last statement produces no
result (lastResultReg < 0, e.g. a bare block with void semantics), emit
LOAD_UNDEF into the outer result register instead of leaving it null.
A null register causes NPE when RETURN reads it.
Results (JPERL_EVAL_USE_INTERPRETER=1 vs without):
- comp/package_block.t: 0/5 -> 4/5 (test 4 is pre-existing)
- comp/parser.t: 58/193 -> 61/193 (tests 36, 38, 40 fixed)
- op/signatures.t: no regression (446/908 in both modes)
62f0927 to
8f708dd
Compare
…normalizeVariableName $main::result .= "..." was silently failing because the sigil was passed to normalizeVariableName, producing "$main::result" (with sigil) as the store key instead of "main::result" (without sigil).
When consume() expects } or ] but finds EOF or wrong token, emit "Missing right curly or square bracket" to match Perl's error text. Fixes comp/package_block.t test 4.
SlowOpcodeHandler.executeListSliceFrom was reading startIndex as two 16-bit halves but emitInt writes a single int slot. This caused register index overflow (e.g. "Index 303 out of bounds") when list assignment to mixed scalar+array targets was compiled inside eval STRING with captured variables in a for loop. Also fix InterpretedCode disassembler: EVAL_TRY and UNKNOWN opcode now read/display correctly. Fix BytecodeInterpreter error message to show full opcode value instead of truncating to 8 bits. Fixes perf/benchmarks.t -10 regression under JPERL_EVAL_USE_INTERPRETER.
…on failure PerlCompilerException(String message) calls RuntimeCode.caller() to get file/line info. When thrown during interpreter eval STRING execution, caller() may throw or return unexpected results, leaving errorMessage empty/null and causing $@ to appear empty after eval catches the error. Fix by wrapping caller() in try/catch — on failure, use bare message. Also re-throw PerlCompilerException directly from BytecodeInterpreter catch block (instead of wrapping in RuntimeException) so outer eval handlers see the correct exception with a usable getMessage().
…on failure PerlCompilerException(String message) calls RuntimeCode.caller() to get file/line info. When thrown during interpreter eval STRING execution, caller() may throw or return unexpected results, leaving errorMessage empty/null and causing $@ to appear empty after eval catches the error. Fix by wrapping caller() in try/catch — on failure, use bare message. Also re-throw PerlCompilerException directly from BytecodeInterpreter catch block (instead of wrapping in RuntimeException) so outer eval handlers see the correct exception with a usable getMessage().
…eric check
OpcodeHandlerExtended.executeBitwiseAndBinary/OrBinary/XorBinary were
calling BitwiseOperators.bitwiseAndBinary/OrBinary/XorBinary directly,
bypassing the looksLikeNumber() check. This caused:
- String operands (e.g. "\xFF" & "\x{100}") to silently use numeric path
- Unicode codepoint error not thrown, $@ not set after eval STRING
Fix: call BitwiseOperators.bitwiseAnd/Or/Xor (the dispatchers) instead,
which check string vs numeric and route to bitwiseAndDot/OrDot/XorDot
for string operands.
Fixes op/bop.t 487/522 (was 480) under JPERL_EVAL_USE_INTERPRETER.
…eCompiler String literal operands like 'curly'->@*, 'larry'->%*, 'name'->** were failing with "Unsupported @ operand: StringNode". These are symbolic references — treat the string as a global variable name and emit LOAD_GLOBAL_ARRAY / LOAD_GLOBAL_HASH / LOAD_GLOB accordingly. Fixes 2 extra tests in op/postfixderef.t under JPERL_EVAL_USE_INTERPRETER.
- Add DEREF_GLOB opcode (333) for $ref->** postfix glob dereference - BytecodeCompiler: emit DEREF_GLOB for * with OperatorNode (e.g. $ref->**) - BytecodeCompiler: emit LOAD_GLOB for * with StringNode (e.g. 'name'->**) - SlowOpcodeHandler.executeDerefGlob: calls globDeref() matching JVM path - BytecodeInterpreter: route DEREF_GLOB through executeSpecialIO Also adds StringNode support for @/%/* symref deref in BytecodeCompiler (already committed separately, included here for context). Fixes op/postfixderef.t 80/128 (was 78) under JPERL_EVAL_USE_INTERPRETER.
- SlowOpcodeHandler.executeDerefGlob: handle RuntimeIO (PVIO) register value directly by wrapping in a temporary glob (matches globDeref() behavior for PVIO case) - InterpretedCode disassembler: add DEREF_GLOB case (3 operands: rd, rs, pkgIdx) to avoid misaligned bytecode display
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Four interpreter-mode fixes for eval STRING correctness.
Fixes
Compound assignment sigil bug (BytecodeCompiler): varName in compound assignment path included the sigil ($main::c) but normalizeVariableName expects bare name (main::c). LOAD/STORE_GLOBAL_SCALAR was using wrong global slot.
Package BLOCK runtime scoping (BytecodeCompiler + CompileOperator): Scoped package Foo { } blocks now emit PUSH_PACKAGE/POP_PACKAGE to save/restore InterpreterState.currentPackage. Added nextPackageIsScoped flag since parser never sets the isScoped annotation.
eval STRING inherits runtime package (EvalStringHandler): Use InterpreterState.currentPackage (runtime) instead of currentCode.compilePackage (compile-time) so eval STRING inside a package BLOCK sees the correct package for PACKAGE.
Bare block value propagation (BytecodeCompiler For3Node): isSimpleBlock path discarded body result register. Now allocates outer register and copies result before exitScope(), matching JVM EmitStatement behaviour.
Results (JPERL_EVAL_USE_INTERPRETER=1 vs without)
Remaining gaps (tests 45, 53 in parser.t, test 4 in package_block.t) are pre-existing missing features.