Implement variable sharing between interpreter and compiled code#191
Merged
Implement variable sharing between interpreter and compiled code#191
Conversation
…tics
Add support for $array[index] and $hash{key} operations using correct
Perl semantics where assignment modifies content, doesn't create new objects.
Changes:
- Add NEW_ARRAY (93) and NEW_HASH (94) opcodes for creating empty containers
- Add ARRAY_SET_FROM_LIST (95) and HASH_SET_FROM_LIST (96) for populating
* Uses setFromList() semantic: modifies existing array/hash content
* Matches compiler behavior: create once, populate/modify separately
- Implement array element access: $a[index]
* Supports both lexical and global arrays
* ARRAY_GET opcode for element retrieval
- Implement hash element access: $h{key}
* Supports both lexical and global hashes
* Bareword keys treated as string literals (not variable lookup)
* HASH_GET opcode for element retrieval
- Support my @array = list and my %hash = list declarations
* Proper two-step: create empty + setFromList
* Allows subsequent reassignment to modify content
Technical fixes:
- Fixed bareword hash key handling: IdentifierNode → string literal
- Replaced incorrect LIST_TO_ARRAY/LIST_TO_HASH opcodes with proper semantics
- Added LOAD_GLOBAL_ARRAY and LOAD_GLOBAL_HASH for global container access
Testing:
```bash
./jperl --interpreter -E 'my @A = (10, 20, 30); print $a[1], "\n"'
# Output: 20
./jperl --interpreter -E 'my %h = (a => 1, b => 2); print $h{a}, " ", $h{b}, "\n"'
# Output: 1 2
```
Dense opcodes: 0-96 (97 total)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use PerlCompilerException with ErrorMessageUtil for interpreter compilation errors, providing user-friendly error messages with file names, line numbers, and code context instead of bare RuntimeExceptions. Changes: - Add ErrorMessageUtil parameter to BytecodeCompiler constructor - Track currentTokenIndex during AST traversal (BinaryOperatorNode, OperatorNode) - Add throwCompilerException() helper that uses PerlCompilerException - Replace "Unsupported operator" RuntimeException/UnsupportedOperationException with properly formatted PerlCompilerException - Update PerlLanguageProvider to pass ctx.errorUtil to BytecodeCompiler - Update test harnesses (InterpreterTest) to pass errorUtil Error message improvement: Before: "Unsupported operator: &" After: "Unsupported operator: & at examples/life.pl line 57, near \"@life = generate;\"" The ErrorMessageUtil automatically: - Adds source file name - Computes line number from token index - Shows code context around the error - Formats with proper Perl-style error messages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add support for calling named subroutines using the & operator to get code references, enabling patterns like foo() and printlife @Args. Changes: - Add & operator support in OperatorNode visitor * Gets code reference using LOAD_GLOBAL_CODE opcode * Adds "main::" package prefix if needed * Returns RuntimeScalar containing code reference - Fix ( operator case to include "(" (was only "()" and "->") * Now handles: foo(args), $coderef->(args), &subname(args) - Use throwCompilerException for & operator errors (proper formatting) This completes the subroutine call chain: 1. & operator → gets code reference 2. ( operator → calls the code reference with arguments 3. CALL_SUB opcode → executes via RuntimeCode.apply() Testing: ```bash ./jperl --interpreter -E 'sub foo { return 42; } my $x = foo(); print "$x\n"' # Output: 42 ./jperl --interpreter -E 'sub add { my ($a, $b) = @_; return $a + $b; } print add(10, 20), "\n"' # Output: 30 ``` Progress on life.pl: Now fails on passing arrays to subroutines (@life) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enable interpreted main scripts to share lexical variables with compiled named subroutines by storing captured variables in persistent globals. Key changes: - Add SET_SCALAR opcode to set values in persistent scalars without overwriting references, preserving aliasing between interpreter and compiled code - Use SLOWOP_RETRIEVE_BEGIN_* opcodes to load persistent variables into interpreter registers, enabling both modes to access the same objects - Implement context detection (wantarray) for subroutine calls based on assignment target type (scalar/array/void) - Fix RANGE opcode to handle null registers gracefully - Add VariableCaptureAnalyzer for identifying shared variables (note: currently uses AST node ids set by parser) This allows programs like examples/life.pl to run correctly in interpreter mode with proper variable sharing and context handling. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.
Summary
Enables interpreted main scripts to share lexical variables with compiled named subroutines, allowing programs like
examples/life.plto run correctly in interpreter mode.Problem
Previously, variables declared in the interpreted main script (like
$width,$height) were stored only in interpreter registers and were inaccessible to compiled named subroutines. This caused programs with mixed interpreted/compiled code to fail.Solution
Store captured variables in persistent globals using the existing BEGIN mechanism:
SLOWOP_RETRIEVE_BEGIN_*opcodesSET_SCALARopcode sets values without overwriting references (preserves aliasing)Key Changes
SET_SCALAR: Calls.set()on RuntimeScalar without overwriting the referenceTesting
Now runs successfully with:
🤖 Generated with Claude Code