Skip to content

Interpreter: fix comp/parser.t and op/postfixderef.t failures#230

Closed
fglock wants to merge 5 commits intomasterfrom
fix-interpreter-missing-features
Closed

Interpreter: fix comp/parser.t and op/postfixderef.t failures#230
fglock wants to merge 5 commits intomasterfrom
fix-interpreter-missing-features

Conversation

@fglock
Copy link
Owner

@fglock fglock commented Feb 24, 2026

Fixes interpreter-mode test failures under JPERL_EVAL_USE_INTERPRETER=1.\n\n## Changes\n\nBytecodeCompiler.java\n- visit(For3Node isSimpleBlock): emit LOAD_UNDEF in non-VOID context so outerResultReg is always initialised. Fixes NPE from eval "{ q,bar, }" where ARRAY_SIZE read a null register.\n- visit(For1Node): emit empty CREATE_LIST when node.list is null.\n\nCompileAssignment.java\n- Add postfix-deref glob lvalue: 'name'->** = value uses LOAD_GLOB_DYNAMIC + STORE_GLOB.\n\nBytecodeInterpreter.java\n- DEREF opcode: delegate to scalarDeref() for all RuntimeScalar; throws Not a SCALAR reference for GLOBREFERENCE.\n\nRuntimeScalar.java\n- scalarDerefNonStrict: throw Not a SCALAR reference for GLOBREFERENCE.\n\n## Test results (JPERL_EVAL_USE_INTERPRETER=1)\n- comp/parser.t: 61 passing (tests 36,38,40 fixed)\n- op/postfixderef.t: 85 passing (tests 27,28,29,59,63 fixed)\n- op/signatures.t: 598, op/chop.t: 137 (no regressions)

- BytecodeCompiler.handleCompoundAssignment: strip sigil before calling
  NameNormalizer for both LOAD_GLOBAL_SCALAR and STORE_GLOBAL_SCALAR.
  Previously "$main::n" was passed directly, causing a different global
  key than the canonical "main::n" used by plain assignment.

- BytecodeCompiler.visit(BlockNode): sync ScopedSymbolTable scope with
  block scope so getCurrentPackage() is correct at each eval() call site
  inside the block (package Foo {} changes don't leak out).

- CompileOperator: bake call-site package into EVAL_STRING opcode as
  pkgIdx, using ScopedSymbolTable.getCurrentPackage() at compile time.

- SlowOpcodeHandler: read pkgIdx from EVAL_STRING opcode and pass it to
  EvalStringHandler as callSitePackage.

- EvalStringHandler: use callSitePackage instead of currentCode.compilePackage
  so eval("__PACKAGE__") returns the correct package at each call site.

- InterpretedCode: update disassembler to consume pkgIdx in EVAL_STRING.

- CompileAssignment: use Perl-compatible error message for chop/chomp
  non-lvalue assignment ("Can't modify chop in scalar assignment").

Fixes comp/package_block.t (4/5, matching JVM baseline),
op/chop.t (148/148).
….t 36,38,40)

When { q,bar, } is parsed as For3Node(isSimpleBlock=true), the body
executes but the block itself produces no value (lastResultReg = -1).
In a non-VOID context the enclosing BlockNode allocates outerResultReg
but never initialises it, leaving a null register slot that causes
ARRAY_SIZE and similar ops to NPE at runtime.

Fix: emit LOAD_UNDEF into a fresh register in the isSimpleBlock path
when currentCallContext != VOID, so callers always get a defined result.
The VOID path still sets lastResultReg = -1 as before (no allocation).

Fixes comp/parser.t tests 36, 38, 40 under JPERL_EVAL_USE_INTERPRETER=1.
@fglock fglock closed this Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant