Skip to content

Commit

Permalink
Merge pull request #615 from luketpeterson/modules
Browse files Browse the repository at this point in the history
Adding `mod-space!` Op Atom, to access the space of a module, loading it if necessary
  • Loading branch information
luketpeterson authored Mar 11, 2024
2 parents 439f4d7 + b686aa9 commit f867494
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 0 deletions.
75 changes: 75 additions & 0 deletions lib/src/metta/runner/stdlib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,64 @@ fn strip_quotes(src: &str) -> &str {
src
}

/// mod-space! returns the space of a specified module, loading the module if it's not loaded already
//NOTE: The "impure" '!' denoted in the op atom name is due to the side effect of loading the module. If
// we want a side-effect-free version, it could be implemented by calling `RunContext::get_module_by_name`
// instead of `RunContext::load_module`, but then the user would need to use `register-module!`, `import!`,
// or some other mechanism to make sure the module is loaded in advance.
#[derive(Clone, Debug)]
pub struct ModSpaceOp {
//TODO-HACK: This is a terrible horrible ugly hack that should be fixed ASAP
context: std::sync::Arc<std::sync::Mutex<Vec<std::sync::Arc<std::sync::Mutex<&'static mut RunContext<'static, 'static, 'static>>>>>>,
}

impl PartialEq for ModSpaceOp {
fn eq(&self, _other: &Self) -> bool { true }
}

impl ModSpaceOp {
pub fn new(metta: Metta) -> Self {
Self{ context: metta.0.context.clone() }
}
}

impl Display for ModSpaceOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "mod-space!")
}
}

impl Grounded for ModSpaceOp {
fn type_(&self) -> Atom {
Atom::expr([ARROW_SYMBOL, ATOM_TYPE_ATOM, UNIT_TYPE()])
}

fn execute(&self, args: &[Atom]) -> Result<Vec<Atom>, ExecError> {
let arg_error = "mod-space! expects a module name argument";
let mod_name_atom = args.get(0).ok_or_else(|| ExecError::from(arg_error))?;

// TODO: replace Symbol by grounded String?
let mod_name = match mod_name_atom {
Atom::Symbol(mod_name) => mod_name.name(),
_ => {return Err(ExecError::from(arg_error))}
};
let mod_name = strip_quotes(mod_name);

// Load the module into the runner, or get the ModId if it's already loaded
//TODO: Remove this hack to access the RunContext, when it's part of the arguments to `execute`
let ctx_ref = self.context.lock().unwrap().last().unwrap().clone();
let mut context = ctx_ref.lock().unwrap();
let mod_id = context.load_module(mod_name)?;

let space = Atom::gnd(context.metta().module_space(mod_id));
Ok(vec![space])
}

fn match_(&self, other: &Atom) -> MatchResultIter {
match_by_equality(self, other)
}
}

/// Provides a way to access [Metta::load_module_at_path] from within MeTTa code
#[derive(Clone, Debug)]
pub struct RegisterModuleOp {
Expand Down Expand Up @@ -1313,6 +1371,8 @@ mod non_minimal_only_stdlib {
tref.register_token(regex(r"get-metatype"), move |_| { get_meta_type_op.clone() });
let register_module_op = Atom::gnd(RegisterModuleOp::new(metta.clone()));
tref.register_token(regex(r"register-module!"), move |_| { register_module_op.clone() });
let mod_space_op = Atom::gnd(ModSpaceOp::new(metta.clone()));
tref.register_token(regex(r"mod-space!"), move |_| { mod_space_op.clone() });
let print_mods_op = Atom::gnd(PrintModsOp::new(metta.clone()));
tref.register_token(regex(r"print-mods!"), move |_| { print_mods_op.clone() });
}
Expand Down Expand Up @@ -1463,6 +1523,21 @@ impl ModuleLoader for CoreLibLoader {
}
}


#[test]
fn mod_space_op() {
let program = r#"
!(bind! &new_space (new-space))
!(add-atom &new_space (mod-space! stdlib))
!(get-atoms &new_space)
"#;
let runner = Metta::new(Some(runner::environment::EnvBuilder::test_env()));
let result = runner.run(SExprParser::new(program)).unwrap();

let stdlib_space = runner.module_space(runner.get_module_by_name("stdlib").unwrap());
assert_eq!(result[2], vec![Atom::gnd(stdlib_space)]);
}

#[cfg(all(test, not(feature = "minimal")))]
mod tests {
use super::*;
Expand Down
2 changes: 2 additions & 0 deletions lib/src/metta/runner/stdlib2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,8 @@ pub fn register_common_tokens(tref: &mut Tokenizer, _tokenizer: Shared<Tokenizer
tref.register_token(regex(r"match"), move |_| { match_op.clone() });
let register_module_op = Atom::gnd(stdlib::RegisterModuleOp::new(metta.clone()));
tref.register_token(regex(r"register-module!"), move |_| { register_module_op.clone() });
let mod_space_op = Atom::gnd(stdlib::ModSpaceOp::new(metta.clone()));
tref.register_token(regex(r"mod-space!"), move |_| { mod_space_op.clone() });
let print_mods_op = Atom::gnd(stdlib::PrintModsOp::new(metta.clone()));
tref.register_token(regex(r"print-mods!"), move |_| { print_mods_op.clone() });
}
Expand Down

0 comments on commit f867494

Please sign in to comment.