Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ public static RuntimeList executePerlCode(CompilerOptions compilerOptions,

/**
* Executes the given Perl code using a syntax tree and returns the result.
* Uses VOID context by default.
*
* @param ast The abstract syntax tree representing the Perl code.
* @param tokens The list of tokens representing the Perl code.
Expand All @@ -214,6 +215,22 @@ public static RuntimeList executePerlCode(CompilerOptions compilerOptions,
public static RuntimeList executePerlAST(Node ast,
List<LexerToken> tokens,
CompilerOptions compilerOptions) throws Exception {
return executePerlAST(ast, tokens, compilerOptions, RuntimeContextType.VOID);
}

/**
* Executes the given Perl code using a syntax tree with specified context.
*
* @param ast The abstract syntax tree representing the Perl code.
* @param tokens The list of tokens representing the Perl code.
* @param compilerOptions Compiler flags, file name and source code.
* @param contextType The context to use for execution (VOID, SCALAR, LIST).
* @return The result of the Perl code execution.
*/
public static RuntimeList executePerlAST(Node ast,
List<LexerToken> tokens,
CompilerOptions compilerOptions,
int contextType) throws Exception {

// Save the current scope so we can restore it after execution.
ScopedSymbolTable savedCurrentScope = SpecialBlockParser.getCurrentScope();
Expand All @@ -229,7 +246,7 @@ public static RuntimeList executePerlAST(Node ast,
globalSymbolTable.snapShot(),
null,
null,
RuntimeContextType.VOID,
contextType,
true,
null,
compilerOptions,
Expand All @@ -255,8 +272,7 @@ public static RuntimeList executePerlAST(Node ast,
// Compile to executable (compiler or interpreter based on flag)
RuntimeCode runtimeCode = compileToExecutable(ast, ctx);

// executePerlAST is always called from special blocks which use VOID context
return executeCode(runtimeCode, ctx, false, RuntimeContextType.VOID);
return executeCode(runtimeCode, ctx, false, contextType);
} finally {
// Restore the caller's scope
if (savedCurrentScope != null) {
Expand Down
25 changes: 20 additions & 5 deletions src/main/java/org/perlonjava/frontend/parser/ParseMapGrepSort.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,27 @@ static BinaryOperatorNode parseSort(Parser parser, LexerToken token) {
if (nextToken.type == LexerTokenType.IDENTIFIER && !nextToken.text.equals("{")
&& !ParserTables.CORE_PROTOTYPES.containsKey(nextToken.text)
&& !ParsePrimary.isIsQuoteLikeOperator(nextToken.text)) {
// This could be a subroutine name for comparison (sort mysub LIST)
// or a class name for method call (sort MyClass->method)
// Save position and try to determine which
int identStart = parser.tokenIndex;
String subName = IdentifierParser.parseSubroutineIdentifier(parser);
Node var = new OperatorNode("&",
new IdentifierNode(subName, parser.tokenIndex), parser.tokenIndex);
operand = ListParser.parseZeroOrMoreList(parser, 0, false, false, false, false);
operand.handle = var;
if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseSort identifier: " + operand.handle + " : " + operand);

// Check if followed by -> (method call) - if so, backtrack and parse as list
if (peek(parser).text.equals("->")) {
// This is a method call like "sort MyClass->method"
// Backtrack and parse the whole thing as a list expression
parser.tokenIndex = identStart;
operand = ListParser.parseZeroOrMoreList(parser, 0, false, false, false, false);
if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseSort method call: " + operand);
} else {
// This is a comparison subroutine name
Node var = new OperatorNode("&",
new IdentifierNode(subName, parser.tokenIndex), parser.tokenIndex);
operand = ListParser.parseZeroOrMoreList(parser, 0, false, false, false, false);
operand.handle = var;
if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseSort identifier: " + operand.handle + " : " + operand);
}
} else {
try {
operand = ListParser.parseZeroOrMoreList(parser, 1, true, false, false, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,27 @@ static Node parseSpecialBlock(Parser parser) {

/**
* Executes a special block with the given block phase and block AST.
* Uses VOID context by default.
*
* @param parser The parser instance.
* @param blockPhase The phase of the block (e.g., BEGIN, END).
* @param block The block AST to execute.
* @return A RuntimeList containing the result of the execution.
*/
static RuntimeList runSpecialBlock(Parser parser, String blockPhase, Node block) {
return runSpecialBlock(parser, blockPhase, block, RuntimeContextType.VOID);
}

/**
* Executes a special block with the given block phase, block AST, and context.
*
* @param parser The parser instance.
* @param blockPhase The phase of the block (e.g., BEGIN, END).
* @param block The block AST to execute.
* @param contextType The context to use for execution (VOID, SCALAR, LIST).
* @return A RuntimeList containing the result of the execution.
*/
static RuntimeList runSpecialBlock(Parser parser, String blockPhase, Node block, int contextType) {
int tokenIndex = parser.tokenIndex;

// Create AST nodes for setting up the capture variables and package declaration
Expand Down Expand Up @@ -252,7 +266,8 @@ static RuntimeList runSpecialBlock(Parser parser, String blockPhase, Node block)
result = PerlLanguageProvider.executePerlAST(
new BlockNode(nodes, tokenIndex),
parser.tokens,
parsedArgs);
parsedArgs,
contextType);
} catch (PerlExitException e) {
// exit() inside BEGIN block should terminate the program, not cause compilation error
// Re-throw so it propagates to the CLI (Main.main()) which will call System.exit()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -658,8 +658,10 @@ public static Node parseUseDeclaration(Parser parser, LexerToken token) {
// call Module->import( LIST )
// or Module->unimport( LIST )

// Execute the argument list immediately
RuntimeList args = runSpecialBlock(parser, "BEGIN", list);
// Execute the argument list immediately in LIST context
// This is necessary for expressions like: use lib ($path =~ /^(.*)$/);
// where the regex match must return captured groups, not just success/failure
RuntimeList args = runSpecialBlock(parser, "BEGIN", list, RuntimeContextType.LIST);

if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Use statement list: " + args);
if (hasParentheses && args.isEmpty()) {
Expand Down
Loading