From 453105eff91c915e5b28cdaa81f11837f8540802 Mon Sep 17 00:00:00 2001 From: ARCJ137442 <61109168+ARCJ137442@users.noreply.github.com> Date: Mon, 25 Mar 2024 14:14:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20:sparkles:=20=E5=88=9D=E6=AD=A5?= =?UTF-8?q?=E6=94=AF=E6=8C=81NARS-Python=EF=BC=88=E7=9B=B4=E6=8E=A5exe?= =?UTF-8?q?=E5=90=AF=E5=8A=A8=EF=BC=89=E4=B8=8EOpenJunars=EF=BC=88?= =?UTF-8?q?=E9=80=9A=E8=BF=87Julia=E8=BF=90=E8=A1=8C=E6=97=B6=EF=BC=89?= =?UTF-8?q?=EF=BC=9B=E9=87=8D=E5=91=BD=E5=90=8D=E3=80=8CCIN=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0=E3=80=8D=E7=9B=AE=E5=BD=95=EF=BC=9B=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. ✅初步完成对现有常见NARS实现的启动器 2. 📌目前仍然只有OpenNARS、ONA、PyNARS能真正投入实际使用 - 其它都多少存在「IO困难」或「进程残留」问题 - 📄已在自述文档中说明 --- .vscode/settings.json | 1 + Cargo.lock | 2 +- Cargo.toml | 13 ++-- README.md | 25 ++++++- src/cin_implements/mod.rs | 34 ++++++++++ src/cin_implements/nars_python/launcher.rs | 48 ++++++++++++++ src/cin_implements/nars_python/mod.rs | 40 +++++++++++ src/cin_implements/nars_python/translators.rs | 63 ++++++++++++++++++ .../ona/launcher.rs | 0 .../ona/mod.rs | 0 .../ona/translators.rs | 5 -- src/cin_implements/open_junars/launcher.rs | 61 +++++++++++++++++ src/cin_implements/open_junars/mod.rs | 55 ++++++++++++++++ src/cin_implements/open_junars/translators.rs | 66 +++++++++++++++++++ .../opennars/launcher.rs | 6 +- .../opennars/mod.rs | 0 .../opennars/translators.rs | 0 .../pynars/launcher.rs | 4 +- .../pynars/mod.rs | 6 +- .../pynars/translators.rs | 0 src/impl_runtime/mod.rs | 18 ----- src/lib.rs | 2 +- src/process_io/io_process.rs | 30 ++++++++- src/runtime/command_vm/runtime.rs | 6 +- 24 files changed, 444 insertions(+), 41 deletions(-) create mode 100644 src/cin_implements/mod.rs create mode 100644 src/cin_implements/nars_python/launcher.rs create mode 100644 src/cin_implements/nars_python/mod.rs create mode 100644 src/cin_implements/nars_python/translators.rs rename src/{impl_runtime => cin_implements}/ona/launcher.rs (100%) rename src/{impl_runtime => cin_implements}/ona/mod.rs (100%) rename src/{impl_runtime => cin_implements}/ona/translators.rs (93%) create mode 100644 src/cin_implements/open_junars/launcher.rs create mode 100644 src/cin_implements/open_junars/mod.rs create mode 100644 src/cin_implements/open_junars/translators.rs rename src/{impl_runtime => cin_implements}/opennars/launcher.rs (96%) rename src/{impl_runtime => cin_implements}/opennars/mod.rs (100%) rename src/{impl_runtime => cin_implements}/opennars/translators.rs (100%) rename src/{impl_runtime => cin_implements}/pynars/launcher.rs (95%) rename src/{impl_runtime => cin_implements}/pynars/mod.rs (64%) rename src/{impl_runtime => cin_implements}/pynars/translators.rs (100%) delete mode 100644 src/impl_runtime/mod.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index 380b1f0..2262744 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,6 +2,7 @@ "rust-analyzer.cargo.features": "all", "editor.formatOnSave": true, "cSpell.words": [ + "Errno", "runpy", "traceback" ] diff --git a/Cargo.lock b/Cargo.lock index 8ffe7c1..9e6fa75 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = 3 [[package]] name = "babel_nar" -version = "0.4.0" +version = "0.5.0" dependencies = [ "nar_dev_utils", "narsese", diff --git a/Cargo.toml b/Cargo.toml index f331345..ebe83a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "babel_nar" -version = "0.4.0" +version = "0.5.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -38,8 +38,13 @@ features = [] # ! 【2024-03-21 09:24:51】暂时没有特性 default = [] # 大杂烩 bundled = [ - "implements" + "cin_implements" ] # 各个独立的特性 # -# 具体接口实现:OpenNARS、ONA、NARS-Python、OpenJunars、PyNARS…… -implements = [] +# 具体接口实现: +# ✅OpenNARS +# ✅ONA +# ✅PyNARS +# ✅NARS-Python(不稳定) +# ✅OpenJunars(不稳定) +cin_implements = [] diff --git a/README.md b/README.md index 81dd3ad..92e1a06 100644 --- a/README.md +++ b/README.md @@ -4,11 +4,11 @@ 该项目使用[语义化版本 2.0.0](https://semver.org/)进行版本号管理。 -[**NAVM.rs**](https://github.com/ARCJ137442/NAVM.rs)的**运行时** +[**NAVM.rs**](https://github.com/ARCJ137442/NAVM.rs)的**运行时**及[CIN](#cin-computer-implement-of-nars)启动器 - 前身为[**BabelNAR.jl**](https://github.com/ARCJ137442/BabelNAR.jl) -- 🎯为「非公理虚拟机模型」提供程序实现 -- 🎯为各CIN实现**统一输入输出**形式 +- ✨为「非公理虚拟机模型」提供程序实现 +- ✨统一各[CIN](#cin-computer-implement-of-nars)的**输入输出**形式,聚合使用各大NARS实现 ## 概念 @@ -22,7 +22,26 @@ 🔗参考[**NAVM.jl**的对应部分](https://github.com/ARCJ137442/navm.jl?tab=readme-ov-file#commonnarsese) +## 各CIN对接情况 + +🕒最后更新时间:【2024-03-25 14:10:36】 + +| CIN | 实现方法 | 进程安全 | 输入转译 | 输出转译 | +| :---------- | :---------: | :--: | :--: | :--: | +| OpenNARS | `java -jar` | ✅ | ✅ | 🚧 | +| ONA | 直接启动exe | ✅ | ✅ | 🚧 | +| PyNARS | `python -m` | ✅ | 🚧 | 🚧 | +| NARS-Python | 直接启动exe | ❓ | 🚧 | 🚧 | +| OpenJunars | `julia` | ✅ | ❌ | ❌ | + +注: + +- 🚧输入输出转译功能仍然在从[BabelNAR_Implements](https://github.com/ARCJ137442/BabelNAR_Implements.jl)迁移 +- ❓NARS-Python的exe界面可能会在终止后延时关闭 +- ❌基于`julia`启动OpenJunars脚本`launch.jl`时,对「输出捕获」尚未有成功记录 + ## 参考 - [BabelNAR](https://github.com/ARCJ137442/BabelNAR.jl) +- [BabelNAR_Implements](https://github.com/ARCJ137442/BabelNAR_Implements.jl) - [NAVM.rs](https://github.com/ARCJ137442/NAVM.rs) diff --git a/src/cin_implements/mod.rs b/src/cin_implements/mod.rs new file mode 100644 index 0000000..4a929ee --- /dev/null +++ b/src/cin_implements/mod.rs @@ -0,0 +1,34 @@ +//! 对各CIN实现「非公理虚拟机」模型 +//! * 🎯基于「NAVM指令/NAVM输出↔字符串」的转换 +//! +//! ! ⚠️关键问题:进程残留 +//! * ✅单元测试中利用`taskkill`初步解决 +//! * ❌【2024-03-25 13:36:30】集成测试`cargo t --all-features`中未能解决 +//! * ❗// ! ↑【少用乃至不用这条命令】 +//! +//! ? 【2024-03-25 12:48:08】如何兼顾「复用」「性能」与「简洁」 +//! * 📌复用:将OpenNARS、ONA抽象成「基于jar的启动逻辑」「基于exe的启动逻辑」等方式,以便后续重复使用 +//! * 📄case:目前ONA、NARS-Python都是基于exe的启动方式 +//! * 📌性能:避免过多的封装、粗暴复合导致的空间浪费 +//! * 📄case:「启动器套启动器」在尝试抽象出「exe启动器」时,因为「没法预先指定转译器」在「复用『设置转译器』函数」时 +//! * ❌不希望在「exe启动器」「jar启动器」中重复套【包含一长串函数闭包】 +//! * 📌简洁:代码简明易懂,方便调用方使用 +//! * 📄case:期望能有形如`ONA::new(path).launch()`的语法 +//! * 💭不希望出现「强行模拟」的情况,如`mod ONA {pub fn new(..) {..}}` +//! * ❌不希望因此再全小写/封装命名空间,如`impls::ona::new` +//! * ❓目前的问题:在Rust基于「特征」的组合式设计哲学下,如何进行兼顾三者的优秀设计 + +// OpenNARS +pub mod opennars; + +// ONA +pub mod ona; + +// NARS-Python +pub mod nars_python; + +// PyNARS +pub mod pynars; + +// OpenJunars +pub mod open_junars; diff --git a/src/cin_implements/nars_python/launcher.rs b/src/cin_implements/nars_python/launcher.rs new file mode 100644 index 0000000..0487ef4 --- /dev/null +++ b/src/cin_implements/nars_python/launcher.rs @@ -0,0 +1,48 @@ +//! NARS-Python运行时的启动器 +//! * 🎯允许NARS-Python对原先运行时特别配置功能,同时也支持为NARS-Python定制配置 +//! * 🚩只憎加「启动器」类型,而不增加「运行时」类型 +//! * ✨不同启动器可以启动到相同运行时 + +use super::{input_translate, output_translate}; +use crate::runtime::{CommandVm, CommandVmRuntime}; +use navm::vm::VmLauncher; +use std::path::PathBuf; + +// ! NARS-Python作为一个独立的`main.exe`,没有默认的启动参数 + +/// NARS-Python运行时启动器 +/// * 🎯配置NARS-Python专有的东西 +/// * 🚩基于exe文件启动NARS-Python exe +/// * 🚩【2024-03-25 08:51:30】目前保留原有缩写的大小写风格,与OpenNARS、PyNARS一致 +#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct NARSPython { + /// exe文件路径 + exe_path: PathBuf, +} + +// ! 🚩【2024-03-25 09:37:22】目前暂时不提取至「VmExe」:参考`impl_runtime`根目录说明 + +impl NARSPython { + /// 构造函数 + pub fn new(exe_path: impl Into) -> Self { + Self { + // 转换为路径 + exe_path: exe_path.into(), + } + } +} + +/// 启动到「命令行运行时」 +impl VmLauncher for NARSPython { + fn launch(self) -> CommandVmRuntime { + // 构造指令,并启动虚拟机 + CommandVm::new(self.exe_path) + // * 🚩固定的「输入输出转换器」 + .input_translator(input_translate) + .output_translator(output_translate) + // 🔥启动 + .launch() + } +} + +// ! 单元测试见[`super`] diff --git a/src/cin_implements/nars_python/mod.rs b/src/cin_implements/nars_python/mod.rs new file mode 100644 index 0000000..9eee0cd --- /dev/null +++ b/src/cin_implements/nars_python/mod.rs @@ -0,0 +1,40 @@ +//! 「非公理虚拟机」的NARS-Python运行时 +//! * 🚩只提供「一行启动」的功能封装 +//! * 🎯无需自行配置「输入输出转译器」 + +// 转译器 +util::mod_and_pub_use! { + // 转译器 + translators + // 启动器 + launcher +} + +/// 单元测试 +#[cfg(test)] +mod tests { + use super::*; + use crate::runtime::{test::EXE_PATH_NARS_PYTHON, CommandVmRuntime}; + use navm::vm::{VmLauncher, VmRuntime}; + + #[test] + fn test() { + // 从别的地方获取exe路径 + let exe_path = EXE_PATH_NARS_PYTHON; + // 一行代码启动NARS-Python + let vm = NARSPython::new(exe_path).launch(); + // 运行专有测试 + _test_nars_python(vm) + } + + /// 测试/NARS-Python + pub(crate) fn _test_nars_python(vm: CommandVmRuntime) { + // TODO: 实际的测试代码 + + // 等待四秒钟,让exe的界面显示出来 + std::thread::sleep(std::time::Duration::from_secs(4)); + + // 终止虚拟机运行时 + vm.terminate().expect("无法终止虚拟机"); + } +} diff --git a/src/cin_implements/nars_python/translators.rs b/src/cin_implements/nars_python/translators.rs new file mode 100644 index 0000000..fc475d8 --- /dev/null +++ b/src/cin_implements/nars_python/translators.rs @@ -0,0 +1,63 @@ +//! NARS-Python在「命令行运行时」的转译器 +//! * 🎯维护与NARS-Python exe的交互 +//! * 📌基于命令行输入输出的字符串读写 +//! * ✨NAVM指令→字符串 +//! * ✨字符串→NAVM输出 + +use navm::{ + cmd::Cmd, + output::{Operation, Output}, +}; +use util::ResultS; + +/// NARS-Python的「输入转译」函数 +/// * 🎯用于将统一的「NAVM指令」转译为「NARS-Python输入」 +/// +/// TODO: ⚠️其有一种不同的语法,需要细致解析 +pub fn input_translate(cmd: Cmd) -> ResultS { + let content = match cmd { + // 直接使用「末尾」,此时将自动格式化任务(可兼容「空预算」的形式) + Cmd::NSE(..) => cmd.tail(), + // CYC指令:运行指定周期数 + // ! NARS-Python Shell同样是自动步进的 + Cmd::CYC(n) => n.to_string(), + // 其它类型 + _ => return Err(format!("该指令类型暂不支持:{cmd:?}")), + }; + // 转译 + Ok(content) +} + +/// NARS-Python的「输出转译」函数 +/// * 🎯用于将NARS-Python Shell的输出(字符串)转译为「NAVM输出」 +/// * 🚩直接根据选取的「头部」进行匹配 +pub fn output_translate(content: String) -> ResultS { + // 根据冒号分隔一次,然后得到「头部」 + let head = content.split_once(':').unwrap_or(("", "")).0.to_lowercase(); + // 根据「头部」生成输出 + let output = match &*head { + // TODO: 有待适配 + "answer" => Output::ANSWER { + content_raw: content, + // TODO: 有待捕获转译 + narsese: None, + }, + "derived" => Output::OUT { + content_raw: content, + // TODO: 有待捕获转译 + narsese: None, + }, + "input" => Output::IN { content }, + "exe" => Output::EXE { + content_raw: content, + // TODO: 有待捕获转译 + operation: Operation::new("UNKNOWN", [].into_iter()), + }, + "err" | "error" => Output::ERROR { + description: content, + }, + _ => Output::OTHER { content }, + }; + // 返回 + Ok(output) +} diff --git a/src/impl_runtime/ona/launcher.rs b/src/cin_implements/ona/launcher.rs similarity index 100% rename from src/impl_runtime/ona/launcher.rs rename to src/cin_implements/ona/launcher.rs diff --git a/src/impl_runtime/ona/mod.rs b/src/cin_implements/ona/mod.rs similarity index 100% rename from src/impl_runtime/ona/mod.rs rename to src/cin_implements/ona/mod.rs diff --git a/src/impl_runtime/ona/translators.rs b/src/cin_implements/ona/translators.rs similarity index 93% rename from src/impl_runtime/ona/translators.rs rename to src/cin_implements/ona/translators.rs index 993ef64..bcb81e6 100644 --- a/src/impl_runtime/ona/translators.rs +++ b/src/cin_implements/ona/translators.rs @@ -48,11 +48,6 @@ pub fn output_translate(content: String) -> ResultS { narsese: None, }, "input" => Output::IN { content }, - "anticipate" => Output::ANTICIPATE { - content_raw: content, - // TODO: 有待捕获转译 - narsese: None, - }, "exe" => Output::EXE { content_raw: content, // TODO: 有待捕获转译 diff --git a/src/cin_implements/open_junars/launcher.rs b/src/cin_implements/open_junars/launcher.rs new file mode 100644 index 0000000..92a0630 --- /dev/null +++ b/src/cin_implements/open_junars/launcher.rs @@ -0,0 +1,61 @@ +//! Julia模块 启动器 +//! * 📌OpenJunars运行时的启动器 +//! * 🎯允许OpenJunars对原先运行时特别配置功能,同时也支持为OpenJunars定制配置 +//! * 🚩只憎加「启动器」类型,而不增加「运行时」类型 +//! * ✨不同启动器可以启动到相同运行时 +//! * 🚩通过`julia`运行`.jl`脚本启动 + +use super::{input_translate, output_translate}; +use crate::runtime::{CommandVm, CommandVmRuntime}; +use navm::vm::VmLauncher; +use std::{path::PathBuf, process::Command}; + +/// 启动Julia运行时的命令 +const COMMAND_JULIA: &str = "julia"; + +/// ! Julia启动脚本无需附加参数 + +/// OpenJunars运行时启动器 +/// * 🎯配置OpenJunars专有的东西 +/// * 🎯以Julia模块形式启动OpenJunars +/// * 📌没有内置的「音量」配置 +/// * 🚩【2024-03-25 08:55:07】基于Julia模块文件启动OpenJunars +/// * 默认预置指令:``julia [`.jl`脚本文件路径]`` +/// * 🚩【2024-03-25 09:15:07】删去[`Default`]派生:因为可能导致无效的路径 +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct VmJulia { + /// Julia脚本文件路径 + jl_path: PathBuf, +} + +/// 兼容性别名 +#[doc(alias = "VmJulia")] +pub type OpenJunars = VmJulia; + +impl VmJulia { + pub fn new(jl_path: impl Into) -> Self { + Self { + // 转换为路径 + jl_path: jl_path.into(), + } + } +} + +/// 启动到「命令行运行时」 +impl VmLauncher for VmJulia { + fn launch(self) -> CommandVmRuntime { + // 构造指令 + let mut command = Command::new(COMMAND_JULIA); + command.arg(self.jl_path); + + // 构造并启动虚拟机 + CommandVm::from_io_process(command.into()) + // * 🚩固定的「输入输出转换器」 + .input_translator(input_translate) + .output_translator(output_translate) + // 🔥启动 + .launch() + } +} + +// ! 单元测试见[`super`] diff --git a/src/cin_implements/open_junars/mod.rs b/src/cin_implements/open_junars/mod.rs new file mode 100644 index 0000000..3f0899c --- /dev/null +++ b/src/cin_implements/open_junars/mod.rs @@ -0,0 +1,55 @@ +//! 「非公理虚拟机」的OpenJunars运行时 +//! * 🚩只提供「一行启动」的功能封装 +//! * 🎯无需自行配置「输入输出转译器」 + +// 转译器 +util::mod_and_pub_use! { + // 转译器 + translators + // 启动器 + launcher +} + +/// 单元测试 +#[cfg(test)] +mod tests { + #![allow(unused)] + + use super::*; + use crate::runtime::{test::JL_PATH_OPEN_JUNARS, CommandVmRuntime}; + use narsese::conversion::string::impl_lexical::shortcuts::*; + use navm::{ + cmd::Cmd, + vm::{VmLauncher, VmRuntime}, + }; + + #[test] + fn test() { + // 从别的地方获取jl路径 + let jl_path = JL_PATH_OPEN_JUNARS; + // 一行代码启动OpenJunars + let vm = OpenJunars::new(jl_path).launch(); + // 运行专有测试 + // ! ❌【2024-03-25 13:56:21】目前无法截取到Julia运行时输出,弃用 + // _test_opennars(vm) + _test_open_junars(vm) + } + + /// 测试/OpenJunars + pub(crate) fn _test_open_junars(mut vm: CommandVmRuntime) { + // ! ❌【2024-03-25 13:55:57】无效:似乎无法截取到Julia运行时输出 + + // vm.input_cmd(Cmd::NSE(nse_task!( B>.))) + // .expect("无法输入指令"); + + // // 等待四秒钟,让Junars启动 + // std::thread::sleep(std::time::Duration::from_secs(1)); + + // vm.input_cmd(Cmd::NSE(nse_task!( B>.))) + // .expect("无法输入指令"); + // std::thread::sleep(std::time::Duration::from_secs(6)); + + // 终止虚拟机运行时 + vm.terminate().expect("无法终止虚拟机"); + } +} diff --git a/src/cin_implements/open_junars/translators.rs b/src/cin_implements/open_junars/translators.rs new file mode 100644 index 0000000..4aeffc0 --- /dev/null +++ b/src/cin_implements/open_junars/translators.rs @@ -0,0 +1,66 @@ +//! OpenJunars在「命令行运行时」的转译器 +//! * 📌基于命令行输入输出的字符串读写 +//! * ✨NAVM指令→字符串 +//! * ✨字符串→NAVM输出 +//! +//! TODO: 🚧自OpenNARS复制而来,一些地方需要特别适配 + +use navm::{ + cmd::Cmd, + output::{Operation, Output}, +}; +use util::ResultS; + +/// OpenJunars的「输入转译」函数 +/// * 🎯用于将统一的「NAVM指令」转译为「OpenJunars Shell输入」 +pub fn input_translate(cmd: Cmd) -> ResultS { + let content = match cmd { + // 直接使用「末尾」,此时将自动格式化任务(可兼容「空预算」的形式) + Cmd::NSE(..) => cmd.tail(), + // CYC指令:运行指定周期数 + Cmd::CYC(n) => format!(":c {n}"), + // 其它类型 + // * 📌【2024-03-24 22:57:18】基本足够支持 + _ => return Err(format!("该指令类型暂不支持:{cmd:?}")), + }; + // 转译 + Ok(content) +} + +/// OpenJunars的「输出转译」函数 +/// * 🎯用于将OpenJunars Shell的输出(字符串)转译为「NAVM输出」 +/// * 🚩直接根据选取的「头部」进行匹配 +pub fn output_translate(content: String) -> ResultS { + // 根据冒号分隔一次,然后得到「头部」 + let head = content.split_once(':').unwrap_or(("", "")).0.to_lowercase(); + // 根据「头部」生成输出 + let output = match &*head { + "answer" => Output::ANSWER { + content_raw: content, + // TODO: 有待捕获转译 + narsese: None, + }, + "out" => Output::OUT { + content_raw: content, + // TODO: 有待捕获转译 + narsese: None, + }, + "in" => Output::IN { content }, + "anticipate" => Output::ANTICIPATE { + content_raw: content, + // TODO: 有待捕获转译 + narsese: None, + }, + "exe" => Output::EXE { + content_raw: content, + // TODO: 有待捕获转译 + operation: Operation::new("UNKNOWN", [].into_iter()), + }, + "err" | "error" => Output::ERROR { + description: content, + }, + _ => Output::OTHER { content }, + }; + // 返回 + Ok(output) +} diff --git a/src/impl_runtime/opennars/launcher.rs b/src/cin_implements/opennars/launcher.rs similarity index 96% rename from src/impl_runtime/opennars/launcher.rs rename to src/cin_implements/opennars/launcher.rs index febc28f..b91c4b9 100644 --- a/src/impl_runtime/opennars/launcher.rs +++ b/src/cin_implements/opennars/launcher.rs @@ -96,12 +96,12 @@ impl VmLauncher for VmJava { // 🔥启动 .launch(); // 设置初始音量 - self.initial_volume.inspect(|volume| { + if let Some(volume) = self.initial_volume { // 输入指令,并在执行错误时打印信息 - if let Err(e) = vm.input_cmd(Cmd::VOL(*volume)) { + if let Err(e) = vm.input_cmd(Cmd::VOL(volume)) { println!("无法设置初始音量「{volume}」:{e}"); } - }); + }; // 返回 vm } diff --git a/src/impl_runtime/opennars/mod.rs b/src/cin_implements/opennars/mod.rs similarity index 100% rename from src/impl_runtime/opennars/mod.rs rename to src/cin_implements/opennars/mod.rs diff --git a/src/impl_runtime/opennars/translators.rs b/src/cin_implements/opennars/translators.rs similarity index 100% rename from src/impl_runtime/opennars/translators.rs rename to src/cin_implements/opennars/translators.rs diff --git a/src/impl_runtime/pynars/launcher.rs b/src/cin_implements/pynars/launcher.rs similarity index 95% rename from src/impl_runtime/pynars/launcher.rs rename to src/cin_implements/pynars/launcher.rs index 7de99d3..648c825 100644 --- a/src/impl_runtime/pynars/launcher.rs +++ b/src/cin_implements/pynars/launcher.rs @@ -12,8 +12,8 @@ use std::{path::PathBuf, process::Command}; /// 启动Python运行时的命令 const COMMAND_PYTHON: &str = "python"; -/// jar文件启动的默认指令参数 -/// * 🎯默认预置指令:`python -m -jar [.jar文件路径]` +/// 启动Python模块的默认指令参数 +/// * 🎯默认预置指令:`python -m [当前工作目录下的Python模块]` const COMMAND_ARGS_PYTHON: [&str; 1] = ["-m"]; /// PyNARS运行时启动器 diff --git a/src/impl_runtime/pynars/mod.rs b/src/cin_implements/pynars/mod.rs similarity index 64% rename from src/impl_runtime/pynars/mod.rs rename to src/cin_implements/pynars/mod.rs index 8fe325c..6bacfed 100644 --- a/src/impl_runtime/pynars/mod.rs +++ b/src/cin_implements/pynars/mod.rs @@ -1,6 +1,10 @@ //! 「非公理虚拟机」的PyNARS运行时 //! * 🚩只提供「一行启动」的功能封装 //! * 🎯无需自行配置「输入输出转译器」 +//! +//! * ❌【2024-03-25 13:00:14】目前无法在Rust侧解决「杀死子进程后,Python继续输出无关信息」的问题 +//! * 📄主要形式:子进程结束后打印错误堆栈,输出`OSError: [Errno 22] Invalid argument` +//! * ❗无法被Rust捕获,可能是Python运行时的问题(输出未链接到管道) // 转译器 util::mod_and_pub_use! { @@ -22,7 +26,7 @@ mod tests { // 从别的地方获取Python模块根目录、模块自身路径 let root_path = MODULE_ROOT_PYNARS; let module_path = MODULE_PATH_PYNARS; - // 一行代码启动PyNARS | python -m pynars.Console @ "..\..\PyNARS-dev" + // 一行代码启动PyNARS | `python -m pynars.Console` @ "..\..\PyNARS-dev" let vm = PyNARS::new(root_path, module_path).launch(); // 直接复用之前对PyNARS的测试 _test_pynars(vm) diff --git a/src/impl_runtime/pynars/translators.rs b/src/cin_implements/pynars/translators.rs similarity index 100% rename from src/impl_runtime/pynars/translators.rs rename to src/cin_implements/pynars/translators.rs diff --git a/src/impl_runtime/mod.rs b/src/impl_runtime/mod.rs deleted file mode 100644 index b20f63a..0000000 --- a/src/impl_runtime/mod.rs +++ /dev/null @@ -1,18 +0,0 @@ -//! 对各CIN实现「非公理虚拟机」模型 -//! * 🎯基于「NAVM指令/NAVM输出↔字符串」的转换 -//! TODO: 支持各大CIN - -// OpenNARS -pub mod opennars; - -// ONA -pub mod ona; - -// NARS-Python -// TODO: 具体实现 - -// PyNARS -pub mod pynars; - -// OpenJunars -// TODO: 具体实现 diff --git a/src/lib.rs b/src/lib.rs index f5081f8..58ad3ab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,5 +17,5 @@ pub mod tools; // 可选模块 // util::feature_pub_mod_and_reexport! { // 运行时实现 - "implements" => impl_runtime + "cin_implements" => cin_implements } diff --git a/src/process_io/io_process.rs b/src/process_io/io_process.rs index 05112dc..ca419aa 100644 --- a/src/process_io/io_process.rs +++ b/src/process_io/io_process.rs @@ -1,4 +1,15 @@ -//! 封装一个简单的「交互式输入输出」 +//! 一个简单的「IO子进程」类型 +//! +//! ## 功能 +//! +//! * ✅封装「标准IO读写」「进程通信」「线程阻塞」等逻辑 +//! * ✨支持「输出侦听」与「输出通道」两种输出处理方式 +//! +//! ## 疑难问题 +//! +//! * ❗进程残留:可能在调用`kill`方法后,子进程并未真正被杀死 +//! * 🚩【2024-03-25 13:29:14】目前解决方案:调用系统`taskkill`指令,利用进程id强制终止 +//! * ⚠️【2024-03-25 13:32:50】 use std::{ ffi::OsStr, @@ -396,6 +407,8 @@ impl IoProcessManager { /// * 🚩设置终止信号,通知子线程(以及标准IO)终止 /// * 🚩调用[`Child::kill`]方法,终止子进程 /// * ⚠️将借走自身所有权,终止并销毁自身 + /// + /// * ❓不稳定:有时会导致「野进程」的情况 pub fn kill(mut self) -> ResultS<()> { // ! ❌【2024-03-23 21:08:56】暂不独立其中的逻辑:无法脱开对`self`的借用 // ! 📌更具体而言:对其中两个线程`thread_write_in`、`thread_read_out`的部分借用 @@ -422,6 +435,21 @@ impl IoProcessManager { // * ⚠️这意味着「输出侦听器」仍然能对其输出产生响应 // 杀死子进程 // + // * 【2024-03-25 13:22:12】尝试使用`taskkill`强制杀死子进程(不会影响后边的kill) + // * 📌启动失败也不影响:主要目的是在系统层面防止「进程残留」 + // * 📄【2024-03-25 13:23:41】目前对OpenNARS有效(Java进程得到了有效终止) + // * ❗可能是系统特定的 + if let Ok(child) = Command::new("taskkill") + // 强制终止id为子进程id的进程 + .args(["-F", "-PID", &self.process.id().to_string()]) + .spawn() + { + // 等待taskkill杀死子进程 + if let Err(err) = child.wait_with_output() { + println!("指令执行失败!{err:?}"); + } + } + // * 🚩通用:调用`Child`对象的`kill`方法 self.process.kill().transform_err_string() } } diff --git a/src/runtime/command_vm/runtime.rs b/src/runtime/command_vm/runtime.rs index abe9baa..aca5810 100644 --- a/src/runtime/command_vm/runtime.rs +++ b/src/runtime/command_vm/runtime.rs @@ -93,11 +93,13 @@ pub(crate) mod test { // 定义一系列路径 // * 📌【2024-03-25 09:28:36】本地调试:都从根目录`BabelNAR.rs`开始 // * 📄退一级到开发目录,再退一级到各NARS下载目录 + pub const JAR_PATH_OPENNARS: &str = r"..\..\NARS-executables\opennars-304-T-modified.jar"; pub const EXE_PATH_ONA: &str = r"..\..\NARS-executables\NAR.exe"; pub const EXE_PATH_PYNARS: &str = r"..\..\NARS-executables\launch-pynars-console-plus.cmd"; - pub const JAR_PATH_OPENNARS: &str = r"..\..\NARS-executables\opennars-304-T-modified.jar"; pub const MODULE_ROOT_PYNARS: &str = r"..\..\PyNARS-dev"; pub const MODULE_PATH_PYNARS: &str = r"pynars.ConsolePlus"; + pub const EXE_PATH_NARS_PYTHON: &str = r"..\..\NARS-executables\main.exe"; + pub const JL_PATH_OPEN_JUNARS: &str = r"..\..\OpenJunars\launch.jl"; const COMMAND_JAVA: &str = "java"; const COMMAND_ARGS_JAVA: [&str; 2] = ["-Xmx1024m", "-jar"]; @@ -227,7 +229,7 @@ pub(crate) mod test { // 专有闭包 | ⚠️无法再提取出另一个闭包:重复借用问题 let mut input_cmd_and_await = |cmd, contains| input_cmd_and_await_contains(&mut vm, cmd, contains); - input_cmd_and_await(Cmd::VOL(0), ""); + // ! ✅【2024-03-25 13:54:36】现在内置进OpenNARS启动器,不再需要执行此操作 input_cmd_and_await(Cmd::NSE(nse_task!( B>.)), " B>."); input_cmd_and_await(Cmd::NSE(nse_task!( C>.)), " C>."); input_cmd_and_await(Cmd::NSE(nse_task!( C>?)), " C>?");