From 6f81feab3fc35df34c778c82afeffe73dedba6b7 Mon Sep 17 00:00:00 2001 From: Luke Date: Tue, 22 Jul 2025 22:34:15 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E8=99=9A?= =?UTF-8?q?=E6=8B=9F=E6=9C=BA=E5=92=8C=E7=BC=96=E8=AF=91=E5=99=A8=E7=9A=84?= =?UTF-8?q?=E8=B0=83=E8=AF=95=E8=BE=93=E5=87=BA=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../snow/compiler/lexer/core/LexerEngine.java | 10 +- .../utils/SemanticAnalysisReporter.java | 4 +- .../org/jcnc/snow/pkg/tasks/CompileTask.java | 155 ++++++++++-------- .../java/org/jcnc/snow/vm/VMInitializer.java | 6 +- .../java/org/jcnc/snow/vm/VMLauncher.java | 7 +- .../vm/commands/flow/control/CallCommand.java | 32 ++-- .../vm/commands/flow/control/RetCommand.java | 4 +- .../snow/vm/engine/VirtualMachineEngine.java | 5 +- .../snow/vm/module/LocalVariableStore.java | 50 ++++-- .../org/jcnc/snow/vm/utils/LoggingUtils.java | 4 +- 10 files changed, 160 insertions(+), 117 deletions(-) diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java index 1ac0792..672116f 100644 --- a/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java +++ b/src/main/java/org/jcnc/snow/compiler/lexer/core/LexerEngine.java @@ -1,5 +1,6 @@ package org.jcnc.snow.compiler.lexer.core; +import org.jcnc.snow.common.SnowConfig; import org.jcnc.snow.compiler.lexer.base.TokenScanner; import org.jcnc.snow.compiler.lexer.scanners.*; import org.jcnc.snow.compiler.lexer.token.Token; @@ -10,6 +11,8 @@ import java.io.File; import java.util.ArrayList; import java.util.List; +import static org.jcnc.snow.common.SnowConfig.print; + /** * Snow 语言词法分析器核心实现。 *

采用“先扫描 → 后批量校验 → 统一报告”策略: @@ -53,14 +56,17 @@ public class LexerEngine { /* 2. 后置整体校验 */ validateTokens(); /* 3. 打印 token */ - TokenPrinter.print(tokens); + if (SnowConfig.isDebug()) { + TokenPrinter.print(tokens); + } + /* 4. 统一报告错误 */ report(errors); } public static void report(List errors) { if (errors == null || errors.isEmpty()) { - System.out.println("\n## 词法分析通过,没有发现错误\n"); + print("\n## 词法分析通过,没有发现错误\n"); return; } System.err.println("\n词法分析发现 " + errors.size() + " 个错误: "); diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java b/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java index edeb9a5..eb332b8 100644 --- a/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java +++ b/src/main/java/org/jcnc/snow/compiler/semantic/utils/SemanticAnalysisReporter.java @@ -4,6 +4,8 @@ import org.jcnc.snow.compiler.semantic.error.SemanticError; import java.util.List; +import static org.jcnc.snow.common.SnowConfig.print; + /** * {@code SemanticAnalysisReporter} 用于在语义分析结束后汇总并打印所有收集到的 * {@link SemanticError}。为了同时满足“完整错误收集”与“按需快速失败”两种使用场景, @@ -28,7 +30,7 @@ public final class SemanticAnalysisReporter { System.err.println("语义分析发现 " + errors.size() + " 个错误: "); errors.forEach(err -> System.err.println(" " + err)); } else { - System.out.println("\n## 语义分析通过,没有发现错误\n"); + print("\n## 语义分析通过,没有发现错误\n"); } } diff --git a/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java b/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java index 844c2fc..c908125 100644 --- a/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java +++ b/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java @@ -1,12 +1,14 @@ package org.jcnc.snow.pkg.tasks; import org.jcnc.snow.cli.commands.CompileCommand; -import org.jcnc.snow.compiler.backend.utils.OpHelper; +import org.jcnc.snow.common.Mode; +import org.jcnc.snow.common.SnowConfig; import org.jcnc.snow.compiler.backend.alloc.RegisterAllocator; import org.jcnc.snow.compiler.backend.builder.VMCodeGenerator; import org.jcnc.snow.compiler.backend.builder.VMProgramBuilder; import org.jcnc.snow.compiler.backend.core.InstructionGenerator; import org.jcnc.snow.compiler.backend.generator.InstructionGeneratorProvider; +import org.jcnc.snow.compiler.backend.utils.OpHelper; import org.jcnc.snow.compiler.ir.builder.IRProgramBuilder; import org.jcnc.snow.compiler.ir.core.IRFunction; import org.jcnc.snow.compiler.ir.core.IRInstruction; @@ -26,6 +28,8 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.*; +import static org.jcnc.snow.common.SnowConfig.print; + /** * CLI 任务: 编译 .snow 源文件为 VM 字节码(.water 文件)。 *

@@ -39,16 +43,20 @@ import java.util.*; * */ public final class CompileTask implements Task { - /** 项目信息 */ + /** + * 项目信息 + */ private final Project project; - /** 原始命令行参数 */ + /** + * 原始命令行参数 + */ private final String[] args; /** * 创建一个编译任务。 * - * @param project 项目信息对象 - * @param args 命令行参数数组 + * @param project 项目信息对象 + * @param args 命令行参数数组 */ public CompileTask(Project project, String[] args) { this.project = project; @@ -64,6 +72,56 @@ public final class CompileTask implements Task { this(project, new String[0]); } + /* ---------------------- 调试输出工具 ---------------------- */ + + /** + * 推断 .water 输出文件名。 + *

+ * + * @param sources 源文件路径列表 + * @param outName 输出文件名(如有指定,否则为 null) + * @param dir 源码目录(如有指定,否则为 null) + * @return 推断出的输出文件路径(.water 文件) + */ + private static Path deriveOutputPath(List sources, String outName, Path dir) { + String base; + if (outName != null) { + base = outName; + } else if (dir != null) { + base = dir.getFileName().toString(); + } else if (sources.size() == 1) { + base = sources.getFirst().getFileName().toString() + .replaceFirst("\\.snow$", ""); + } else { + base = "program"; + } + return Path.of(base + ".water"); + } + + /** + * 将 main 函数调整至函数列表首位,确保程序入口为 PC=0。 + * + * @param in 原始 IRProgram + * @return 调整入口后的 IRProgram + */ + private static IRProgram reorderForEntry(IRProgram in) { + List ordered = new ArrayList<>(in.functions()); + for (int i = 0; i < ordered.size(); i++) { + if ("main".equals(ordered.get(i).name())) { + Collections.swap(ordered, 0, i); + break; + } + } + IRProgram out = new IRProgram(); + ordered.forEach(out::add); + return out; + } + /** * 执行编译任务。该方法会解析参数并调用 {@link #execute(String[])} 进行实际编译流程。 * @@ -96,6 +154,7 @@ public final class CompileTask implements Task { String arg = args[i]; switch (arg) { case "run" -> runAfterCompile = true; + case "-debug" -> SnowConfig.MODE = Mode.DEBUG; case "-o" -> { if (i + 1 < args.length) outputName = args[++i]; else { @@ -151,8 +210,8 @@ public final class CompileTask implements Task { // ---------------- 1. 词法/语法分析,并打印源代码 ---------------- List allAst = new ArrayList<>(); - System.out.println("## 编译器输出"); - System.out.println("### Snow 源代码"); + print("## 编译器输出"); + print("### Snow 源代码"); for (Path p : sources) { if (!Files.exists(p)) { @@ -163,8 +222,8 @@ public final class CompileTask implements Task { String code = Files.readString(p, StandardCharsets.UTF_8); // 打印源码 - System.out.println("#### " + p.getFileName()); - System.out.println(code); + print("#### " + p.getFileName()); + print(code); // 词法、语法分析 LexerEngine lexer = new LexerEngine(code, p.toString()); @@ -185,11 +244,11 @@ public final class CompileTask implements Task { program = reorderForEntry(program); // 打印 AST 和 IR - System.out.println("### AST"); - ASTPrinter.printJson(allAst); + print("### AST"); + if (SnowConfig.isDebug()) ASTPrinter.printJson(allAst); - System.out.println("### IR"); - System.out.println(program); + print("### IR"); + print(program.toString()); // ---------------- 4. IR → VM 指令 ---------------- VMProgramBuilder builder = new VMProgramBuilder(); @@ -203,74 +262,28 @@ public final class CompileTask implements Task { } List finalCode = builder.build(); - System.out.println("### VM code"); - for (int i = 0; i < finalCode.size(); i++) { - String[] parts = finalCode.get(i).split(" "); - String name = OpHelper.opcodeName(parts[0]); - parts = Arrays.copyOfRange(parts, 1, parts.length); - System.out.printf("%04d: %-10s %s\n", i, name, String.join(" ", parts)); + print("### VM code"); + if (SnowConfig.isDebug()) { + for (int i = 0; i < finalCode.size(); i++) { + String[] parts = finalCode.get(i).split(" "); + String name = OpHelper.opcodeName(parts[0]); + parts = Arrays.copyOfRange(parts, 1, parts.length); + print("%04d: %-10s %s%n", i, name, String.join(" ", parts)); + } } // ---------------- 5. 写出 .water 文件 ---------------- Path outputFile = deriveOutputPath(sources, outputName, dir); Files.write(outputFile, finalCode, StandardCharsets.UTF_8); - System.out.println("Written to " + outputFile.toAbsolutePath()); + print("Written to " + outputFile.toAbsolutePath()); - // ---------------- 6. 可选: 立即运行 VM ---------------- + // ---------------- 6. 立即运行 VM ---------------- if (runAfterCompile) { - System.out.println("\n=== Launching VM ==="); + print("\n=== Launching VM ==="); VMLauncher.main(new String[]{outputFile.toString()}); - System.out.println("\n=== VM exited ==="); + print("\n=== VM exited ==="); } return 0; } - - /** - * 推断 .water 输出文件名。 - *
    - *
  • 如果指定 -o,直接使用该名称。
  • - *
  • 目录编译时,取目录名。
  • - *
  • 单文件编译时,取文件名去掉 .snow 后缀。
  • - *
  • 否则默认 "program"。
  • - *
- * - * @param sources 源文件路径列表 - * @param outName 输出文件名(如有指定,否则为 null) - * @param dir 源码目录(如有指定,否则为 null) - * @return 推断出的输出文件路径(.water 文件) - */ - private static Path deriveOutputPath(List sources, String outName, Path dir) { - String base; - if (outName != null) { - base = outName; - } else if (dir != null) { - base = dir.getFileName().toString(); - } else if (sources.size() == 1) { - base = sources.getFirst().getFileName().toString() - .replaceFirst("\\.snow$", ""); - } else { - base = "program"; - } - return Path.of(base + ".water"); - } - - /** - * 将 main 函数调整至函数列表首位,确保程序入口为 PC=0。 - * - * @param in 原始 IRProgram - * @return 调整入口后的 IRProgram - */ - private static IRProgram reorderForEntry(IRProgram in) { - List ordered = new ArrayList<>(in.functions()); - for (int i = 0; i < ordered.size(); i++) { - if ("main".equals(ordered.get(i).name())) { - Collections.swap(ordered, 0, i); - break; - } - } - IRProgram out = new IRProgram(); - ordered.forEach(out::add); - return out; - } } diff --git a/src/main/java/org/jcnc/snow/vm/VMInitializer.java b/src/main/java/org/jcnc/snow/vm/VMInitializer.java index fc1ce08..ca11e3b 100644 --- a/src/main/java/org/jcnc/snow/vm/VMInitializer.java +++ b/src/main/java/org/jcnc/snow/vm/VMInitializer.java @@ -1,8 +1,8 @@ package org.jcnc.snow.vm; +import org.jcnc.snow.common.Mode; import org.jcnc.snow.vm.execution.CommandLoader; import org.jcnc.snow.vm.engine.VMCommandExecutor; -import org.jcnc.snow.vm.engine.VMMode; import org.jcnc.snow.vm.engine.VirtualMachineEngine; import org.jcnc.snow.vm.io.FilePathResolver; import org.jcnc.snow.vm.utils.VMStateLogger; @@ -45,7 +45,7 @@ public class VMInitializer { * @param vmMode The mode in which the virtual machine should operate. * This can be used to specify different operational modes (e.g., debug mode, normal mode). */ - public static void initializeAndRunVM(String[] args, VMMode vmMode) { + public static void initializeAndRunVM(String[] args, Mode vmMode) { // Retrieve and validate file path String filePath = FilePathResolver.getFilePath(args); if (filePath == null) return; @@ -55,7 +55,7 @@ public class VMInitializer { if (commands.isEmpty()) return; // Execute the commands using the virtual machine engine - VirtualMachineEngine virtualMachineEngine = new VirtualMachineEngine(vmMode); + VirtualMachineEngine virtualMachineEngine = new VirtualMachineEngine(); VMCommandExecutor.executeInstructions(virtualMachineEngine, commands); // Print the virtual machine's state diff --git a/src/main/java/org/jcnc/snow/vm/VMLauncher.java b/src/main/java/org/jcnc/snow/vm/VMLauncher.java index 345d9d1..ecda6cb 100644 --- a/src/main/java/org/jcnc/snow/vm/VMLauncher.java +++ b/src/main/java/org/jcnc/snow/vm/VMLauncher.java @@ -1,6 +1,7 @@ package org.jcnc.snow.vm; -import org.jcnc.snow.vm.engine.VMMode; + +import org.jcnc.snow.common.Mode; import static org.jcnc.snow.vm.VMInitializer.initializeAndRunVM; @@ -12,7 +13,7 @@ import static org.jcnc.snow.vm.VMInitializer.initializeAndRunVM; * *

This class provides the entry point to launch the virtual machine. The main method retrieves the file path * of the VM instructions from the command-line arguments, initializes the VM engine, and runs the VM in the - * specified mode (e.g., {@link VMMode#DEBUG}).

+ * specified mode (e.g., {@link Mode#DEBUG}).

*/ public class VMLauncher { @@ -44,6 +45,6 @@ public class VMLauncher { */ public static void main(String[] args) { // Call the method that initializes and runs the VM in DEBUG mode - initializeAndRunVM(args, VMMode.RUN); + initializeAndRunVM(args, Mode.RUN); } } diff --git a/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java b/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java index 26dda90..90741be 100644 --- a/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java +++ b/src/main/java/org/jcnc/snow/vm/commands/flow/control/CallCommand.java @@ -1,9 +1,11 @@ package org.jcnc.snow.vm.commands.flow.control; -import org.jcnc.snow.vm.engine.VMMode; +import org.jcnc.snow.common.Mode; import org.jcnc.snow.vm.interfaces.Command; import org.jcnc.snow.vm.module.*; +import static org.jcnc.snow.common.SnowConfig.print; + /** * The CallCommand class implements the {@link Command} interface and represents a subroutine/function call * instruction in the virtual machine. @@ -32,18 +34,18 @@ public class CallCommand implements Command { * and control transfer to the target function address. *

* - * @param parts The instruction parameters. Must include: - *
    - *
  • {@code parts[0]}: The "CALL" operator.
  • - *
  • {@code parts[1]}: The target address of the callee function.
  • - *
  • {@code parts[2]}: The number of arguments to pass.
  • - *
- * @param currentPC The current program counter, used to record the return address for after the call. - * @param operandStack The operand stack manager. Arguments are popped from this stack. - * @param callerLVS The local variable store of the caller function (not directly modified here). - * @param callStack The virtual machine's call stack manager, used to push the new stack frame. + * @param parts The instruction parameters. Must include: + *
    + *
  • {@code parts[0]}: The "CALL" operator.
  • + *
  • {@code parts[1]}: The target address of the callee function.
  • + *
  • {@code parts[2]}: The number of arguments to pass.
  • + *
+ * @param currentPC The current program counter, used to record the return address for after the call. + * @param operandStack The operand stack manager. Arguments are popped from this stack. + * @param callerLVS The local variable store of the caller function (not directly modified here). + * @param callStack The virtual machine's call stack manager, used to push the new stack frame. * @return The new program counter value, which is the address of the callee function (i.e., jump target). - * The VM should transfer control to this address after setting up the call frame. + * The VM should transfer control to this address after setting up the call frame. * @throws IllegalArgumentException If the instruction parameters are malformed or missing. * @throws IllegalStateException If the operand stack does not contain enough arguments. */ @@ -61,13 +63,13 @@ public class CallCommand implements Command { int nArgs; try { targetAddr = Integer.parseInt(parts[1]); - nArgs = Integer.parseInt(parts[2]); + nArgs = Integer.parseInt(parts[2]); } catch (NumberFormatException e) { throw new IllegalArgumentException("CALL: malformed operands", e); } /* build new frame & local table for callee */ - LocalVariableStore calleeLVS = new LocalVariableStore(VMMode.RUN); + LocalVariableStore calleeLVS = new LocalVariableStore(); /* transfer arguments: operand stack top is last arg */ for (int slot = nArgs - 1; slot >= 0; slot--) { @@ -80,7 +82,7 @@ public class CallCommand implements Command { new MethodContext("subroutine@" + targetAddr, null)); callStack.pushFrame(newFrame); - System.out.println("\nCalling function at address: " + targetAddr); + print("\nCalling function at address: " + targetAddr); return targetAddr; // jump } } diff --git a/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java b/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java index 505f378..c31ec96 100644 --- a/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java +++ b/src/main/java/org/jcnc/snow/vm/commands/flow/control/RetCommand.java @@ -3,6 +3,8 @@ package org.jcnc.snow.vm.commands.flow.control; import org.jcnc.snow.vm.interfaces.Command; import org.jcnc.snow.vm.module.*; +import static org.jcnc.snow.common.SnowConfig.print; + /** * Implements the {@code RET} instruction (method return). * @@ -44,7 +46,7 @@ public class RetCommand implements Command { finished.getLocalVariableStore().clearVariables(); int returnAddr = finished.getReturnAddress(); - System.out.println("\nReturn " + returnAddr); + print("\nReturn " + returnAddr); return returnAddr; } } diff --git a/src/main/java/org/jcnc/snow/vm/engine/VirtualMachineEngine.java b/src/main/java/org/jcnc/snow/vm/engine/VirtualMachineEngine.java index 0f188ab..704822b 100644 --- a/src/main/java/org/jcnc/snow/vm/engine/VirtualMachineEngine.java +++ b/src/main/java/org/jcnc/snow/vm/engine/VirtualMachineEngine.java @@ -1,5 +1,6 @@ package org.jcnc.snow.vm.engine; +import org.jcnc.snow.common.Mode; import org.jcnc.snow.vm.execution.CommandExecutionHandler; import org.jcnc.snow.vm.module.*; @@ -53,10 +54,10 @@ public class VirtualMachineEngine { * * @param vmMode execution mode (DEBUG / RUN) */ - public VirtualMachineEngine(VMMode vmMode) { + public VirtualMachineEngine() { this.operandStack = new OperandStack(); this.callStack = new CallStack(); - this.localVariableStore = new LocalVariableStore(vmMode); // shared with root frame + this.localVariableStore = new LocalVariableStore(); // shared with root frame this.commandExecutionHandler = new CommandExecutionHandler(operandStack, localVariableStore, callStack); this.programCounter = 0; diff --git a/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java b/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java index 8c64ff9..e1b3bd1 100644 --- a/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java +++ b/src/main/java/org/jcnc/snow/vm/module/LocalVariableStore.java @@ -1,11 +1,10 @@ package org.jcnc.snow.vm.module; +import org.jcnc.snow.common.SnowConfig; import org.jcnc.snow.vm.gui.LocalVariableStoreSwing; import org.jcnc.snow.vm.utils.LoggingUtils; -import org.jcnc.snow.vm.engine.VMMode; import java.util.ArrayList; -import java.util.Objects; /** * The {@code LocalVariableStore} represents a simple dynamically-sized @@ -18,25 +17,23 @@ import java.util.Objects; public class LocalVariableStore { private final ArrayList localVariables; - private final VMMode vmMode; - /* ---------- construction ---------- */ - public LocalVariableStore(VMMode vmMode, int initialCapacity) { + public LocalVariableStore(int initialCapacity) { this.localVariables = new ArrayList<>(initialCapacity); - this.vmMode = vmMode; handleMode(); } - public LocalVariableStore(VMMode vmMode) { + public LocalVariableStore() { this.localVariables = new ArrayList<>(); - this.vmMode = vmMode; handleMode(); } /* ---------- public API ---------- */ - /** Sets the value at {@code index}, expanding the list if necessary. */ + /** + * Sets the value at {@code index}, expanding the list if necessary. + */ public void setVariable(int index, Object value) { ensureCapacity(index + 1); localVariables.set(index, value); @@ -46,10 +43,17 @@ public class LocalVariableStore { * 兼容早期实现: VM 指令译码器可直接调用 store / load * 而无需关心内部命名差异。 * ------------------------------------------------------------ */ - public void store(int index, Object value) { setVariable(index, value); } - public Object load(int index) { return getVariable(index); } + public void store(int index, Object value) { + setVariable(index, value); + } - /** Returns the value at {@code index}. */ + public Object load(int index) { + return getVariable(index); + } + + /** + * Returns the value at {@code index}. + */ public Object getVariable(int index) { /* 修改点 #1 —— 自动扩容以避免 LOAD 越界异常 */ if (index < 0) @@ -58,12 +62,16 @@ public class LocalVariableStore { return localVariables.get(index); // 可能为 null,符合 JVM 语义 } - /** Exposes the backing list (read-only preferred). */ + /** + * Exposes the backing list (read-only preferred). + */ public ArrayList getLocalVariables() { return localVariables; } - /** Prints every slot to the logger. */ + /** + * Prints every slot to the logger. + */ public void printLv() { if (localVariables.isEmpty()) { LoggingUtils.logInfo("Local variable table is empty", ""); @@ -76,7 +84,9 @@ public class LocalVariableStore { } } - /** Clears all variables (used when a stack frame is popped). */ + /** + * Clears all variables (used when a stack frame is popped). + */ public void clearVariables() { localVariables.clear(); } @@ -99,7 +109,9 @@ public class LocalVariableStore { /* ---------- internal helpers ---------- */ - /** Ensures backing list can hold {@code minCapacity} slots. */ + /** + * Ensures backing list can hold {@code minCapacity} slots. + */ private void ensureCapacity(int minCapacity) { /* 修改点 #3 —— 使用 while 循环填充 null,确保 slot 可随机写入 */ while (localVariables.size() < minCapacity) { @@ -107,10 +119,12 @@ public class LocalVariableStore { } } - /** Mode-specific UI hook (unchanged). */ + /** + * Mode-specific UI hook (unchanged). + */ private void handleMode() { /* no-op */ - if (Objects.requireNonNull(vmMode) == VMMode.DEBUG) { + if (SnowConfig.isDebug()) { LocalVariableStoreSwing.display(this, "Local Variable Table"); } } diff --git a/src/main/java/org/jcnc/snow/vm/utils/LoggingUtils.java b/src/main/java/org/jcnc/snow/vm/utils/LoggingUtils.java index 2367cb7..3cc4eeb 100644 --- a/src/main/java/org/jcnc/snow/vm/utils/LoggingUtils.java +++ b/src/main/java/org/jcnc/snow/vm/utils/LoggingUtils.java @@ -3,6 +3,8 @@ package org.jcnc.snow.vm.utils; import java.util.logging.Level; import java.util.logging.Logger; +import static org.jcnc.snow.common.SnowConfig.print; + /** * The LoggingUtils class provides logging functionality, supporting different log levels for output. * This class uses Java's built-in logging system for logging, supporting both console output and log file recording. @@ -51,6 +53,6 @@ public class LoggingUtils { */ public static void logInfo(String title, String message) { // Output the informational message to the console - System.out.println(title + message); + print(title + message); } }