From d9aebbccb05135c31e8351b5f1286d07e84d57b2 Mon Sep 17 00:00:00 2001 From: Vitaly Bogdanov Date: Thu, 14 Nov 2024 10:20:52 +0300 Subject: [PATCH] Make UNIT_TYPE and UNIT_ATOM constant expressions --- c/src/metta.rs | 4 +-- lib/src/atom/mod.rs | 18 +++++++---- lib/src/metta/mod.rs | 22 +++++++------ .../metta/runner/builtin_mods/catalog_mods.rs | 6 ++-- lib/src/metta/runner/stdlib_minimal.rs | 32 +++++++++---------- lib/tests/metta.rs | 2 +- lib/tests/types.rs | 2 +- 7 files changed, 47 insertions(+), 39 deletions(-) diff --git a/c/src/metta.rs b/c/src/metta.rs index 1e59ed170..0c8595b8a 100644 --- a/c/src/metta.rs +++ b/c/src/metta.rs @@ -617,7 +617,7 @@ pub extern "C" fn atom_error_message(atom: *const atom_ref_t, buf: *mut c_char, /// @return The `atom_t` representing the atom /// @note The returned `atom_t` must be freed with `atom_free()` /// -#[no_mangle] pub extern "C" fn ATOM_TYPE_UNIT() -> atom_t { hyperon::metta::UNIT_TYPE().into() } +#[no_mangle] pub extern "C" fn ATOM_TYPE_UNIT() -> atom_t { hyperon::metta::UNIT_TYPE.into() } /// @brief Creates a Symbol atom for the special MeTTa symbol used to indicate empty results /// returned by function. @@ -636,7 +636,7 @@ pub extern "C" fn atom_error_message(atom: *const atom_ref_t, buf: *mut c_char, /// @note The returned `atom_t` must be freed with `atom_free()` /// #[no_mangle] pub extern "C" fn UNIT_ATOM() -> atom_t { - hyperon::metta::UNIT_ATOM().into() + hyperon::metta::UNIT_ATOM.into() } /// @brief Creates a Symbol atom for the special MeTTa symbol used to indicate diff --git a/lib/src/atom/mod.rs b/lib/src/atom/mod.rs index 9293296ef..34aa3aff5 100644 --- a/lib/src/atom/mod.rs +++ b/lib/src/atom/mod.rs @@ -83,8 +83,16 @@ macro_rules! expr { use $crate::*; (&&$crate::Wrap($x)).to_atom() }}; - (($($x:tt)*)) => { $crate::Atom::expr(vec![ $( expr!($x) , )* ]) }; - ($($x:tt)*) => { $crate::Atom::expr(vec![ $( expr!($x) , )* ]) }; + (($($x:tt)*)) => { $crate::Atom::expr([ $( expr!($x) , )* ]) }; + ($($x:tt)*) => { $crate::Atom::expr([ $( expr!($x) , )* ]) }; +} + +#[macro_export] +macro_rules! constexpr { + () => { $crate::Atom::Expression($crate::ExpressionAtom::new($crate::common::collections::CowArray::Literal(&[]))) }; + ($x:literal) => { $crate::Atom::Symbol($crate::SymbolAtom::new($crate::common::collections::ImmutableString::Literal($x))) }; + (($($x:tt)*)) => { $crate::Atom::Expression($crate::ExpressionAtom::new($crate::common::collections::CowArray::Literal(const { &[ $( constexpr!($x) , )* ] }))) }; + ($($x:tt)*) => { $crate::Atom::Expression($crate::ExpressionAtom::new($crate::common::collections::CowArray::Literal(const { &[ $( constexpr!($x) , )* ] }))) }; } /// Constructs new symbol atom. Can be used to construct `const` instances. @@ -130,7 +138,6 @@ pub struct SymbolAtom { impl SymbolAtom { /// Constructs new symbol from `name`. Not intended to be used directly, /// use [sym!] or [Atom::sym] instead. - #[doc(hidden)] pub const fn new(name: ImmutableString) -> Self { Self{ name } } @@ -157,9 +164,8 @@ pub struct ExpressionAtom { impl ExpressionAtom { /// Constructs new expression from vector of sub-atoms. Not intended to be - /// used directly, use [Atom::expr] instead. - #[doc(hidden)] - pub(crate) fn new(children: CowArray) -> Self { + /// used directly, use [expr!], [constexpr!] or [Atom::expr] instead. + pub const fn new(children: CowArray) -> Self { Self{ children } } diff --git a/lib/src/metta/mod.rs b/lib/src/metta/mod.rs index 9fd87623d..3064b8425 100644 --- a/lib/src/metta/mod.rs +++ b/lib/src/metta/mod.rs @@ -42,16 +42,8 @@ pub const SUPERPOSE_BIND_SYMBOL : Atom = sym!("superpose-bind"); pub const METTA_SYMBOL : Atom = sym!("metta"); pub const CALL_NATIVE_SYMBOL : Atom = sym!("call-native"); -//TODO: convert these from functions to static strcutures, when Atoms are Send+Sync -#[allow(non_snake_case)] -pub fn UNIT_ATOM() -> Atom { - Atom::expr([]) -} - -#[allow(non_snake_case)] -pub fn UNIT_TYPE() -> Atom { - Atom::expr([ARROW_SYMBOL]) -} +pub const UNIT_ATOM: Atom = constexpr!(); +pub const UNIT_TYPE: Atom = constexpr!(("->")); /// Initializes an error expression atom pub fn error_atom(err_atom: Option, err_code: Option, message: String) -> Atom { @@ -95,3 +87,13 @@ pub fn atom_error_message(atom: &Atom) -> &str { } } +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn unit_type() { + assert_eq!(UNIT_ATOM, Atom::expr([])); + assert_eq!(UNIT_TYPE, Atom::expr([ARROW_SYMBOL])); + } +} diff --git a/lib/src/metta/runner/builtin_mods/catalog_mods.rs b/lib/src/metta/runner/builtin_mods/catalog_mods.rs index e46a8b211..be850be1e 100644 --- a/lib/src/metta/runner/builtin_mods/catalog_mods.rs +++ b/lib/src/metta/runner/builtin_mods/catalog_mods.rs @@ -88,7 +88,7 @@ impl CatalogListOp { impl Grounded for CatalogListOp { fn type_(&self) -> Atom { //TODO-FUTURE, we may want to return the list as atoms, but now it just prints to stdout - Atom::expr([ARROW_SYMBOL, ATOM_TYPE_SYMBOL, UNIT_TYPE()]) + Atom::expr([ARROW_SYMBOL, ATOM_TYPE_SYMBOL, UNIT_TYPE]) } fn as_execute(&self) -> Option<&dyn CustomExecute> { @@ -153,7 +153,7 @@ impl CatalogUpdateOp { impl Grounded for CatalogUpdateOp { fn type_(&self) -> Atom { //TODO-FUTURE, we may want to return the list as atoms, but now it just prints to stdout - Atom::expr([ARROW_SYMBOL, ATOM_TYPE_SYMBOL, UNIT_TYPE()]) + Atom::expr([ARROW_SYMBOL, ATOM_TYPE_SYMBOL, UNIT_TYPE]) } fn as_execute(&self) -> Option<&dyn CustomExecute> { @@ -213,7 +213,7 @@ impl CatalogClearOp { impl Grounded for CatalogClearOp { fn type_(&self) -> Atom { //TODO-FUTURE, we may want to return the list as atoms, but now it just prints to stdout - Atom::expr([ARROW_SYMBOL, ATOM_TYPE_SYMBOL, UNIT_TYPE()]) + Atom::expr([ARROW_SYMBOL, ATOM_TYPE_SYMBOL, UNIT_TYPE]) } fn as_execute(&self) -> Option<&dyn CustomExecute> { diff --git a/lib/src/metta/runner/stdlib_minimal.rs b/lib/src/metta/runner/stdlib_minimal.rs index 025ae692b..03cdb8672 100644 --- a/lib/src/metta/runner/stdlib_minimal.rs +++ b/lib/src/metta/runner/stdlib_minimal.rs @@ -26,7 +26,7 @@ use super::arithmetics::*; use super::string::*; pub(crate) fn unit_result() -> Result, ExecError> { - Ok(vec![UNIT_ATOM()]) + Ok(vec![UNIT_ATOM]) } pub(crate) fn regex(regex: &str) -> Regex { @@ -68,7 +68,7 @@ impl Grounded for ImportOp { //TODO: Ideally the "import as" / "import into" part would be optional //A deeper discussion on arg semantics as it relates to import! is here: // https://github.com/trueagi-io/hyperon-experimental/pull/580#discussion_r1491332304 - Atom::expr([ARROW_SYMBOL, ATOM_TYPE_ATOM, ATOM_TYPE_ATOM, UNIT_TYPE()]) + Atom::expr([ARROW_SYMBOL, ATOM_TYPE_ATOM, ATOM_TYPE_ATOM, UNIT_TYPE]) } fn as_execute(&self) -> Option<&dyn CustomExecute> { @@ -279,7 +279,7 @@ impl PrintModsOp { impl Grounded for PrintModsOp { fn type_(&self) -> Atom { - Atom::expr([ARROW_SYMBOL, UNIT_TYPE()]) + Atom::expr([ARROW_SYMBOL, UNIT_TYPE]) } fn as_execute(&self) -> Option<&dyn CustomExecute> { @@ -309,7 +309,7 @@ impl BindOp { impl Grounded for BindOp { fn type_(&self) -> Atom { - Atom::expr([ARROW_SYMBOL, ATOM_TYPE_SYMBOL, ATOM_TYPE_UNDEFINED, UNIT_TYPE()]) + Atom::expr([ARROW_SYMBOL, ATOM_TYPE_SYMBOL, ATOM_TYPE_UNDEFINED, UNIT_TYPE]) } fn as_execute(&self) -> Option<&dyn CustomExecute> { @@ -363,7 +363,7 @@ grounded_op!(AddAtomOp, "add-atom"); impl Grounded for AddAtomOp { fn type_(&self) -> Atom { Atom::expr([ARROW_SYMBOL, rust_type_atom::(), - ATOM_TYPE_ATOM, UNIT_TYPE()]) + ATOM_TYPE_ATOM, UNIT_TYPE]) } fn as_execute(&self) -> Option<&dyn CustomExecute> { @@ -390,7 +390,7 @@ grounded_op!(RemoveAtomOp, "remove-atom"); impl Grounded for RemoveAtomOp { fn type_(&self) -> Atom { Atom::expr([ARROW_SYMBOL, rust_type_atom::(), - ATOM_TYPE_ATOM, UNIT_TYPE()]) + ATOM_TYPE_ATOM, UNIT_TYPE]) } fn as_execute(&self) -> Option<&dyn CustomExecute> { @@ -529,7 +529,7 @@ grounded_op!(PrintlnOp, "println!"); impl Grounded for PrintlnOp { fn type_(&self) -> Atom { - Atom::expr([ARROW_SYMBOL, ATOM_TYPE_UNDEFINED, UNIT_TYPE()]) + Atom::expr([ARROW_SYMBOL, ATOM_TYPE_UNDEFINED, UNIT_TYPE]) } fn as_execute(&self) -> Option<&dyn CustomExecute> { @@ -872,7 +872,7 @@ pub(crate) mod pkg_mgmt_ops { impl Grounded for RegisterModuleOp { fn type_(&self) -> Atom { - Atom::expr([ARROW_SYMBOL, ATOM_TYPE_ATOM, UNIT_TYPE()]) + Atom::expr([ARROW_SYMBOL, ATOM_TYPE_ATOM, UNIT_TYPE]) } fn as_execute(&self) -> Option<&dyn CustomExecute> { @@ -927,7 +927,7 @@ pub(crate) mod pkg_mgmt_ops { impl Grounded for GitModuleOp { fn type_(&self) -> Atom { - Atom::expr([ARROW_SYMBOL, ATOM_TYPE_ATOM, UNIT_TYPE()]) + Atom::expr([ARROW_SYMBOL, ATOM_TYPE_ATOM, UNIT_TYPE]) } fn as_execute(&self) -> Option<&dyn CustomExecute> { @@ -1356,7 +1356,7 @@ grounded_op!(PrintAlternativesOp, "print-alternatives!"); impl Grounded for PrintAlternativesOp { fn type_(&self) -> Atom { - Atom::expr([ARROW_SYMBOL, ATOM_TYPE_ATOM, ATOM_TYPE_EXPRESSION, UNIT_TYPE()]) + Atom::expr([ARROW_SYMBOL, ATOM_TYPE_ATOM, ATOM_TYPE_EXPRESSION, UNIT_TYPE]) } fn as_execute(&self) -> Option<&dyn CustomExecute> { @@ -1374,7 +1374,7 @@ impl CustomExecute for PrintAlternativesOp { .collect(); println!("{} {}:", args.len(), atom); args.iter().for_each(|arg| println!(" {}", arg)); - Ok(vec![UNIT_ATOM()]) + Ok(vec![UNIT_ATOM]) } } @@ -2191,7 +2191,7 @@ mod tests { "; assert_eq!(metta.run(SExprParser::new(program)), Ok(vec![])); assert_eq!(metta.run(SExprParser::new("!(assertEqual (foo A) (bar A))")), Ok(vec![ - vec![UNIT_ATOM()], + vec![UNIT_ATOM], ])); assert_eq!(metta.run(SExprParser::new("!(assertEqual (foo A) (bar B))")), Ok(vec![ vec![expr!("Error" ({assert.clone()} ("foo" "A") ("bar" "B")) "\nExpected: [B]\nGot: [A]\nMissed result: B")], @@ -2214,7 +2214,7 @@ mod tests { "; assert_eq!(metta.run(SExprParser::new(program)), Ok(vec![])); assert_eq!(metta.run(SExprParser::new("!(assertEqualToResult (foo) (A B))")), Ok(vec![ - vec![UNIT_ATOM()], + vec![UNIT_ATOM], ])); assert_eq!(metta.run(SExprParser::new("!(assertEqualToResult (bar) (A))")), Ok(vec![ vec![expr!("Error" ({assert.clone()} ("bar") ("A")) "\nExpected: [A]\nGot: [C]\nMissed result: A")], @@ -2500,7 +2500,7 @@ mod tests { assert_eq_metta_results!(run_program(program), Ok(vec![ vec![expr!("baz")], - vec![UNIT_ATOM()], + vec![UNIT_ATOM], vec![expr!(("foo"))], vec![expr!(("bar"))], ])); @@ -2764,7 +2764,7 @@ mod tests { let space = DynSpace::new(GroundingSpace::new()); let satom = Atom::gnd(space.clone()); let res = AddAtomOp{}.execute(&mut vec![satom, expr!(("foo" "bar"))]).expect("No result returned"); - assert_eq!(res, vec![UNIT_ATOM()]); + assert_eq!(res, vec![UNIT_ATOM]); let space_atoms: Vec = space.borrow().as_space().atom_iter().unwrap().cloned().collect(); assert_eq_no_order!(space_atoms, vec![expr!(("foo" "bar"))]); } @@ -2778,7 +2778,7 @@ mod tests { let satom = Atom::gnd(space.clone()); let res = RemoveAtomOp{}.execute(&mut vec![satom, expr!(("foo" "bar"))]).expect("No result returned"); // REM: can return Bool in future - assert_eq!(res, vec![UNIT_ATOM()]); + assert_eq!(res, vec![UNIT_ATOM]); let space_atoms: Vec = space.borrow().as_space().atom_iter().unwrap().cloned().collect(); assert_eq_no_order!(space_atoms, vec![expr!(("bar" "foo"))]); } diff --git a/lib/tests/metta.rs b/lib/tests/metta.rs index 0d9081038..d16c067de 100644 --- a/lib/tests/metta.rs +++ b/lib/tests/metta.rs @@ -18,5 +18,5 @@ fn test_reduce_higher_order() { let result = metta.run(SExprParser::new(program)); - assert_eq!(result, Ok(vec![vec![UNIT_ATOM()]])); + assert_eq!(result, Ok(vec![vec![UNIT_ATOM]])); } diff --git a/lib/tests/types.rs b/lib/tests/types.rs index b76bd05aa..318798524 100644 --- a/lib/tests/types.rs +++ b/lib/tests/types.rs @@ -25,7 +25,7 @@ fn test_types_in_metta() { let metta = Metta::new(Some(EnvBuilder::test_env())); metta.tokenizer().borrow_mut().register_token(regex::Regex::new("is-int").unwrap(), |_t| Atom::gnd(IsInt{})); let result = metta.run(SExprParser::new(program)); - assert_eq!(result, Ok(vec![vec![UNIT_ATOM()], vec![UNIT_ATOM()], vec![UNIT_ATOM()], vec![UNIT_ATOM()], vec![UNIT_ATOM()], vec![UNIT_ATOM()]])); + assert_eq!(result, Ok(vec![vec![UNIT_ATOM], vec![UNIT_ATOM], vec![UNIT_ATOM], vec![UNIT_ATOM], vec![UNIT_ATOM], vec![UNIT_ATOM]])); } #[derive(Clone, Debug)]