hyperon/metta/runner/stdlib/
package.rs1use super::{grounded_op, regex, unit_result};
2use hyperon_atom::*;
3use crate::metta::*;
4use crate::metta::text::Tokenizer;
5use crate::metta::runner::{Metta, RunContext,
6 git_catalog::ModuleGitLocation,
7 mod_name_from_url,
8 pkg_mgmt::UpdateMode};
9use hyperon_atom::gnd::str::expect_string_like_atom;
10
11#[derive(Clone, Debug)]
13pub struct RegisterModuleOp {
14 metta: Metta
15}
16
17grounded_op!(RegisterModuleOp, "register-module!");
18
19impl RegisterModuleOp {
20 pub fn new(metta: Metta) -> Self {
21 Self{ metta }
22 }
23}
24
25impl Grounded for RegisterModuleOp {
26 fn type_(&self) -> Atom {
27 Atom::expr([ARROW_SYMBOL, ATOM_TYPE_ATOM, UNIT_TYPE])
28 }
29
30 fn as_execute(&self) -> Option<&dyn CustomExecute> {
31 Some(self)
32 }
33}
34
35impl CustomExecute for RegisterModuleOp {
36 fn execute(&self, args: &[Atom]) -> Result<Vec<Atom>, ExecError> {
37 let arg_error = "register-module! expects a file system path; use quotes if needed";
38 let path = args.get(0).and_then(expect_string_like_atom).ok_or_else(|| ExecError::from(arg_error))?;
39
40 let path = std::path::PathBuf::from(path);
41
42 self.metta.load_module_at_path(path, None).map_err(|e| ExecError::from(e))?;
48
49 unit_result()
50 }
51}
52
53#[derive(Clone, Debug)]
61pub struct GitModuleOp {
62 context: std::sync::Arc<std::sync::Mutex<Vec<std::sync::Arc<std::sync::Mutex<&'static mut RunContext<'static, 'static>>>>>>,
64}
65
66grounded_op!(GitModuleOp, "git-module!");
67
68impl GitModuleOp {
69 pub fn new(metta: Metta) -> Self {
70 Self{ context: metta.0.context.clone() }
71 }
72}
73
74impl Grounded for GitModuleOp {
75 fn type_(&self) -> Atom {
76 Atom::expr([ARROW_SYMBOL, ATOM_TYPE_ATOM, UNIT_TYPE])
77 }
78
79 fn as_execute(&self) -> Option<&dyn CustomExecute> {
80 Some(self)
81 }
82}
83
84impl CustomExecute for GitModuleOp {
85 fn execute(&self, args: &[Atom]) -> Result<Vec<Atom>, ExecError> {
86 let arg_error = "git-module! expects a URL; use quotes if needed";
87 let url = args.get(0).and_then(expect_string_like_atom).ok_or_else(|| ExecError::from(arg_error))?;
88 let mod_name = match mod_name_from_url(&url) {
93 Some(mod_name) => mod_name,
94 None => return Err(ExecError::from("git-module! error extracting module name from URL"))
95 };
96
97 let ctx_ref = self.context.lock().unwrap().last().unwrap().clone();
98 let mut context = ctx_ref.lock().unwrap();
99
100 let git_mod_location = ModuleGitLocation::new(url.to_string());
101
102 match context.metta.environment().specified_mods.as_ref() {
103 Some(specified_mods) => if let Some((loader, descriptor)) = specified_mods.loader_for_explicit_git_module(&mod_name, UpdateMode::TryFetchLatest, &git_mod_location)? {
104 context.get_or_init_module_with_descriptor(&mod_name, descriptor, loader).map_err(|e| ExecError::from(e))?;
105 },
106 None => return Err(ExecError::from(format!("Unable to pull module \"{mod_name}\" from git; no local \"caches\" directory available")))
107 }
108
109 unit_result()
110 }
111}
112
113pub(super) fn register_context_dependent_tokens(tref: &mut Tokenizer, metta: &Metta) {
114 let register_module_op = Atom::gnd(RegisterModuleOp::new(metta.clone()));
115 tref.register_token(regex(r"register-module!"), move |_| { register_module_op.clone() });
116 let git_module_op = Atom::gnd(GitModuleOp::new(metta.clone()));
117 tref.register_token(regex(r"git-module!"), move |_| { git_module_op.clone() });
118}