@@ -221,6 +221,60 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c
221221 break ;
222222 }
223223
224+ case Opcodes .STORE_GLOBAL_CODE : {
225+ // Store global code: GlobalVariable.globalCodeRefs.put(name, codeRef)
226+ int nameIdx = bytecode [pc ++] & 0xFF ;
227+ int codeReg = bytecode [pc ++] & 0xFF ;
228+ String name = code .stringPool [nameIdx ];
229+ RuntimeScalar codeRef = (RuntimeScalar ) registers [codeReg ];
230+ // Store the code reference in the global namespace
231+ GlobalVariable .globalCodeRefs .put (name , codeRef );
232+ break ;
233+ }
234+
235+ case Opcodes .CREATE_CLOSURE : {
236+ // Create closure with captured variables
237+ // Format: CREATE_CLOSURE rd template_idx num_captures reg1 reg2 ...
238+ int rd = bytecode [pc ++] & 0xFF ;
239+ int templateIdx = bytecode [pc ++] & 0xFF ;
240+ int numCaptures = bytecode [pc ++] & 0xFF ;
241+
242+ // Get the template InterpretedCode from constants
243+ InterpretedCode template = (InterpretedCode ) code .constants [templateIdx ];
244+
245+ // Capture the current register values
246+ RuntimeBase [] capturedVars = new RuntimeBase [numCaptures ];
247+ for (int i = 0 ; i < numCaptures ; i ++) {
248+ int captureReg = bytecode [pc ++] & 0xFF ;
249+ capturedVars [i ] = registers [captureReg ];
250+ }
251+
252+ // Create a new InterpretedCode with the captured variables
253+ InterpretedCode closureCode = new InterpretedCode (
254+ template .bytecode ,
255+ template .constants ,
256+ template .stringPool ,
257+ template .maxRegisters ,
258+ capturedVars , // The captured variables!
259+ template .sourceName ,
260+ template .sourceLine ,
261+ template .pcToTokenIndex
262+ );
263+
264+ // Wrap in RuntimeScalar
265+ registers [rd ] = new RuntimeScalar ((RuntimeCode ) closureCode );
266+ break ;
267+ }
268+
269+ case Opcodes .SET_SCALAR : {
270+ // Set scalar value: registers[rd].set(registers[rs])
271+ // Used to set the value in a persistent scalar without overwriting the reference
272+ int rd = bytecode [pc ++] & 0xFF ;
273+ int rs = bytecode [pc ++] & 0xFF ;
274+ ((RuntimeScalar ) registers [rd ]).set ((RuntimeScalar ) registers [rs ]);
275+ break ;
276+ }
277+
224278 // =================================================================
225279 // ARITHMETIC OPERATORS
226280 // =================================================================
@@ -313,6 +367,21 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c
313367 break ;
314368 }
315369
370+ case Opcodes .REPEAT : {
371+ // String/list repetition: rd = rs1 x rs2
372+ int rd = bytecode [pc ++] & 0xFF ;
373+ int rs1 = bytecode [pc ++] & 0xFF ;
374+ int rs2 = bytecode [pc ++] & 0xFF ;
375+ // Call Operator.repeat(base, count, context)
376+ // Context: 1 = scalar context (for string repetition)
377+ registers [rd ] = Operator .repeat (
378+ registers [rs1 ],
379+ (RuntimeScalar ) registers [rs2 ],
380+ 1 // scalar context
381+ );
382+ break ;
383+ }
384+
316385 case Opcodes .LENGTH : {
317386 // String length: rd = length(rs)
318387 int rd = bytecode [pc ++] & 0xFF ;
@@ -408,6 +477,14 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c
408477 int rd = bytecode [pc ++] & 0xFF ;
409478 int arrayReg = bytecode [pc ++] & 0xFF ;
410479 int indexReg = bytecode [pc ++] & 0xFF ;
480+
481+ // Check type
482+ if (!(registers [arrayReg ] instanceof RuntimeArray )) {
483+ throw new RuntimeException ("ARRAY_GET: register " + arrayReg + " contains " +
484+ (registers [arrayReg ] == null ? "null" : registers [arrayReg ].getClass ().getName ()) +
485+ " instead of RuntimeArray" );
486+ }
487+
411488 RuntimeArray arr = (RuntimeArray ) registers [arrayReg ];
412489 RuntimeScalar idx = (RuntimeScalar ) registers [indexReg ];
413490 // Uses RuntimeArray API directly
@@ -438,11 +515,24 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c
438515 }
439516
440517 case Opcodes .ARRAY_SIZE : {
441- // Array size: rd = scalar(@array)
518+ // Array size: rd = scalar(@array) or scalar(list)
442519 int rd = bytecode [pc ++] & 0xFF ;
443- int arrayReg = bytecode [pc ++] & 0xFF ;
444- RuntimeArray arr = (RuntimeArray ) registers [arrayReg ];
445- registers [rd ] = new RuntimeScalar (arr .size ());
520+ int operandReg = bytecode [pc ++] & 0xFF ;
521+ RuntimeBase operand = registers [operandReg ];
522+
523+ int size ;
524+ if (operand instanceof RuntimeArray ) {
525+ size = ((RuntimeArray ) operand ).size ();
526+ } else if (operand instanceof RuntimeList ) {
527+ size = ((RuntimeList ) operand ).size ();
528+ } else if (operand instanceof RuntimeScalar ) {
529+ // Scalar in array context - treat as 1-element list
530+ size = 1 ;
531+ } else {
532+ throw new RuntimeException ("ARRAY_SIZE: register " + operandReg + " contains unexpected type: " +
533+ (operand == null ? "null" : operand .getClass ().getName ()));
534+ }
535+ registers [rd ] = new RuntimeScalar (size );
446536 break ;
447537 }
448538
@@ -899,8 +989,15 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c
899989 int startReg = bytecode [pc ++] & 0xFF ;
900990 int endReg = bytecode [pc ++] & 0xFF ;
901991
902- RuntimeScalar start = (RuntimeScalar ) registers [startReg ];
903- RuntimeScalar end = (RuntimeScalar ) registers [endReg ];
992+ RuntimeBase startBase = registers [startReg ];
993+ RuntimeBase endBase = registers [endReg ];
994+
995+ // Handle null registers by creating undef scalars
996+ RuntimeScalar start = (startBase instanceof RuntimeScalar ) ? (RuntimeScalar ) startBase :
997+ (startBase == null ) ? new RuntimeScalar () : startBase .scalar ();
998+ RuntimeScalar end = (endBase instanceof RuntimeScalar ) ? (RuntimeScalar ) endBase :
999+ (endBase == null ) ? new RuntimeScalar () : endBase .scalar ();
1000+
9041001 PerlRange range = PerlRange .createRange (start , end );
9051002 registers [rd ] = range ;
9061003 break ;
@@ -946,6 +1043,50 @@ public static RuntimeList execute(InterpretedCode code, RuntimeArray args, int c
9461043 break ;
9471044 }
9481045
1046+ case Opcodes .NEW_ARRAY : {
1047+ // Create empty array: rd = new RuntimeArray()
1048+ int rd = bytecode [pc ++] & 0xFF ;
1049+ registers [rd ] = new RuntimeArray ();
1050+ break ;
1051+ }
1052+
1053+ case Opcodes .NEW_HASH : {
1054+ // Create empty hash: rd = new RuntimeHash()
1055+ int rd = bytecode [pc ++] & 0xFF ;
1056+ registers [rd ] = new RuntimeHash ();
1057+ break ;
1058+ }
1059+
1060+ case Opcodes .ARRAY_SET_FROM_LIST : {
1061+ // Set array content from list: array_reg.setFromList(list_reg)
1062+ // Format: [ARRAY_SET_FROM_LIST] [array_reg] [list_reg]
1063+ int arrayReg = bytecode [pc ++] & 0xFF ;
1064+ int listReg = bytecode [pc ++] & 0xFF ;
1065+
1066+ RuntimeArray array = (RuntimeArray ) registers [arrayReg ];
1067+ RuntimeBase listBase = registers [listReg ];
1068+ RuntimeList list = listBase .getList ();
1069+
1070+ // setFromList clears and repopulates the array
1071+ array .setFromList (list );
1072+ break ;
1073+ }
1074+
1075+ case Opcodes .HASH_SET_FROM_LIST : {
1076+ // Set hash content from list: hash_reg = RuntimeHash.createHash(list_reg)
1077+ // Format: [HASH_SET_FROM_LIST] [hash_reg] [list_reg]
1078+ int hashReg = bytecode [pc ++] & 0xFF ;
1079+ int listReg = bytecode [pc ++] & 0xFF ;
1080+
1081+ RuntimeHash existingHash = (RuntimeHash ) registers [hashReg ];
1082+ RuntimeBase listBase = registers [listReg ];
1083+
1084+ // Create new hash from list, then copy elements to existing hash
1085+ RuntimeHash newHash = RuntimeHash .createHash (listBase );
1086+ existingHash .elements = newHash .elements ;
1087+ break ;
1088+ }
1089+
9491090 // =================================================================
9501091 // SLOW OPERATIONS
9511092 // =================================================================
0 commit comments