From 94d9991e37fd63ccd5a1f0cb748e4a5778ea06ef Mon Sep 17 00:00:00 2001 From: Vitaly Bogdanov Date: Wed, 7 Feb 2024 19:14:56 +0300 Subject: [PATCH 1/4] Add println! into minimal MeTTa standard library --- lib/src/metta/runner/stdlib2.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/src/metta/runner/stdlib2.rs b/lib/src/metta/runner/stdlib2.rs index 7230423d5..d610c252b 100644 --- a/lib/src/metta/runner/stdlib2.rs +++ b/lib/src/metta/runner/stdlib2.rs @@ -405,6 +405,8 @@ pub fn register_runner_tokens(metta: &Metta) { tref.register_token(regex(r"bind!"), move |_| { bind_op.clone() }); let trace_op = Atom::gnd(stdlib::TraceOp{}); tref.register_token(regex(r"trace!"), move |_| { trace_op.clone() }); + let println_op = Atom::gnd(stdlib::PrintlnOp{}); + tref.register_token(regex(r"println!"), move |_| { println_op.clone() }); // &self should be updated // TODO: adding &self might be done not by stdlib, but by MeTTa itself. // TODO: adding &self introduces self referencing and thus prevents space From d4d2406a335310608406961c5ec30981df92c849 Mon Sep 17 00:00:00 2001 From: Vitaly Bogdanov Date: Wed, 7 Feb 2024 19:14:00 +0300 Subject: [PATCH 2/4] Temporary add stdlib space into importing space as a hotfix of import! --- lib/src/metta/runner/mod.rs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/src/metta/runner/mod.rs b/lib/src/metta/runner/mod.rs index 59291afcc..8c367945e 100644 --- a/lib/src/metta/runner/mod.rs +++ b/lib/src/metta/runner/mod.rs @@ -147,6 +147,11 @@ impl Metta { metta } + // Loads stdlib into a separate space and returns it + fn stdlib_space(&self) -> DynSpace { + self.load_module_space(PathBuf::from("stdlib")).unwrap() + } + /// Returns a new MeTTa interpreter intended for use loading MeTTa modules during import fn new_loading_runner(metta: &Metta, path: &Path) -> Self { let space = DynSpace::new(GroundingSpace::new()); @@ -182,16 +187,31 @@ impl Metta { // Load the module to the new space let runner = Metta::new_loading_runner(self, &path); + let mut loading_stdlib = false; let program = match path.to_str() { - Some("stdlib") => METTA_CODE.to_string(), + Some("stdlib") => { + loading_stdlib = true; + METTA_CODE.to_string() + }, _ => std::fs::read_to_string(&path).map_err( |err| format!("Could not read file, path: {}, error: {}", path.display(), err))?, }; + + let stdlib_space = if !loading_stdlib { + let stdlib_space = Atom::gnd(runner.stdlib_space()); + runner.space().borrow_mut().add(stdlib_space.clone()); + Some(stdlib_space) + } else { + None + }; // Make the imported module be immediately available to itself // to mitigate circular imports self.0.modules.borrow_mut().insert(path.clone(), runner.space().clone()); runner.run(SExprParser::new(program.as_str())) .map_err(|err| format!("Cannot import module, path: {}, error: {}", path.display(), err))?; + if let Some(stdlib_space) = stdlib_space { + runner.space().borrow_mut().remove(&stdlib_space); + } Ok(runner.space().clone()) } From 693fd8cbb99aad040f29c098654240af54b52597 Mon Sep 17 00:00:00 2001 From: Vitaly Bogdanov Date: Wed, 7 Feb 2024 19:53:17 +0300 Subject: [PATCH 3/4] Fix f1_imports.metta test Make it not rely on order of atoms returned by get-atoms. Other issue is that get-atoms returns duplicates of $x variable. --- python/tests/scripts/f1_imports.metta | 38 +++++++++++++++++---------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/python/tests/scripts/f1_imports.metta b/python/tests/scripts/f1_imports.metta index be40786ac..d606a5101 100644 --- a/python/tests/scripts/f1_imports.metta +++ b/python/tests/scripts/f1_imports.metta @@ -22,12 +22,23 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; !(import! &m f1_moduleA.metta) +; Check whether passed expression contains atom for which condition is True +(: contains (-> Expression (-> Atom Bool) Bool)) +(= (contains $list $condition) + (if (== $list ()) False + (let $head (car-atom $list) + (if ($condition $head) True + (let $tail (cdr-atom $list) (contains $tail $condition)) )))) + +; Check whether atom is space comparing its type with type of the &self atom +(: is-space (-> Atom Bool)) +(= (is-space $atom) + (let* (($type (get-type $atom)) ($space (get-type &self))) (== $type $space))) + ; It's first atom is a space !(assertEqual - (let* (($x (collapse (get-atoms &m))) - ($y (car-atom $x))) - (get-type $y)) - (get-type &self)) + (let $xx (collapse (get-atoms &m)) (contains $xx is-space)) + True) ; FIXME? Now, it is moduleC space. ; Should it be `stdlib` atom for a separately imported space @@ -55,25 +66,24 @@ !(assertEqual (g 2) 102) !(assertEqual (f 2) 103) +; Check whether atom is &m +(: is-m (-> Atom Bool)) +(= (is-m $atom) (== $atom &m)) + ; `&self` contains 3 atoms-spaces now: ; - stdlib ; - moduleC imported by moduleA and removed from A after its import to &self ; - moduleA itself, which is the same as &m -!(assertEqual &m - (let* (($a (collapse (get-atoms &self))) - ($x (cdr-atom $a)) - ($y (cdr-atom $x))) - (car-atom $y))) +!(assertEqual + (let $a (collapse (get-atoms &self)) (contains $a is-m)) + True) ; NOTE: now the first atom, which was a space, is removed from `&m`, ; because we load modules only once, and we collect atoms-spaces to ; prevent duplication !(assertEqual - (== (let* (($x (collapse (get-atoms &m))) - ($y (car-atom $x))) - (get-type $y)) - (get-type &self)) - False) + (let $xx (collapse (get-atoms &m)) (contains $xx is-space)) + False) ; Let's check that `if` from stdlib is not duplicated and gives only one result !(assertEqual From 4f0da687d431eb6884aad2737ce4bb36934511f3 Mon Sep 17 00:00:00 2001 From: Vitaly Bogdanov Date: Wed, 7 Feb 2024 20:03:46 +0300 Subject: [PATCH 4/4] Make variables returned by get-atoms unique This corresponds to other methods which return atoms from the space. --- lib/src/metta/runner/stdlib.rs | 4 +++- python/tests/scripts/f1_imports.metta | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/src/metta/runner/stdlib.rs b/lib/src/metta/runner/stdlib.rs index 0d36593b1..1d4d6d220 100644 --- a/lib/src/metta/runner/stdlib.rs +++ b/lib/src/metta/runner/stdlib.rs @@ -306,7 +306,9 @@ impl Grounded for GetAtomsOp { let arg_error = || ExecError::from("get-atoms expects one argument: space"); let space = args.get(0).ok_or_else(arg_error)?; let space = Atom::as_gnd::(space).ok_or("get-atoms expects a space as its argument")?; - space.borrow().as_space().atom_iter().map(|iter| iter.cloned().collect()).ok_or(ExecError::Runtime("Unsupported Operation. Can't traverse atoms in this space".to_string())) + space.borrow().as_space().atom_iter() + .map(|iter| iter.cloned().map(|a| make_variables_unique(a)).collect()) + .ok_or(ExecError::Runtime("Unsupported Operation. Can't traverse atoms in this space".to_string())) } fn match_(&self, other: &Atom) -> MatchResultIter { diff --git a/python/tests/scripts/f1_imports.metta b/python/tests/scripts/f1_imports.metta index d606a5101..7aa549bbe 100644 --- a/python/tests/scripts/f1_imports.metta +++ b/python/tests/scripts/f1_imports.metta @@ -37,7 +37,7 @@ ; It's first atom is a space !(assertEqual - (let $xx (collapse (get-atoms &m)) (contains $xx is-space)) + (let $x (collapse (get-atoms &m)) (contains $x is-space)) True) ; FIXME? Now, it is moduleC space. @@ -82,7 +82,7 @@ ; because we load modules only once, and we collect atoms-spaces to ; prevent duplication !(assertEqual - (let $xx (collapse (get-atoms &m)) (contains $xx is-space)) + (let $x (collapse (get-atoms &m)) (contains $x is-space)) False) ; Let's check that `if` from stdlib is not duplicated and gives only one result