1313import java .nio .file .Files ;
1414import java .nio .file .Path ;
1515import java .nio .file .Paths ;
16- import java .util .List ;
1716
1817import static org .perlonjava .perlmodule .Feature .featureManager ;
1918import static org .perlonjava .runtime .ExceptionFormatter .findInnermostCause ;
@@ -304,8 +303,11 @@ else if (runtimeScalar.type == RuntimeScalarType.GLOB || runtimeScalar.type == R
304303 else if (code == null ) {
305304
306305 // Check if the filename is an absolute path or starts with ./ or ../
306+ // and if it exists on the filesystem
307307 Path filePath = Paths .get (fileName );
308- if (filePath .isAbsolute () || fileName .startsWith ("./" ) || fileName .startsWith ("../" )) {
308+ boolean tryDirectPath = filePath .isAbsolute () || fileName .startsWith ("./" ) || fileName .startsWith ("../" );
309+
310+ if (tryDirectPath ) {
309311 // For absolute or explicit relative paths, resolve using RuntimeIO.getPath
310312 filePath = RuntimeIO .resolvePath (fileName );
311313 if (Files .exists (filePath )) {
@@ -317,42 +319,77 @@ else if (code == null) {
317319 fullName = filePath ;
318320 actualFileName = fullName .toString ();
319321 }
320- } else {
321- // Otherwise, search in INC directories
322- List <RuntimeScalar > inc = GlobalVariable .getGlobalArray ("main::INC" ).elements ;
322+ }
323+
324+ // If we haven't found the file yet, search in INC directories
325+ // This handles:
326+ // 1. Relative module names (e.g., Foo::Bar)
327+ // 2. Absolute/relative paths that don't exist on filesystem (try @INC hooks only)
328+ if (fullName == null ) {
329+ // Search in INC directories
330+ RuntimeArray incArray = GlobalVariable .getGlobalArray ("main::INC" );
323331
324332 // Make sure the jar files are in @INC - the Perl test files can remove it
325333 boolean seen = false ;
326- for (RuntimeBase dir : inc ) {
334+ int incSize = incArray .size ();
335+ for (int i = 0 ; i < incSize ; i ++) {
336+ RuntimeScalar dir = incArray .get (i );
337+ // Handle tied scalars
338+ if (dir .type == RuntimeScalarType .TIED_SCALAR ) {
339+ dir = dir .tiedFetch ();
340+ }
327341 if (dir .toString ().equals (GlobalContext .JAR_PERLLIB )) {
328342 seen = true ;
329343 break ;
330344 }
331345 }
332346 if (!seen ) {
333- inc . add (new RuntimeScalar (GlobalContext .JAR_PERLLIB ));
347+ incArray . push (new RuntimeScalar (GlobalContext .JAR_PERLLIB ));
334348 }
335349
336- for (RuntimeBase dir : inc ) {
337- RuntimeScalar dirScalar = dir .scalar ();
350+ // Iterate using indexed access to properly handle tied arrays
351+ incSize = incArray .size ();
352+ for (int i = 0 ; i < incSize ; i ++) {
353+ RuntimeScalar dirScalar = incArray .get (i );
354+
355+ // If this is a tied scalar, fetch the actual value
356+ if (dirScalar .type == RuntimeScalarType .TIED_SCALAR ) {
357+ dirScalar = dirScalar .tiedFetch ();
358+ }
359+
360+ // For absolute/relative paths (starting with /, ./, ../), only try hooks
361+ // Regular directory entries should be skipped for such paths
362+ boolean isHook = dirScalar .type == RuntimeScalarType .CODE ||
363+ dirScalar .type == RuntimeScalarType .REFERENCE ||
364+ dirScalar .type == RuntimeScalarType .ARRAYREFERENCE ||
365+ dirScalar .type == RuntimeScalarType .HASHREFERENCE ;
366+
367+ if (tryDirectPath && !isHook ) {
368+ // Skip regular directory entries for absolute/relative paths
369+ continue ;
370+ }
338371
339372 // Check if this @INC entry is a CODE reference, ARRAY reference, or blessed object
340- if (dirScalar .type == RuntimeScalarType .CODE ||
341- dirScalar .type == RuntimeScalarType .REFERENCE ||
342- dirScalar .type == RuntimeScalarType .ARRAYREFERENCE ||
343- dirScalar .type == RuntimeScalarType .HASHREFERENCE ) {
373+ if (isHook ) {
344374
345375 RuntimeBase hookResult = tryIncHook (dirScalar , fileName );
346376 if (hookResult != null ) {
347377 // Hook returned something useful
348378 RuntimeScalar hookResultScalar = hookResult .scalar ();
349379
350- // Check if it's a filehandle (GLOB) or array ref with filehandle
380+ // Check if it's a filehandle (GLOB), array ref with filehandle, or scalar ref with code
351381 RuntimeScalar filehandle = null ;
352382
353383 if (hookResultScalar .type == RuntimeScalarType .GLOB ||
354384 hookResultScalar .type == RuntimeScalarType .GLOBREFERENCE ) {
355385 filehandle = hookResultScalar ;
386+ } else if (hookResultScalar .type == RuntimeScalarType .REFERENCE ) {
387+ // Hook returned a scalar reference - treat the dereferenced value as code
388+ RuntimeScalar derefValue = hookResultScalar .scalarDeref ();
389+ code = derefValue .toString ();
390+ actualFileName = fileName ;
391+ incHookRef = dirScalar ;
392+ break ;
356393 } else if (hookResultScalar .type == RuntimeScalarType .ARRAYREFERENCE &&
357394 hookResultScalar .value instanceof RuntimeArray ) {
358395 RuntimeArray resultArray = (RuntimeArray ) hookResultScalar .value ;
@@ -382,7 +419,7 @@ else if (code == null) {
382419 }
383420
384421 // Original string handling for directory paths
385- String dirName = dir .toString ();
422+ String dirName = dirScalar .toString ();
386423 if (dirName .equals (GlobalContext .JAR_PERLLIB )) {
387424 // Try to find in jar at "src/main/perl/lib"
388425 String resourcePath = "/lib/" + fileName ;
0 commit comments