diff --git a/demo/demo-main.scm b/demo/demo-main.scm new file mode 100644 index 00000000..468da6f4 --- /dev/null +++ b/demo/demo-main.scm @@ -0,0 +1,9 @@ +(import (scheme process-context)) + +(define (main) + (display "Hello from demo-main.scm!") + (newline) + (display "Arguments: ") + (display (command-line)) + (newline) +) ;define diff --git a/demo/demo/hello.scm b/demo/demo/hello.scm new file mode 100644 index 00000000..846a8b27 --- /dev/null +++ b/demo/demo/hello.scm @@ -0,0 +1,9 @@ +(define-library (demo hello) + (export main) + (import (scheme base)) + (begin + (define (main) + (display "Hello from (demo hello)!") + (newline)) + ) +) diff --git a/demo/demo/lib.scm b/demo/demo/lib.scm new file mode 100644 index 00000000..ebb1aa6d --- /dev/null +++ b/demo/demo/lib.scm @@ -0,0 +1,10 @@ +(define-library (demo lib) + (export main) + (import (scheme base) + (scheme write)) + (begin + (define (main) + (display "Hello from (demo lib)!") + (newline)) + ) +) diff --git a/demo/liii/demo-main.scm b/demo/liii/demo-main.scm new file mode 100644 index 00000000..63465c21 --- /dev/null +++ b/demo/liii/demo-main.scm @@ -0,0 +1,6 @@ +(import (scheme base)) + +(define (main) + (display "Hello from demo/liii/demo-main.scm!") + (newline) +) ;define diff --git a/devel/200_40.md b/devel/200_40.md new file mode 100644 index 00000000..6826cfe0 --- /dev/null +++ b/devel/200_40.md @@ -0,0 +1,59 @@ +# [200_40] 新增 gf run 子命令 + +## 任务相关的代码文件 +- src/goldfish.hpp +- devel/200_40.md +- demo/demo-main.scm +- demo/liii/demo-main.scm +- demo/demo/hello.scm + +## 如何测试 +```bash +# 构建 +xmake b goldfish + +# 测试运行文件 +bin/gf run demo/demo-main.scm + +# 测试运行带路径的文件 +bin/gf run demo/liii/demo-main.scm + +# 测试运行模块(模块需要在 load path 中) +bin/gf run liii.demo-main + +# 测试不存在的文件 +bin/gf run nonexistent.scm + +# 测试没有 main 函数的文件 +bin/gf run liii.base +``` + +## 2026-03-21 实现 gf run 子命令 + +### What +新增 `gf run` 子命令,支持以下用法: + +1. `gf run x/y/z.scm` - 运行指定文件中的 main 函数 +2. `gf run x.y` - 导入模块 (x y) 后运行 main 函数 +3. `gf run z.scm` - 按文件处理(如果文件不存在则报错) + +### 实现逻辑 +- 解析 run 子命令后的参数 +- 判断目标类型: + - 包含 `/` 或以 `.scm` 结尾:按文件路径处理,检查文件是否存在 + - 其他:按模块名处理(如 `liii.string` -> `(liii string)`) +- 导入或加载后,调用 main 函数 + +### How +在 goldfish.hpp 中添加: +1. 帮助信息中添加 run 子命令说明 +2. 添加 run 子命令处理逻辑: + - 获取目标参数 + - 判断类型并处理(文件或模块) + - 检查 main 函数是否存在 + - 运行 main 函数 + +### Demo 文件 +- `demo/demo-main.scm` - 普通文件形式的 demo +- `demo/liii/demo-main.scm` - 带路径的文件 demo +- `demo/demo/hello.scm` - 模块形式的 demo((demo hello)) diff --git a/src/goldfish.hpp b/src/goldfish.hpp index cbca68de..69b641cc 100644 --- a/src/goldfish.hpp +++ b/src/goldfish.hpp @@ -3369,6 +3369,11 @@ display_help () { cout << " Options:" << endl; cout << " --only PATTERN Run tests matching PATTERN" << endl; cout << " (e.g. json, sicp, list-test.scm)" << endl; + cout << " run TARGET Run main function from TARGET" << endl; + cout << " TARGET can be:" << endl; + cout << " FILE.scm Load file and run main" << endl; + cout << " x/y/z.scm Load file and run main" << endl; + cout << " module.name Import (module name) and run main" << endl; #ifdef GOLDFISH_WITH_REPL cout << " repl Enter interactive REPL mode" << endl; #endif @@ -4524,6 +4529,84 @@ repl_for_community_edition (s7_scheme* sc, int argc, char** argv) { return 0; } + // 处理 run 子命令 + if (command == "run") { + // 获取 TARGET 参数 + string target; + for (int i= command_index + 1; i < argc; ++i) { + string arg= argv[i]; + if (arg == "--mode" || arg == "-m") { + i++; // skip mode value + continue; + } + if (arg.rfind ("--mode=", 0) == 0 || arg.rfind ("-m=", 0) == 0) { + continue; + } + target= arg; + break; + } + if (target.empty ()) { + std::cerr << "Error: 'run' requires TARGET argument.\n" << std::endl; + s7_close_output_port (sc, s7_current_error_port (sc)); + s7_set_current_error_port (sc, old_port); + if (gc_loc != -1) s7_gc_unprotect_at (sc, gc_loc); + exit (1); + } + + // 判断类型并处理 + if (target.find ('/') != string::npos || target.rfind (".scm") == target.length () - 4) { + // 包含 / 或以 .scm 结尾,按文件路径处理 + // 检查文件是否存在 + std::error_code ec; + if (!fs::exists (target, ec) || !fs::is_regular_file (target, ec)) { + s7_close_output_port (sc, s7_current_error_port (sc)); + s7_set_current_error_port (sc, old_port); + if (gc_loc != -1) s7_gc_unprotect_at (sc, gc_loc); + std::cerr << "Error: File not found: " << target << std::endl; + return 1; + } + goldfish_eval_file (sc, target, true); + } + else { + // 按模块名处理,例如: liii.string -> (liii string) + string import_expr= "(import (" + target + "))"; + // 将 . 替换为空格 + for (size_t i= 0; i < import_expr.length (); ++i) { + if (import_expr[i] == '.') import_expr[i]= ' '; + } + s7_eval_c_string (sc, import_expr.c_str ()); + } + + errmsg= s7_get_output_string (sc, s7_current_error_port (sc)); + if ((errmsg) && (*errmsg)) { + cout << errmsg; + s7_close_output_port (sc, s7_current_error_port (sc)); + s7_set_current_error_port (sc, old_port); + if (gc_loc != -1) s7_gc_unprotect_at (sc, gc_loc); + return 1; + } + + // 检查并调用 main 函数 + s7_pointer main_func= s7_name_to_value (sc, "main"); + if ((!main_func) || (!s7_is_procedure (main_func))) { + s7_close_output_port (sc, s7_current_error_port (sc)); + s7_set_current_error_port (sc, old_port); + if (gc_loc != -1) s7_gc_unprotect_at (sc, gc_loc); + std::cerr << "Error: No main function found in target: " << target << std::endl; + return 1; + } + + // 调用 main 函数 + s7_call (sc, main_func, s7_nil (sc)); + + errmsg= s7_get_output_string (sc, s7_current_error_port (sc)); + if ((errmsg) && (*errmsg)) cout << errmsg; + s7_close_output_port (sc, s7_current_error_port (sc)); + s7_set_current_error_port (sc, old_port); + if (gc_loc != -1) s7_gc_unprotect_at (sc, gc_loc); + return 0; + } + // 处理直接执行文件(以 .scm 结尾或存在的文件) // 检查是否是文件 std::error_code ec;