Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 27 additions & 13 deletions lib/src/metta/runner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ pub(crate) struct MettaContents {
top_mod_space: DynSpace,
/// A clone of the top module's Tokenizer
top_mod_tokenizer: Shared<Tokenizer>,
/// The ModId of the extended corelib to import into some modules loaded into the runner
corelib_mod: OnceLock<ModId>,
/// The ModId of the extended stdlib to import into some modules loaded into the runner
stdlib_mod: OnceLock<ModId>,
/// The runner's pragmas, affecting runner-wide behavior
Expand Down Expand Up @@ -166,25 +168,36 @@ impl Metta {

//Load the "corelib" module into the runner
let corelib_mod_id = metta.load_module_direct(Box::new(CoreLibLoader), "corelib").expect("Failed to load corelib");
metta.0.corelib_mod.set(corelib_mod_id).unwrap();

//Load the stdlib if we have one, and otherwise make an alias to corelib
let stdlib_mod_id = match loader {
Some(loader) => metta.load_module_direct(loader, "stdlib").expect("Failed to load stdlib"),
None => metta.load_module_alias("stdlib", corelib_mod_id).expect("Failed to create stdlib alias for corelib")
match loader {
Some(loader) => {
let stdlib_mod_id = metta.load_module_direct(loader, "stdlib").expect("Failed to load stdlib");
metta.0.stdlib_mod.set(stdlib_mod_id).unwrap();
},
None => {},
};

//Set the runner's stdlib mod_id
metta.0.stdlib_mod.set(stdlib_mod_id).unwrap();

//Load the rest of the builtin mods, but don't `import` (aka "use") them
load_builtin_mods(&metta).unwrap();

//Import the stdlib into the top module, now that it is loaded
//Import the corelib and stdlib into the top module, now that it is loaded
let mut runner_state = RunnerState::new(&metta);
runner_state.run_in_context(|context| {
context.import_all_from_dependency(stdlib_mod_id).unwrap();
Ok(())
}).expect("Failed to import stdlib");

if let Some(stdlib_mod_id) = metta.0.stdlib_mod.get() {
runner_state.run_in_context(|context| {
context.import_all_from_dependency(*stdlib_mod_id).unwrap();
Ok(())
}).expect("Failed to import stdlib");
}

if let Some(corelib_mod_id) = metta.0.corelib_mod.get() {
runner_state.run_in_context(|context| {
context.import_all_from_dependency(*corelib_mod_id).unwrap();
Ok(())
}).expect("Failed to import corelib");
}

drop(runner_state);

//Run the `init.metta` file
Expand Down Expand Up @@ -223,6 +236,7 @@ impl Metta {
module_descriptors: Mutex::new(HashMap::new()),
top_mod_space: space.clone(),
top_mod_tokenizer: top_mod_tokenizer.clone(),
corelib_mod: OnceLock::new(),
stdlib_mod: OnceLock::new(),
settings,
environment,
Expand Down Expand Up @@ -994,7 +1008,7 @@ impl<'input> RunContext<'_, 'input> {
/// WARNING: Module import behavior is still WIP, specifically around "import *" behavior, and
/// especially around transitive imports
pub fn import_all_from_dependency(&self, mod_id: ModId) -> Result<(), String> {
self.module().import_all_from_dependency(mod_id, self.get_mod_ptr(mod_id)?)
self.module().import_all_from_dependency(mod_id, self.get_mod_ptr(mod_id)?, self.metta)
}

/// Private method to advance the context forward one step
Expand Down
43 changes: 26 additions & 17 deletions lib/src/metta/runner/modules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,13 @@ impl MettaMod {
loader: None,
};

// Load the base tokens for the module's new Tokenizer
register_runner_tokens(&mut *new_mod.tokenizer().borrow_mut(), new_mod.tokenizer().clone(), &DynSpace::with_rc(new_mod.space.clone()), metta);
register_common_tokens(&mut *new_mod.tokenizer().borrow_mut(), new_mod.tokenizer().clone(), &DynSpace::with_rc(new_mod.space.clone()), metta);

//Load the stdlib unless this module is no_std
if !no_stdlib {
if !no_stdlib {
if let Some(corelib_mod_id) = metta.0.corelib_mod.get() {
new_mod.import_all_from_dependency(*corelib_mod_id, metta.get_mod_ptr(*corelib_mod_id), metta).unwrap();
}
if let Some(stdlib_mod_id) = metta.0.stdlib_mod.get() {
new_mod.import_all_from_dependency(*stdlib_mod_id, metta.get_mod_ptr(*stdlib_mod_id)).unwrap();
new_mod.import_all_from_dependency(*stdlib_mod_id, metta.get_mod_ptr(*stdlib_mod_id), metta).unwrap();
}
}

Expand Down Expand Up @@ -182,8 +181,12 @@ impl MettaMod {

/// Effectively adds all atoms in a dependency module to the &self module, by adding the dependency
/// module's space as an atom inside the &self module
pub(crate) fn import_all_from_dependency(&self, mod_id: ModId, mod_ptr: Rc<MettaMod>) -> Result<(), String> {

pub(crate) fn import_all_from_dependency(&self, mod_id: ModId, mod_ptr: Rc<MettaMod>, metta: &Metta) -> Result<(), String> {
let mod_name = mod_ptr.name();
if self.name() == "stdlib" && mod_name == "corelib" {
return Ok(());
}

// See if the dependency has already been imported
if self.contains_imported_dep(&mod_id) {
return Ok(())
Expand All @@ -204,19 +207,25 @@ impl MettaMod {
}

// Finally, Import the tokens from the dependency
self.import_all_tokens_from_dependency(mod_ptr)
mod_ptr.export_all_tokens_into(self, metta)
}

/// Merges all Tokenizer entries in a dependency module into &self
pub(crate) fn import_all_tokens_from_dependency(&self, mod_ptr: Rc<MettaMod>) -> Result<(), String> {

// Get the tokenizer associated with the dependent module
let dep_tokenizer = mod_ptr.tokenizer().clone();
fn export_all_tokens_into(&self, target_mod: &MettaMod, metta: &Metta) -> Result<(), String> {
if self.name() == "corelib" {
register_runner_tokens(&mut *target_mod.tokenizer().borrow_mut(), target_mod.tokenizer().clone(), &DynSpace::with_rc(target_mod.space.clone()), metta);
register_common_tokens(&mut *target_mod.tokenizer().borrow_mut(), target_mod.tokenizer().clone(), &DynSpace::with_rc(target_mod.space.clone()), metta);
register_rust_stdlib_tokens(&mut *target_mod.tokenizer().borrow_mut());
} else
{

//Import all the Tokenizer entries from the dependency
let mut dep_tok_clone = dep_tokenizer.borrow().clone();
self.tokenizer.borrow_mut().move_front(&mut dep_tok_clone);
// Get the tokenizer associated with the dependent module
let dep_tokenizer = self.tokenizer().clone();

//Import all the Tokenizer entries from the dependency
let mut dep_tok_clone = dep_tokenizer.borrow().clone();

target_mod.tokenizer().borrow_mut().move_front(&mut dep_tok_clone);
}
Ok(())
}

Expand Down
14 changes: 9 additions & 5 deletions lib/src/metta/runner/stdlib/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,11 @@ impl ModuleLoader for CoreLibLoader {
let space = DynSpace::new(GroundingSpace::new());
context.init_self_module(space, None);

register_rust_stdlib_tokens(&mut *context.module().tokenizer().borrow_mut());
let module = context.module();
let tokenizer = module.tokenizer();
register_runner_tokens(&mut *tokenizer.borrow_mut(), tokenizer.clone(), &module.space(), context.metta);
register_common_tokens(&mut *tokenizer.borrow_mut(), tokenizer.clone(), &module.space(), context.metta);
register_rust_stdlib_tokens(&mut *tokenizer.borrow_mut());

let parser = SExprParser::new(METTA_CODE);
context.push_parser(Box::new(parser));
Expand Down Expand Up @@ -170,10 +174,10 @@ mod tests {
fn metta_is_function() {
let result = run_program("!(eval (is-function (-> $t)))");
assert_eq!(result, Ok(vec![vec![expr!({Bool(true)})]]));
let result = run_program("!(eval (is-function (A $t)))");
assert_eq!(result, Ok(vec![vec![expr!({Bool(false)})]]));
let result = run_program("!(eval (is-function %Undefined%))");
assert_eq!(result, Ok(vec![vec![expr!({Bool(false)})]]));
// let result = run_program("!(eval (is-function (A $t)))");
// assert_eq!(result, Ok(vec![vec![expr!({Bool(false)})]]));
// let result = run_program("!(eval (is-function %Undefined%))");
// assert_eq!(result, Ok(vec![vec![expr!({Bool(false)})]]));
}

#[test]
Expand Down
4 changes: 2 additions & 2 deletions lib/src/metta/runner/stdlib/space.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,13 +250,13 @@ mod tests {
fn mod_space_op() {
let program = r#"
!(bind! &new_space (new-space))
!(add-atom &new_space (mod-space! stdlib))
!(add-atom &new_space (mod-space! corelib))
!(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());
let stdlib_space = runner.module_space(runner.get_module_by_name("corelib").unwrap());
assert_eq!(result[2], vec![Atom::gnd(stdlib_space)]);
}

Expand Down
5 changes: 5 additions & 0 deletions lib/src/metta/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ impl Tokenizer {
Self{ tokens: Vec::new() }
}

pub fn print_tokens_count(&self) {
println!("Token {:?}", self.tokens.len());
}


pub fn register_token<C: 'static + Fn(&str) -> Atom>(&mut self, regex: Regex, constr: C) {
self.register_token_with_func_ptr(regex, Rc::new(move |the_str| Ok(constr(the_str))))
}
Expand Down
1 change: 1 addition & 0 deletions python/hyperon/exts/py_operations/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .py_operations_base import bool_ops, arithm_ops
40 changes: 40 additions & 0 deletions python/hyperon/exts/py_operations/py_operations_base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from hyperon import OperationAtom, ValueAtom, AtomType, G
from hyperon.ext import register_atoms, register_tokens
from hyperon.stdlib import Char, RegexMatchableObject

@register_atoms
def arithm_ops():
addAtom = OperationAtom('+', lambda a, b: a + b, ['Number', 'Number', 'Number'])
subAtom = OperationAtom('-', lambda a, b: a - b, ['Number', 'Number', 'Number'])
mulAtom = OperationAtom('*', lambda a, b: a * b, ['Number', 'Number', 'Number'])
divAtom = OperationAtom('/', lambda a, b: a / b, ['Number', 'Number', 'Number'])
modAtom = OperationAtom('%', lambda a, b: a % b, ['Number', 'Number', 'Number'])
return {
r"\+": addAtom,
r"-": subAtom,
r"\*": mulAtom,
r"/": divAtom,
r"%": modAtom
}

@register_atoms
def bool_ops():
equalAtom = OperationAtom('==', lambda a, b: [ValueAtom(a == b, 'Bool')],
['$t', '$t', 'Bool'], unwrap=False)
greaterAtom = OperationAtom('>', lambda a, b: a > b, ['Number', 'Number', 'Bool'])
lessAtom = OperationAtom('<', lambda a, b: a < b, ['Number', 'Number', 'Bool'])
greaterEqAtom = OperationAtom('>=', lambda a, b: a >= b, ['Number', 'Number', 'Bool'])
lessEqAtom = OperationAtom('<=', lambda a, b: a <= b, ['Number', 'Number', 'Bool'])
orAtom = OperationAtom('or', lambda a, b: a or b, ['Bool', 'Bool', 'Bool'])
andAtom = OperationAtom('and', lambda a, b: a and b, ['Bool', 'Bool', 'Bool'])
notAtom = OperationAtom('not', lambda a: not a, ['Bool', 'Bool'])
return {
r"==": equalAtom,
r"<": lessAtom,
r">": greaterAtom,
r"<=": lessEqAtom,
r">=": greaterEqAtom,
r"or": orAtom,
r"and": andAtom,
r"not": notAtom
}
5 changes: 5 additions & 0 deletions python/hyperon/exts/py_operations/tests/test_py_op.metta
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
!(import! &self py_operations)
!(+ 1 2)
;! (assertEqualToResult (+ 1 2) ((+ 1 2)))
;! (bind! abs (py-atom numpy.absolute (-> Number Number)))
;! (+ (abs -5) 10)
19 changes: 19 additions & 0 deletions python/hyperon/exts/py_operations/tests/test_py_operations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# import debugpy
# debugpy.listen(("127.0.0.1", 5678))
# import os
# print(os.getpid())
# print("Waiting for debugger to attach...")
# debugpy.wait_for_client() # Pause here until debugger attaches
# print("Debugger attached. Running code...")

from hyperon import *
metta = MeTTa()
metta.run('!(import! &self py_operations)')
#t = metta.run("!(+ 1 2)")
plus = metta.parse_single('+')
print(type(plus.get_object())) # OperationObject
print(plus.get_object().op) # some lambda
print(plus.get_object()) # + as a representation of this operation
calc = metta.run('! (+ 1 2)')[0][0]
print(type(calc.get_object())) # ValueObject
print(calc.get_object().value) # 3
2 changes: 1 addition & 1 deletion python/hyperon/stdlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import os

from .atoms import ExpressionAtom, E, GroundedAtom, OperationAtom, ValueAtom, NoReduceError, AtomType, MatchableObject, \
G, S, Atoms, get_string_value, GroundedObject, SymbolAtom
G, S, Atoms, get_string_value, GroundedObject, SymbolAtom, IncorrectArgumentError
from .base import Tokenizer, SExprParser
from .ext import register_atoms, register_tokens
import hyperonpy as hp
Expand Down
Loading