diff --git a/src/impl_runtime/mod.rs b/src/impl_runtime/mod.rs index ad5a807..b20f63a 100644 --- a/src/impl_runtime/mod.rs +++ b/src/impl_runtime/mod.rs @@ -12,7 +12,7 @@ pub mod ona; // TODO: 具体实现 // PyNARS -// TODO: 具体实现 +pub mod pynars; // OpenJunars // TODO: 具体实现 diff --git a/src/impl_runtime/ona/launcher.rs b/src/impl_runtime/ona/launcher.rs index 66bf981..b8b4301 100644 --- a/src/impl_runtime/ona/launcher.rs +++ b/src/impl_runtime/ona/launcher.rs @@ -5,7 +5,10 @@ use super::{input_translate, output_translate}; use crate::runtime::{CommandVm, CommandVmRuntime}; -use navm::vm::VmLauncher; +use navm::{ + cmd::Cmd, + vm::{VmLauncher, VmRuntime}, +}; use std::{path::PathBuf, process::Command}; /// ONA Shell启动的默认指令参数 @@ -14,19 +17,25 @@ const COMMAND_ARGS_ONA: [&str; 1] = ["shell"]; /// ONA运行时启动器 /// * 🎯配置ONA专有的东西 -/// * 🎯以Java运行时专有形式启动ONA /// * 🚩基于exe文件启动ONA Shell /// * 默认预置指令:`[.exe文件路径] shell` -/// * 📌【2024-03-25 08:41:16】目前跟随Rust命名规则,仅首字母大写 +/// * 🚩【2024-03-25 08:51:30】目前保留原有缩写的大小写风格,与OpenNARS、PyNARS一致 #[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct Ona { +pub struct ONA { /// exe文件路径 exe_path: PathBuf, - /// ONA Shell - default_volume: Option, + /// ONA Shell的初始音量 + /// * 🚩可能没有:此时不会输入指令 + initial_volume: Option, } -impl Ona { +// ! 🚩【2024-03-25 09:37:22】目前暂时不提取至「VmExe」:预置的`shell`参数需要被处理 +// /// 兼容性别名 +// #[doc(alias = "VmExe")] +// pub type OpenNARS = VmExe; + +impl ONA { + /// 构造函数 pub fn new(exe_path: impl Into) -> Self { Self { // 转换为路径 @@ -38,7 +47,7 @@ impl Ona { } /// 启动到「命令行运行时」 -impl VmLauncher for Ona { +impl VmLauncher for ONA { fn launch(self) -> CommandVmRuntime { // 构造指令 let mut command = Command::new(self.exe_path); @@ -46,12 +55,20 @@ impl VmLauncher for Ona { command.args(COMMAND_ARGS_ONA); // 构造并启动虚拟机 - CommandVm::from_io_process(command.into()) + let mut vm = CommandVm::from_io_process(command.into()) // * 🚩固定的「输入输出转换器」 .input_translator(input_translate) .output_translator(output_translate) // 🔥启动 - .launch() + .launch(); + // 选择性设置初始音量 + if let Some(volume) = self.initial_volume { + // 输入指令,并在执行错误时打印信息 + if let Err(e) = vm.input_cmd(Cmd::VOL(volume)) { + println!("无法设置初始音量「{volume}」:{e}"); + } + }; + vm } } diff --git a/src/impl_runtime/ona/mod.rs b/src/impl_runtime/ona/mod.rs index 70afe15..51bfa18 100644 --- a/src/impl_runtime/ona/mod.rs +++ b/src/impl_runtime/ona/mod.rs @@ -19,10 +19,10 @@ mod tests { #[test] fn test() { - // 从别的地方获取jar路径 - let jar_path = EXE_PATH_ONA; + // 从别的地方获取exe路径 + let exe_path = EXE_PATH_ONA; // 一行代码启动ONA - let vm = Ona::new(jar_path).launch(); + let vm = ONA::new(exe_path).launch(); // 直接复用之前对ONA的测试 _test_ona(vm) } diff --git a/src/impl_runtime/opennars/launcher.rs b/src/impl_runtime/opennars/launcher.rs index 660f897..febc28f 100644 --- a/src/impl_runtime/opennars/launcher.rs +++ b/src/impl_runtime/opennars/launcher.rs @@ -1,11 +1,16 @@ -//! OpenNARS运行时的启动器 +//! Java jar启动器 +//! * 📌OpenNARS运行时的启动器 //! * 🎯允许OpenNARS对原先运行时特别配置功能,同时也支持为OpenNARS定制配置 +//! * 🚩从jar文件启动NARS //! * 🚩只憎加「启动器」类型,而不增加「运行时」类型 //! * ✨不同启动器可以启动到相同运行时 use super::{input_translate, output_translate}; use crate::runtime::{CommandVm, CommandVmRuntime}; -use navm::vm::VmLauncher; +use navm::{ + cmd::Cmd, + vm::{VmLauncher, VmRuntime}, +}; use std::{path::PathBuf, process::Command}; /// 启动Java运行时的命令 @@ -13,23 +18,50 @@ const COMMAND_JAVA: &str = "java"; /// jar文件启动的默认指令参数 /// * 🎯默认预置指令:`java -Xmx1024m -jar [.jar文件路径]` -const COMMAND_ARGS_JAVA: [&str; 2] = ["-Xmx1024m", "-jar"]; +/// * 🚩实际上"-Xmx1024m"非必要 +const COMMAND_ARGS_JAVA: [&str; 1] = ["-jar"]; -/// OpenNARS运行时启动器 +/// Java运行时启动配置参数:初始堆大小/最小堆大小 +#[inline(always)] +fn command_arg_xms(size: usize) -> String { + format!("-Xms{size}m") +} + +/// Java运行时启动配置参数:最大堆大小 +#[inline(always)] +fn command_arg_xmx(size: usize) -> String { + format!("-Xmx{size}m") +} + +/// Java jar启动器 /// * 🎯配置OpenNARS专有的东西 /// * 🎯以Java运行时专有形式启动OpenNARS /// * 🚩基于jar文件启动OpenNARS Shell -/// * 默认预置指令:`java -Xmx1024m -jar [.jar文件路径]` +/// * 默认预置指令:`java -jar [.jar文件路径]` #[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct OpenNARS { +pub struct VmJava { /// jar文件路径 /// * 📌必须有 jar_path: PathBuf, - /// OpenNARS Shell - default_volume: Option, + /// NARS的初始音量 + /// * 🚩可能没有:此时不会输入指令 + initial_volume: Option, + /// Java运行时的初始堆大小/最小堆大小 + /// * 📄在Java指令中的参数:`-Xms[数值]m` + /// * 🚩可能没有:此时不会附加参数 + min_heap_size: Option, + /// Java运行时的最大堆大小 + /// * 📄在Java指令中的参数:`-Xmx[数值]m` + /// * 🚩可能没有:此时不会附加参数 + max_heap_size: Option, } -impl OpenNARS { +/// 兼容性别名 +#[doc(alias = "VmJava")] +pub type OpenNARS = VmJava; + +impl VmJava { + /// 构造函数 pub fn new(jar_path: impl Into) -> Self { Self { // 转换为路径 @@ -41,20 +73,37 @@ impl OpenNARS { } /// 启动到「命令行运行时」 -impl VmLauncher for OpenNARS { +impl VmLauncher for VmJava { fn launch(self) -> CommandVmRuntime { // 构造指令 let mut command_java = Command::new(COMMAND_JAVA); // * 📝这里的`args`、`arg都返回的可变借用。。 command_java.args(COMMAND_ARGS_JAVA).arg(self.jar_path); + // 选择性添加参数 |设置初始音量 + if let Some(size) = self.min_heap_size { + command_java.arg(command_arg_xms(size)); + } + if let Some(size) = self.max_heap_size { + command_java.arg(command_arg_xmx(size)); + } + // 构造并启动虚拟机 - CommandVm::from_io_process(command_java.into()) + let mut vm = CommandVm::from_io_process(command_java.into()) // * 🚩固定的「输入输出转换器」 .input_translator(input_translate) .output_translator(output_translate) // 🔥启动 - .launch() + .launch(); + // 设置初始音量 + self.initial_volume.inspect(|volume| { + // 输入指令,并在执行错误时打印信息 + if let Err(e) = vm.input_cmd(Cmd::VOL(*volume)) { + println!("无法设置初始音量「{volume}」:{e}"); + } + }); + // 返回 + vm } } diff --git a/src/impl_runtime/pynars/launcher.rs b/src/impl_runtime/pynars/launcher.rs new file mode 100644 index 0000000..7de99d3 --- /dev/null +++ b/src/impl_runtime/pynars/launcher.rs @@ -0,0 +1,77 @@ +//! Python模块 启动器 +//! * 📌PyNARS运行时的启动器 +//! * 🎯允许PyNARS对原先运行时特别配置功能,同时也支持为PyNARS定制配置 +//! * 🚩只憎加「启动器」类型,而不增加「运行时」类型 +//! * ✨不同启动器可以启动到相同运行时 + +use super::{input_translate, output_translate}; +use crate::runtime::{CommandVm, CommandVmRuntime}; +use navm::vm::VmLauncher; +use std::{path::PathBuf, process::Command}; + +/// 启动Python运行时的命令 +const COMMAND_PYTHON: &str = "python"; + +/// jar文件启动的默认指令参数 +/// * 🎯默认预置指令:`python -m -jar [.jar文件路径]` +const COMMAND_ARGS_PYTHON: [&str; 1] = ["-m"]; + +/// PyNARS运行时启动器 +/// * 🎯配置PyNARS专有的东西 +/// * 🎯以Python模块形式启动PyNARS +/// * 📌没有内置的「音量」配置 +/// * ⚠️该配置参考的是PyNARS的`ConsolePlus`模块 +/// * 🚩【2024-03-25 08:55:07】基于Python模块文件启动PyNARS Shell +/// * 默认预置指令:`python -m [Python模块根目录] [Python模块路径]` +/// * 🚩【2024-03-25 09:15:07】删去[`Default`]派生:因为可能导致无效的路径 +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct VmPython { + /// 根目录 + /// * 📄`root/home/dev/pynars` + root_path: PathBuf, + + /// 模块路径 + /// * 📌相对根目录而言 + /// * 📄`pynars.Console` + /// * 📄`root_path` + `pynars.Console` => `root_path/pynars/Console` + module_path: String, +} + +/// 兼容性别名 +#[doc(alias = "VmPython")] +pub type PyNARS = VmPython; + +impl VmPython { + pub fn new(root_path: impl Into, module_path: &str) -> Self { + Self { + // 转换为路径 + root_path: root_path.into(), + // 转换为字符串 + module_path: module_path.to_string(), + } + } +} + +/// 启动到「命令行运行时」 +impl VmLauncher for VmPython { + fn launch(self) -> CommandVmRuntime { + // 构造指令 + let mut command = Command::new(COMMAND_PYTHON); + command + // * 🚩设置指令工作目录 + // * 📝`python -m`无法自行指定所执行的工作目录,必须在`Command`中设置 + .current_dir(self.root_path) // 以此设置当前工作目录 + .args(COMMAND_ARGS_PYTHON) + .arg(self.module_path); + + // 构造并启动虚拟机 + CommandVm::from_io_process(command.into()) + // * 🚩固定的「输入输出转换器」 + .input_translator(input_translate) + .output_translator(output_translate) + // 🔥启动 + .launch() + } +} + +// ! 单元测试见[`super`] diff --git a/src/impl_runtime/pynars/mod.rs b/src/impl_runtime/pynars/mod.rs new file mode 100644 index 0000000..8fe325c --- /dev/null +++ b/src/impl_runtime/pynars/mod.rs @@ -0,0 +1,30 @@ +//! 「非公理虚拟机」的PyNARS运行时 +//! * 🚩只提供「一行启动」的功能封装 +//! * 🎯无需自行配置「输入输出转译器」 + +// 转译器 +util::mod_and_pub_use! { + // 转译器 + translators + // 启动器 + launcher +} + +/// 单元测试 +#[cfg(test)] +mod tests { + use super::*; + use crate::runtime::test::{_test_pynars, MODULE_PATH_PYNARS, MODULE_ROOT_PYNARS}; + use navm::vm::VmLauncher; + + #[test] + fn test() { + // 从别的地方获取Python模块根目录、模块自身路径 + let root_path = MODULE_ROOT_PYNARS; + let module_path = MODULE_PATH_PYNARS; + // 一行代码启动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/impl_runtime/pynars/translators.rs new file mode 100644 index 0000000..def5b0f --- /dev/null +++ b/src/impl_runtime/pynars/translators.rs @@ -0,0 +1,69 @@ +//! ONA在「命令行运行时」的转译器 +//! * 🎯维护与ONA Shell的交互 +//! * 📌基于命令行输入输出的字符串读写 +//! * ✨NAVM指令→字符串 +//! * ✨字符串→NAVM输出 + +use navm::{ + cmd::Cmd, + output::{Operation, Output}, +}; +use util::ResultS; + +/// ONA的「输入转译」函数 +/// * 🎯用于将统一的「NAVM指令」转译为「ONA Shell输入」 +pub fn input_translate(cmd: Cmd) -> ResultS { + let content = match cmd { + // 直接使用「末尾」,此时将自动格式化任务(可兼容「空预算」的形式) + Cmd::NSE(..) => cmd.tail(), + // CYC指令:运行指定周期数 + // * 📌PyNARS需要手动指定步进数 + Cmd::CYC(n) => n.to_string(), + // VOL指令:调整音量 + // ! ⚠️该指令仅适用于`ConsolePlus` + Cmd::VOL(n) => format!("/volume {n}"), + // 其它类型 + // * 📌【2024-03-24 22:57:18】基本足够支持 + _ => return Err(format!("该指令类型暂不支持:{cmd:?}")), + }; + // 转译 + Ok(content) +} + +/// ONA的「输出转译」函数 +/// * 🎯用于将ONA 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, + }, + "derived" => Output::OUT { + content_raw: content, + // TODO: 有待捕获转译 + narsese: None, + }, + "input" => 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/runtime/command_vm/runtime.rs b/src/runtime/command_vm/runtime.rs index c4bdf91..abe9baa 100644 --- a/src/runtime/command_vm/runtime.rs +++ b/src/runtime/command_vm/runtime.rs @@ -91,11 +91,13 @@ pub(crate) mod test { use util::first; // 定义一系列路径 - #[allow(dead_code)] + // * 📌【2024-03-25 09:28:36】本地调试:都从根目录`BabelNAR.rs`开始 + // * 📄退一级到开发目录,再退一级到各NARS下载目录 pub const EXE_PATH_ONA: &str = r"..\..\NARS-executables\NAR.exe"; - #[allow(dead_code)] 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"; const COMMAND_JAVA: &str = "java"; const COMMAND_ARGS_JAVA: [&str; 2] = ["-Xmx1024m", "-jar"];