diff --git a/src/main/java/org/jcnc/snow/cli/commands/CompileCommand.java b/src/main/java/org/jcnc/snow/cli/commands/CompileCommand.java
index 8d77e8d..6cc11e2 100644
--- a/src/main/java/org/jcnc/snow/cli/commands/CompileCommand.java
+++ b/src/main/java/org/jcnc/snow/cli/commands/CompileCommand.java
@@ -1,48 +1,20 @@
package org.jcnc.snow.cli.commands;
-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.cli.CLICommand;
-import org.jcnc.snow.compiler.ir.builder.IRProgramBuilder;
-import org.jcnc.snow.compiler.ir.core.IRFunction;
-import org.jcnc.snow.compiler.ir.core.IRInstruction;
-import org.jcnc.snow.compiler.ir.core.IRProgram;
-import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
-import org.jcnc.snow.compiler.lexer.core.LexerEngine;
-import org.jcnc.snow.compiler.parser.ast.base.Node;
-import org.jcnc.snow.compiler.parser.context.ParserContext;
-import org.jcnc.snow.compiler.parser.core.ParserEngine;
-import org.jcnc.snow.compiler.parser.function.ASTPrinter;
-import org.jcnc.snow.compiler.semantic.core.SemanticAnalyzerRunner;
-import org.jcnc.snow.vm.VMLauncher;
-
-import java.nio.charset.StandardCharsets;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.*;
+import org.jcnc.snow.pkg.dsl.CloudDSLParser;
+import org.jcnc.snow.pkg.model.Project;
+import org.jcnc.snow.pkg.tasks.CompileTask;
+import java.nio.file.Paths;
/**
- * CLI 命令:将 .snow 源文件编译为 VM 字节码(.water 文件)。
+ * CLI 命令:编译当前项目。
*
- * 支持递归目录、多文件编译,可选编译后立即运行。
- * 命令参数支持 run、-o、-d 等。
+ * 负责读取项目描述文件并委托给 {@link CompileTask},
*
- *
- *
- * 用法示例:
- * $ snow compile [run] [-o <name>] [-d <srcDir>] [file1.snow file2.snow …]
- *
*/
public final class CompileCommand implements CLICommand {
- /* --------------------------------------------------------------------- */
- /* CLICommand 接口实现 */
- /* --------------------------------------------------------------------- */
-
@Override
public String name() {
return "compile";
@@ -60,198 +32,14 @@ public final class CompileCommand implements CLICommand {
System.out.println("Options:");
System.out.println(" run compile then run");
System.out.println(" -o specify output base name (without .water suffix)");
- System.out.println(" -d recursively compile all .snow files in directory");
- }
-
- /* --------------------------------------------------------------------- */
- /* 核心:执行 compile 子命令 */
- /* --------------------------------------------------------------------- */
+ System.out.println(" -d recursively compile all .snow files in directory"); }
@Override
public int execute(String[] args) throws Exception {
- /* ---------------- 解析命令行参数 ---------------- */
- boolean runAfterCompile = false;
- String outputName = null;
- Path dir = null;
- List sources = new ArrayList<>();
-
- for (int i = 0; i < args.length; i++) {
- String arg = args[i];
- switch (arg) {
- case "run" -> runAfterCompile = true;
- case "-o" -> {
- if (i + 1 < args.length) outputName = args[++i];
- else {
- System.err.println("Missing argument for -o");
- printUsage();
- return 1;
- }
- }
- case "-d" -> {
- if (i + 1 < args.length) dir = Path.of(args[++i]);
- else {
- System.err.println("Missing argument for -d");
- printUsage();
- return 1;
- }
- }
- default -> {
- if (arg.endsWith(".snow")) {
- sources.add(Path.of(arg));
- } else {
- System.err.println("Unknown option or file: " + arg);
- printUsage();
- return 1;
- }
- }
- }
- }
-
- /* --------- 如果指定了目录则递归收集所有 *.snow --------- */
- if (dir != null) {
- if (!Files.isDirectory(dir)) {
- System.err.println("Not a directory: " + dir);
- return 1;
- }
- try (var stream = Files.walk(dir)) {
- stream.filter(p -> p.toString().endsWith(".snow"))
- .sorted() // 确保稳定顺序
- .forEach(sources::add);
- }
- }
-
- if (sources.isEmpty()) {
- System.err.println("No .snow source files found.");
- return 1;
- }
-
- /* 多文件但未指定 -o 且非目录编译 —— 提示必须指定输出名 */
- if (sources.size() > 1 && outputName == null && dir == null) {
- System.err.println("Please specify output name using -o ");
- return 1;
- }
-
- /* ----------------------------------------------------------------- */
- /* 1. 词法 + 语法分析;同时打印源代码 */
- /* ----------------------------------------------------------------- */
- List allAst = new ArrayList<>();
-
- System.out.println("## 编译器输出");
- System.out.println("### Snow 源代码"); // ========== 新增:二级标题 ==========
-
- for (Path p : sources) {
- if (!Files.exists(p)) {
- System.err.println("File not found: " + p);
- return 1;
- }
-
- String code = Files.readString(p, StandardCharsets.UTF_8);
-
- // ------- 打印每个文件的源码 -------
- System.out.println("#### " + p.getFileName());
- System.out.println(code);
- // --------------------------------------------------------
-
- /* 词法 + 语法 */
- LexerEngine lexer = new LexerEngine(code, p.toString());
- ParserContext ctx = new ParserContext(lexer.getAllTokens(), p.toString());
- allAst.addAll(new ParserEngine(ctx).parse());
- }
-
- /* ----------------------------------------------------------------- */
- /* 2. 语义分析 */
- /* ----------------------------------------------------------------- */
- SemanticAnalyzerRunner.runSemanticAnalysis(allAst, false);
-
- /* ----------------------------------------------------------------- */
- /* 3. AST → IR,并把 main 函数调到首位 */
- /* ----------------------------------------------------------------- */
- IRProgram program = new IRProgramBuilder().buildProgram(allAst);
- program = reorderForEntry(program);
-
- /* ---------------- 打印 AST / IR ---------------- */
- System.out.println("### AST");
- ASTPrinter.printJson(allAst);
-
- System.out.println("### IR");
- System.out.println(program);
-
- /* ----------------------------------------------------------------- */
- /* 4. IR → VM 指令 */
- /* ----------------------------------------------------------------- */
- VMProgramBuilder builder = new VMProgramBuilder();
- List> generators =
- InstructionGeneratorProvider.defaultGenerators();
-
- for (IRFunction fn : program.functions()) {
- Map slotMap =
- new RegisterAllocator().allocate(fn);
- new VMCodeGenerator(slotMap, builder, generators).generate(fn);
- }
- List finalCode = builder.build();
-
- System.out.println("### VM code");
- finalCode.forEach(System.out::println);
-
- /* ----------------------------------------------------------------- */
- /* 5. 写出 .water 文件 */
- /* ----------------------------------------------------------------- */
- Path outputFile = deriveOutputPath(sources, outputName, dir);
- Files.write(outputFile, finalCode, StandardCharsets.UTF_8);
- System.out.println("Written to " + outputFile.toAbsolutePath());
-
- /* ----------------------------------------------------------------- */
- /* 6. 可选:立即运行 VM */
- /* ----------------------------------------------------------------- */
- if (runAfterCompile) {
- System.out.println("\n=== Launching VM ===");
- VMLauncher.main(new String[]{outputFile.toString()});
- }
-
+ // 解析云项目描述文件(默认为工作目录下的 cloud.snow)
+ Project project = CloudDSLParser.parse(Paths.get("project.cloud"));
+ // 委托给 CompileTask 处理核心编译逻辑
+ new CompileTask(project, args).run();
return 0;
}
-
- /* --------------------------------------------------------------------- */
- /* 辅助方法 */
- /* --------------------------------------------------------------------- */
-
- /**
- * 根据输入情况推断 .water 输出文件名:
- *
- * - 若指定 -o,则直接使用
- * - 目录编译:取目录名
- * - 单文件编译:取文件名去掉 .snow
- * - 其他情况兜底为 "program"
- *
- */
- 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 即入口。
- */
- 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;
- }
-}
+}
\ No newline at end of file
diff --git a/src/main/java/org/jcnc/snow/cli/commands/RunCommand.java b/src/main/java/org/jcnc/snow/cli/commands/RunCommand.java
index 09a10d4..c81e6f8 100644
--- a/src/main/java/org/jcnc/snow/cli/commands/RunCommand.java
+++ b/src/main/java/org/jcnc/snow/cli/commands/RunCommand.java
@@ -1,65 +1,41 @@
+
package org.jcnc.snow.cli.commands;
import org.jcnc.snow.cli.CLICommand;
-import org.jcnc.snow.vm.VMLauncher;
+import org.jcnc.snow.pkg.tasks.RunTask;
/**
* CLI 命令:运行已编译的 VM 字节码文件(.water)。
*
- * 用于执行 VM 程序文件。支持传递额外 VM 参数,实际运行由 {@link VMLauncher#main(String[])} 完成。
+ * 仅解析参数并委托给 {@link RunTask},
+ * 将 VM 运行逻辑下沉至 pkg 层,保持 CLI 无状态、薄封装。
*
- *
- *
- * 用法示例:
- * $ snow run program.water [additional VM options]
- *
*/
public final class RunCommand implements CLICommand {
- /**
- * 返回命令名,用于 CLI 调用。
- *
- * @return 命令名称字符串("run")
- */
@Override
public String name() {
return "run";
}
- /**
- * 返回命令简介,用于 CLI 帮助或命令列表展示。
- *
- * @return 命令描述字符串
- */
@Override
public String description() {
- return "Execute compiled VM instructions.";
+ return "Run the compiled VM bytecode file (.water)";
}
- /**
- * 打印该命令的用法说明。
- */
- @Override
- public void printUsage() {
- System.out.println("""
- Usage: snow run [additional VM options]
- """);
- }
-
- /**
- * 执行 run 命令,运行指定的 VM 字节码文件。
- *
- * @param args 剩余参数(不含命令名),第一个应为 .water 文件路径,其后为可选 VM 参数
- * @return 0 表示执行成功,1 表示参数错误
- * @throws Exception VM 启动或执行过程中可能抛出的异常
- */
@Override
public int execute(String[] args) throws Exception {
if (args.length == 0) {
printUsage();
return 1;
}
- VMLauncher.main(args);
+ new RunTask(args).run();
return 0;
}
+
+ @Override
+ public void printUsage() {
+ System.out.println("Usage:");
+ System.out.println(" snow run [vm-options]");
+ }
}
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 fb3fb99..ae39157 100644
--- a/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java
+++ b/src/main/java/org/jcnc/snow/pkg/tasks/CompileTask.java
@@ -1,43 +1,251 @@
package org.jcnc.snow.pkg.tasks;
+import org.jcnc.snow.cli.commands.CompileCommand;
import org.jcnc.snow.pkg.model.Project;
+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.ir.builder.IRProgramBuilder;
+import org.jcnc.snow.compiler.ir.core.IRFunction;
+import org.jcnc.snow.compiler.ir.core.IRInstruction;
+import org.jcnc.snow.compiler.ir.core.IRProgram;
+import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
+import org.jcnc.snow.compiler.lexer.core.LexerEngine;
+import org.jcnc.snow.compiler.parser.ast.base.Node;
+import org.jcnc.snow.compiler.parser.context.ParserContext;
+import org.jcnc.snow.compiler.parser.core.ParserEngine;
+import org.jcnc.snow.compiler.parser.function.ASTPrinter;
+import org.jcnc.snow.compiler.semantic.core.SemanticAnalyzerRunner;
+import org.jcnc.snow.vm.VMLauncher;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.*;
+
/**
- * 编译项目源代码的任务实现。
+ * CLI 命令:将 .snow 源文件编译为 VM 字节码(.water 文件)。
*
- * 实现 {@link Task} 接口,用于构建流程中的编译阶段。当前仅为示例,未集成实际编译器。
+ * 支持递归目录、多文件编译,可选编译后立即运行。
+ * 命令参数支持 run、-o、-d 等。
*
+ *
+ *
+ * 用法示例:
+ * $ snow compile [run] [-o <name>] [-d <srcDir>] [file1.snow file2.snow …]
+ *
*/
public final class CompileTask implements Task {
-
- /** 待编译的项目 */
+ /** 项目信息 */
private final Project project;
+ /** 原始命令行参数 */
+ private final String[] args;
- /**
- * 创建 CompileTask 实例。
- *
- * @param project 目标项目
- */
- public CompileTask(Project project) {
+ public CompileTask(Project project, String[] args) {
this.project = project;
+ this.args = args;
+ }
+
+ public CompileTask(Project project) {
+ this(project, new String[0]);
}
- /**
- * 执行编译任务,打印源代码目录和输出目录。
- *
- * 实际编译尚未实现(TODO)。
- *
- *
- * @throws Exception 预留,未来集成编译器可能抛出异常
- */
@Override
public void run() throws Exception {
- // 获取源码目录和输出目录,默认分别为 "src" 和 "build/classes"
- Path srcDir = Path.of(project.getProperties().getOrDefault("src_dir", "src"));
- Path outDir = Path.of(project.getProperties().getOrDefault("output_dir", "build/classes"));
- System.out.println("[compile] sources=" + srcDir + " output=" + outDir);
- // TODO: 集成实际的编译器
+ // 将任务委托给原始 execute 实现
+ execute(this.args);
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* 执行 compile 子命令 */
+ /* --------------------------------------------------------------------- */
+ public int execute(String[] args) throws Exception {
+ /* ---------------- 解析命令行参数 ---------------- */
+ boolean runAfterCompile = false;
+ String outputName = null;
+ Path dir = null;
+ List sources = new ArrayList<>();
+
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i];
+ switch (arg) {
+ case "run" -> runAfterCompile = true;
+ case "-o" -> {
+ if (i + 1 < args.length) outputName = args[++i];
+ else {
+ System.err.println("Missing argument for -o");
+ new CompileCommand().printUsage();
+ return 1;
+ }
+ }
+ case "-d" -> {
+ if (i + 1 < args.length) dir = Path.of(args[++i]);
+ else {
+ System.err.println("Missing argument for -d");
+ new CompileCommand().printUsage();
+ return 1;
+ }
+ }
+ default -> {
+ if (arg.endsWith(".snow")) {
+ sources.add(Path.of(arg));
+ } else {
+ System.err.println("Unknown option or file: " + arg);
+ new CompileCommand().printUsage();
+ return 1;
+ }
+ }
+ }
+ }
+
+ /* --------- 如果指定了目录则递归收集所有 *.snow --------- */
+ if (dir != null) {
+ if (!Files.isDirectory(dir)) {
+ System.err.println("Not a directory: " + dir);
+ return 1;
+ }
+ try (var stream = Files.walk(dir)) {
+ stream.filter(p -> p.toString().endsWith(".snow"))
+ .sorted() // 确保稳定顺序
+ .forEach(sources::add);
+ }
+ }
+
+ if (sources.isEmpty()) {
+ System.err.println("No .snow source files found.");
+ return 1;
+ }
+
+ /* 多文件但未指定 -o 且非目录编译 —— 提示必须指定输出名 */
+ if (sources.size() > 1 && outputName == null && dir == null) {
+ System.err.println("Please specify output name using -o ");
+ return 1;
+ }
+
+ /* ----------------------------------------------------------------- */
+ /* 1. 词法 + 语法分析;同时打印源代码 */
+ /* ----------------------------------------------------------------- */
+ List allAst = new ArrayList<>();
+
+ System.out.println("## 编译器输出");
+ System.out.println("### Snow 源代码"); // ========== 新增:二级标题 ==========
+
+ for (Path p : sources) {
+ if (!Files.exists(p)) {
+ System.err.println("File not found: " + p);
+ return 1;
+ }
+
+ String code = Files.readString(p, StandardCharsets.UTF_8);
+
+ // ------- 打印每个文件的源码 -------
+ System.out.println("#### " + p.getFileName());
+ System.out.println(code);
+ // --------------------------------------------------------
+
+ /* 词法 + 语法 */
+ LexerEngine lexer = new LexerEngine(code, p.toString());
+ ParserContext ctx = new ParserContext(lexer.getAllTokens(), p.toString());
+ allAst.addAll(new ParserEngine(ctx).parse());
+ }
+
+ /* ----------------------------------------------------------------- */
+ /* 2. 语义分析 */
+ /* ----------------------------------------------------------------- */
+ SemanticAnalyzerRunner.runSemanticAnalysis(allAst, false);
+
+ /* ----------------------------------------------------------------- */
+ /* 3. AST → IR,并把 main 函数调到首位 */
+ /* ----------------------------------------------------------------- */
+ IRProgram program = new IRProgramBuilder().buildProgram(allAst);
+ program = reorderForEntry(program);
+
+ /* ---------------- 打印 AST / IR ---------------- */
+ System.out.println("### AST");
+ ASTPrinter.printJson(allAst);
+
+ System.out.println("### IR");
+ System.out.println(program);
+
+ /* ----------------------------------------------------------------- */
+ /* 4. IR → VM 指令 */
+ /* ----------------------------------------------------------------- */
+ VMProgramBuilder builder = new VMProgramBuilder();
+ List> generators =
+ InstructionGeneratorProvider.defaultGenerators();
+
+ for (IRFunction fn : program.functions()) {
+ Map slotMap =
+ new RegisterAllocator().allocate(fn);
+ new VMCodeGenerator(slotMap, builder, generators).generate(fn);
+ }
+ List finalCode = builder.build();
+
+ System.out.println("### VM code");
+ finalCode.forEach(System.out::println);
+
+ /* ----------------------------------------------------------------- */
+ /* 5. 写出 .water 文件 */
+ /* ----------------------------------------------------------------- */
+ Path outputFile = deriveOutputPath(sources, outputName, dir);
+ Files.write(outputFile, finalCode, StandardCharsets.UTF_8);
+ System.out.println("Written to " + outputFile.toAbsolutePath());
+
+ /* ----------------------------------------------------------------- */
+ /* 6. 可选:立即运行 VM */
+ /* ----------------------------------------------------------------- */
+ if (runAfterCompile) {
+ System.out.println("\n=== Launching VM ===");
+ VMLauncher.main(new String[]{outputFile.toString()});
+ }
+
+ return 0;
+ }
+
+ /* --------------------------------------------------------------------- */
+ /* 辅助方法 */
+ /* --------------------------------------------------------------------- */
+
+ /**
+ * 根据输入情况推断 .water 输出文件名:
+ *
+ * - 若指定 -o,则直接使用
+ * - 目录编译:取目录名
+ * - 单文件编译:取文件名去掉 .snow
+ * - 其他情况兜底为 "program"
+ *
+ */
+ 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 即入口。
+ */
+ 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/pkg/tasks/RunTask.java b/src/main/java/org/jcnc/snow/pkg/tasks/RunTask.java
new file mode 100644
index 0000000..1eb871a
--- /dev/null
+++ b/src/main/java/org/jcnc/snow/pkg/tasks/RunTask.java
@@ -0,0 +1,39 @@
+
+package org.jcnc.snow.pkg.tasks;
+
+import org.jcnc.snow.vm.VMLauncher;
+
+/**
+ * 任务:执行已编译的 VM 字节码文件(.water)。
+ *
+ * 作为 CLI、IDE 插件或其他宿主环境启动虚拟机的统一入口,
+ * 将调用 {@link VMLauncher#main(String[])} 执行。
+ *
+ */
+public final class RunTask implements Task {
+
+ /** 传递给 VM 的完整参数列表(第一个应为 .water 文件路径) */
+ private final String[] args;
+
+ /**
+ * 创建运行任务。
+ *
+ * @param args VM 参数数组(第一个为程序路径,其后为可选参数)
+ */
+ public RunTask(String... args) {
+ this.args = args;
+ }
+
+ /**
+ * 执行运行任务,内部委托 {@link VMLauncher#main(String[])}。
+ *
+ * @throws Exception 虚拟机启动或运行期间抛出的异常
+ */
+ @Override
+ public void run() throws Exception {
+ if (args == null || args.length == 0) {
+ throw new IllegalArgumentException("VM run requires at least the program file path.");
+ }
+ VMLauncher.main(args);
+ }
+}