From 8166a2b539f40861f03ad2921cbc68f938d5a1a7 Mon Sep 17 00:00:00 2001 From: "Flavio S. Glock" Date: Thu, 12 Mar 2026 07:48:58 +0100 Subject: [PATCH] Gate debug logging with static DEBUG_ENABLED flag Add CompilerOptions.DEBUG_ENABLED static boolean that is set when --debug or -D flags are parsed. All logDebug() calls are now guarded with a one-line if statement check for fast short-circuit evaluation when debugging is disabled. This improves performance by avoiding method call overhead and string concatenation for debug messages when not in debug mode. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin --- .../perlonjava/app/cli/ArgumentParser.java | 2 + .../perlonjava/app/cli/CompilerOptions.java | 5 ++ .../scriptengine/PerlLanguageProvider.java | 22 ++++---- .../perlonjava/backend/jvm/Dereference.java | 40 ++++++------- .../backend/jvm/EmitBinaryOperator.java | 4 +- .../backend/jvm/EmitBinaryOperatorNode.java | 4 +- .../org/perlonjava/backend/jvm/EmitBlock.java | 12 ++-- .../backend/jvm/EmitControlFlow.java | 24 ++++---- .../org/perlonjava/backend/jvm/EmitEval.java | 6 +- .../perlonjava/backend/jvm/EmitForeach.java | 20 ++++--- .../perlonjava/backend/jvm/EmitFormat.java | 6 +- .../perlonjava/backend/jvm/EmitLiteral.java | 28 +++++----- .../backend/jvm/EmitLogicalOperator.java | 8 ++- .../perlonjava/backend/jvm/EmitOperator.java | 32 ++++++----- .../backend/jvm/EmitOperatorDeleteExists.java | 6 +- .../backend/jvm/EmitOperatorFileTest.java | 4 +- .../backend/jvm/EmitOperatorNode.java | 4 +- .../perlonjava/backend/jvm/EmitStatement.java | 24 ++++---- .../backend/jvm/EmitSubroutine.java | 22 ++++---- .../perlonjava/backend/jvm/EmitVariable.java | 54 +++++++++--------- .../backend/jvm/EmitterMethodCreator.java | 18 +++--- .../org/perlonjava/core/Configuration.java | 2 +- .../frontend/parser/CoreOperatorResolver.java | 4 +- .../frontend/parser/DataSection.java | 10 ++-- .../frontend/parser/FormatParser.java | 34 +++++------ .../frontend/parser/IdentifierParser.java | 4 +- .../frontend/parser/ListParser.java | 36 ++++++------ .../frontend/parser/OperatorParser.java | 16 +++--- .../frontend/parser/ParseBlock.java | 4 +- .../frontend/parser/ParseHeredoc.java | 30 +++++----- .../frontend/parser/ParseInfix.java | 6 +- .../frontend/parser/ParseMapGrepSort.java | 8 ++- .../perlonjava/frontend/parser/Parser.java | 8 ++- .../frontend/parser/SpecialBlockParser.java | 8 +-- .../frontend/parser/StatementParser.java | 28 +++++----- .../frontend/parser/StatementResolver.java | 56 ++++++++++--------- .../frontend/parser/StringDoubleQuoted.java | 4 +- .../frontend/parser/StringParser.java | 12 ++-- .../frontend/parser/StringSegmentParser.java | 30 +++++----- .../frontend/parser/SubroutineParser.java | 12 ++-- .../frontend/parser/TokenUtils.java | 6 +- .../perlonjava/frontend/parser/Variable.java | 18 +++--- 42 files changed, 380 insertions(+), 301 deletions(-) diff --git a/src/main/java/org/perlonjava/app/cli/ArgumentParser.java b/src/main/java/org/perlonjava/app/cli/ArgumentParser.java index 85ba5350a..25a612044 100644 --- a/src/main/java/org/perlonjava/app/cli/ArgumentParser.java +++ b/src/main/java/org/perlonjava/app/cli/ArgumentParser.java @@ -942,6 +942,7 @@ private static int processLongSwitches(String[] args, CompilerOptions parsedArgs case "--debug": // Enable debugging mode parsedArgs.debugEnabled = true; + CompilerOptions.DEBUG_ENABLED = true; break; case "--tokenize": // Enable tokenize-only mode @@ -1193,6 +1194,7 @@ private static int handleDebugFlags(String[] args, CompilerOptions parsedArgs, i // Store debug flags for potential future use parsedArgs.debugFlags = debugFlags; parsedArgs.debugEnabled = true; + CompilerOptions.DEBUG_ENABLED = true; return index; } diff --git a/src/main/java/org/perlonjava/app/cli/CompilerOptions.java b/src/main/java/org/perlonjava/app/cli/CompilerOptions.java index 447096908..fec62f910 100644 --- a/src/main/java/org/perlonjava/app/cli/CompilerOptions.java +++ b/src/main/java/org/perlonjava/app/cli/CompilerOptions.java @@ -33,6 +33,11 @@ * - unicodeStdin/Stdout/Stderr/etc.: Unicode/encoding flags for different I/O streams. */ public class CompilerOptions implements Cloneable { + /** + * Global static flag to gate debug logging. Set once at CLI parsing time. + * Use this for fast short-circuit evaluation before calling logDebug(). + */ + public static boolean DEBUG_ENABLED = false; public boolean debugEnabled = false; public boolean disassembleEnabled = false; public boolean useInterpreter = false; diff --git a/src/main/java/org/perlonjava/app/scriptengine/PerlLanguageProvider.java b/src/main/java/org/perlonjava/app/scriptengine/PerlLanguageProvider.java index c046501f2..0c330d8d8 100644 --- a/src/main/java/org/perlonjava/app/scriptengine/PerlLanguageProvider.java +++ b/src/main/java/org/perlonjava/app/scriptengine/PerlLanguageProvider.java @@ -120,8 +120,8 @@ public static RuntimeList executePerlCode(CompilerOptions compilerOptions, globalInitialized = true; } - ctx.logDebug("parse code: " + compilerOptions.code); - ctx.logDebug(" call context " + ctx.contextType); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("parse code: " + compilerOptions.code); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug(" call context " + ctx.contextType); // Apply any BEGIN-block filters before tokenization if requested // This is a workaround for the limitation that our architecture tokenizes all source upfront @@ -175,10 +175,10 @@ public static RuntimeList executePerlCode(CompilerOptions compilerOptions, RuntimeIO.closeAllHandles(); return null; // success } - ctx.logDebug("-- AST:\n" + ast + "--\n"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("-- AST:\n" + ast + "--\n"); // Create the Java class from the AST - ctx.logDebug("createClassWithMethod"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("createClassWithMethod"); // Create a new instance of ErrorMessageUtil, resetting the line counter ctx.errorUtil = new ErrorMessageUtil(ctx.compilerOptions.fileName, tokens); // Snapshot the symbol table after parsing. @@ -241,11 +241,11 @@ public static RuntimeList executePerlAST(Node ast, globalInitialized = true; } - ctx.logDebug("Using provided AST"); - ctx.logDebug(" call context " + ctx.contextType); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Using provided AST"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug(" call context " + ctx.contextType); // Create the Java class from the AST - ctx.logDebug("createClassWithMethod"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("createClassWithMethod"); ctx.errorUtil = new ErrorMessageUtil(ctx.compilerOptions.fileName, tokens); // Snapshot the symbol table as seen by the parser (includes lexical decls + pragma state). ctx.symbolTable = ctx.symbolTable.snapShot(); @@ -323,7 +323,7 @@ private static RuntimeList executeCode(RuntimeCode runtimeCode, EmitterContext c throw new RuntimeException(t); } - ctx.logDebug("Result of generatedMethod: " + result); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Result of generatedMethod: " + result); RuntimeIO.flushAllHandles(); return result; @@ -343,7 +343,7 @@ private static RuntimeList executeCode(RuntimeCode runtimeCode, EmitterContext c private static RuntimeCode compileToExecutable(Node ast, EmitterContext ctx) throws Exception { if (ctx.compilerOptions.useInterpreter || RuntimeCode.FORCE_INTERPRETER) { // Interpreter path - returns InterpretedCode (extends RuntimeCode) - ctx.logDebug("Compiling to bytecode interpreter"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Compiling to bytecode interpreter"); BytecodeCompiler compiler = new BytecodeCompiler( ctx.compilerOptions.fileName, 1, // sourceLine (legacy parameter) @@ -361,7 +361,7 @@ private static RuntimeCode compileToExecutable(Node ast, EmitterContext ctx) thr return interpretedCode; } else { // Compiler path - returns CompiledCode (wrapper around generated class) - ctx.logDebug("Compiling to JVM bytecode"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Compiling to JVM bytecode"); try { Class generatedClass = EmitterMethodCreator.createClassWithMethod( ctx, @@ -399,7 +399,7 @@ private static RuntimeCode compileToExecutable(Node ast, EmitterContext ctx) thr System.err.println("Note: Method too large after AST splitting, using interpreter backend."); } - ctx.logDebug("Falling back to bytecode interpreter due to method size"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Falling back to bytecode interpreter due to method size"); // Reset strict/feature/warning flags before fallback compilation. // The JVM compiler already processed BEGIN blocks (use strict, etc.) // which set these flags on ctx.symbolTable. But the interpreter will diff --git a/src/main/java/org/perlonjava/backend/jvm/Dereference.java b/src/main/java/org/perlonjava/backend/jvm/Dereference.java index 274b69bd3..28d96cdb6 100644 --- a/src/main/java/org/perlonjava/backend/jvm/Dereference.java +++ b/src/main/java/org/perlonjava/backend/jvm/Dereference.java @@ -1,5 +1,7 @@ package org.perlonjava.backend.jvm; +import org.perlonjava.app.cli.CompilerOptions; + import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.perlonjava.frontend.analysis.EmitterVisitor; @@ -19,7 +21,7 @@ public class Dereference { * Handles the postfix `[]` operator. */ static void handleArrayElementOperator(EmitterVisitor emitterVisitor, BinaryOperatorNode node, String arrayOperation) { - emitterVisitor.ctx.logDebug("handleArrayElementOperator " + node + " in context " + emitterVisitor.ctx.contextType); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleArrayElementOperator " + node + " in context " + emitterVisitor.ctx.contextType); EmitterVisitor scalarVisitor = emitterVisitor.with(RuntimeContextType.SCALAR); // execute operands in scalar context @@ -37,7 +39,7 @@ static void handleArrayElementOperator(EmitterVisitor emitterVisitor, BinaryOper // Rewrite the variable node from `$` to `@` OperatorNode varNode = new OperatorNode("@", identifierNode, sigilNode.tokenIndex); - emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var[] "); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var[] "); varNode.accept(emitterVisitor.with(RuntimeContextType.LIST)); // target - left parameter int arraySlot = emitterVisitor.ctx.javaClassInfo.acquireSpillSlot(); @@ -104,7 +106,7 @@ static void handleArrayElementOperator(EmitterVisitor emitterVisitor, BinaryOper * Instead, it evaluates EXPR and applies the subscript directly. * This allows ${$aref}[0] to work even though ${$aref} alone would fail. */ - emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) ${BLOCK}[] "); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) ${BLOCK}[] "); // Evaluate the block expression to get a RuntimeScalar (might be array/hash ref) sigilNode.operand.accept(scalarVisitor); @@ -159,7 +161,7 @@ static void handleArrayElementOperator(EmitterVisitor emitterVisitor, BinaryOper * NumberNode: 10 * NumberNode: 20 */ - emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var[] "); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var[] "); sigilNode.accept(emitterVisitor.with(RuntimeContextType.LIST)); // target - left parameter int arraySlot = emitterVisitor.ctx.javaClassInfo.acquireSpillSlot(); @@ -208,7 +210,7 @@ static void handleArrayElementOperator(EmitterVisitor emitterVisitor, BinaryOper * Perl index/value slice: returns alternating index and value. */ - emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) %var[] "); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) %var[] "); // Evaluate base as scalar (array reference) sigilNode.operand.accept(scalarVisitor); @@ -312,7 +314,7 @@ static void handleArrayElementOperator(EmitterVisitor emitterVisitor, BinaryOper * hashOperation is one of: "get", "delete", "exists" */ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, BinaryOperatorNode node, String hashOperation) { - emitterVisitor.ctx.logDebug("handleHashElementOperator " + node + " in context " + emitterVisitor.ctx.contextType); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleHashElementOperator " + node + " in context " + emitterVisitor.ctx.contextType); EmitterVisitor scalarVisitor = emitterVisitor.with(RuntimeContextType.SCALAR); // execute operands in scalar context @@ -331,7 +333,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina // Rewrite the variable node from `$` to `%` OperatorNode varNode = new OperatorNode("%", identifierNode, sigilNode.tokenIndex); - emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var{} "); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var{} "); varNode.accept(emitterVisitor.with(RuntimeContextType.LIST)); // target - left parameter int leftSlot = emitterVisitor.ctx.javaClassInfo.acquireSpillSlot(); @@ -351,7 +353,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina nodeZero = nodeRight.elements.getFirst(); // Update nodeZero to the new StringNode } - emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var{} autoquote " + node.right); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var{} autoquote " + node.right); // Optimization: if there's only one element and it's a string literal if (nodeRight.elements.size() == 1 && nodeZero instanceof StringNode) { @@ -431,7 +433,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina * Instead, it evaluates EXPR and applies the subscript directly. * This allows ${$href}{key} to work even though ${$href} alone would fail. */ - emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) ${BLOCK}{} "); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) ${BLOCK}{} "); // Evaluate the block expression to get a RuntimeScalar (might be array/hash ref) sigilNode.operand.accept(scalarVisitor); @@ -493,7 +495,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina // Rewrite the variable node from `@` to `%` OperatorNode varNode = new OperatorNode("%", sigilNode.operand, sigilNode.tokenIndex); - emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var{} " + varNode); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var{} " + varNode); varNode.accept(emitterVisitor.with(RuntimeContextType.LIST)); // target - left parameter int leftSlot = emitterVisitor.ctx.javaClassInfo.acquireSpillSlot(); @@ -505,7 +507,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina // emit the {x} as a RuntimeList ListNode nodeRight = ((HashLiteralNode) node.right).asListNode(); - emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var{} as listNode: " + nodeRight); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var{} as listNode: " + nodeRight); if (!nodeRight.elements.isEmpty()) { Node nodeZero = nodeRight.elements.getFirst(); @@ -515,7 +517,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina } } - emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var{} autoquote " + node.right); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var{} autoquote " + node.right); nodeRight.accept(emitterVisitor.with(RuntimeContextType.LIST)); int keyListSlot = emitterVisitor.ctx.javaClassInfo.acquireSpillSlot(); @@ -561,7 +563,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina // Rewrite the variable node from `@` to `%` OperatorNode varNode = new OperatorNode("%", sigilNode.operand, sigilNode.tokenIndex); - emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var{} " + varNode); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var{} " + varNode); varNode.accept(emitterVisitor.with(RuntimeContextType.LIST)); // target - left parameter int leftSlot = emitterVisitor.ctx.javaClassInfo.acquireSpillSlot(); @@ -573,7 +575,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina // emit the {x} as a RuntimeList ListNode nodeRight = ((HashLiteralNode) node.right).asListNode(); - emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var{} as listNode: " + nodeRight); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) @var{} as listNode: " + nodeRight); if (!nodeRight.elements.isEmpty()) { Node nodeZero = nodeRight.elements.getFirst(); @@ -583,7 +585,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina } } - emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var{} autoquote " + node.right); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) $var{} autoquote " + node.right); nodeRight.accept(emitterVisitor.with(RuntimeContextType.LIST)); int keyListSlot = emitterVisitor.ctx.javaClassInfo.acquireSpillSlot(); @@ -628,7 +630,7 @@ public static void handleHashElementOperator(EmitterVisitor emitterVisitor, Bina */ static void handleArrowOperator(EmitterVisitor emitterVisitor, BinaryOperatorNode node) { MethodVisitor mv = emitterVisitor.ctx.mv; - emitterVisitor.ctx.logDebug("handleArrowOperator " + node + " in context " + emitterVisitor.ctx.contextType); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleArrowOperator " + node + " in context " + emitterVisitor.ctx.contextType); EmitterVisitor scalarVisitor = emitterVisitor.with(RuntimeContextType.SCALAR); // execute operands in scalar context @@ -785,7 +787,7 @@ static void handleArrowOperator(EmitterVisitor emitterVisitor, BinaryOperatorNod } public static void handleArrowArrayDeref(EmitterVisitor emitterVisitor, BinaryOperatorNode node, String arrayOperation) { - emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) ->[] "); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) ->[] "); EmitterVisitor scalarVisitor = emitterVisitor.with(RuntimeContextType.SCALAR); // execute operands in scalar context @@ -894,7 +896,7 @@ public static void handleArrowArrayDeref(EmitterVisitor emitterVisitor, BinaryOp } public static void handleArrowHashDeref(EmitterVisitor emitterVisitor, BinaryOperatorNode node, String hashOperation) { - emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) ->{} " + node); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) ->{} " + node); EmitterVisitor scalarVisitor = emitterVisitor.with(RuntimeContextType.SCALAR); // execute operands in scalar context @@ -918,7 +920,7 @@ public static void handleArrowHashDeref(EmitterVisitor emitterVisitor, BinaryOpe } } - emitterVisitor.ctx.logDebug("visit -> (HashLiteralNode) autoquote " + node.right); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit -> (HashLiteralNode) autoquote " + node.right); nodeRight.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); int keySlot = emitterVisitor.ctx.javaClassInfo.acquireSpillSlot(); diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitBinaryOperator.java b/src/main/java/org/perlonjava/backend/jvm/EmitBinaryOperator.java index 563b5c5bf..d32fb325e 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitBinaryOperator.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitBinaryOperator.java @@ -1,5 +1,7 @@ package org.perlonjava.backend.jvm; +import org.perlonjava.app.cli.CompilerOptions; + import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.perlonjava.frontend.analysis.EmitterVisitor; @@ -20,7 +22,7 @@ public class EmitBinaryOperator { static void handleBinaryOperator(EmitterVisitor emitterVisitor, BinaryOperatorNode node, OperatorHandler operatorHandler) { EmitterVisitor scalarVisitor = emitterVisitor.with(RuntimeContextType.SCALAR); // execute operands in scalar context - emitterVisitor.ctx.logDebug("handleBinaryOperator: " + node.toString()); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleBinaryOperator: " + node.toString()); // Optimization if ((node.operator.equals("+") diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitBinaryOperatorNode.java b/src/main/java/org/perlonjava/backend/jvm/EmitBinaryOperatorNode.java index 96eef2cc7..cc09a8f04 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitBinaryOperatorNode.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitBinaryOperatorNode.java @@ -1,5 +1,7 @@ package org.perlonjava.backend.jvm; +import org.perlonjava.app.cli.CompilerOptions; + import org.objectweb.asm.Opcodes; import org.perlonjava.frontend.analysis.EmitterVisitor; import org.perlonjava.frontend.astnode.BinaryOperatorNode; @@ -9,7 +11,7 @@ public class EmitBinaryOperatorNode { public static void emitBinaryOperatorNode(EmitterVisitor emitterVisitor, BinaryOperatorNode node) { - emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) %s in context %s" + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) %s in context %s" .formatted(node.operator, emitterVisitor.ctx.contextType)); switch (node.operator) { diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitBlock.java b/src/main/java/org/perlonjava/backend/jvm/EmitBlock.java index 855119691..28034310a 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitBlock.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitBlock.java @@ -1,5 +1,7 @@ package org.perlonjava.backend.jvm; +import org.perlonjava.app.cli.CompilerOptions; + import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -125,7 +127,7 @@ public static void emitBlock(EmitterVisitor emitterVisitor, BlockNode node) { return; } - emitterVisitor.ctx.logDebug("generateCodeBlock start context:" + emitterVisitor.ctx.contextType); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("generateCodeBlock start context:" + emitterVisitor.ctx.contextType); int scopeIndex = emitterVisitor.ctx.symbolTable.enterScope(); EmitterVisitor voidVisitor = emitterVisitor.with(RuntimeContextType.VOID); // statements in the middle of the block have context VOID @@ -247,7 +249,7 @@ public static void emitBlock(EmitterVisitor emitterVisitor, BlockNode node) { // "not a statement, continue parsing" (e.g., AUTOLOAD without {}, try without feature enabled) // ParseBlock.parseBlock() adds these null results to the statements list if (element == null) { - emitterVisitor.ctx.logDebug("Skipping null element in block at index " + i); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("Skipping null element in block at index " + i); continue; } @@ -256,11 +258,11 @@ public static void emitBlock(EmitterVisitor emitterVisitor, BlockNode node) { // Emit the statement with current context if (i == lastNonNullIndex) { // Special case for the last element - emitterVisitor.ctx.logDebug("Last element: " + element); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("Last element: " + element); element.accept(emitterVisitor); } else { // General case for all other elements - emitterVisitor.ctx.logDebug("Element: " + element); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("Element: " + element); element.accept(voidVisitor); } @@ -306,7 +308,7 @@ public static void emitBlock(EmitterVisitor emitterVisitor, BlockNode node) { } emitterVisitor.ctx.symbolTable.exitScope(scopeIndex); - emitterVisitor.ctx.logDebug("generateCodeBlock end"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("generateCodeBlock end"); } } diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitControlFlow.java b/src/main/java/org/perlonjava/backend/jvm/EmitControlFlow.java index d346b0de9..a1efd56dc 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitControlFlow.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitControlFlow.java @@ -1,5 +1,7 @@ package org.perlonjava.backend.jvm; +import org.perlonjava.app.cli.CompilerOptions; + import org.objectweb.asm.Label; import org.objectweb.asm.Opcodes; import org.perlonjava.frontend.analysis.EmitterVisitor; @@ -32,7 +34,7 @@ public class EmitControlFlow { * @throws PerlCompilerException if the operator is used outside a loop block */ static void handleNextOperator(EmitterContext ctx, OperatorNode node) { - ctx.logDebug("visit(next)"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("visit(next)"); String operator = node.operator; @@ -73,7 +75,7 @@ static void handleNextOperator(EmitterContext ctx, OperatorNode node) { } else { loopLabels = ctx.javaClassInfo.findLoopLabelsByName(labelStr); } - ctx.logDebug("visit(next) operator: " + operator + " label: " + labelStr + " labels: " + loopLabels); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("visit(next) operator: " + operator + " label: " + labelStr + " labels: " + loopLabels); // Check if we're trying to use next/last/redo in a pseudo-loop (do-while/bare block) if (loopLabels != null && !loopLabels.isTrueLoop) { @@ -84,7 +86,7 @@ static void handleNextOperator(EmitterContext ctx, OperatorNode node) { if (loopLabels == null) { // Non-local control flow: return tagged RuntimeControlFlowList - ctx.logDebug("visit(next): Non-local control flow for " + operator + " " + labelStr); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("visit(next): Non-local control flow for " + operator + " " + labelStr); // Determine control flow type ControlFlowType type = operator.equals("next") ? ControlFlowType.NEXT @@ -158,8 +160,8 @@ static void handleReturnOperator(EmitterVisitor emitterVisitor, OperatorNode nod ctx.errorUtil); } - ctx.logDebug("visit(return) in context " + emitterVisitor.ctx.contextType); - ctx.logDebug("visit(return) will visit " + node.operand + " in context " + emitterVisitor.ctx.with(RuntimeContextType.RUNTIME).contextType); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("visit(return) in context " + emitterVisitor.ctx.contextType); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("visit(return) will visit " + node.operand + " in context " + emitterVisitor.ctx.with(RuntimeContextType.RUNTIME).contextType); boolean hasOperand = !(node.operand == null || (node.operand instanceof ListNode list && list.elements.isEmpty())); @@ -193,7 +195,7 @@ static void handleReturnOperator(EmitterVisitor emitterVisitor, OperatorNode nod static void handleGotoSubroutine(EmitterVisitor emitterVisitor, OperatorNode subNode, Node argsNode) { EmitterContext ctx = emitterVisitor.ctx; - ctx.logDebug("visit(goto &sub): Emitting TAILCALL marker"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("visit(goto &sub): Emitting TAILCALL marker"); subNode.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); int codeRefSlot = ctx.javaClassInfo.acquireSpillSlot(); @@ -263,7 +265,7 @@ static void handleGotoSubroutine(EmitterVisitor emitterVisitor, OperatorNode sub static void handleGotoSubroutineBlock(EmitterVisitor emitterVisitor, BlockNode blockNode, Node argsNode, int tokenIndex) { EmitterContext ctx = emitterVisitor.ctx; - ctx.logDebug("visit(goto &{expr}): Emitting TAILCALL marker"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("visit(goto &{expr}): Emitting TAILCALL marker"); // Evaluate the block to get the subroutine name/reference blockNode.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); @@ -371,14 +373,14 @@ static void handleGotoLabel(EmitterVisitor emitterVisitor, OperatorNode node) { if (arg instanceof BinaryOperatorNode callNode && callNode.operator.equals("(")) { Node callTarget = callNode.left; if (callTarget instanceof OperatorNode opNode && opNode.operator.equals("&")) { - ctx.logDebug("visit(goto): Detected goto &NAME tail call"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("visit(goto): Detected goto &NAME tail call"); handleGotoSubroutine(emitterVisitor, opNode, callNode.right); return; } // Handle goto &{expr} - symbolic code dereference // BlockNode contains an expression that evaluates to a subroutine name if (callTarget instanceof BlockNode blockNode) { - ctx.logDebug("visit(goto): Detected goto &{expr} tail call"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("visit(goto): Detected goto &{expr} tail call"); handleGotoSubroutineBlock(emitterVisitor, blockNode, callNode.right, node.tokenIndex); return; } @@ -387,7 +389,7 @@ static void handleGotoLabel(EmitterVisitor emitterVisitor, OperatorNode node) { // Check if this is a tail call (goto EXPR where EXPR is a coderef) // This handles: goto __SUB__, goto $coderef, etc. if (arg instanceof OperatorNode opNode && opNode.operator.equals("__SUB__")) { - ctx.logDebug("visit(goto): Detected goto __SUB__ tail call"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("visit(goto): Detected goto __SUB__ tail call"); // Create a ListNode with @_ as the argument ListNode argsNode = new ListNode(opNode.tokenIndex); OperatorNode atUnderscore = new OperatorNode("@", @@ -399,7 +401,7 @@ static void handleGotoLabel(EmitterVisitor emitterVisitor, OperatorNode node) { // Dynamic label (goto EXPR) - expression evaluated at runtime isDynamic = true; - ctx.logDebug("visit(goto): Dynamic goto with expression"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("visit(goto): Dynamic goto with expression"); // Evaluate the expression to get the label name at runtime arg.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitEval.java b/src/main/java/org/perlonjava/backend/jvm/EmitEval.java index d7a495f35..1270302f2 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitEval.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitEval.java @@ -103,7 +103,7 @@ static void handleEvalOperator(EmitterVisitor emitterVisitor, OperatorNode node) " file=" + emitterVisitor.ctx.compilerOptions.fileName + " token=" + node.tokenIndex); // Log current symbol table state for debugging - emitterVisitor.ctx.logDebug("(eval) ctx.symbolTable.getAllVisibleVariables"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("(eval) ctx.symbolTable.getAllVisibleVariables"); // Capture the current lexical environment // This creates a snapshot of all variables visible at this eval site @@ -115,7 +115,7 @@ static void handleEvalOperator(EmitterVisitor emitterVisitor, OperatorNode node) // Get list of all captured variable names String[] newEnv = newSymbolTable.getVariableNames(); - emitterVisitor.ctx.logDebug("evalStringHelper newSymbolTable: " + newSymbolTable); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("evalStringHelper newSymbolTable: " + newSymbolTable); // Generate unique identifier for this eval site // This counter is incremented globally, ensuring each eval gets a unique tag @@ -724,7 +724,7 @@ private static void emitEvalCompilerPath(EmitterVisitor emitterVisitor, String e mv.visitIntInsn(Opcodes.BIPUSH, index - skipVariables); mv.visitVarInsn(Opcodes.ALOAD, emitterVisitor.ctx.symbolTable.getVariableIndex(varName)); mv.visitInsn(Opcodes.AASTORE); - emitterVisitor.ctx.logDebug("Put variable " + emitterVisitor.ctx.symbolTable.getVariableIndex(varName) + " at parameter #" + (index - skipVariables) + " " + varName); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("Put variable " + emitterVisitor.ctx.symbolTable.getVariableIndex(varName) + " at parameter #" + (index - skipVariables) + " " + varName); } } // Stack: [Constructor, Object[]] diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitForeach.java b/src/main/java/org/perlonjava/backend/jvm/EmitForeach.java index 0da0c6502..e7350967f 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitForeach.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitForeach.java @@ -1,5 +1,7 @@ package org.perlonjava.backend.jvm; +import org.perlonjava.app.cli.CompilerOptions; + import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -90,7 +92,7 @@ private static String extractSimpleVariableName(Node node) { } public static void emitFor1(EmitterVisitor emitterVisitor, For1Node node) { - emitterVisitor.ctx.logDebug("FOR1 start"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("FOR1 start"); Node variableNode = node.variable; @@ -100,7 +102,7 @@ public static void emitFor1(EmitterVisitor emitterVisitor, For1Node node) { opNode.operand instanceof OperatorNode nestedOpNode && opNode.operator.equals("$") && nestedOpNode.operator.equals("$")) { - emitterVisitor.ctx.logDebug("FOR1 emitting complex lvalue $$var as while loop"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("FOR1 emitting complex lvalue $$var as while loop"); emitFor1AsWhileLoop(emitterVisitor, node); return; } @@ -228,7 +230,7 @@ public static void emitFor1(EmitterVisitor emitterVisitor, For1Node node) { } mv.visitVarInsn(Opcodes.ASTORE, savedValueIndex); - emitterVisitor.ctx.logDebug("FOR1 ref-alias: saved local var " + varName + " to index " + savedValueIndex); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("FOR1 ref-alias: saved local var " + varName + " to index " + savedValueIndex); } else { // Global variable - save its current value String globalName = ((IdentifierNode) innerOp.operand).name; @@ -260,7 +262,7 @@ public static void emitFor1(EmitterVisitor emitterVisitor, For1Node node) { } mv.visitVarInsn(Opcodes.ASTORE, savedValueIndex); - emitterVisitor.ctx.logDebug("FOR1 ref-alias: saved global var " + globalName + " to index " + savedValueIndex); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("FOR1 ref-alias: saved global var " + globalName + " to index " + savedValueIndex); } } @@ -464,7 +466,7 @@ public static void emitFor1(EmitterVisitor emitterVisitor, For1Node node) { continue; } int varIndex = emitterVisitor.ctx.symbolTable.getVariableIndex(varName); - emitterVisitor.ctx.logDebug("FOR1 multi var name:" + varName + " index:" + varIndex); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("FOR1 multi var name:" + varName + " index:" + varIndex); mv.visitVarInsn(Opcodes.ASTORE, varIndex); } } @@ -538,7 +540,7 @@ public static void emitFor1(EmitterVisitor emitterVisitor, For1Node node) { // Unsupported variable shape; skip assignment rather than failing compilation. } else { loopVarIndex = emitterVisitor.ctx.symbolTable.getVariableIndex(varName); - emitterVisitor.ctx.logDebug("FOR1 single var name:" + varName + " index:" + loopVarIndex); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("FOR1 single var name:" + varName + " index:" + loopVarIndex); mv.visitVarInsn(Opcodes.ASTORE, loopVarIndex); } } @@ -657,7 +659,7 @@ public static void emitFor1(EmitterVisitor emitterVisitor, For1Node node) { if (varIndex != -1) { // Local variable - restore it mv.visitVarInsn(Opcodes.ASTORE, varIndex); - emitterVisitor.ctx.logDebug("FOR1 ref-alias: restored local var " + varName + " from index " + savedValueIndex); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("FOR1 ref-alias: restored local var " + varName + " from index " + savedValueIndex); } else { // Global variable - restore it String globalName = ((IdentifierNode) innerOp.operand).name; @@ -684,7 +686,7 @@ public static void emitFor1(EmitterVisitor emitterVisitor, For1Node node) { false); } - emitterVisitor.ctx.logDebug("FOR1 ref-alias: restored global var " + globalName + " from index " + savedValueIndex); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("FOR1 ref-alias: restored global var " + globalName + " from index " + savedValueIndex); } } } @@ -740,7 +742,7 @@ public static void emitFor1(EmitterVisitor emitterVisitor, For1Node node) { } } - emitterVisitor.ctx.logDebug("FOR1 end"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("FOR1 end"); } /** diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitFormat.java b/src/main/java/org/perlonjava/backend/jvm/EmitFormat.java index ffdb6dfe1..b8b0bbc9d 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitFormat.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitFormat.java @@ -1,5 +1,7 @@ package org.perlonjava.backend.jvm; +import org.perlonjava.app.cli.CompilerOptions; + import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.perlonjava.frontend.analysis.EmitterVisitor; @@ -23,7 +25,7 @@ public static void emitFormat(EmitterVisitor emitterVisitor, FormatNode node) { EmitterContext ctx = emitterVisitor.ctx; MethodVisitor mv = ctx.mv; - ctx.logDebug("FORMAT start: " + node.formatName); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("FORMAT start: " + node.formatName); // Always generate format bytecode, even in VOID context // The side effect of storing the format is important @@ -81,7 +83,7 @@ public static void emitFormat(EmitterVisitor emitterVisitor, FormatNode node) { mv.visitInsn(Opcodes.POP); } - ctx.logDebug("FORMAT end: " + node.formatName); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("FORMAT end: " + node.formatName); } /** diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitLiteral.java b/src/main/java/org/perlonjava/backend/jvm/EmitLiteral.java index 8fee9b56f..6072738a5 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitLiteral.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitLiteral.java @@ -1,5 +1,7 @@ package org.perlonjava.backend.jvm; +import org.perlonjava.app.cli.CompilerOptions; + import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.perlonjava.frontend.analysis.EmitterVisitor; @@ -47,7 +49,7 @@ public class EmitLiteral { * @param node The ArrayLiteralNode representing the array literal in the AST */ public static void emitArrayLiteral(EmitterVisitor emitterVisitor, ArrayLiteralNode node) { - emitterVisitor.ctx.logDebug("visit(ArrayLiteralNode) in context " + emitterVisitor.ctx.contextType); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(ArrayLiteralNode) in context " + emitterVisitor.ctx.contextType); MethodVisitor mv = emitterVisitor.ctx.mv; // Perl semantics: array literal elements are always evaluated in LIST context @@ -60,7 +62,7 @@ public static void emitArrayLiteral(EmitterVisitor emitterVisitor, ArrayLiteralN // Pop the list result since we don't need it mv.visitInsn(Opcodes.POP); } - emitterVisitor.ctx.logDebug("visit(ArrayLiteralNode) end"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(ArrayLiteralNode) end"); return; } @@ -97,7 +99,7 @@ public static void emitArrayLiteral(EmitterVisitor emitterVisitor, ArrayLiteralN mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/perlonjava/runtime/runtimetypes/RuntimeBase", "createReference", "()Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;", false); - emitterVisitor.ctx.logDebug("visit(ArrayLiteralNode) end"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(ArrayLiteralNode) end"); } /** @@ -117,7 +119,7 @@ public static void emitArrayLiteral(EmitterVisitor emitterVisitor, ArrayLiteralN * @param node The HashLiteralNode representing the hash literal in the AST */ public static void emitHashLiteral(EmitterVisitor emitterVisitor, HashLiteralNode node) { - emitterVisitor.ctx.logDebug("visit(HashLiteralNode) in context " + emitterVisitor.ctx.contextType); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(HashLiteralNode) in context " + emitterVisitor.ctx.contextType); MethodVisitor mv = emitterVisitor.ctx.mv; // Optimization: In VOID context, evaluate elements for side effects only @@ -128,7 +130,7 @@ public static void emitHashLiteral(EmitterVisitor emitterVisitor, HashLiteralNod // Pop the list result since we don't need it mv.visitInsn(Opcodes.POP); } - emitterVisitor.ctx.logDebug("visit(HashLiteralNode) end"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(HashLiteralNode) end"); return; } @@ -143,7 +145,7 @@ public static void emitHashLiteral(EmitterVisitor emitterVisitor, HashLiteralNod "createHashRef", "(Lorg/perlonjava/runtime/runtimetypes/RuntimeBase;)Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;", false); - emitterVisitor.ctx.logDebug("visit(HashLiteralNode) end"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(HashLiteralNode) end"); } /** @@ -315,7 +317,7 @@ private static void emitStringValue(MethodVisitor mv, String value) { * @param node The ListNode representing the list literal in the AST */ public static void emitList(EmitterVisitor emitterVisitor, ListNode node) { - emitterVisitor.ctx.logDebug("visit(ListNode) in context " + emitterVisitor.ctx.contextType); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(ListNode) in context " + emitterVisitor.ctx.contextType); MethodVisitor mv = emitterVisitor.ctx.mv; int contextType = emitterVisitor.ctx.contextType; @@ -324,7 +326,7 @@ public static void emitList(EmitterVisitor emitterVisitor, ListNode node) { for (Node element : node.elements) { element.accept(emitterVisitor); } - emitterVisitor.ctx.logDebug("visit(ListNode) end"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(ListNode) end"); return; } @@ -347,7 +349,7 @@ public static void emitList(EmitterVisitor emitterVisitor, ListNode node) { node.elements.getLast().accept(emitterVisitor); // The last element's value remains on stack as the result } - emitterVisitor.ctx.logDebug("visit(ListNode) end"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(ListNode) end"); return; } @@ -380,7 +382,7 @@ public static void emitList(EmitterVisitor emitterVisitor, ListNode node) { emitterVisitor.ctx.javaClassInfo.loadSpillRef(mv, listRef); emitterVisitor.ctx.javaClassInfo.releaseSpillRef(listRef); - emitterVisitor.ctx.logDebug("visit(ListNode) end"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(ListNode) end"); } /** @@ -401,7 +403,7 @@ public static void emitList(EmitterVisitor emitterVisitor, ListNode node) { * @param node The NumberNode containing the numeric value as a string */ public static void emitNumber(EmitterContext ctx, NumberNode node) { - ctx.logDebug("visit(NumberNode) in context " + ctx.contextType); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("visit(NumberNode) in context " + ctx.contextType); // Skip code generation in void context if (ctx.contextType == RuntimeContextType.VOID) { @@ -422,7 +424,7 @@ public static void emitNumber(EmitterContext ctx, NumberNode node) { if (ctx.isBoxed) { // Boxed context: create a RuntimeScalar object if (isInteger) { - ctx.logDebug("visit(NumberNode) emit boxed integer"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("visit(NumberNode) emit boxed integer"); // Use cached RuntimeScalar for common integer values mv.visitLdcInsn(Integer.valueOf(value)); mv.visitMethodInsn(Opcodes.INVOKESTATIC, @@ -432,7 +434,7 @@ public static void emitNumber(EmitterContext ctx, NumberNode node) { } else if (isLargeInteger) { // Store large integers as strings to preserve precision // This emulates 32-bit Perl behavior - ctx.logDebug("visit(NumberNode) emit large integer as string"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("visit(NumberNode) emit large integer as string"); mv.visitTypeInsn(Opcodes.NEW, "org/perlonjava/runtime/runtimetypes/RuntimeScalar"); mv.visitInsn(Opcodes.DUP); mv.visitLdcInsn(value); diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitLogicalOperator.java b/src/main/java/org/perlonjava/backend/jvm/EmitLogicalOperator.java index 4b8546000..3e47dd338 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitLogicalOperator.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitLogicalOperator.java @@ -1,5 +1,7 @@ package org.perlonjava.backend.jvm; +import org.perlonjava.app.cli.CompilerOptions; + import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -387,7 +389,7 @@ private static void emitLogicalOperatorSimple(EmitterVisitor emitterVisitor, Bin * @param node The ternary operator node representing the operation. */ public static void emitTernaryOperator(EmitterVisitor emitterVisitor, TernaryOperatorNode node) { - emitterVisitor.ctx.logDebug("TERNARY_OP start"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("TERNARY_OP start"); // Create labels for the else and end branches Label elseLabel = new Label(); @@ -417,7 +419,7 @@ public static void emitTernaryOperator(EmitterVisitor emitterVisitor, TernaryOpe // Visit the end label mv.visitLabel(endLabel); - emitterVisitor.ctx.logDebug("TERNARY_OP end"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("TERNARY_OP end"); return; } @@ -448,6 +450,6 @@ public static void emitTernaryOperator(EmitterVisitor emitterVisitor, TernaryOpe emitterVisitor.ctx.javaClassInfo.releaseSpillSlot(); } - emitterVisitor.ctx.logDebug("TERNARY_OP end"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("TERNARY_OP end"); } } diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitOperator.java b/src/main/java/org/perlonjava/backend/jvm/EmitOperator.java index 59964e876..3d379c1ac 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitOperator.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitOperator.java @@ -1,5 +1,7 @@ package org.perlonjava.backend.jvm; +import org.perlonjava.app.cli.CompilerOptions; + import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.perlonjava.frontend.analysis.EmitterVisitor; @@ -35,7 +37,7 @@ static void emitOperator(Node node, EmitterVisitor emitterVisitor) { if (operatorHandler == null) { throw new PerlCompilerException(node.getIndex(), "Operator \"" + operator + "\" doesn't have a defined JVM descriptor", emitterVisitor.ctx.errorUtil); } - emitterVisitor.ctx.logDebug("emitOperator " + + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("emitOperator " + operatorHandler.methodType() + " " + operatorHandler.className() + " " + operatorHandler.methodName() + " " + @@ -63,7 +65,7 @@ static void emitOperatorWithKey(String operator, Node node, EmitterVisitor emitt if (operatorHandler == null) { throw new PerlCompilerException(node.getIndex(), "Operator \"" + operator + "\" doesn't have a defined JVM descriptor", emitterVisitor.ctx.errorUtil); } - emitterVisitor.ctx.logDebug("emitOperator " + + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("emitOperator " + operatorHandler.methodType() + " " + operatorHandler.className() + " " + operatorHandler.methodName() + " " + @@ -131,7 +133,7 @@ static void handleEach(EmitterVisitor emitterVisitor, OperatorNode node) { */ static void handleReadlineOperator(EmitterVisitor emitterVisitor, BinaryOperatorNode node) { String operator = node.operator; - emitterVisitor.ctx.logDebug("handleReadlineOperator " + node); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleReadlineOperator " + node); // Emit the File Handle emitFileHandle(emitterVisitor.with(RuntimeContextType.SCALAR), node.left); @@ -337,7 +339,7 @@ static void handleOperator(EmitterVisitor emitterVisitor, OperatorNode node) { static void handleDieBuiltin(EmitterVisitor emitterVisitor, OperatorNode node) { // Handle: die LIST // static RuntimeBase die(RuntimeBase value, int ctx) - emitterVisitor.ctx.logDebug("handleDieBuiltin " + node); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleDieBuiltin " + node); MethodVisitor mv = emitterVisitor.ctx.mv; // Accept the operand in LIST context. node.operand.accept(emitterVisitor.with(RuntimeContextType.LIST)); @@ -359,7 +361,7 @@ static void handleDieBuiltin(EmitterVisitor emitterVisitor, OperatorNode node) { static void handleSystemBuiltin(EmitterVisitor emitterVisitor, OperatorNode node) { // Handle: reverse LIST // static RuntimeBase reverse(RuntimeBase value, int ctx) - emitterVisitor.ctx.logDebug("handleSystemBuiltin " + node); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleSystemBuiltin " + node); ListNode operand = (ListNode) node.operand; boolean hasHandle = false; @@ -389,7 +391,7 @@ static void handleSystemBuiltin(EmitterVisitor emitterVisitor, OperatorNode node // Handles the 'splice' built-in function, which modifies an array. static void handleSpliceBuiltin(EmitterVisitor emitterVisitor, OperatorNode node) { // Handle: splice @array, LIST - emitterVisitor.ctx.logDebug("handleSpliceBuiltin " + node); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleSpliceBuiltin " + node); Node args = node.operand; if (args instanceof ListNode listArgs) { if (!listArgs.elements.isEmpty()) { @@ -476,7 +478,7 @@ static void handleMapOperator(EmitterVisitor emitterVisitor, BinaryOperatorNode static void handleDiamondBuiltin(EmitterVisitor emitterVisitor, OperatorNode node) { MethodVisitor mv = emitterVisitor.ctx.mv; String argument = ((StringNode) ((ListNode) node.operand).elements.getFirst()).value; - emitterVisitor.ctx.logDebug("visit diamond " + argument); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit diamond " + argument); if (argument.isEmpty() || argument.equals("<>")) { // Handle null filehandle: <> <<>> node.operand.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); @@ -979,7 +981,7 @@ static void handleLengthOperator(OperatorNode node, EmitterVisitor emitterVisito // Check if 'use bytes' is in effect if (emitterVisitor.ctx.symbolTable != null && emitterVisitor.ctx.symbolTable.isStrictOptionEnabled(Strict.HINT_BYTES)) { - emitterVisitor.ctx.logDebug("handleLengthOperator: Using lengthBytes (bytes pragma enabled)"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleLengthOperator: Using lengthBytes (bytes pragma enabled)"); // Use lengthBytes when bytes pragma is in effect mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/perlonjava/runtime/operators/StringOperators", @@ -987,7 +989,7 @@ static void handleLengthOperator(OperatorNode node, EmitterVisitor emitterVisito "(Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;)Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;", false); } else { - emitterVisitor.ctx.logDebug("handleLengthOperator: Using normal length (bytes pragma not enabled)"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleLengthOperator: Using normal length (bytes pragma not enabled)"); // Use normal length mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/perlonjava/runtime/operators/StringOperators", @@ -1012,7 +1014,7 @@ static void handleChrOperator(OperatorNode node, EmitterVisitor emitterVisitor) // Check if 'use bytes' is in effect if (emitterVisitor.ctx.symbolTable != null && emitterVisitor.ctx.symbolTable.isStrictOptionEnabled(Strict.HINT_BYTES)) { - emitterVisitor.ctx.logDebug("handleChrOperator: Using chrBytes (bytes pragma enabled)"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleChrOperator: Using chrBytes (bytes pragma enabled)"); // Use chrBytes when bytes pragma is in effect mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/perlonjava/runtime/operators/StringOperators", @@ -1020,7 +1022,7 @@ static void handleChrOperator(OperatorNode node, EmitterVisitor emitterVisitor) "(Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;)Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;", false); } else { - emitterVisitor.ctx.logDebug("handleChrOperator: Using normal chr (bytes pragma not enabled)"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleChrOperator: Using normal chr (bytes pragma not enabled)"); // Use normal chr mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/perlonjava/runtime/operators/StringOperators", @@ -1045,7 +1047,7 @@ static void handleOrdOperator(OperatorNode node, EmitterVisitor emitterVisitor) // Check if 'use bytes' is in effect if (emitterVisitor.ctx.symbolTable != null && emitterVisitor.ctx.symbolTable.isStrictOptionEnabled(Strict.HINT_BYTES)) { - emitterVisitor.ctx.logDebug("handleOrdOperator: Using ordBytes (bytes pragma enabled)"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleOrdOperator: Using ordBytes (bytes pragma enabled)"); // Use ordBytes when bytes pragma is in effect mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/perlonjava/runtime/operators/ScalarOperators", @@ -1053,7 +1055,7 @@ static void handleOrdOperator(OperatorNode node, EmitterVisitor emitterVisitor) "(Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;)Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;", false); } else { - emitterVisitor.ctx.logDebug("handleOrdOperator: Using normal ord (bytes pragma not enabled)"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleOrdOperator: Using normal ord (bytes pragma not enabled)"); // Use normal ord mv.visitMethodInsn(Opcodes.INVOKESTATIC, "org/perlonjava/runtime/operators/ScalarOperators", @@ -1194,7 +1196,7 @@ static void handleUcfirstOperator(OperatorNode node, EmitterVisitor emitterVisit static void handleArrayUnaryBuiltin(EmitterVisitor emitterVisitor, OperatorNode node, String operator) { Node operand = node.operand; - emitterVisitor.ctx.logDebug("handleArrayUnaryBuiltin " + operand); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleArrayUnaryBuiltin " + operand); if (operand instanceof ListNode listNode) { operand = listNode.elements.getFirst(); } @@ -1230,7 +1232,7 @@ static void handleCreateReference(EmitterVisitor emitterVisitor, OperatorNode no } else { if (node.operand instanceof OperatorNode operatorNode && operatorNode.operator.equals("&")) { - emitterVisitor.ctx.logDebug("Handle \\& " + operatorNode.operand); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("Handle \\& " + operatorNode.operand); if (operatorNode.operand instanceof IdentifierNode identifierNode) { emitterVisitor.ctx.mv.visitTypeInsn(Opcodes.NEW, "org/perlonjava/runtime/runtimetypes/RuntimeScalar"); emitterVisitor.ctx.mv.visitInsn(Opcodes.DUP); diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitOperatorDeleteExists.java b/src/main/java/org/perlonjava/backend/jvm/EmitOperatorDeleteExists.java index a4781e17a..438392e11 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitOperatorDeleteExists.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitOperatorDeleteExists.java @@ -1,5 +1,7 @@ package org.perlonjava.backend.jvm; +import org.perlonjava.app.cli.CompilerOptions; + import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.perlonjava.frontend.analysis.EmitterVisitor; @@ -43,7 +45,7 @@ private static void handleDeleteExistsInner(OperatorNode node, EmitterVisitor em if (operand.elements.size() == 1) { if (operand.elements.getFirst() instanceof OperatorNode operatorNode) { if ((operator.equals("exists") || operator.equals("defined")) && operatorNode.operator.equals("&")) { - emitterVisitor.ctx.logDebug(operator + " & " + operatorNode.operand); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug(operator + " & " + operatorNode.operand); if (operatorNode.operand instanceof IdentifierNode identifierNode) { // exists/defined &sub handleExistsSubroutine(emitterVisitor, operator, identifierNode); @@ -191,7 +193,7 @@ static void handleDefined(OperatorNode node, String operator, if (operand.elements.size() == 1) { if (operand.elements.getFirst() instanceof OperatorNode operatorNode) { if (operator.equals("defined") && operatorNode.operator.equals("&")) { - emitterVisitor.ctx.logDebug("defined & " + operatorNode.operand); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("defined & " + operatorNode.operand); if (operatorNode.operand instanceof IdentifierNode identifierNode) { // exists &sub handleExistsSubroutine(emitterVisitor, operator, identifierNode); diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitOperatorFileTest.java b/src/main/java/org/perlonjava/backend/jvm/EmitOperatorFileTest.java index 979dc77c5..41614a5d3 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitOperatorFileTest.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitOperatorFileTest.java @@ -1,5 +1,7 @@ package org.perlonjava.backend.jvm; +import org.perlonjava.app.cli.CompilerOptions; + import org.objectweb.asm.Opcodes; import org.perlonjava.frontend.analysis.EmitterVisitor; import org.perlonjava.frontend.astnode.IdentifierNode; @@ -14,7 +16,7 @@ public class EmitOperatorFileTest { static void handleFileTestBuiltin(EmitterVisitor emitterVisitor, OperatorNode node) { // Handle: -d FILE, -r -w -x FILE - emitterVisitor.ctx.logDebug("handleFileTestBuiltin " + node); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleFileTestBuiltin " + node); // Collect stacked operators by traversing nested OperatorNodes List operators = new ArrayList<>(); diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitOperatorNode.java b/src/main/java/org/perlonjava/backend/jvm/EmitOperatorNode.java index f15614e8d..966a9d241 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitOperatorNode.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitOperatorNode.java @@ -1,5 +1,7 @@ package org.perlonjava.backend.jvm; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.frontend.analysis.EmitterVisitor; import org.perlonjava.frontend.astnode.OperatorNode; import org.perlonjava.runtime.perlmodule.Strict; @@ -20,7 +22,7 @@ public class EmitOperatorNode { * @param node The operator node to process */ public static void emitOperatorNode(EmitterVisitor emitterVisitor, OperatorNode node) { - emitterVisitor.ctx.logDebug("visit(OperatorNode) " + node.operator + " in context " + emitterVisitor.ctx.contextType); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(OperatorNode) " + node.operator + " in context " + emitterVisitor.ctx.contextType); switch (node.operator) { // Subroutine related diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitStatement.java b/src/main/java/org/perlonjava/backend/jvm/EmitStatement.java index 9ca318ee1..f1522a190 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitStatement.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitStatement.java @@ -1,5 +1,7 @@ package org.perlonjava.backend.jvm; +import org.perlonjava.app.cli.CompilerOptions; + import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -42,7 +44,7 @@ public static void emitSignalCheck(MethodVisitor mv) { * @param node The if node representing the if statement. */ public static void emitIf(EmitterVisitor emitterVisitor, IfNode node) { - emitterVisitor.ctx.logDebug("IF start: " + node.operator); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("IF start: " + node.operator); List branchLabels = new ArrayList<>(); EmitBlock.collectIfChainLabels(node, branchLabels); @@ -93,7 +95,7 @@ public static void emitIf(EmitterVisitor emitterVisitor, IfNode node) { emitterVisitor.ctx.javaClassInfo.popGotoLabels(); } - emitterVisitor.ctx.logDebug("IF end"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("IF end"); } /** @@ -106,7 +108,7 @@ public static void emitFor3(EmitterVisitor emitterVisitor, For3Node node) { if (node.isDoWhile) { emitDoWhile(emitterVisitor, node); } else { - emitterVisitor.ctx.logDebug("FOR3 start"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("FOR3 start"); MethodVisitor mv = emitterVisitor.ctx.mv; EmitterVisitor voidVisitor = emitterVisitor.with(RuntimeContextType.VOID); // some parts have context VOID @@ -163,7 +165,7 @@ public static void emitFor3(EmitterVisitor emitterVisitor, For3Node node) { if (node.useNewScope) { // Register next/redo/last labels - emitterVisitor.ctx.logDebug("FOR3 label: " + node.labelName); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("FOR3 label: " + node.labelName); // A simple-block For3Node (isSimpleBlock=true) is used to model bare/labeled // blocks like `{ ... }` and `LABEL: { ... }` (including `... } continue { ... }`). // Unlabeled next/last/redo must be allowed for *bare* blocks (no label), but @@ -230,7 +232,7 @@ public static void emitFor3(EmitterVisitor emitterVisitor, For3Node node) { EmitOperator.emitUndef(emitterVisitor.ctx.mv); } - emitterVisitor.ctx.logDebug("FOR end"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("FOR end"); } } @@ -241,7 +243,7 @@ public static void emitFor3(EmitterVisitor emitterVisitor, For3Node node) { * @param node The for-loop node representing the do-while loop. */ static void emitDoWhile(EmitterVisitor emitterVisitor, For3Node node) { - emitterVisitor.ctx.logDebug("DO-WHILE start"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("DO-WHILE start"); MethodVisitor mv = emitterVisitor.ctx.mv; // Enter a new scope in the symbol table @@ -329,11 +331,11 @@ static void emitDoWhile(EmitterVisitor emitterVisitor, For3Node node) { EmitOperator.emitUndef(emitterVisitor.ctx.mv); } - emitterVisitor.ctx.logDebug("DO-WHILE end"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("DO-WHILE end"); } public static void emitTryCatch(EmitterVisitor emitterVisitor, TryNode node) { - emitterVisitor.ctx.logDebug("emitTryCatch start"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("emitTryCatch start"); MethodVisitor mv = emitterVisitor.ctx.mv; @@ -414,7 +416,7 @@ public static void emitTryCatch(EmitterVisitor emitterVisitor, TryNode node) { mv.visitVarInsn(Opcodes.ALOAD, resultSlot); } - emitterVisitor.ctx.logDebug("emitTryCatch end"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("emitTryCatch end"); } /** @@ -432,7 +434,7 @@ public static void emitTryCatch(EmitterVisitor emitterVisitor, TryNode node) { * @param node The defer node representing the defer statement. */ public static void emitDefer(EmitterVisitor emitterVisitor, org.perlonjava.frontend.astnode.DeferNode node) { - emitterVisitor.ctx.logDebug("emitDefer start"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("emitDefer start"); MethodVisitor mv = emitterVisitor.ctx.mv; @@ -474,7 +476,7 @@ public static void emitDefer(EmitterVisitor emitterVisitor, org.perlonjava.front false); // Stack: empty - emitterVisitor.ctx.logDebug("emitDefer end"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("emitDefer end"); } /** diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitSubroutine.java b/src/main/java/org/perlonjava/backend/jvm/EmitSubroutine.java index 23f5f7631..fabfa9b63 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitSubroutine.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitSubroutine.java @@ -1,5 +1,7 @@ package org.perlonjava.backend.jvm; +import org.perlonjava.app.cli.CompilerOptions; + import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -78,7 +80,7 @@ public class EmitSubroutine { * @param node The subroutine node representing the subroutine. */ public static void emitSubroutine(EmitterContext ctx, SubroutineNode node) { - ctx.logDebug("SUB start"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("SUB start"); if (ctx.contextType == RuntimeContextType.VOID) { return; } @@ -109,7 +111,7 @@ public static void emitSubroutine(EmitterContext ctx, SubroutineNode node) { }); } - ctx.logDebug("AnonSub ctx.symbolTable.getAllVisibleVariables"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("AnonSub ctx.symbolTable.getAllVisibleVariables"); // Create a new symbol table for the subroutine, but manually add only the filtered variables ScopedSymbolTable newSymbolTable = new ScopedSymbolTable(); @@ -131,7 +133,7 @@ public static void emitSubroutine(EmitterContext ctx, SubroutineNode node) { newSymbolTable.strictOptionsStack.push(ctx.symbolTable.strictOptionsStack.peek()); String[] newEnv = newSymbolTable.getVariableNames(); - ctx.logDebug("AnonSub " + newSymbolTable); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("AnonSub " + newSymbolTable); // Reset the index counter to start after the closure variables // This prevents allocateLocalVariable() from creating slots that overlap with uninitialized slots @@ -169,8 +171,8 @@ public static void emitSubroutine(EmitterContext ctx, SubroutineNode node) { subCtx, node.block, node.useTryCatch ); String newClassNameDot = subCtx.javaClassInfo.javaClassName.replace('/', '.'); - ctx.logDebug("Generated class name: " + newClassNameDot + " internal " + subCtx.javaClassInfo.javaClassName); - ctx.logDebug("Generated class env: " + Arrays.toString(newEnv)); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Generated class name: " + newClassNameDot + " internal " + subCtx.javaClassInfo.javaClassName); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Generated class env: " + Arrays.toString(newEnv)); RuntimeCode.anonSubs.put(subCtx.javaClassInfo.javaClassName, generatedClass); // Cache the class // Direct instantiation approach - no reflection needed! @@ -223,7 +225,7 @@ public static void emitSubroutine(EmitterContext ctx, SubroutineNode node) { } } catch (InterpreterFallbackException fallback) { // JVM compilation failed (e.g., ASM frame crash) - use InterpretedCode instead - ctx.logDebug("Using interpreter fallback for subroutine"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Using interpreter fallback for subroutine"); // Store the InterpretedCode in the interpretedSubs map with a unique key String fallbackKey = "interpreted_" + System.identityHashCode(fallback.interpretedCode); @@ -314,7 +316,7 @@ public static void emitSubroutine(EmitterContext ctx, SubroutineNode node) { // If the context is not VOID, the stack should contain [RuntimeScalar] (the CODE variable) // If the context is VOID, the stack should be empty - ctx.logDebug("SUB end"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("SUB end"); } /** @@ -324,7 +326,7 @@ public static void emitSubroutine(EmitterContext ctx, SubroutineNode node) { * @param node The binary operator node representing the apply operation. */ static void handleApplyOperator(EmitterVisitor emitterVisitor, BinaryOperatorNode node) { - emitterVisitor.ctx.logDebug("handleApplyElementOperator " + node + " in context " + emitterVisitor.ctx.contextType); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleApplyElementOperator " + node + " in context " + emitterVisitor.ctx.contextType); MethodVisitor mv = emitterVisitor.ctx.mv; // Capture the call context into a local slot early. @@ -340,7 +342,7 @@ static void handleApplyOperator(EmitterVisitor emitterVisitor, BinaryOperatorNod if (node.left instanceof OperatorNode operatorNode && operatorNode.operator.equals("&")) { if (operatorNode.operand instanceof IdentifierNode identifierNode) { subroutineName = NameNormalizer.normalizeVariableName(identifierNode.name, emitterVisitor.ctx.symbolTable.getCurrentPackage()); - emitterVisitor.ctx.logDebug("handleApplyElementOperator subroutine " + subroutineName); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleApplyElementOperator subroutine " + subroutineName); } } @@ -632,7 +634,7 @@ static void handleApplyOperator(EmitterVisitor emitterVisitor, BinaryOperatorNod * @param node The operator node representing the `__SUB__` operation. */ static void handleSelfCallOperator(EmitterVisitor emitterVisitor, OperatorNode node) { - emitterVisitor.ctx.logDebug("handleSelfCallOperator " + node + " in context " + emitterVisitor.ctx.contextType); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleSelfCallOperator " + node + " in context " + emitterVisitor.ctx.contextType); MethodVisitor mv = emitterVisitor.ctx.mv; diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitVariable.java b/src/main/java/org/perlonjava/backend/jvm/EmitVariable.java index e58d6b937..c484a205b 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitVariable.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitVariable.java @@ -1,5 +1,7 @@ package org.perlonjava.backend.jvm; +import org.perlonjava.app.cli.CompilerOptions; + import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -146,7 +148,7 @@ private static boolean isBuiltinSpecialContainerVar(String sigil, String name) { private static void fetchGlobalVariable(EmitterContext ctx, boolean createIfNotExists, String sigil, String varName, int tokenIndex) { String var = NameNormalizer.normalizeVariableName(varName, ctx.symbolTable.getCurrentPackage()); - ctx.logDebug("GETVAR lookup global " + sigil + varName + " normalized to " + var + " createIfNotExists:" + createIfNotExists); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("GETVAR lookup global " + sigil + varName + " normalized to " + var + " createIfNotExists:" + createIfNotExists); // Perl creates package symbols at compile time when they are referenced. // Our emitter runs before the program executes, so we pre-vivify globals here @@ -274,7 +276,7 @@ static void handleVariableOperator(EmitterVisitor emitterVisitor, OperatorNode n // Examples: $var, @array, %hash, *glob, &sub if (node.operand instanceof IdentifierNode identifierNode) { // $a @a %a String name = identifierNode.name; - emitterVisitor.ctx.logDebug("GETVAR " + sigil + name); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("GETVAR " + sigil + name); if (sigil.equals("*")) { // typeglob @@ -387,13 +389,13 @@ static void handleVariableOperator(EmitterVisitor emitterVisitor, OperatorNode n mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/perlonjava/runtime/runtimetypes/RuntimeBase", "scalar", "()Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;", false); } - emitterVisitor.ctx.logDebug("GETVAR end " + symbolEntry); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("GETVAR end " + symbolEntry); return; } switch (sigil) { case "@": // `@$a` - emitterVisitor.ctx.logDebug("GETVAR `@$a`"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("GETVAR `@$a`"); if (emitterVisitor.ctx.symbolTable.isStrictOptionEnabled(HINT_STRICT_REFS)) { node.operand.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/perlonjava/runtime/runtimetypes/RuntimeScalar", "arrayDeref", "()Lorg/perlonjava/runtime/runtimetypes/RuntimeArray;", false); @@ -409,7 +411,7 @@ static void handleVariableOperator(EmitterVisitor emitterVisitor, OperatorNode n return; case "%": // `%$a` - emitterVisitor.ctx.logDebug("GETVAR `%$a`"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("GETVAR `%$a`"); if (emitterVisitor.ctx.symbolTable.isStrictOptionEnabled(HINT_STRICT_REFS)) { node.operand.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/perlonjava/runtime/runtimetypes/RuntimeScalar", "hashDeref", "()Lorg/perlonjava/runtime/runtimetypes/RuntimeHash;", false); @@ -425,7 +427,7 @@ static void handleVariableOperator(EmitterVisitor emitterVisitor, OperatorNode n return; case "$": // `$$a` - emitterVisitor.ctx.logDebug("GETVAR `$$a`"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("GETVAR `$$a`"); if (emitterVisitor.ctx.symbolTable.isStrictOptionEnabled(HINT_STRICT_REFS)) { node.operand.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/perlonjava/runtime/runtimetypes/RuntimeScalar", "scalarDeref", "()Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;", false); @@ -438,7 +440,7 @@ static void handleVariableOperator(EmitterVisitor emitterVisitor, OperatorNode n return; case "*": // `*$a` - emitterVisitor.ctx.logDebug("GETVAR `*$a`"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("GETVAR `*$a`"); boolean isPostfixDeref = Boolean.TRUE.equals(node.getAnnotation("postfixDeref")); boolean postfixLiteralSymbol = isPostfixDeref && (node.operand instanceof StringNode || node.operand instanceof IdentifierNode); @@ -463,14 +465,14 @@ static void handleVariableOperator(EmitterVisitor emitterVisitor, OperatorNode n return; case "&": // `&$a` or `&{sub ...}` - emitterVisitor.ctx.logDebug("GETVAR `&$a` or `&{sub ...}`"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("GETVAR `&$a` or `&{sub ...}`"); // Special handling for &{sub ...} - BlockNode containing SubroutineNode if (node.operand instanceof BlockNode blockNode && blockNode.elements.size() == 1 && blockNode.elements.get(0) instanceof SubroutineNode) { - emitterVisitor.ctx.logDebug("GETVAR `&{sub ...}` - emitting subroutine as RuntimeScalar"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("GETVAR `&{sub ...}` - emitting subroutine as RuntimeScalar"); // Emit the subroutine directly as a RuntimeScalar (code reference) blockNode.elements.get(0).accept(emitterVisitor.with(RuntimeContextType.SCALAR)); } else { @@ -498,7 +500,7 @@ static void handleVariableOperator(EmitterVisitor emitterVisitor, OperatorNode n } } - emitterVisitor.ctx.logDebug("EmitVariable: about to call RuntimeCode.apply for &$var"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("EmitVariable: about to call RuntimeCode.apply for &$var"); mv.visitVarInsn(Opcodes.ALOAD, 1); // push @_ to stack emitterVisitor.pushCallContext(); // push call context to stack @@ -660,12 +662,12 @@ static void handleVariableOperator(EmitterVisitor emitterVisitor, OperatorNode n static void handleAssignOperator(EmitterVisitor emitterVisitor, BinaryOperatorNode node) { EmitterContext ctx = emitterVisitor.ctx; - ctx.logDebug("SET " + node); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("SET " + node); MethodVisitor mv = ctx.mv; // Determine the assign type based on the left side. // Inspect the AST and get the L-value context: SCALAR or LIST int lvalueContext = LValueVisitor.getContext(node); - ctx.logDebug("SET Lvalue context: " + lvalueContext); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("SET Lvalue context: " + lvalueContext); // Execute the right side first: assignment is right-associative Node left = node.left; @@ -675,7 +677,7 @@ static void handleAssignOperator(EmitterVisitor emitterVisitor, BinaryOperatorNo switch (lvalueContext) { case RuntimeContextType.SCALAR: - ctx.logDebug("SET right side scalar"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("SET right side scalar"); if (node.left instanceof OperatorNode operatorNode && operatorNode.operator.equals("state")) { emitStateInitialization(emitterVisitor, node, operatorNode, ctx); @@ -795,7 +797,7 @@ static void handleAssignOperator(EmitterVisitor emitterVisitor, BinaryOperatorNo } break; case RuntimeContextType.LIST: - emitterVisitor.ctx.logDebug("SET right side list"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("SET right side list"); if (node.left instanceof OperatorNode operatorNode && operatorNode.operator.equals("state")) { emitStateInitialization(emitterVisitor, node, operatorNode, ctx); @@ -852,12 +854,12 @@ static void handleAssignOperator(EmitterVisitor emitterVisitor, BinaryOperatorNo throw new PerlCompilerException(node.tokenIndex, "Unsupported assignment context: " + lvalueContext, ctx.errorUtil); } EmitOperator.handleVoidContext(emitterVisitor); - emitterVisitor.ctx.logDebug("SET end"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("SET end"); } private static void emitStateInitialization(EmitterVisitor emitterVisitor, BinaryOperatorNode node, OperatorNode operatorNode, EmitterContext ctx) { // This is a state variable initialization, it should run exactly once. - ctx.logDebug("handleAssignOperator initialize state variable " + operatorNode); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("handleAssignOperator initialize state variable " + operatorNode); OperatorNode varNode = (OperatorNode) operatorNode.operand; IdentifierNode nameNode = (IdentifierNode) varNode.operand; String sigil = varNode.operator; @@ -881,7 +883,7 @@ private static void emitStateInitialization(EmitterVisitor emitterVisitor, Binar ), tokenIndex ); - ctx.logDebug("handleAssignOperator initialize state variable " + testStateVariable); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("handleAssignOperator initialize state variable " + testStateVariable); // testStateVariable.accept(emitterVisitor.with(RuntimeContextType.SCALAR)); // Determine the method to call and its descriptor based on the sigil @@ -907,7 +909,7 @@ private static void emitStateInitialization(EmitterVisitor emitterVisitor, Binar ), tokenIndex ); - ctx.logDebug("handleAssignOperator initialize state variable " + initStateVariable); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("handleAssignOperator initialize state variable " + initStateVariable); // initStateVariable.accept(emitterVisitor.with(RuntimeContextType.VOID)); new BinaryOperatorNode("||", testStateVariable, initStateVariable, tokenIndex) @@ -920,10 +922,10 @@ static void handleMyOperator(EmitterVisitor emitterVisitor, OperatorNode node) { EmitterContext ctx = emitterVisitor.ctx; String operator = node.operator; - ctx.logDebug("handleMyOperator: operator=" + operator + ", operand type=" + (node.operand != null ? node.operand.getClass().getSimpleName() : "null") + ", contextType=" + ctx.contextType); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("handleMyOperator: operator=" + operator + ", operand type=" + (node.operand != null ? node.operand.getClass().getSimpleName() : "null") + ", contextType=" + ctx.contextType); if (node.operand instanceof ListNode listNode) { // my ($a, $b) our ($a, $b) // process each item of the list; then returns the list - ctx.logDebug("handleMyOperator: ListNode operand, contextType=" + ctx.contextType + ", annotations=" + node.annotations); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("handleMyOperator: ListNode operand, contextType=" + ctx.contextType + ", annotations=" + node.annotations); for (Node element : listNode.elements) { if (element instanceof OperatorNode && "undef".equals(((OperatorNode) element).operator)) { continue; // skip "undef" @@ -984,7 +986,7 @@ static void handleMyOperator(EmitterVisitor emitterVisitor, OperatorNode node) { if (isDeclaredReference) { // For declared references, return a list of references to the variables - emitterVisitor.ctx.logDebug("handleMyOperator: isDeclaredReference=true, emitting references for list elements"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleMyOperator: isDeclaredReference=true, emitting references for list elements"); MethodVisitor mv = emitterVisitor.ctx.mv; // Create a new RuntimeList @@ -994,9 +996,9 @@ static void handleMyOperator(EmitterVisitor emitterVisitor, OperatorNode node) { // For each element in the list, emit the variable and create a reference for (Node element : listNode.elements) { - ctx.logDebug("handleMyOperator: processing element: " + element + ", class=" + element.getClass().getSimpleName()); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("handleMyOperator: processing element: " + element + ", class=" + element.getClass().getSimpleName()); if (element instanceof OperatorNode elemOpNode && "$@%".contains(elemOpNode.operator)) { - ctx.logDebug("handleMyOperator: emitting createReference for " + elemOpNode.operator); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("handleMyOperator: emitting createReference for " + elemOpNode.operator); mv.visitInsn(Opcodes.DUP); // Dup the RuntimeList // Emit the variable in SCALAR context @@ -1032,7 +1034,7 @@ static void handleMyOperator(EmitterVisitor emitterVisitor, OperatorNode node) { if (hasAnyDeclaredRef) { // Mixed case: some elements are declared refs, some are not // Build the list manually, emitting references for declared refs - emitterVisitor.ctx.logDebug("handleMyOperator: hasAnyDeclaredRef=true, building mixed list"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleMyOperator: hasAnyDeclaredRef=true, building mixed list"); MethodVisitor mv = emitterVisitor.ctx.mv; mv.visitTypeInsn(Opcodes.NEW, "org/perlonjava/runtime/runtimetypes/RuntimeList"); @@ -1062,7 +1064,7 @@ static void handleMyOperator(EmitterVisitor emitterVisitor, OperatorNode node) { } } } else { - emitterVisitor.ctx.logDebug("handleMyOperator: isDeclaredReference=false, emitting listNode directly"); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("handleMyOperator: isDeclaredReference=false, emitting listNode directly"); listNode.accept(emitterVisitor); } } @@ -1091,7 +1093,7 @@ static void handleMyOperator(EmitterVisitor emitterVisitor, OperatorNode node) { if (identifierNode instanceof IdentifierNode) { // my $a String name = ((IdentifierNode) identifierNode).name; String var = sigil + name; - emitterVisitor.ctx.logDebug("MY " + operator + " " + sigil + name); + if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("MY " + operator + " " + sigil + name); if (emitterVisitor.ctx.symbolTable.getVariableIndexInCurrentScope(var) != -1) { if (Warnings.warningManager.isWarningEnabled("redefine")) { System.err.println( diff --git a/src/main/java/org/perlonjava/backend/jvm/EmitterMethodCreator.java b/src/main/java/org/perlonjava/backend/jvm/EmitterMethodCreator.java index 42626fe7d..63e190361 100644 --- a/src/main/java/org/perlonjava/backend/jvm/EmitterMethodCreator.java +++ b/src/main/java/org/perlonjava/backend/jvm/EmitterMethodCreator.java @@ -1,5 +1,7 @@ package org.perlonjava.backend.jvm; +import org.perlonjava.app.cli.CompilerOptions; + import org.objectweb.asm.*; import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; @@ -433,7 +435,7 @@ private static byte[] getBytecodeInternal(EmitterContext ctx, Node ast, boolean // Define the class with version, access flags, name, signature, superclass, and interfaces cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, className, null, "java/lang/Object", null); - ctx.logDebug("Create class: " + className); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Create class: " + className); // Add instance fields to the class for closure variables for (String fieldName : env) { @@ -442,7 +444,7 @@ private static byte[] getBytecodeInternal(EmitterContext ctx, Node ast, boolean continue; } String descriptor = getVariableDescriptor(fieldName); - ctx.logDebug("Create instance field: " + descriptor); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Create instance field: " + descriptor); cw.visitField(Opcodes.ACC_PUBLIC, fieldName, descriptor, null, null).visitEnd(); } @@ -457,7 +459,7 @@ private static byte[] getBytecodeInternal(EmitterContext ctx, Node ast, boolean constructorDescriptor.append(descriptor); } constructorDescriptor.append(")V"); - ctx.logDebug("constructorDescriptor: " + constructorDescriptor); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("constructorDescriptor: " + constructorDescriptor); ctx.mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "", constructorDescriptor.toString(), null, null); MethodVisitor mv = ctx.mv; @@ -486,7 +488,7 @@ private static byte[] getBytecodeInternal(EmitterContext ctx, Node ast, boolean mv.visitEnd(); // Create the public "apply" method for the generated class - ctx.logDebug("Create the method"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Create the method"); ctx.mv = cw.visitMethod( Opcodes.ACC_PUBLIC, @@ -511,7 +513,7 @@ private static byte[] getBytecodeInternal(EmitterContext ctx, Node ast, boolean } String descriptor = getVariableDescriptor(env[i]); mv.visitVarInsn(Opcodes.ALOAD, 0); // Load 'this' - ctx.logDebug("Init closure variable: " + descriptor); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Init closure variable: " + descriptor); mv.visitFieldInsn(Opcodes.GETFIELD, ctx.javaClassInfo.javaClassName, env[i], descriptor); mv.visitVarInsn(Opcodes.ASTORE, i); } @@ -625,7 +627,7 @@ private static byte[] getBytecodeInternal(EmitterContext ctx, Node ast, boolean Label endCatch = null; if (useTryCatch) { - ctx.logDebug("useTryCatch"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("useTryCatch"); // -------------------------------- // Start of try-catch block @@ -663,7 +665,7 @@ private static byte[] getBytecodeInternal(EmitterContext ctx, Node ast, boolean mv.visitJumpInsn(Opcodes.GOTO, ctx.javaClassInfo.returnLabel); // Handle the return value - ctx.logDebug("Return the last value"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Return the last value"); // -------------------------------- @@ -688,7 +690,7 @@ private static byte[] getBytecodeInternal(EmitterContext ctx, Node ast, boolean mv.visitJumpInsn(Opcodes.GOTO, ctx.javaClassInfo.returnLabel); // Handle the return value - ctx.logDebug("Return the last value"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Return the last value"); } // Join point for all returns/gotos. Must be stack-neutral. diff --git a/src/main/java/org/perlonjava/core/Configuration.java b/src/main/java/org/perlonjava/core/Configuration.java index 515d130ee..b2af5d58e 100644 --- a/src/main/java/org/perlonjava/core/Configuration.java +++ b/src/main/java/org/perlonjava/core/Configuration.java @@ -33,7 +33,7 @@ public final class Configuration { * Automatically populated by Gradle/Maven during build. * DO NOT EDIT MANUALLY - this value is replaced at build time. */ - public static final String gitCommitId = "50f341b0f"; + public static final String gitCommitId = "587670ac7"; /** * Git commit date of the build (ISO format: YYYY-MM-DD). diff --git a/src/main/java/org/perlonjava/frontend/parser/CoreOperatorResolver.java b/src/main/java/org/perlonjava/frontend/parser/CoreOperatorResolver.java index 0d20223e1..06e14b861 100644 --- a/src/main/java/org/perlonjava/frontend/parser/CoreOperatorResolver.java +++ b/src/main/java/org/perlonjava/frontend/parser/CoreOperatorResolver.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.frontend.astnode.*; import org.perlonjava.frontend.lexer.LexerToken; import org.perlonjava.frontend.lexer.LexerTokenType; @@ -118,7 +120,7 @@ private static Node parseWithPrototype(Parser parser, LexerToken token, int curr String prototype = CORE_PROTOTYPES.get(operator); if (prototype != null) { - parser.ctx.logDebug("CORE operator " + operator + " with prototype " + prototype); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("CORE operator " + operator + " with prototype " + prototype); // Set the operator name as the subroutine name for better error messages String previousSubName = parser.ctx.symbolTable.getCurrentSubroutine(); parser.ctx.symbolTable.setCurrentSubroutine(operator); diff --git a/src/main/java/org/perlonjava/frontend/parser/DataSection.java b/src/main/java/org/perlonjava/frontend/parser/DataSection.java index c54672aef..6ce66c67a 100644 --- a/src/main/java/org/perlonjava/frontend/parser/DataSection.java +++ b/src/main/java/org/perlonjava/frontend/parser/DataSection.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.frontend.lexer.LexerToken; import org.perlonjava.frontend.lexer.LexerTokenType; import org.perlonjava.runtime.io.ScalarBackedIO; @@ -38,7 +40,7 @@ public static void createPlaceholderDataHandle(Parser parser) { placeholderCreated.add(handleName); - parser.ctx.logDebug("Creating placeholder DATA handle for package: " + handleName); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Creating placeholder DATA handle for package: " + handleName); // Create an empty placeholder file handle that will be populated later RuntimeScalar emptyContent = new RuntimeScalar(""); @@ -55,7 +57,7 @@ public static void createPlaceholderDataHandle(Parser parser) { public static void createDataHandle(Parser parser, String content) { String handleName = parser.ctx.symbolTable.getCurrentPackage() + "::DATA"; - parser.ctx.logDebug("Populating DATA handle for package: " + handleName + " with content: " + content); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Populating DATA handle for package: " + handleName + " with content: " + content); // Get the existing RuntimeIO (which should be the placeholder we created earlier) RuntimeIO existingIO = GlobalVariable.getGlobalIO(handleName).getRuntimeIO(); @@ -66,13 +68,13 @@ public static void createDataHandle(Parser parser, String content) { RuntimeScalar contentScalar = new RuntimeScalar(content); ScalarBackedIO newScalarIO = new ScalarBackedIO(contentScalar); existingIO.ioHandle = newScalarIO; - parser.ctx.logDebug("Updated existing DATA handle with new content"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Updated existing DATA handle with new content"); } else { // Fallback: create new handle if no placeholder exists RuntimeScalar contentScalar = new RuntimeScalar(content); var fileHandle = RuntimeIO.open(contentScalar.createReference(), "<"); GlobalVariable.getGlobalIO(handleName).setIO(fileHandle); - parser.ctx.logDebug("Created new DATA handle"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Created new DATA handle"); } } diff --git a/src/main/java/org/perlonjava/frontend/parser/FormatParser.java b/src/main/java/org/perlonjava/frontend/parser/FormatParser.java index 07f30f36e..00a7010a3 100644 --- a/src/main/java/org/perlonjava/frontend/parser/FormatParser.java +++ b/src/main/java/org/perlonjava/frontend/parser/FormatParser.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.frontend.astnode.*; import org.perlonjava.frontend.lexer.Lexer; import org.perlonjava.frontend.lexer.LexerToken; @@ -47,7 +49,7 @@ public static FormatNode parseFormatDeclaration(Parser parser, String formatName // This ensures EmitFormat and typeglob access use the same key formatName = NameNormalizer.normalizeVariableName(formatName, parser.ctx.symbolTable.getCurrentPackage()); - parser.ctx.logDebug("Parsing format declaration: " + formatName); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Parsing format declaration: " + formatName); // Parse format template content immediately List templateLines = parseFormatTemplateContentImmediate(parser); @@ -72,12 +74,12 @@ private static List parseFormatTemplateContentImmediate(Parser parse boolean foundTerminator = false; int lineIndex = parser.tokenIndex; - parser.ctx.logDebug("FormatParser.parseFormatTemplateContentImmediate: Starting at tokenIndex=" + parser.tokenIndex); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("FormatParser.parseFormatTemplateContentImmediate: Starting at tokenIndex=" + parser.tokenIndex); // Process tokens until we find the terminator '.' while (parser.tokenIndex < tokens.size()) { LexerToken token = tokens.get(parser.tokenIndex); - parser.ctx.logDebug(" Processing token: " + token.text + " type: " + token.type); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug(" Processing token: " + token.text + " type: " + token.type); if (token.type == LexerTokenType.EOF) { break; @@ -86,11 +88,11 @@ private static List parseFormatTemplateContentImmediate(Parser parse if (token.type == LexerTokenType.NEWLINE) { // End of current line String line = currentLine.toString(); - parser.ctx.logDebug(" Completed line: '" + line + "'"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug(" Completed line: '" + line + "'"); // Check if this line is the terminator if (line.trim().equals(".")) { - parser.ctx.logDebug("Found format terminator '.' at token index " + lineIndex); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Found format terminator '.' at token index " + lineIndex); foundTerminator = true; parser.tokenIndex++; // consume the newline break; @@ -126,7 +128,7 @@ private static List parseFormatTemplateContentImmediate(Parser parse "Format not terminated", parser.ctx.errorUtil); } - parser.ctx.logDebug("FormatParser.parseFormatTemplateContentImmediate: Parsed " + + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("FormatParser.parseFormatTemplateContentImmediate: Parsed " + templateLines.size() + " template lines"); return templateLines; @@ -140,12 +142,12 @@ private static List parseFormatTemplateContentImmediate(Parser parse * @param parser The parser instance */ public static void parseFormatTemplateContent(Parser parser) { - parser.ctx.logDebug("FORMAT_PROCESSING_START"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("FORMAT_PROCESSING_START"); List formatNodes = parser.getFormatNodes(); List tokens = parser.tokens; int currentIndex = parser.tokenIndex; - parser.ctx.logDebug("FormatParser.parseFormatTemplateContent: Starting at tokenIndex=" + + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("FormatParser.parseFormatTemplateContent: Starting at tokenIndex=" + currentIndex + ", format count=" + formatNodes.size()); // Process all pending format nodes @@ -154,11 +156,11 @@ public static void parseFormatTemplateContent(Parser parser) { while (!formatNodes.isEmpty()) { FormatNode formatNode = formatNodes.removeFirst(); - parser.ctx.logDebug("Processing format: " + formatNode.formatName); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Processing format: " + formatNode.formatName); // Check if we have enough tokens if (currentIndex + 1 >= tokens.size()) { - parser.ctx.logDebug("Deferring format " + formatNode.formatName + " - not enough tokens"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Deferring format " + formatNode.formatName + " - not enough tokens"); deferredFormats.add(formatNode); continue; } @@ -169,22 +171,22 @@ public static void parseFormatTemplateContent(Parser parser) { StringBuilder currentLine = new StringBuilder(); boolean foundTerminator = false; - parser.ctx.logDebug(" Looking for format content starting at token index: " + lineIndex); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug(" Looking for format content starting at token index: " + lineIndex); while (lineIndex < tokens.size()) { LexerToken token = tokens.get(lineIndex); - parser.ctx.logDebug(" Token[" + lineIndex + "]: type=" + token.type + + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug(" Token[" + lineIndex + "]: type=" + token.type + ", text='" + token.text.replace("\n", "\\n") + "'"); if (token.type == LexerTokenType.NEWLINE || token.type == LexerTokenType.EOF) { // End of current line String line = currentLine.toString(); - parser.ctx.logDebug(" Completed line: '" + line + "'"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug(" Completed line: '" + line + "'"); // Check if this line is the terminator if (line.trim().equals(".")) { - parser.ctx.logDebug("Found format terminator '.' at token index " + lineIndex); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Found format terminator '.' at token index " + lineIndex); foundTerminator = true; break; } @@ -212,7 +214,7 @@ public static void parseFormatTemplateContent(Parser parser) { } // Defer for parent context to handle - parser.ctx.logDebug("Format " + formatNode.formatName + " terminator not found - deferring"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Format " + formatNode.formatName + " terminator not found - deferring"); deferredFormats.add(formatNode); continue; } @@ -230,7 +232,7 @@ public static void parseFormatTemplateContent(Parser parser) { // Re-add deferred formats formatNodes.addAll(deferredFormats); - parser.ctx.logDebug("FormatParser.parseFormatTemplateContent: Deferred " + + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("FormatParser.parseFormatTemplateContent: Deferred " + deferredFormats.size() + " formats back to queue"); parser.tokenIndex = currentIndex; diff --git a/src/main/java/org/perlonjava/frontend/parser/IdentifierParser.java b/src/main/java/org/perlonjava/frontend/parser/IdentifierParser.java index 158c27045..6286cec7a 100644 --- a/src/main/java/org/perlonjava/frontend/parser/IdentifierParser.java +++ b/src/main/java/org/perlonjava/frontend/parser/IdentifierParser.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import com.ibm.icu.lang.UCharacter; import com.ibm.icu.lang.UProperty; import org.perlonjava.frontend.lexer.LexerToken; @@ -339,7 +341,7 @@ public static String parseComplexIdentifierInner(Parser parser, boolean insideBr // `$^` can be followed by an optional uppercase identifier: `$^A` // ^A is control-A char(1) TokenUtils.consume(parser); // consume the ^ - parser.ctx.logDebug("parse $^ at token " + TokenUtils.peek(parser).text); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parse $^ at token " + TokenUtils.peek(parser).text); // `$^LAST_FH` is parsed as `$^L` + `AST_FH` // `${^LAST_FH}` is parsed as `${^LAST_FH}` String str = insideBraces diff --git a/src/main/java/org/perlonjava/frontend/parser/ListParser.java b/src/main/java/org/perlonjava/frontend/parser/ListParser.java index e9580ab76..80579b5eb 100644 --- a/src/main/java/org/perlonjava/frontend/parser/ListParser.java +++ b/src/main/java/org/perlonjava/frontend/parser/ListParser.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.frontend.astnode.ListNode; import org.perlonjava.frontend.astnode.Node; import org.perlonjava.frontend.astnode.OperatorNode; @@ -79,7 +81,7 @@ static ListNode parseZeroOrOneList(Parser parser, int minItems) { * @throws PerlCompilerException If the syntax is incorrect or the minimum number of items is not met. */ static ListNode parseZeroOrMoreList(Parser parser, int minItems, boolean wantBlockNode, boolean obeyParentheses, boolean wantFileHandle, boolean wantRegex) { - parser.ctx.logDebug("parseZeroOrMoreList start"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseZeroOrMoreList start"); ListNode expr = new ListNode(parser.tokenIndex); int currentIndex = parser.tokenIndex; @@ -191,7 +193,7 @@ static ListNode parseZeroOrMoreList(Parser parser, int minItems, boolean wantBlo if (hasParen) { TokenUtils.consume(parser, LexerTokenType.OPERATOR, ")"); } - parser.ctx.logDebug("parseZeroOrMoreList end: " + expr); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseZeroOrMoreList end: " + expr); if (expr.elements.size() < minItems) { parser.throwError("syntax error"); @@ -252,18 +254,18 @@ static boolean isListTerminator(Parser parser, LexerToken token) { * @throws PerlCompilerException If the syntax is incorrect or the minimum number of items is not met. */ static List parseList(Parser parser, String close, int minItems) { - parser.ctx.logDebug("parseList start"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseList start"); ListNode expr; LexerToken token = TokenUtils.peek(parser); - parser.ctx.logDebug("parseList start at " + token); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseList start at " + token); if (token.text.equals(close)) { // Empty list TokenUtils.consume(parser); expr = new ListNode(parser.tokenIndex); } else { expr = ListNode.makeList(parser.parseExpression(0)); - parser.ctx.logDebug("parseList end at " + TokenUtils.peek(parser)); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseList end at " + TokenUtils.peek(parser)); // Check for closing delimiter with better error message for hash/array literals LexerToken closingToken = TokenUtils.peek(parser); @@ -282,7 +284,7 @@ static List parseList(Parser parser, String close, int minItems) { if (expr.elements.size() < minItems) { parser.throwError("syntax error"); } - parser.ctx.logDebug("parseList end"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseList end"); return expr.elements; } @@ -320,39 +322,39 @@ public static boolean looksLikeEmptyList(Parser parser) { } else if (token.text.equals("-")) { // -d, -e, -f, -l, -p, -x // -$v - parser.ctx.logDebug("parseZeroOrMoreList looks like file test operator or unary minus"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseZeroOrMoreList looks like file test operator or unary minus"); } else if (ParserTables.INFIX_OP.contains(token.text) || token.text.equals(",")) { - parser.ctx.logDebug("parseZeroOrMoreList infix `" + token.text + "` followed by `" + nextToken.text + "`"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseZeroOrMoreList infix `" + token.text + "` followed by `" + nextToken.text + "`"); if (token.text.equals("<") || token.text.equals("<<")) { // Looks like diamond operator - parser.ctx.logDebug("parseZeroOrMoreList looks like <>"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseZeroOrMoreList looks like <>"); } else if (token.text.equals("+")) { // Looks like a prefix `+`, not an infix `+` - parser.ctx.logDebug("parseZeroOrMoreList looks like prefix plus"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseZeroOrMoreList looks like prefix plus"); } else if (token.text.equals("*")) { // Looks like a prefix `*`, not an infix `*` - parser.ctx.logDebug("parseZeroOrMoreList looks like typeglob prefix"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseZeroOrMoreList looks like typeglob prefix"); } else if (token.text.equals("&")) { // Looks like a subroutine call, not an infix `&` - parser.ctx.logDebug("parseZeroOrMoreList looks like subroutine call"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseZeroOrMoreList looks like subroutine call"); } else if (token.text.equals("%") && (nextToken.text.equals("$") || nextToken.text.equals("{") || nextToken.type == LexerTokenType.IDENTIFIER)) { // Looks like a hash deref, not an infix `%` // %$ref, %{expr}, %hash - parser.ctx.logDebug("parseZeroOrMoreList looks like Hash: token=" + token.text + " nextToken=" + nextToken.text); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseZeroOrMoreList looks like Hash: token=" + token.text + " nextToken=" + nextToken.text); } else if (token.text.equals("@") && nextToken.text.equals("{")) { // Looks like an array deref @{expr}, not an infix `@` - parser.ctx.logDebug("parseZeroOrMoreList looks like Array deref"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseZeroOrMoreList looks like Array deref"); } else if (token.text.equals(".") && token1.type == LexerTokenType.NUMBER) { // Looks like a fractional number, not an infix `.` - parser.ctx.logDebug("parseZeroOrMoreList looks like Number"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseZeroOrMoreList looks like Number"); } else if (token.text.equals("/")) { // Looks like a regex pattern, not division // In Perl, /pattern/ at the start of a list context is a regex match // Note: // is the defined-or operator, not a regex, so we don't include it here - parser.ctx.logDebug("parseZeroOrMoreList looks like regex"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseZeroOrMoreList looks like regex"); } else { // Subroutine call with zero arguments, followed by infix operator: `pos = 3` - parser.ctx.logDebug("parseZeroOrMoreList return zero at `" + parser.tokens.get(parser.tokenIndex) + "`"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseZeroOrMoreList return zero at `" + parser.tokens.get(parser.tokenIndex) + "`"); // if (LVALUE_INFIX_OP.contains(token.text)) { // throw new PerlCompilerException(tokenIndex, "Can't modify non-lvalue subroutine call", ctx.errorUtil); // } diff --git a/src/main/java/org/perlonjava/frontend/parser/OperatorParser.java b/src/main/java/org/perlonjava/frontend/parser/OperatorParser.java index f4e416752..ce48e6ec6 100644 --- a/src/main/java/org/perlonjava/frontend/parser/OperatorParser.java +++ b/src/main/java/org/perlonjava/frontend/parser/OperatorParser.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.backend.jvm.EmitterContext; import org.perlonjava.backend.jvm.EmitterMethodCreator; import org.perlonjava.frontend.astnode.*; @@ -126,10 +128,10 @@ static Node parseDiamondOperator(Parser parser, LexerToken token) { // Check if the token is a dollar sign, indicating a variable if (tokenText.equals("$")) { // Handle the case for <$fh> - parser.ctx.logDebug("diamond operator " + token.text + parser.tokens.get(parser.tokenIndex)); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("diamond operator " + token.text + parser.tokens.get(parser.tokenIndex)); parser.tokenIndex++; Node var = Variable.parseVariable(parser, "$"); // Parse the variable following the dollar sign - parser.ctx.logDebug("diamond operator var " + var); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("diamond operator var " + var); // Check if the next token is a closing angle bracket if (parser.tokens.get(parser.tokenIndex).text.equals(">")) { @@ -147,7 +149,7 @@ static Node parseDiamondOperator(Parser parser, LexerToken token) { // Check if the token is one of the standard input sources if (tokenText.equals("STDIN") || tokenText.equals("DATA") || tokenText.equals("ARGV")) { // Handle the case for , , or - parser.ctx.logDebug("diamond operator " + token.text + parser.tokens.get(parser.tokenIndex)); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("diamond operator " + token.text + parser.tokens.get(parser.tokenIndex)); parser.tokenIndex++; // Check if the next token is a closing angle bracket @@ -205,7 +207,7 @@ static BinaryOperatorNode parsePrint(Parser parser, LexerToken token, int curren if (paren) { TokenUtils.consume(parser, OPERATOR, ")"); } - parser.ctx.logDebug("parsePrint: " + operand.handle + " : " + operand); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parsePrint: " + operand.handle + " : " + operand); } handle = operand.handle; @@ -295,7 +297,7 @@ static OperatorNode parseVariableDeclaration(Parser parser, String operator, int // Create OperatorNode ($, @, %), ListNode (includes undef), SubroutineNode Node operand = ParsePrimary.parsePrimary(parser); - parser.ctx.logDebug("parseVariableDeclaration " + operator + ": " + operand + " (ref=" + isDeclaredReference + ")"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseVariableDeclaration " + operator + ": " + operand + " (ref=" + isDeclaredReference + ")"); // Add variables to the scope if (operand instanceof ListNode listNode) { // my ($a, $b) our ($a, $b) @@ -1013,7 +1015,7 @@ static OperatorNode parseRequire(Parser parser) { // with the same name exists in the current package (e.g., sub Encode in Image::ExifTool) // But don't intercept quote-like operators like q(), qq(), etc. String moduleName = IdentifierParser.parseSubroutineIdentifier(parser); - parser.ctx.logDebug("require module name `" + moduleName + "`"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("require module name `" + moduleName + "`"); if (moduleName == null) { throw new PerlCompilerException(parser.tokenIndex, "Syntax error", parser.ctx.errorUtil); } @@ -1051,7 +1053,7 @@ static OperatorNode parseRequire(Parser parser) { if (firstElement instanceof IdentifierNode identifierNode) { // `require` module String moduleName = identifierNode.name; - parser.ctx.logDebug("name `" + moduleName + "`"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("name `" + moduleName + "`"); if (moduleName == null) { throw new PerlCompilerException(parser.tokenIndex, "Syntax error", parser.ctx.errorUtil); } diff --git a/src/main/java/org/perlonjava/frontend/parser/ParseBlock.java b/src/main/java/org/perlonjava/frontend/parser/ParseBlock.java index 9e572eaf4..d1c5a1f4a 100644 --- a/src/main/java/org/perlonjava/frontend/parser/ParseBlock.java +++ b/src/main/java/org/perlonjava/frontend/parser/ParseBlock.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.frontend.astnode.BlockNode; import org.perlonjava.frontend.astnode.LabelNode; import org.perlonjava.frontend.astnode.ListNode; @@ -102,7 +104,7 @@ public static BlockWithScope parseBlock(Parser parser, boolean exitScope) { statements.add(statement); } else { // This should never happen - log and skip - parser.ctx.logDebug("WARNING: parseStatement returned null at token: " + token.text); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("WARNING: parseStatement returned null at token: " + token.text); } token = peek(parser); diff --git a/src/main/java/org/perlonjava/frontend/parser/ParseHeredoc.java b/src/main/java/org/perlonjava/frontend/parser/ParseHeredoc.java index 9c024913a..c66b04e5f 100644 --- a/src/main/java/org/perlonjava/frontend/parser/ParseHeredoc.java +++ b/src/main/java/org/perlonjava/frontend/parser/ParseHeredoc.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.frontend.astnode.ListNode; import org.perlonjava.frontend.astnode.Node; import org.perlonjava.frontend.astnode.OperatorNode; @@ -25,7 +27,7 @@ static OperatorNode parseHeredoc(Parser parser, String tokenText) { node.setAnnotation("indent", indent); LexerToken token = TokenUtils.peek(parser); - parser.ctx.logDebug("Heredoc " + token); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Heredoc " + token); tokenText = token.text; String delimiter = ""; String identifier = ""; @@ -62,7 +64,7 @@ static OperatorNode parseHeredoc(Parser parser, String tokenText) { } node.setAnnotation("identifier", identifier); - parser.ctx.logDebug("Heredoc " + node); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Heredoc " + node); parser.getHeredocNodes().add(node); return node; } @@ -88,7 +90,7 @@ public static void parseHeredocAfterNewline(Parser parser) { List tokens = parser.tokens; int newlineIndex = parser.tokenIndex; - parser.ctx.logDebug("ParseHeredoc.parseHeredocAfterNewline: Starting at tokenIndex=" + newlineIndex + ", heredoc count=" + heredocNodes.size() + ", total tokens=" + tokens.size()); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("ParseHeredoc.parseHeredocAfterNewline: Starting at tokenIndex=" + newlineIndex + ", heredoc count=" + heredocNodes.size() + ", total tokens=" + tokens.size()); // Create a list to track heredocs we couldn't process List deferredHeredocs = new ArrayList<>(); @@ -100,12 +102,12 @@ public static void parseHeredocAfterNewline(Parser parser) { String identifier = (String) heredocNode.getAnnotation("identifier"); boolean indent = heredocNode.getBooleanAnnotation("indent"); - parser.ctx.logDebug("Processing heredoc with identifier: " + identifier + ", delimiter: " + delimiter); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Processing heredoc with identifier: " + identifier + ", delimiter: " + delimiter); // Check if we have enough tokens to potentially find this heredoc // If we're near the end of tokens and haven't found content yet, defer this heredoc if (newlineIndex + 1 >= tokens.size()) { - parser.ctx.logDebug("Deferring heredoc " + identifier + " - not enough tokens in current context"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Deferring heredoc " + identifier + " - not enough tokens in current context"); deferredHeredocs.add(heredocNode); continue; } @@ -118,19 +120,19 @@ public static void parseHeredocAfterNewline(Parser parser) { boolean foundTerminator = false; // Track if we found the terminator boolean lastTokenWasNewline = false; // Track if last token was a newline - parser.ctx.logDebug(" Looking for heredoc content starting at token index: " + currentIndex); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug(" Looking for heredoc content starting at token index: " + currentIndex); while (currentIndex < tokens.size()) { LexerToken token = tokens.get(currentIndex); // Debug: Log current token - parser.ctx.logDebug(" Token[" + currentIndex + "]: type=" + token.type + ", text='" + token.text.replace("\n", "\\n") + "'"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug(" Token[" + currentIndex + "]: type=" + token.type + ", text='" + token.text.replace("\n", "\\n") + "'"); if (token.type == LexerTokenType.NEWLINE || (!identifier.isEmpty() && token.type == LexerTokenType.EOF)) { lastTokenWasNewline = (token.type == LexerTokenType.NEWLINE); // End of the current line String line = currentLine.toString(); - parser.ctx.logDebug(" Completed line: '" + line + "'"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug(" Completed line: '" + line + "'"); lines.add(line); currentLine.setLength(0); // Reset the current line @@ -147,8 +149,8 @@ public static void parseHeredocAfterNewline(Parser parser) { // Determine the indentation of the end marker indentWhitespace = line.substring(0, line.length() - lineToCompare.length()); - parser.ctx.logDebug("Detected end marker indentation: '" + indentWhitespace + "'"); - parser.ctx.logDebug("Found heredoc terminator '" + identifier + "' at token index " + currentIndex); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Detected end marker indentation: '" + indentWhitespace + "'"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Found heredoc terminator '" + identifier + "' at token index " + currentIndex); foundTerminator = true; // Mark that we found the terminator break; } @@ -171,7 +173,7 @@ public static void parseHeredocAfterNewline(Parser parser) { (currentIndex < tokens.size() && tokens.get(currentIndex).type == LexerTokenType.EOF))) { // The last line we collected should be the content // An implicit blank line at EOF terminates the heredoc - parser.ctx.logDebug("Blank heredoc terminated by EOF after newline"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Blank heredoc terminated by EOF after newline"); foundTerminator = true; } // If we're at EOF and still haven't found the terminator, this is an error @@ -181,7 +183,7 @@ else if (currentIndex >= tokens.size() || heredocError(parser, heredocNode); } else { // Otherwise, if we're in a nested context, defer for parent to handle - parser.ctx.logDebug("Heredoc " + identifier + " terminator not found in current context - deferring"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Heredoc " + identifier + " terminator not found in current context - deferring"); deferredHeredocs.add(heredocNode); continue; } @@ -208,7 +210,7 @@ else if (currentIndex >= tokens.size() || } String string = content.toString(); - parser.ctx.logDebug("Final heredoc content: <<" + string + ">>"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Final heredoc content: <<" + string + ">>"); // Rewrite the heredoc node, according to the delimiter Node operand = null; @@ -240,7 +242,7 @@ else if (currentIndex >= tokens.size() || // Re-add deferred heredocs back to the queue for processing in outer context heredocNodes.addAll(deferredHeredocs); - parser.ctx.logDebug("ParseHeredoc.parseHeredocAfterNewline: Deferred " + deferredHeredocs.size() + " heredocs back to queue"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("ParseHeredoc.parseHeredocAfterNewline: Deferred " + deferredHeredocs.size() + " heredocs back to queue"); parser.debugHeredocState("HEREDOC_AFTER_CLEAR"); parser.tokenIndex = newlineIndex; diff --git a/src/main/java/org/perlonjava/frontend/parser/ParseInfix.java b/src/main/java/org/perlonjava/frontend/parser/ParseInfix.java index a6bf5e483..53e3c8a06 100644 --- a/src/main/java/org/perlonjava/frontend/parser/ParseInfix.java +++ b/src/main/java/org/perlonjava/frontend/parser/ParseInfix.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.frontend.astnode.*; import org.perlonjava.frontend.lexer.LexerToken; import org.perlonjava.frontend.lexer.LexerTokenType; @@ -311,7 +313,7 @@ public static Node parseInfixOperation(Parser parser, Node left, int precedence) } else { // Method call with ->method or ->method() right = SubroutineParser.parseSubroutineCall(parser, true); - parser.ctx.logDebug("method call -> " + right); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("method call -> " + right); } parser.parsingForLoopVariable = false; @@ -387,7 +389,7 @@ private static List parseArraySubscript(Parser parser) { } static List parseHashSubscript(Parser parser) { - parser.ctx.logDebug("parseHashSubscript start"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseHashSubscript start"); int currentIndex = parser.tokenIndex; LexerToken ident = TokenUtils.consume(parser); diff --git a/src/main/java/org/perlonjava/frontend/parser/ParseMapGrepSort.java b/src/main/java/org/perlonjava/frontend/parser/ParseMapGrepSort.java index 129fefa1d..0c45f4f15 100644 --- a/src/main/java/org/perlonjava/frontend/parser/ParseMapGrepSort.java +++ b/src/main/java/org/perlonjava/frontend/parser/ParseMapGrepSort.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.frontend.astnode.*; import org.perlonjava.frontend.lexer.LexerToken; import org.perlonjava.frontend.lexer.LexerTokenType; @@ -31,7 +33,7 @@ static BinaryOperatorNode parseSort(Parser parser, LexerToken token) { new IdentifierNode(subName, parser.tokenIndex), parser.tokenIndex); operand = ListParser.parseZeroOrMoreList(parser, 0, false, false, false, false); operand.handle = var; - parser.ctx.logDebug("parseSort identifier: " + operand.handle + " : " + operand); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseSort identifier: " + operand.handle + " : " + operand); } else { try { operand = ListParser.parseZeroOrMoreList(parser, 1, true, false, false, false); @@ -53,7 +55,7 @@ static BinaryOperatorNode parseSort(Parser parser, LexerToken token) { if (paren) { TokenUtils.consume(parser, OPERATOR, ")"); } - parser.ctx.logDebug("parseSort: " + operand.handle + " : " + operand); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseSort: " + operand.handle + " : " + operand); } } @@ -106,7 +108,7 @@ static BinaryOperatorNode parseMapGrep(Parser parser, LexerToken token) { if (paren) { TokenUtils.consume(parser, OPERATOR, ")"); } - parser.ctx.logDebug("parseMap: " + operand.handle + " : " + operand); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseMap: " + operand.handle + " : " + operand); } // transform: { 123 } diff --git a/src/main/java/org/perlonjava/frontend/parser/Parser.java b/src/main/java/org/perlonjava/frontend/parser/Parser.java index a536021e0..4f9425628 100644 --- a/src/main/java/org/perlonjava/frontend/parser/Parser.java +++ b/src/main/java/org/perlonjava/frontend/parser/Parser.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.backend.jvm.EmitterContext; import org.perlonjava.frontend.astnode.FormatNode; import org.perlonjava.frontend.astnode.Node; @@ -205,11 +207,11 @@ public Node parseExpression(int precedence) { // If the operator is right associative (like exponentiation), parse it with lower precedence. if (ParserTables.RIGHT_ASSOC_OP.contains(token.text)) { - ctx.logDebug("parseExpression `" + token.text + "` precedence: " + tokenPrecedence + " right assoc"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("parseExpression `" + token.text + "` precedence: " + tokenPrecedence + " right assoc"); left = ParseInfix.parseInfixOperation(this, left, tokenPrecedence - 1); // Parse the right side with lower precedence. } else { // Otherwise, parse it normally with the same precedence. - ctx.logDebug("parseExpression `" + token.text + "` precedence: " + tokenPrecedence + " left assoc"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("parseExpression `" + token.text + "` precedence: " + tokenPrecedence + " left assoc"); left = ParseInfix.parseInfixOperation(this, left, tokenPrecedence); } } @@ -237,7 +239,7 @@ public void throwCleanError(String message) { } public void debugHeredocState(String location) { - this.ctx.logDebug("HEREDOC_STATE [" + location + "] tokenIndex=" + tokenIndex + + if (CompilerOptions.DEBUG_ENABLED) this.ctx.logDebug("HEREDOC_STATE [" + location + "] tokenIndex=" + tokenIndex + " heredocCount=" + heredocNodes.size()); } diff --git a/src/main/java/org/perlonjava/frontend/parser/SpecialBlockParser.java b/src/main/java/org/perlonjava/frontend/parser/SpecialBlockParser.java index f2a2b0928..4251fe6b9 100644 --- a/src/main/java/org/perlonjava/frontend/parser/SpecialBlockParser.java +++ b/src/main/java/org/perlonjava/frontend/parser/SpecialBlockParser.java @@ -178,13 +178,13 @@ static RuntimeList runSpecialBlock(Parser parser, String blockPhase, Node block) // Put in the appropriate global map based on variable type if (runtimeValue instanceof RuntimeArray) { GlobalVariable.globalArrays.put(fullName, (RuntimeArray) runtimeValue); - parser.ctx.logDebug("BEGIN block: Aliased array " + fullName); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("BEGIN block: Aliased array " + fullName); } else if (runtimeValue instanceof RuntimeHash) { GlobalVariable.globalHashes.put(fullName, (RuntimeHash) runtimeValue); - parser.ctx.logDebug("BEGIN block: Aliased hash " + fullName); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("BEGIN block: Aliased hash " + fullName); } else if (runtimeValue instanceof RuntimeScalar) { GlobalVariable.globalVariables.put(fullName, (RuntimeScalar) runtimeValue); - parser.ctx.logDebug("BEGIN block: Aliased scalar " + fullName); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("BEGIN block: Aliased scalar " + fullName); } } } @@ -235,7 +235,7 @@ static RuntimeList runSpecialBlock(Parser parser, String blockPhase, Node block) CompilerOptions parsedArgs = parser.ctx.compilerOptions.clone(); parsedArgs.compileOnly = false; // Special blocks are always run - parser.ctx.logDebug("Special block captures " + parser.ctx.symbolTable.getAllVisibleVariables()); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Special block captures " + parser.ctx.symbolTable.getAllVisibleVariables()); RuntimeList result; try { setCurrentScope(parser.ctx.symbolTable); diff --git a/src/main/java/org/perlonjava/frontend/parser/StatementParser.java b/src/main/java/org/perlonjava/frontend/parser/StatementParser.java index 86bc2c112..3fab0526e 100644 --- a/src/main/java/org/perlonjava/frontend/parser/StatementParser.java +++ b/src/main/java/org/perlonjava/frontend/parser/StatementParser.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.backend.jvm.EmitterContext; import org.perlonjava.core.Configuration; import org.perlonjava.frontend.analysis.ExtractValueVisitor; @@ -480,7 +482,7 @@ public static Node parseGivenStatement(Parser parser) { */ public static Node parseUseDeclaration(Parser parser, LexerToken token) { EmitterContext ctx = parser.ctx; - ctx.logDebug("use: " + token.text); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("use: " + token.text); boolean isNoDeclaration = token.text.equals("no"); TokenUtils.consume(parser); // "use" @@ -493,13 +495,13 @@ public static Node parseUseDeclaration(Parser parser, LexerToken token) { // Not a valid module name token throw new PerlCompilerException(parser.tokenIndex, "syntax error", parser.ctx.errorUtil); } - ctx.logDebug("use module: " + token); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("use module: " + token); packageName = IdentifierParser.parseSubroutineIdentifier(parser); if (packageName == null) { throw new PerlCompilerException(parser.tokenIndex, "syntax error", parser.ctx.errorUtil); } fullName = NameNormalizer.moduleToFilename(packageName); - ctx.logDebug("use fullName: " + fullName); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("use fullName: " + fullName); } // Parse Version string @@ -514,7 +516,7 @@ public static Node parseUseDeclaration(Parser parser, LexerToken token) { } } if (versionNode != null) { - parser.ctx.logDebug("use version: " + versionNode + " next:" + TokenUtils.peek(parser)); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("use version: " + versionNode + " next:" + TokenUtils.peek(parser)); // Extract version string using ExtractValueVisitor RuntimeList versionValues = ExtractValueVisitor.getValues(versionNode); if (!versionValues.isEmpty()) { @@ -522,7 +524,7 @@ public static Node parseUseDeclaration(Parser parser, LexerToken token) { // parser.ctx.logDebug("use version String: " + printable(versionString)); versionScalar = versionValues.getFirst(); if (packageName == null) { - parser.ctx.logDebug("use version: check Perl version"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("use version: check Perl version"); VersionHelper.compareVersion( new RuntimeScalar(Configuration.version), versionScalar, @@ -576,7 +578,7 @@ public static Node parseUseDeclaration(Parser parser, LexerToken token) { // Parse the parameter list boolean hasParentheses = TokenUtils.peek(parser).text.equals("("); Node list = ListParser.parseZeroOrMoreList(parser, 0, false, false, false, false); - ctx.logDebug("Use statement list hasParentheses:" + hasParentheses + " ast:" + list); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Use statement list hasParentheses:" + hasParentheses + " ast:" + list); StatementResolver.parseStatementTerminator(parser); @@ -591,15 +593,15 @@ public static Node parseUseDeclaration(Parser parser, LexerToken token) { ctx.errorUtil.getLineNumber(parser.tokenIndex)); try { - ctx.logDebug("Use statement: " + fullName + " called from " + CallerStack.peek(0)); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Use statement: " + fullName + " called from " + CallerStack.peek(0)); // execute 'require(fullName)' RuntimeScalar ret = ModuleOperators.require(new RuntimeScalar(fullName)); - ctx.logDebug("Use statement return: " + ret); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Use statement return: " + ret); if (versionNode != null) { // check module version - parser.ctx.logDebug("use version: check module version"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("use version: check module version"); RuntimeArray args = new RuntimeArray(); RuntimeArray.push(args, new RuntimeScalar(packageName)); RuntimeArray.push(args, versionScalar); @@ -612,7 +614,7 @@ public static Node parseUseDeclaration(Parser parser, LexerToken token) { // Execute the argument list immediately RuntimeList args = runSpecialBlock(parser, "BEGIN", list); - ctx.logDebug("Use statement list: " + args); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Use statement list: " + args); if (hasParentheses && args.isEmpty()) { // do not import } else { @@ -630,12 +632,12 @@ public static Node parseUseDeclaration(Parser parser, LexerToken token) { InheritanceResolver.autoloadEnabled = true; } - ctx.logDebug("Use can(" + packageName + ", " + importMethod + "): " + codeList); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Use can(" + packageName + ", " + importMethod + "): " + codeList); if (codeList.size() == 1) { RuntimeScalar code = codeList.getFirst(); if (code.getBoolean()) { // call the method - ctx.logDebug("Use call : " + importMethod + "(" + args + ")"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("Use call : " + importMethod + "(" + args + ")"); RuntimeArray importArgs = args.getArrayOfAlias(); RuntimeArray.unshift(importArgs, new RuntimeScalar(packageName)); setCurrentScope(parser.ctx.symbolTable); @@ -688,7 +690,7 @@ public static Node parsePackageDeclaration(Parser parser, LexerToken token) { // Parse Version string and store it in the symbol table Node version = parseOptionalPackageVersion(parser); - parser.ctx.logDebug("package version: " + version); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("package version: " + version); if (version != null) { // Extract the actual version value from the node String versionString = null; diff --git a/src/main/java/org/perlonjava/frontend/parser/StatementResolver.java b/src/main/java/org/perlonjava/frontend/parser/StatementResolver.java index 62232aeb2..b70b1488c 100644 --- a/src/main/java/org/perlonjava/frontend/parser/StatementResolver.java +++ b/src/main/java/org/perlonjava/frontend/parser/StatementResolver.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.backend.jvm.ByteCodeSourceMapper; import org.perlonjava.backend.jvm.EmitterMethodCreator; import org.perlonjava.frontend.astnode.*; @@ -33,7 +35,7 @@ public class StatementResolver { public static Node parseStatement(Parser parser, String label) { int currentIndex = parser.tokenIndex; LexerToken token = peek(parser); - parser.ctx.logDebug("parseStatement `" + token.text + "`"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parseStatement `" + token.text + "`"); // Store the current source location - this will be used for stack trace generation ByteCodeSourceMapper.saveSourceLocation(parser.ctx, parser.tokenIndex); @@ -690,7 +692,7 @@ yield new BlockNode( if (isDoWhile) { // Special case: `do { BLOCK } while CONDITION` // Executes the loop at least once - parser.ctx.logDebug("do-while " + expression); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("do-while " + expression); } yield new For3Node(null, false, @@ -723,14 +725,14 @@ public static boolean isHashLiteral(Parser parser) { boolean hasBlockIndicator = false; // Found ;, or statement modifier boolean hasContent = false; // Track if we've seen any content - parser.ctx.logDebug("isHashLiteral START - initial braceCount: " + braceCount); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral START - initial braceCount: " + braceCount); while (braceCount > 0) { LexerToken token = consume(parser); - parser.ctx.logDebug("isHashLiteral token: '" + token.text + "' type:" + token.type + " braceCount:" + braceCount); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral token: '" + token.text + "' type:" + token.type + " braceCount:" + braceCount); if (token.type == LexerTokenType.EOF) { - parser.ctx.logDebug("isHashLiteral EOF reached"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral EOF reached"); break; // Let caller handle EOF error } @@ -748,22 +750,22 @@ public static boolean isHashLiteral(Parser parser) { }; if (oldBraceCount != braceCount) { - parser.ctx.logDebug("isHashLiteral braceCount changed from " + oldBraceCount + " to " + braceCount); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral braceCount changed from " + oldBraceCount + " to " + braceCount); } // Only check for indicators at depth 1 if (braceCount == 1 && !token.text.matches("[{(\\[)}\\]]")) { - parser.ctx.logDebug("isHashLiteral checking token '" + token.text + "' at depth 1"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral checking token '" + token.text + "' at depth 1"); switch (token.text) { case "=>" -> { // Fat comma is a definitive hash indicator - parser.ctx.logDebug("isHashLiteral found => (hash indicator)"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral found => (hash indicator)"); hasHashIndicator = true; } case ";" -> { // Semicolon is a definitive block indicator - parser.ctx.logDebug("isHashLiteral found ; (block indicator)"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral found ; (block indicator)"); hasBlockIndicator = true; } case "=" -> { @@ -774,15 +776,15 @@ public static boolean isHashLiteral(Parser parser) { int searchIndex = parser.tokenIndex - 1; while (searchIndex >= currentIndex && searchIndex < parser.tokens.size()) { LexerToken checkToken = parser.tokens.get(searchIndex); - parser.ctx.logDebug("isHashLiteral checking token '" + checkToken.text + "' at index " + searchIndex); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral checking token '" + checkToken.text + "' at index " + searchIndex); if (checkToken.type == LexerTokenType.IDENTIFIER && ParsePrimary.isIsQuoteLikeOperator(checkToken.text)) { - parser.ctx.logDebug("isHashLiteral found = after quote-like operator '" + checkToken.text + "', treating as q-string delimiter"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral found = after quote-like operator '" + checkToken.text + "', treating as q-string delimiter"); isQStringDelimiter = true; break; } // If we hit a meaningful token that's not a quote-like operator, stop searching if (checkToken.type != LexerTokenType.OPERATOR || !checkToken.text.equals("=")) { - parser.ctx.logDebug("isHashLiteral stopping search at token '" + checkToken.text + "'"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral stopping search at token '" + checkToken.text + "'"); break; } searchIndex--; @@ -803,46 +805,46 @@ public static boolean isHashLiteral(Parser parser) { if (!isQStringDelimiter && looksLikeAssignment) { // This looks like an assignment - parser.ctx.logDebug("isHashLiteral found = (block indicator)"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral found = (block indicator)"); hasBlockIndicator = true; } else { - parser.ctx.logDebug("isHashLiteral found = but not treating as block indicator (q-string or not assignment-like)"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral found = but not treating as block indicator (q-string or not assignment-like)"); } } case "," -> { // Comma alone is not definitive - could be function args or hash // Continue scanning for more evidence - parser.ctx.logDebug("isHashLiteral found comma, continuing scan"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral found comma, continuing scan"); } case "for", "while", "if", "unless", "until", "foreach", "my", "our", "say", "print", "local" -> { // Check if this is a hash key (followed by =>) or statement modifier LexerToken nextToken = TokenUtils.peek(parser); - parser.ctx.logDebug("isHashLiteral found keyword '" + token.text + "', next token: '" + nextToken.text + "'"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral found keyword '" + token.text + "', next token: '" + nextToken.text + "'"); if (!nextToken.text.equals("=>") && !nextToken.text.equals(",")) { // Statement modifier - definitive block indicator - parser.ctx.logDebug("isHashLiteral found statement modifier (block indicator)"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral found statement modifier (block indicator)"); hasBlockIndicator = true; } else { - parser.ctx.logDebug("isHashLiteral keyword followed by => or , (possible hash key)"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral keyword followed by => or , (possible hash key)"); } } default -> { - parser.ctx.logDebug("isHashLiteral token '" + token.text + "' not a special indicator"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral token '" + token.text + "' not a special indicator"); } } } else if (braceCount == 1) { - parser.ctx.logDebug("isHashLiteral skipping bracket token '" + token.text + "' at depth 1"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral skipping bracket token '" + token.text + "' at depth 1"); } // Early exit if we have definitive evidence if (hasBlockIndicator) { - parser.ctx.logDebug("isHashLiteral EARLY EXIT - block indicator found, returning FALSE"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral EARLY EXIT - block indicator found, returning FALSE"); parser.tokenIndex = currentIndex; return false; } if (braceCount == 0) { - parser.ctx.logDebug("isHashLiteral braceCount reached 0, exiting loop"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral braceCount reached 0, exiting loop"); } } @@ -853,20 +855,20 @@ public static boolean isHashLiteral(Parser parser) { // - If we found block indicators, it's a block // - Empty {} is a hash ref // - Otherwise, default to block (safer when parsing is incomplete) - parser.ctx.logDebug("isHashLiteral FINAL DECISION - hasHashIndicator:" + hasHashIndicator + + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral FINAL DECISION - hasHashIndicator:" + hasHashIndicator + " hasBlockIndicator:" + hasBlockIndicator + " hasContent:" + hasContent); if (hasHashIndicator) { - parser.ctx.logDebug("isHashLiteral RESULT: TRUE - hash indicator found"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral RESULT: TRUE - hash indicator found"); return true; } else if (hasBlockIndicator) { - parser.ctx.logDebug("isHashLiteral RESULT: FALSE - block indicator found"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral RESULT: FALSE - block indicator found"); return false; } else if (!hasContent) { - parser.ctx.logDebug("isHashLiteral RESULT: TRUE - empty {} is hash ref"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral RESULT: TRUE - empty {} is hash ref"); return true; // Empty {} is a hash ref } else { - parser.ctx.logDebug("isHashLiteral RESULT: FALSE - default for ambiguous case (assuming block)"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("isHashLiteral RESULT: FALSE - default for ambiguous case (assuming block)"); return false; // Default: assume block when we can't determine } } diff --git a/src/main/java/org/perlonjava/frontend/parser/StringDoubleQuoted.java b/src/main/java/org/perlonjava/frontend/parser/StringDoubleQuoted.java index 72920c5bc..cf2a2d57e 100644 --- a/src/main/java/org/perlonjava/frontend/parser/StringDoubleQuoted.java +++ b/src/main/java/org/perlonjava/frontend/parser/StringDoubleQuoted.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.backend.jvm.EmitterContext; import org.perlonjava.frontend.astnode.*; import org.perlonjava.frontend.lexer.Lexer; @@ -137,7 +139,7 @@ static Node parseDoubleQuotedString(EmitterContext ctx, StringParser.ParsedStrin // In regex context, we preserve escapes for the regex engine var isRegex = !parseEscapes; - ctx.logDebug("parseDoubleQuotedString isRegex:" + isRegex); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("parseDoubleQuotedString isRegex:" + isRegex); // Tokenize the string content var lexer = new Lexer(input); diff --git a/src/main/java/org/perlonjava/frontend/parser/StringParser.java b/src/main/java/org/perlonjava/frontend/parser/StringParser.java index c2958f21c..da1ae8ca4 100644 --- a/src/main/java/org/perlonjava/frontend/parser/StringParser.java +++ b/src/main/java/org/perlonjava/frontend/parser/StringParser.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.backend.jvm.EmitterContext; import org.perlonjava.frontend.astnode.*; import org.perlonjava.frontend.lexer.Lexer; @@ -72,12 +74,12 @@ public static ParsedString parseRawStringWithDelimiter(EmitterContext ctx, List< // Process heredocs at newlines during string parsing if (currentToken.type == LexerTokenType.NEWLINE) { - ctx.logDebug("parseRawStringWithDelimiter: Found NEWLINE at tokPos=" + tokPos + + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("parseRawStringWithDelimiter: Found NEWLINE at tokPos=" + tokPos + ", parser=" + (parser != null) + ", heredocCount=" + (parser != null ? parser.getHeredocNodes().size() : 0)); if (parser != null && !parser.getHeredocNodes().isEmpty()) { - ctx.logDebug("parseRawStringWithDelimiter: Processing heredocs"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("parseRawStringWithDelimiter: Processing heredocs"); // Save the current parser position int savedIndex = parser.tokenIndex; @@ -91,7 +93,7 @@ public static ParsedString parseRawStringWithDelimiter(EmitterContext ctx, List< int afterHeredocTokPos = parser.tokenIndex; int tokensConsumed = afterHeredocTokPos - beforeHeredocTokPos; - ctx.logDebug("parseRawStringWithDelimiter: Heredoc consumed " + tokensConsumed + " tokens"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("parseRawStringWithDelimiter: Heredoc consumed " + tokensConsumed + " tokens"); // If heredoc consumed more than just the newline, we need to handle it if (tokensConsumed > 1) { @@ -334,7 +336,7 @@ public static OperatorNode parseRegexReplace(EmitterContext ctx, ParsedString ra Node replace; if (modifierStr.contains("e")) { // if modifiers include `e`, then parse the `replace` code - ctx.logDebug("regex e-modifier: " + replaceStr); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("regex e-modifier: " + replaceStr); Parser blockParser = new Parser(ctx, new Lexer(replaceStr).tokenize(), parser.getHeredocNodes()); replace = ParseBlock.parseBlock(blockParser); } else if (rawStr.secondBufferStartDelim != '\'') { @@ -548,7 +550,7 @@ static StringNode parseVstring(Parser parser, String vStringPart, int currentInd } } - parser.ctx.logDebug("v-string: " + printable(vStringBuilder.toString()) + " next:" + TokenUtils.peek(parser)); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("v-string: " + printable(vStringBuilder.toString()) + " next:" + TokenUtils.peek(parser)); // Create a StringNode with the constructed v-string return new StringNode(vStringBuilder.toString(), true, currentIndex); diff --git a/src/main/java/org/perlonjava/frontend/parser/StringSegmentParser.java b/src/main/java/org/perlonjava/frontend/parser/StringSegmentParser.java index af1a1ef7f..5b14817ac 100644 --- a/src/main/java/org/perlonjava/frontend/parser/StringSegmentParser.java +++ b/src/main/java/org/perlonjava/frontend/parser/StringSegmentParser.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.backend.jvm.EmitterContext; import org.perlonjava.frontend.analysis.ConstantFoldingVisitor; import org.perlonjava.frontend.astnode.*; @@ -172,7 +174,7 @@ protected void flushCurrentSegment() { protected void parseVariableInterpolation(String sigil) { flushCurrentSegment(); - ctx.logDebug("str sigil"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("str sigil"); Node operand; var isArray = "@".equals(sigil); @@ -197,7 +199,7 @@ protected void parseVariableInterpolation(String sigil) { // Apply @ to dereference the block result operand = new OperatorNode("@", block, tokenIndex); - ctx.logDebug("str @{[...]} operand " + operand); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("str @{[...]} operand " + operand); } catch (PerlCompilerException e) { // Re-throw with offset-aware error reporting createOffsetAwareError(tokenIndex, "Syntax error in @{[...]} block: " + e.getMessage()); @@ -235,7 +237,7 @@ protected void parseVariableInterpolation(String sigil) { } } - ctx.logDebug("str operand " + operand); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("str operand " + operand); } else { // Parse simple variables using shared logic, but keep the exact same flow operand = parseSimpleVariableInterpolation(sigil); @@ -361,7 +363,7 @@ private Node parseSimpleVariableInterpolation(String sigil) { // Add validation that was missing - this fixes $01, $02 issues IdentifierParser.validateIdentifier(parser, identifier, startIndex); - ctx.logDebug("str Identifier: " + identifier); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("str Identifier: " + identifier); // Check if this is a field that needs transformation to $self->{field} // This mirrors the logic in Variable.parseVariable @@ -532,19 +534,19 @@ yield new BinaryOperatorNode("join", * @return the final AST node representing the parsed string */ public Node parse() { - ctx.logDebug("StringSegmentParser.parse: Starting with " + tokens.size() + " tokens, heredoc count: " + parser.getHeredocNodes().size()); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("StringSegmentParser.parse: Starting with " + tokens.size() + " tokens, heredoc count: " + parser.getHeredocNodes().size()); while (true) { if (parser.tokenIndex >= tokens.size()) { - ctx.logDebug("StringSegmentParser.parse: Reached end of tokens at index " + parser.tokenIndex); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("StringSegmentParser.parse: Reached end of tokens at index " + parser.tokenIndex); break; } var token = tokens.get(parser.tokenIndex++); - ctx.logDebug("StringSegmentParser.parse: Token at " + (parser.tokenIndex - 1) + ": type=" + token.type + ", text='" + token.text.replace("\n", "\\n") + "'"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("StringSegmentParser.parse: Token at " + (parser.tokenIndex - 1) + ": type=" + token.type + ", text='" + token.text.replace("\n", "\\n") + "'"); if (token.type == LexerTokenType.EOF) { - ctx.logDebug("StringSegmentParser.parse: Found EOF token"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("StringSegmentParser.parse: Found EOF token"); break; } @@ -552,11 +554,11 @@ public Node parse() { if (token.type == LexerTokenType.NEWLINE) { // Check if there are pending heredocs to process if (!parser.getHeredocNodes().isEmpty()) { - ctx.logDebug("StringSegmentParser: Found NEWLINE with " + parser.getHeredocNodes().size() + " pending heredocs at index " + (parser.tokenIndex - 1)); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("StringSegmentParser: Found NEWLINE with " + parser.getHeredocNodes().size() + " pending heredocs at index " + (parser.tokenIndex - 1)); // Log which heredocs are pending for (OperatorNode heredoc : parser.getHeredocNodes()) { - ctx.logDebug(" Pending heredoc: " + heredoc.getAnnotation("identifier")); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug(" Pending heredoc: " + heredoc.getAnnotation("identifier")); } // Flush current segment before processing heredocs @@ -565,18 +567,18 @@ public Node parse() { // Adjust tokenIndex to point to the NEWLINE token for parseHeredocAfterNewline parser.tokenIndex--; // Back up to the NEWLINE token - ctx.logDebug("StringSegmentParser: Calling parseHeredocAfterNewline with tokenIndex=" + parser.tokenIndex); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("StringSegmentParser: Calling parseHeredocAfterNewline with tokenIndex=" + parser.tokenIndex); // Process ALL heredocs after the newline ParseHeredoc.parseHeredocAfterNewline(parser); // Check if we've consumed all tokens if (parser.tokenIndex >= tokens.size()) { - ctx.logDebug("StringSegmentParser: Heredoc processing consumed all remaining tokens"); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("StringSegmentParser: Heredoc processing consumed all remaining tokens"); break; } - ctx.logDebug("StringSegmentParser: After heredoc processing, tokenIndex = " + parser.tokenIndex + ", remaining tokens = " + (tokens.size() - parser.tokenIndex)); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("StringSegmentParser: After heredoc processing, tokenIndex = " + parser.tokenIndex + ", remaining tokens = " + (tokens.size() - parser.tokenIndex)); // parseHeredocAfterNewline updates parser.tokenIndex, so continue from there continue; @@ -596,7 +598,7 @@ public Node parse() { appendToCurrentSegment(text); } - ctx.logDebug("StringSegmentParser.parse: Finished parsing, segments count: " + segments.size()); + if (CompilerOptions.DEBUG_ENABLED) ctx.logDebug("StringSegmentParser.parse: Finished parsing, segments count: " + segments.size()); return buildResult(); } diff --git a/src/main/java/org/perlonjava/frontend/parser/SubroutineParser.java b/src/main/java/org/perlonjava/frontend/parser/SubroutineParser.java index 0620a4a2b..23cf70842 100644 --- a/src/main/java/org/perlonjava/frontend/parser/SubroutineParser.java +++ b/src/main/java/org/perlonjava/frontend/parser/SubroutineParser.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.backend.bytecode.InterpretedCode; import org.perlonjava.backend.jvm.CompiledCode; import org.perlonjava.backend.jvm.EmitterContext; @@ -45,7 +47,7 @@ static Node parseSubroutineCall(Parser parser, boolean isMethod) { int currentIndex = parser.tokenIndex; String subName = IdentifierParser.parseSubroutineIdentifier(parser); - parser.ctx.logDebug("SubroutineCall subName `" + subName + "` package " + parser.ctx.symbolTable.getCurrentPackage()); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("SubroutineCall subName `" + subName + "` package " + parser.ctx.symbolTable.getCurrentPackage()); if (subName == null) { throw new PerlCompilerException(parser.tokenIndex, "Syntax error", parser.ctx.errorUtil); } @@ -187,7 +189,7 @@ static Node parseSubroutineCall(Parser parser, boolean isMethod) { if (!subExists && !isNewMethod && !isMethod) { subExists = GlobalVariable.existsGlobalCodeRefAsScalar(fullName).getBoolean(); } - parser.ctx.logDebug("SubroutineCall exists " + subExists + " prototype `" + prototype + "` attributes " + attributes); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("SubroutineCall exists " + subExists + " prototype `" + prototype + "` attributes " + attributes); boolean prototypeHasGlob = prototype != null && prototype.contains("*"); @@ -466,11 +468,11 @@ public static Node parseSubroutineDefinition(Parser parser, boolean wantName, St // Check if the next token is an opening parenthesis '(' indicating a prototype. if (peek(parser).text.equals("(")) { if (parser.ctx.symbolTable.isFeatureCategoryEnabled("signatures")) { - parser.ctx.logDebug("Signatures feature enabled"); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Signatures feature enabled"); // If the signatures feature is enabled, we parse a signature. signature = parseSignature(parser, subName); - parser.ctx.logDebug("Signature AST: " + signature); - parser.ctx.logDebug("next token " + peek(parser)); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Signature AST: " + signature); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("next token " + peek(parser)); } else { // If the signatures feature is not enabled, we just parse the prototype as a string. // If a prototype exists, we parse it using 'parseRawString' method which handles it like the 'q()' operator. diff --git a/src/main/java/org/perlonjava/frontend/parser/TokenUtils.java b/src/main/java/org/perlonjava/frontend/parser/TokenUtils.java index fd65284ee..08effc3ed 100644 --- a/src/main/java/org/perlonjava/frontend/parser/TokenUtils.java +++ b/src/main/java/org/perlonjava/frontend/parser/TokenUtils.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.frontend.lexer.LexerToken; import org.perlonjava.frontend.lexer.LexerTokenType; import org.perlonjava.runtime.runtimetypes.PerlCompilerException; @@ -70,13 +72,13 @@ public static String consumeChar(Parser parser) { } else { str = token.text.substring(0, 1); token.text = token.text.substring(1); - parser.ctx.logDebug("consumeChar left: " + token); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("consumeChar left: " + token); if (token.text.equals("=")) { LexerToken next = parser.tokens.get(parser.tokenIndex + 1); if (next.text.equals("=")) { next.text = "=="; parser.tokenIndex++; - parser.ctx.logDebug("consumeChar resync: " + TokenUtils.peek(parser)); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("consumeChar resync: " + TokenUtils.peek(parser)); } } } diff --git a/src/main/java/org/perlonjava/frontend/parser/Variable.java b/src/main/java/org/perlonjava/frontend/parser/Variable.java index 983678a65..cdf6eb2dd 100644 --- a/src/main/java/org/perlonjava/frontend/parser/Variable.java +++ b/src/main/java/org/perlonjava/frontend/parser/Variable.java @@ -1,5 +1,7 @@ package org.perlonjava.frontend.parser; +import org.perlonjava.app.cli.CompilerOptions; + import org.perlonjava.frontend.astnode.*; import org.perlonjava.frontend.lexer.LexerToken; import org.perlonjava.frontend.lexer.LexerTokenType; @@ -152,7 +154,7 @@ public static Node parseVariable(Parser parser, String sigil) { int startIndex = parser.tokenIndex; String varName = IdentifierParser.parseComplexIdentifier(parser, sigil.equals("*")); - parser.ctx.logDebug("Parsing variable: " + varName); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("Parsing variable: " + varName); if (varName != null) { if (varName.isEmpty()) { @@ -291,7 +293,7 @@ static Node parseArrayHashAccessInBraces(Parser parser, Node operand, boolean is if (operand == null) { throw new PerlCompilerException(parser.tokenIndex, "syntax error: Missing closing bracket", parser.ctx.errorUtil); } - parser.ctx.logDebug("str operand " + operand); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("str operand " + operand); } case "{" -> { // Hash access @@ -299,7 +301,7 @@ static Node parseArrayHashAccessInBraces(Parser parser, Node operand, boolean is if (operand == null) { throw new PerlCompilerException(parser.tokenIndex, "syntax error: Missing closing brace", parser.ctx.errorUtil); } - parser.ctx.logDebug("str operand " + operand); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("str operand " + operand); } case "->" -> { // Method call or dereference @@ -315,7 +317,7 @@ static Node parseArrayHashAccessInBraces(Parser parser, Node operand, boolean is if (operand == null) { throw new PerlCompilerException(parser.tokenIndex, "syntax error: Unterminated dereference", parser.ctx.errorUtil); } - parser.ctx.logDebug("str operand " + operand); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("str operand " + operand); } default -> { // Not a dereference we can handle @@ -412,7 +414,7 @@ static Node parseArrayHashAccess(Parser parser, Node operand, boolean isRegex) { throw new PerlCompilerException(parser.tokenIndex, "syntax error: Missing closing bracket", parser.ctx.errorUtil); } operand = result; - parser.ctx.logDebug("str operand " + operand); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("str operand " + operand); } case "{" -> { // Hash access @@ -429,7 +431,7 @@ static Node parseArrayHashAccess(Parser parser, Node operand, boolean isRegex) { throw new PerlCompilerException(parser.tokenIndex, "syntax error: Missing closing brace", parser.ctx.errorUtil); } operand = result; - parser.ctx.logDebug("str operand " + operand); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("str operand " + operand); } case "->" -> { // Method call or dereference @@ -446,7 +448,7 @@ static Node parseArrayHashAccess(Parser parser, Node operand, boolean isRegex) { throw new PerlCompilerException(parser.tokenIndex, "syntax error: Unterminated dereference", parser.ctx.errorUtil); } operand = result; - parser.ctx.logDebug("str operand " + operand); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("str operand " + operand); } default -> { // Not a dereference we can handle @@ -597,7 +599,7 @@ static Node parseCoderefVariable(Parser parser, LexerToken token) { return node; } - parser.ctx.logDebug("parse & node: " + node); + if (CompilerOptions.DEBUG_ENABLED) parser.ctx.logDebug("parse & node: " + node); // Check if the node is an OperatorNode with a BinaryOperatorNode operand if (node instanceof OperatorNode operatorNode) {