1use hyperon_atom::*;
60use hyperon_common::shared::Shared;
61
62use super::*;
63use hyperon_space::*;
64use super::text::{Tokenizer, Parser, SExprParser};
65use super::types::{AtomType, get_atom_types};
66
67pub mod modules;
68use modules::{MettaMod, ModId, ModuleInitState, ModNameNode, ModuleLoader, ResourceKey, Resource, TOP_MOD_NAME, ModNameNodeDisplayWrapper, normalize_relative_module_name};
69#[cfg(feature = "pkg_mgmt")]
70use modules::{decompose_name_path, compose_name_path};
71
72#[cfg(feature = "pkg_mgmt")]
73pub mod pkg_mgmt;
74#[cfg(feature = "pkg_mgmt")]
75use pkg_mgmt::*;
76
77#[cfg(not(feature = "pkg_mgmt"))]
78pub(crate) type ModuleDescriptor = ();
79
80use std::rc::Rc;
81use std::path::PathBuf;
82use std::collections::HashMap;
83use std::sync::{Arc, Mutex, OnceLock};
84
85mod environment;
86pub use environment::{Environment, EnvBuilder};
87
88use super::interpreter::{interpret, interpret_init, interpret_step, InterpreterState};
89
90#[macro_use]
91pub mod stdlib;
92use stdlib::CoreLibLoader;
93
94mod builtin_mods;
95use builtin_mods::*;
96
97const EXEC_SYMBOL : Atom = sym!("!");
98
99#[derive(Clone, Debug)]
105pub struct Metta(Rc<MettaContents>);
106
107impl PartialEq for Metta {
108 fn eq(&self, other: &Self) -> bool {
109 Rc::ptr_eq(&self.0, &other.0)
110 }
111}
112
113#[derive(Clone, Debug)]
114pub struct PragmaSettings(Shared<HashMap<String, Atom>>);
115
116impl PragmaSettings {
117 pub fn new() -> Self {
118 Self(Shared::new(HashMap::new()))
119 }
120
121 pub fn set(&self, key: String, value: Atom) {
122 self.0.borrow_mut().insert(key, value);
123 }
124
125 pub fn get(&self, key: &str) -> Option<Atom> {
126 self.0.borrow().get(key).cloned()
127 }
128
129 pub fn get_string(&self, key: &str) -> Option<String> {
130 self.0.borrow().get(key).map(|a| a.to_string())
131 }
132}
133
134#[derive(Debug)]
135pub(crate) struct MettaContents {
136 modules: Mutex<Vec<Rc<MettaMod>>>,
138 module_names: Mutex<ModNameNode>,
140 #[cfg(feature = "pkg_mgmt")]
141 module_descriptors: Mutex<HashMap<ModuleDescriptor, ModId>>,
143 top_mod_space: DynSpace,
149 top_mod_tokenizer: Shared<Tokenizer>,
151 corelib_mod: OnceLock<ModId>,
153 stdlib_mod: OnceLock<ModId>,
155 settings: PragmaSettings,
157 environment: Arc<Environment>,
159 context: Arc<Mutex<Vec<Arc<Mutex<&'static mut RunContext<'static, 'static>>>>>>,
163}
164
165impl Metta {
166
167 pub fn new(env_builder: Option<EnvBuilder>) -> Metta {
171 Self::new_with_stdlib_loader(None, None, env_builder)
172 }
173
174 pub fn new_with_stdlib_loader(loader: Option<Box<dyn ModuleLoader>>, space: Option<DynSpace>, env_builder: Option<EnvBuilder>) -> Metta {
182
183 let metta = Metta::new_core(space, env_builder);
185
186 let corelib_mod_id = metta.load_module_direct(Box::new(CoreLibLoader), "corelib").expect("Failed to load corelib");
188 metta.0.corelib_mod.set(corelib_mod_id).unwrap();
189
190 match loader {
192 Some(loader) => {
193 let stdlib_mod_id = metta.load_module_direct(loader, "stdlib").expect("Failed to load stdlib");
194 metta.0.stdlib_mod.set(stdlib_mod_id).unwrap();
195 },
196 None => {
197 metta.load_module_alias("stdlib", corelib_mod_id).expect("Failed to create stdlib alias for corelib");
198 ()
199 }
200 };
201
202 load_builtin_mods(&metta).unwrap();
204
205 let mut runner_state = RunnerState::new(&metta);
207
208 if let Some(corelib_mod_id) = metta.0.corelib_mod.get() {
209 runner_state.run_in_context(|context| {
210 context.import_all_from_dependency(*corelib_mod_id).unwrap();
211 Ok(())
212 }).expect("Failed to import corelib");
213 }
214
215 if let Some(stdlib_mod_id) = metta.0.stdlib_mod.get() {
216 runner_state.run_in_context(|context| {
217 context.import_all_from_dependency(*stdlib_mod_id).unwrap();
218 Ok(())
219 }).expect("Failed to import stdlib");
220 }
221 drop(runner_state);
222
223 if let Some(init_meta_file_path) = metta.0.environment.initialization_metta_file_path() {
225 let metta_file = match std::fs::File::open(init_meta_file_path).map(std::io::BufReader::new)
226 {
227 Ok(metta_file) => metta_file,
228 Err(err) => panic!("Could not read file, path: {}, error: {}", init_meta_file_path.display(), err)
229 };
230 metta.run(SExprParser::new(metta_file)).unwrap();
231 }
232 metta
233 }
234
235 pub fn new_core(space: Option<DynSpace>, env_builder: Option<EnvBuilder>) -> Self {
241 let space = match space {
242 Some(space) => space,
243 None => GroundingSpace::new().into(),
244 };
245 let settings = PragmaSettings::new();
246 let environment = match env_builder {
247 Some(env_builder) => Arc::new(env_builder.build()),
248 None => Environment::common_env_arc()
249 };
250 let top_mod_resource_dir = environment.working_dir().map(|path| path.into());
251 let top_mod_tokenizer = Shared::new(Tokenizer::new());
252 let contents = MettaContents{
253 modules: Mutex::new(vec![]),
254 module_names: Mutex::new(ModNameNode::top()),
255 #[cfg(feature = "pkg_mgmt")]
256 module_descriptors: Mutex::new(HashMap::new()),
257 top_mod_space: space.clone(),
258 top_mod_tokenizer: top_mod_tokenizer.clone(),
259 corelib_mod: OnceLock::new(),
260 stdlib_mod: OnceLock::new(),
261 settings,
262 environment,
263 context: std::sync::Arc::new(std::sync::Mutex::new(vec![])),
264 };
265 let metta = Self(Rc::new(contents));
266
267 let top_mod = MettaMod::new_with_tokenizer(&metta, TOP_MOD_NAME.to_string(), space, top_mod_tokenizer, top_mod_resource_dir, false);
268 assert_eq!(metta.add_module(top_mod).unwrap(), ModId::TOP);
269
270 metta
271 }
272
273 pub fn load_module_direct(&self, loader: Box<dyn ModuleLoader>, mod_name: &str) -> Result<ModId, String> {
279 let mut state = RunnerState::new_with_module(self, ModId::TOP);
280 state.run_in_context(|context| {
281 context.load_module_direct(loader, mod_name)
282 })
283 }
284
285 #[cfg(feature = "pkg_mgmt")]
295 pub fn load_module_at_path<P: AsRef<std::path::Path>>(&self, path: P, mod_name: Option<&str>) -> Result<ModId, String> {
296 let mut state = RunnerState::new_with_module(self, ModId::TOP);
297 state.run_in_context(|context| {
298 context.load_module_at_path(&path, mod_name)
299 })
300 }
301
302 pub(crate) fn get_mod_ptr(&self, mod_id: ModId) -> Rc<MettaMod> {
304 let mod_ref = self.0.modules.lock().unwrap();
305 mod_ref.get(mod_id.0).unwrap().clone()
306 }
307
308 fn get_module_by_name(&self, mod_name: &str) -> Result<ModId, String> {
313 let module_names = self.0.module_names.lock().unwrap();
314 module_names.resolve(mod_name).ok_or_else(|| format!("Unable to locate module: {mod_name}"))
315 }
316
317 fn add_module_to_name_tree(&self, mod_name: &str, mod_id: ModId) -> Result<(), String> {
319 assert!(!mod_id.is_relative());
320 let mut module_names = self.0.module_names.lock().unwrap();
321 module_names.add(mod_name, mod_id)
322 }
323
324 pub fn load_module_alias(&self, mod_name: &str, mod_id: ModId) -> Result<ModId, String> {
330 let mut state = RunnerState::new_with_module(self, ModId::TOP);
331 state.run_in_context(|context| {
332 context.load_module_alias(mod_name, mod_id)
333 })
334 }
335
336 pub fn display_loaded_modules(&self) {
338 let module_names = self.0.module_names.lock().unwrap();
339 let wrapper = ModNameNodeDisplayWrapper::new(TOP_MOD_NAME, &*module_names, |mod_id: ModId, f: &mut std::fmt::Formatter| write!(f, "{}", mod_id.0));
340 println!("{wrapper}");
341 }
342
343 #[cfg(feature = "pkg_mgmt")]
344 pub fn get_module_with_descriptor(&self, descriptor: &ModuleDescriptor) -> Option<ModId> {
346 let descriptors = self.0.module_descriptors.lock().unwrap();
347 descriptors.get(descriptor).cloned()
348 }
349
350 #[cfg(feature = "pkg_mgmt")]
351 fn add_module_descriptor(&self, descriptor: ModuleDescriptor, mod_id: ModId) {
353 let mut descriptors = self.0.module_descriptors.lock().unwrap();
354 descriptors.insert(descriptor, mod_id);
355 }
356
357 fn merge_init_state(&self, init_state: ModuleInitState) -> Result<ModId, String> {
359 let mut main_mod_id = ModId::INVALID;
360 let (frames, descriptors) = init_state.decompose();
361
362 let mut mod_name_subtrees: Vec<(String, ModNameNode)> = Vec::with_capacity(frames.len());
365 let mut mod_id_mapping = HashMap::with_capacity(frames.len());
366 for (frame_idx, frame) in frames.into_iter().enumerate() {
367 let old_mod_id = ModId::new_relative(frame_idx);
368 let mod_name = frame.new_mod_name.unwrap();
369 let module = frame.the_mod.unwrap();
370
371 mod_name_subtrees.push((mod_name, frame.sub_module_names));
372
373 let new_mod_id = self.add_module(Rc::into_inner(module).unwrap())?;
374 mod_id_mapping.insert(old_mod_id, new_mod_id);
375
376 if frame_idx == 0 {
377 main_mod_id = new_mod_id;
378 }
379 }
380
381 let mut module_names = self.0.module_names.lock().unwrap();
383 for (mod_name, mut subtree) in mod_name_subtrees.into_iter() {
384 subtree.visit_mut("", |_name, node: &mut ModNameNode| {
385 if let Some(new_mod_id) = mod_id_mapping.get(&node.mod_id) {
386 node.mod_id = *new_mod_id;
387 }
388 });
389 module_names.merge_subtree_into(&mod_name, subtree)?;
390 }
391
392 #[cfg(feature = "pkg_mgmt")]
394 for (descriptor, mod_id) in descriptors.into_iter() {
395 let mod_id = match mod_id_mapping.get(&mod_id) {
396 Some(mapped_id) => *mapped_id,
397 None => mod_id,
398 };
399 self.add_module_descriptor(descriptor, mod_id);
400 }
401 #[cfg(not(feature = "pkg_mgmt"))]
402 let _ = descriptors;
403
404 for added_mod_id in mod_id_mapping.values() {
406 let mod_ptr = self.get_mod_ptr(*added_mod_id);
407 mod_ptr.remap_imported_deps(&mod_id_mapping);
408 }
409
410 Ok(main_mod_id)
411 }
412
413 fn add_module(&self, module: MettaMod) -> Result<ModId, String> {
415 let mut vec_ref = self.0.modules.lock().unwrap();
416 let new_id = ModId(vec_ref.len());
417 vec_ref.push(Rc::new(module));
418 Ok(new_id)
419 }
420
421 pub fn environment(&self) -> &Environment {
423 &self.0.environment
424 }
425
426 pub fn space(&self) -> &DynSpace {
428 &self.0.top_mod_space
429 }
430
431 pub fn module_space(&self, mod_id: ModId) -> DynSpace {
433 let modules = self.0.modules.lock().unwrap();
434 modules.get(mod_id.0).unwrap().space().clone()
435 }
436
437 pub fn get_module_resource(&self, mod_id: ModId, res_key: ResourceKey) -> Result<Resource, String> {
439 let modules = self.0.modules.lock().unwrap();
440 modules.get(mod_id.0).unwrap().get_resource(res_key)
441 }
442
443 pub fn tokenizer(&self) -> &Shared<Tokenizer> {
445 &self.0.top_mod_tokenizer
446 }
447
448 pub fn settings(&self) -> &PragmaSettings {
449 &self.0.settings
450 }
451
452 pub fn get_setting_string(&self, key: &str) -> Option<String> {
453 self.0.settings.get(key).map(|a| a.to_string())
454 }
455
456 pub fn run(&self, parser: impl Parser) -> Result<Vec<Vec<Atom>>, String> {
457 let state = RunnerState::new_with_parser(self, Box::new(parser));
458 state.run_to_completion()
459 }
460
461 pub fn run_in_module(&self, mod_id: ModId, parser: impl Parser) -> Result<Vec<Vec<Atom>>, String> {
462 let mut state = RunnerState::new_with_module(self, mod_id);
463 state.i_wrapper.input_src.push_parser(Box::new(parser));
464 state.run_to_completion()
465 }
466
467 pub fn evaluate_atom(&self, atom: Atom) -> Result<Vec<Atom>, String> {
468 let atom = if is_bare_minimal_interpreter(self) {
469 atom
470 } else {
471 wrap_atom_by_metta_interpreter(self.module_space(ModId::TOP), atom)
472 };
473 if self.type_check_is_enabled() {
474 let types = get_atom_types(&self.module_space(ModId::TOP), &atom);
475 if types.iter().all(AtomType::is_error) {
476 return Ok(types.into_iter().map(AtomType::into_error_unchecked).collect());
477 }
478 }
479 interpret(self.space().clone(), &atom)
480 }
481
482 fn type_check_is_enabled(&self) -> bool {
483 self.settings().get_string("type-check").map_or(false, |val| val == "auto")
484 }
485
486}
487
488pub struct RunnerState<'m, 'i> {
520 metta: &'m Metta,
521 mod_id: ModId,
522 mod_ptr: Option<Rc<MettaMod>>,
523 init_state: ModuleInitState,
524 i_wrapper: InterpreterWrapper<'i>,
525}
526
527impl std::fmt::Debug for RunnerState<'_, '_> {
528 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
529 f.debug_struct("RunnerState")
530 .field("mode", &self.i_wrapper.mode)
531 .field("interpreter_state", &self.i_wrapper.interpreter_state)
532 .finish()
533 }
534}
535
536impl<'m, 'input> RunnerState<'m, 'input> {
537
538 fn new_internal(metta: &'m Metta, mod_id: ModId, init_state: ModuleInitState) -> Self {
539 Self {
540 metta,
541 mod_id,
542 mod_ptr: None,
543 init_state: init_state,
544 i_wrapper: InterpreterWrapper::default(),
545 }
546 }
547
548 pub fn new(metta: &'m Metta) -> Self {
550 Self::new_with_module(metta, ModId::TOP)
551 }
552
553 pub(crate) fn new_for_loading(metta: &'m Metta, new_mod_name: &str, init_state: &mut ModuleInitState) -> Self {
555 let normalized_name = normalize_relative_module_name("top", &new_mod_name).unwrap();
556 let mod_id = init_state.push(normalized_name);
557 Self::new_internal(metta, mod_id, init_state.new_child())
558 }
559
560 pub(crate) fn new_with_module_and_init_state(metta: &'m Metta, mod_id: ModId, init_state: ModuleInitState) -> Self {
562 let mut state = Self::new_internal(metta, mod_id, init_state);
563 let mod_ptr = state.init_state.get_mod_ptr(metta, mod_id).unwrap();
564 state.mod_ptr = Some(mod_ptr);
565 state
566 }
567
568 pub(crate) fn new_with_module(metta: &'m Metta, mod_id: ModId) -> Self {
570 Self::new_with_module_and_init_state(metta, mod_id, ModuleInitState::empty())
571 }
572
573 pub fn new_with_parser(metta: &'m Metta, parser: Box<dyn Parser + 'input>) -> Self {
575 let mut state = Self::new(metta);
576 state.i_wrapper.input_src.push_parser(parser);
577 state
578 }
579
580 pub fn new_with_atoms(metta: &'m Metta, atoms: &'input[Atom]) -> Self {
582 let mut state = Self::new(metta);
583 state.i_wrapper.input_src.push_parser(Box::new(atoms));
584 state
585 }
586
587 pub fn run_to_completion(mut self) -> Result<Vec<Vec<Atom>>, String> {
589 while !self.is_complete() {
590 self.run_step()?;
591 }
592 Ok(self.into_results())
593 }
594
595 pub fn run_step(&mut self) -> Result<(), String> {
597 self.run_in_context(|context| context.step())
598 }
599
600 pub fn is_complete(&self) -> bool {
603 self.i_wrapper.mode == MettaRunnerMode::TERMINATE
604 }
605
606 pub fn current_results(&self) -> &Vec<Vec<Atom>> {
608 &self.i_wrapper.results
609 }
610
611 pub fn into_results(self) -> Vec<Vec<Atom>> {
613 self.i_wrapper.results
614 }
615
616 fn run_in_context<T, F: FnOnce(&mut RunContext<'_, 'input>) -> Result<T, String>>(&mut self, f: F) -> Result<T, String> {
621
622 let mut context = RunContext {
624 metta: &self.metta,
625 mod_id: self.mod_id,
626 mod_ptr: &mut self.mod_ptr,
627 init_state: &mut self.init_state,
628 i_wrapper: &mut self.i_wrapper,
629 };
630
631 self.metta.0.context.lock().unwrap().push(Arc::new(Mutex::new( unsafe{ std::mem::transmute(&mut context) } )));
636 let result = f(&mut context);
640
641 self.metta.0.context.lock().unwrap().pop();
644 result
647 }
648
649 pub(crate) fn finalize_loading(self) -> Result<ModId, String> {
651 for result_vec in self.i_wrapper.results {
652 for result in result_vec {
653 if atom_is_error(&result) {
654 return Err(atom_error_message(&result).to_owned())
655 }
656 }
657 }
658 let mod_ptr = match self.mod_ptr {
659 Some(mod_ptr) => mod_ptr,
660 None => return Err(format!("Module loader finished without running RunContext::init_self_module"))
661 };
662
663 self.init_state.in_frame(self.mod_id, |frame| frame.the_mod = Some(mod_ptr));
664 Ok(self.mod_id)
665 }
666}
667
668pub struct RunContext<'a, 'input> {
677 metta: &'a Metta,
678 mod_id: ModId,
679 mod_ptr: &'a mut Option<Rc<MettaMod>>,
680 init_state: &'a mut ModuleInitState,
681 i_wrapper: &'a mut InterpreterWrapper<'input>
682}
683
684impl std::fmt::Debug for RunContext<'_, '_> {
685 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
686 f.debug_struct("RunContext")
687 .finish()
688 }
689}
690
691impl<'input> RunContext<'_, 'input> {
692 pub fn metta(&self) -> &Metta {
694 &self.metta
695 }
696
697 pub fn module(&self) -> &MettaMod {
699 self.mod_ptr.as_ref().unwrap_or_else(|| panic!("No module available"))
700 }
701
702 pub fn module_mut(&mut self) -> Option<&mut MettaMod> {
704 Rc::get_mut(self.mod_ptr.as_mut().unwrap_or_else(|| panic!("No module available")))
705 }
706
707 pub fn push_parser(&mut self, parser: Box<dyn Parser + 'input>) {
709 self.i_wrapper.input_src.push_parser(parser);
710 }
711
712 pub fn push_atoms(&mut self, atoms: &'input[Atom]) {
714 self.i_wrapper.input_src.push_parser(Box::new(atoms));
715 }
716
717 pub fn push_func<F: FnOnce(&mut RunContext) -> Result<(), String> + 'input>(&mut self, f: F) {
719 self.i_wrapper.input_src.push_func(f);
720 }
721
722 pub fn run_inline<F: FnOnce(&mut RunContext) -> Result<(), String>>(&mut self, f: F) -> Result<Vec<Vec<Atom>>, String> {
736 let mut new_interpreter = InterpreterWrapper::default();
737 let mut new_context = RunContext {
738 metta: &self.metta,
739 i_wrapper: &mut new_interpreter,
740 mod_id: self.mod_id,
741 mod_ptr: self.mod_ptr,
742 init_state: self.init_state,
743 };
744
745 let mut err = None;
746 match f(&mut new_context) {
747 Ok(_) => {
748 while new_context.i_wrapper.mode != MettaRunnerMode::TERMINATE {
749 if new_context.step().is_err() {
750 break;
751 }
752 }
753 },
754 Err(e) => err = Some(e)
755 }
756
757 match err {
758 None => Ok(new_interpreter.results),
759 Some(e) => Err(e)
760 }
761 }
762
763 #[allow(dead_code)] fn in_mod_context<T, F: FnOnce(&mut RunContext) -> Result<T, String>>(&mut self, mod_id: ModId, f: F) -> Result<T, String> {
766 if mod_id == self.mod_id {
767 f(self)
768 } else {
769 let mut state = RunnerState::new_with_module_and_init_state(&self.metta, mod_id, self.init_state.new_child());
770 state.run_in_context(f)
771 }
772 }
773
774 pub fn get_module_by_name(&self, mod_name: &str) -> Result<ModId, String> {
776 let normalized_mod_name = normalize_relative_module_name(self.module().path(), mod_name)?;
777 self.init_state.get_module_by_name(&self.metta, &normalized_mod_name)
778 }
779
780 fn add_module_to_name_tree(&mut self, mod_name: &str, mod_id: ModId) -> Result<(), String> {
785 let normalized_mod_name = normalize_relative_module_name(self.module().path(), mod_name)?;
786 self.init_state.add_module_to_name_tree(&self.metta, self.mod_id, &normalized_mod_name, mod_id)
787 }
788
789 pub fn normalize_module_name(&self, mod_name: &str) -> Result<String, String> {
791 let self_mod_path = self.mod_ptr.as_ref()
792 .map(|mod_ptr| mod_ptr.path()).ok_or_else(|| "RunContext::init_self_module must be called prior to this operation".to_string())?;
793 normalize_relative_module_name(self_mod_path, mod_name)
794 }
795
796 pub fn load_module_direct(&mut self, loader: Box<dyn ModuleLoader>, mod_name: &str) -> Result<ModId, String> {
798
799 if self.get_module_by_name(mod_name).is_ok() {
801 return Err(format!("Attempt to load module with name that conflicts with existing module: {mod_name}"));
802 }
803
804 let absolute_mod_name = self.normalize_module_name(mod_name)?;
805 self.init_module(&absolute_mod_name, loader)
806 }
807
808 #[cfg(feature = "pkg_mgmt")]
810 pub fn load_module_at_path<P: AsRef<std::path::Path>>(&mut self, path: P, mod_name: Option<&str>) -> Result<ModId, String> {
811
812 let absolute_mod_name = match mod_name {
813 Some(mod_name) => {
814 if self.get_module_by_name(mod_name).is_ok() {
815 return Err(format!("Attempt to load module with name that conflicts with existing module: {mod_name}"));
816 }
817 Some(self.normalize_module_name(mod_name)?)
818 },
819 None => None
820 };
821
822 let (loader, descriptor) = match loader_for_module_at_path(self.metta.environment().fs_mod_formats(), &path, absolute_mod_name.as_deref(), self.module().resource_dir())? {
824 Some((loader, descriptor)) => (loader, descriptor),
825 None => return Err(format!("Failed to resolve module at path: {}", path.as_ref().display()))
826 };
827
828 let mod_name = match absolute_mod_name {
829 Some(mod_name) => mod_name,
830 None => descriptor.name().to_string()
831 };
832
833 self.get_or_init_module_with_descriptor(&mod_name, descriptor, loader)
835 }
836
837 pub fn load_module_alias(&mut self, mod_name: &str, mod_id: ModId) -> Result<ModId, String> {
839
840 if self.get_module_by_name(&mod_name).is_ok() {
841 return Err(format!("Attempt to create module alias with name that conflicts with existing module: {mod_name}"));
842 }
843 self.add_module_to_name_tree(&mod_name, mod_id)?;
844 Ok(mod_id)
845 }
846
847 pub fn init_self_module(&mut self, space: DynSpace, resource_dir: Option<PathBuf>) {
852 if self.mod_ptr.is_some() {
853 panic!("Module already initialized")
854 }
855 *self.mod_ptr = Some(self.init_state.in_frame(self.mod_id, |frame| {
856 frame.init_self_module(self.mod_id, &self.metta, space, resource_dir)
857 }));
858 }
859
860 pub fn load_module(&mut self, mod_name: &str) -> Result<ModId, String> {
863 let absolute_mod_path = self.normalize_module_name(mod_name)?;
864
865 if let Ok(mod_id) = self.get_module_by_name(&absolute_mod_path) {
867 return Ok(mod_id);
868 }
869
870 #[cfg(not(feature = "pkg_mgmt"))]
871 return Err(format!("Failed to resolve module {absolute_mod_path}"));
872
873 #[cfg(feature = "pkg_mgmt")]
875 {
876 let parent_mod_id = self.load_module_parents(&absolute_mod_path)?;
877 self.load_module_internal(&absolute_mod_path, parent_mod_id)
878 }
879 }
880
881 #[cfg(feature = "pkg_mgmt")]
884 fn load_module_parents(&mut self, mod_name: &str) -> Result<ModId, String> {
885
886 let mod_name_components = decompose_name_path(mod_name)?;
888 let parent_mod_id = if mod_name_components.len() > 1 {
889 let parent_name = compose_name_path(&mod_name_components[..mod_name_components.len()-1])?;
890 if let Ok(parent_mod_id) = self.get_module_by_name(&parent_name) {
891 parent_mod_id
892 } else {
893 let parent_of_parent = self.load_module_parents(&parent_name)?;
894 self.load_module_internal(&parent_name, parent_of_parent)?
895 }
896 } else {
897 ModId::TOP
898 };
899 Ok(parent_mod_id)
900 }
901
902 fn get_mod_ptr(&self, mod_id: ModId) -> Result<Rc<MettaMod>, String> {
905 self.init_state.get_mod_ptr(&self.metta, mod_id)
906 }
907
908 #[cfg(feature = "pkg_mgmt")]
910 fn load_module_internal(&mut self, mod_path: &str, parent_mod_id: ModId) -> Result<ModId, String> {
911 self.in_mod_context(parent_mod_id, |context| {
912 match resolve_module(context.module().pkg_info(), context, mod_path)? {
913 Some((loader, descriptor)) => {
914 context.get_or_init_module_with_descriptor(mod_path, descriptor, loader)
915 },
916 None => {return Err(format!("Failed to resolve module {mod_path}"))}
917 }
918 })
919 }
920
921 pub fn load_resource_from_module(&mut self, mod_name: &str, res_key: ResourceKey) -> Result<Resource, String> {
926
927 if let Ok(mod_id) = self.get_module_by_name(mod_name) {
929 self.metta().get_module_resource(mod_id, res_key)
930 } else {
931 #[cfg(not(feature = "pkg_mgmt"))]
932 return Err(format!("Failed to resolve module {mod_name}"));
933
934 #[cfg(feature = "pkg_mgmt")]
936 {
937 let parent_mod_id = self.load_module_parents(mod_name)?;
938 let normalized_mod_path = self.normalize_module_name(mod_name)?;
939 self.in_mod_context(parent_mod_id, |context| {
940 match resolve_module(context.module().pkg_info(), context, &normalized_mod_path)? {
941 Some((loader, _descriptor)) => {
942 loader.get_resource(res_key)
943 },
944 None => {return Err(format!("Failed to resolve module {mod_name}"))}
945 }
946 })
947 }
948 }
949 }
950
951 #[cfg(feature = "pkg_mgmt")]
952 pub(crate) fn get_or_init_module_with_descriptor(&mut self, mod_name: &str, descriptor: ModuleDescriptor, loader: Box<dyn ModuleLoader>) -> Result<ModId, String> {
962 match self.init_state.get_module_with_descriptor(&self.metta, &descriptor) {
963 Some(mod_id) => {
964 self.load_module_alias(mod_name, mod_id)
965 },
966 None => {
967 let new_id = self.init_module(mod_name, loader)?;
968 self.init_state.add_module_descriptor(&self.metta, descriptor, new_id);
969 Ok(new_id)
970 }
971 }
972 }
973
974 fn init_module(&mut self, mod_name: &str, loader: Box<dyn ModuleLoader>) -> Result<ModId, String> {
978 let new_mod_id = self.init_state.init_module(&self.metta, mod_name, loader)?;
979
980 if self.init_state.is_root() {
981 let mut init_state = ModuleInitState::empty();
982 core::mem::swap(&mut init_state, self.init_state);
983 self.metta.merge_init_state(init_state)
984 } else {
985 Ok(new_mod_id)
986 }
987 }
988
989 pub fn import_dependency_as(&self, mod_id: ModId, name: Option<String>) -> Result<(), String> {
992 self.module().import_dependency_as(self.get_mod_ptr(mod_id)?, name)
993 }
994
995 pub fn import_item_from_dependency_as(&self, from_name: &str, mod_id: ModId, name: Option<&str>) -> Result<(), String> {
1016 self.module().import_item_from_dependency_as(from_name, self.get_mod_ptr(mod_id)?, name)
1017 }
1018
1019 pub fn import_all_from_dependency(&self, mod_id: ModId) -> Result<(), String> {
1025 self.module().import_all_from_dependency(mod_id, self.get_mod_ptr(mod_id)?, self.metta)
1026 }
1027
1028 fn step(&mut self) -> Result<(), String> {
1030
1031 if let Some(interpreter_state) = core::mem::take(&mut self.i_wrapper.interpreter_state) {
1033
1034 if interpreter_state.has_next() {
1035
1036 self.i_wrapper.interpreter_state = Some(interpret_step(interpreter_state))
1038 } else {
1039
1040 let result = interpreter_state.into_result().unwrap();
1042 let error = result.iter().any(|atom| atom_is_error(atom));
1043 self.i_wrapper.results.push(result);
1044 if error {
1045 self.i_wrapper.mode = MettaRunnerMode::TERMINATE;
1046 return Ok(());
1047 }
1048 }
1049
1050 Ok(())
1051 } else {
1052
1053 let tokenizer_option = self.mod_ptr.as_ref().map(|module| module.tokenizer().borrow());
1055 let tokenizer = tokenizer_option.as_ref().map(|tok| &**tok as &Tokenizer);
1056 let next_op = match self.i_wrapper.input_src.next_op(tokenizer) {
1057 Ok(atom) => atom,
1058 Err(err) => {
1059 self.i_wrapper.mode = MettaRunnerMode::TERMINATE;
1060 return Err(err);
1061 }
1062 };
1063 drop(tokenizer_option);
1064
1065 match next_op {
1067 Some(Executable::Func(func)) => {
1068 func(self)
1069 },
1070 Some(Executable::Atom(atom)) => {
1072 if atom == EXEC_SYMBOL {
1073 self.i_wrapper.mode = MettaRunnerMode::INTERPRET;
1074 return Ok(());
1075 }
1076 match self.i_wrapper.mode {
1077 MettaRunnerMode::ADD => {
1078 if let Err(errors) = self.module().add_atom(atom, self.metta.type_check_is_enabled()) {
1079 self.i_wrapper.results.push(errors);
1080 self.i_wrapper.mode = MettaRunnerMode::TERMINATE;
1081 return Ok(());
1082 }
1083 },
1084 MettaRunnerMode::INTERPRET => {
1085
1086 if self.metta.type_check_is_enabled() {
1087 let types = get_atom_types(&self.module().space(), &atom);
1088 if types.iter().all(AtomType::is_error) {
1089 self.i_wrapper.interpreter_state = Some(InterpreterState::new_finished(self.module().space().clone(),
1090 types.into_iter().map(AtomType::into_error_unchecked).collect()));
1091 return Ok(())
1092 }
1093 }
1094 let atom = if is_bare_minimal_interpreter(self.metta) {
1095 atom
1096 } else {
1097 wrap_atom_by_metta_interpreter(self.module().space().clone(), atom)
1098 };
1099 self.i_wrapper.interpreter_state = Some(interpret_init(self.module().space().clone(), &atom));
1100 if let Some(depth) = self.metta.settings().get_string("max-stack-depth") {
1101 let depth = depth.parse::<usize>().unwrap();
1102 self.i_wrapper.interpreter_state.as_mut().map(|state| state.set_max_stack_depth(depth));
1103 }
1104 },
1105 MettaRunnerMode::TERMINATE => {
1106 return Ok(());
1107 },
1108 }
1109 self.i_wrapper.mode = MettaRunnerMode::ADD;
1110 Ok(())
1111 },
1112 None => {
1113 self.i_wrapper.mode = MettaRunnerMode::TERMINATE;
1114 Ok(())
1115 }
1116 }
1117 }
1118 }
1119
1120}
1121
1122fn is_bare_minimal_interpreter(metta: &Metta) -> bool {
1123 metta.settings().get_string("interpreter") == Some("bare-minimal".into())
1124}
1125
1126#[derive(Default)]
1133struct InterpreterWrapper<'i> {
1134 mode: MettaRunnerMode,
1135 input_src: InputStream<'i>,
1136 interpreter_state: Option<InterpreterState>,
1137 results: Vec<Vec<Atom>>,
1138}
1139
1140#[derive(Debug, Default, PartialEq, Eq)]
1141enum MettaRunnerMode {
1142 #[default]
1143 ADD,
1144 INTERPRET,
1145 TERMINATE,
1146}
1147
1148enum InputSource<'i> {
1150 Parser(Box<dyn Parser + 'i>),
1151 Func(Box<dyn FnOnce(&mut RunContext) -> Result<(), String> + 'i>)
1152}
1153
1154enum Executable<'i> {
1172 Atom(Atom),
1173 Func(Box<dyn FnOnce(&mut RunContext) -> Result<(), String> + 'i>)
1174}
1175
1176#[derive(Default)]
1178struct InputStream<'a>(Vec<InputSource<'a>>);
1179
1180impl<'i> InputStream<'i> {
1181 fn push_parser(&mut self, parser: Box<dyn Parser + 'i>) {
1182 self.0.push(InputSource::Parser(parser))
1183 }
1184 fn push_func<F: FnOnce(&mut RunContext) -> Result<(), String> + 'i>(&mut self, f: F) {
1185 self.0.push(InputSource::Func(Box::new(f)))
1186 }
1187 fn next_op(&mut self, tokenizer: Option<&Tokenizer>) -> Result<Option<Executable<'i>>, String> {
1190 match self.0.get_mut(0) {
1191 None => Ok(None),
1192 Some(src) => {
1193 match src {
1194 InputSource::Func(_) => match self.0.remove(0) {
1195 InputSource::Func(f) => Ok(Some(Executable::Func(f))),
1196 _ => unreachable!()
1197 },
1198 InputSource::Parser(parser) => {
1199 match parser.next_atom(tokenizer.as_ref()
1200 .unwrap_or_else(|| panic!("Module must be initialized to parse MeTTa code")))? {
1201 Some(atom) => Ok(Some(Executable::Atom(atom))),
1202 None => {
1203 self.0.remove(0);
1204 self.next_op(tokenizer)
1205 }
1206 }
1207 }
1208 }
1209 }
1210 }
1211 }
1212}
1213
1214fn wrap_atom_by_metta_interpreter(space: DynSpace, atom: Atom) -> Atom {
1215 let space = Atom::gnd(space);
1216 let interpret = Atom::expr([METTA_SYMBOL, atom, ATOM_TYPE_UNDEFINED, space]);
1217 interpret
1218}
1219
1220#[cfg(test)]
1225pub fn run_program(program: &str) -> Result<Vec<Vec<Atom>>, String> {
1226 let metta = Metta::new(Some(EnvBuilder::test_env()));
1227 metta.run(SExprParser::new(program))
1228}
1229
1230#[cfg(test)]
1231mod tests {
1232 use hyperon_atom::gnd::number::Number;
1233 use super::*;
1234 use hyperon_atom::gnd::bool::Bool;
1235 use hyperon_macros::metta;
1236
1237 #[test]
1238 fn test_space() {
1239 let program = "
1240 (= (And T T) T)
1241 (= (frog $x)
1242 (And (croaks $x)
1243 (eat_flies $x)))
1244 (= (croaks Fritz) T)
1245 (= (eat_flies Fritz) T)
1246 (= (green $x) (frog $x))
1247 !(green Fritz)
1248 ";
1249
1250 let metta = Metta::new(Some(EnvBuilder::test_env()));
1251 let result = metta.run(SExprParser::new(program));
1252 assert_eq!(result, Ok(vec![vec![Atom::sym("T")]]));
1253 }
1254
1255 #[test]
1256 fn metta_type_check_incorrect_number_of_arguments() {
1257 let program = "
1258 (: foo (-> A B))
1259 (foo)
1260 ";
1261
1262 let metta = Metta::new_core(None, Some(EnvBuilder::test_env()));
1263 metta.settings().set("type-check".into(), sym!("auto"));
1264 let result = metta.run(SExprParser::new(program));
1265 assert_eq!(result, Ok(vec![vec![expr!("Error" ("foo") "IncorrectNumberOfArguments")]]));
1266 }
1267
1268 #[test]
1269 fn metta_add_type_check() {
1270 let program = "
1271 (: foo (-> A B))
1272 (: b B)
1273 (foo b)
1274 ";
1275
1276 let metta = Metta::new_core(None, Some(EnvBuilder::test_env()));
1277 metta.settings().set("type-check".into(), sym!("auto"));
1278 let result = metta.run(SExprParser::new(program));
1279 assert_eq!(result, Ok(vec![vec![expr!("Error" ("foo" "b") ("BadArgType" {Number::Integer(1)} "A" "B"))]]));
1280 }
1281
1282 #[test]
1283 fn metta_interpret_type_check() {
1284 let program = "
1285 (: foo (-> A B))
1286 (: b B)
1287 !(foo b)
1288 ";
1289
1290 let metta = Metta::new_core(None, Some(EnvBuilder::test_env()));
1291 metta.settings().set("type-check".into(), sym!("auto"));
1292 let result = metta.run(SExprParser::new(program));
1293 assert_eq!(result, Ok(vec![vec![expr!("Error" ("foo" "b") ("BadArgType" {Number::Integer(1)} "A" "B"))]]));
1294 }
1295
1296 #[derive(Clone, Debug)]
1297 struct ErrorOp{}
1298
1299 grounded_op!(ErrorOp, "error");
1300
1301 impl Grounded for ErrorOp {
1302 fn type_(&self) -> Atom {
1303 Atom::expr([ARROW_SYMBOL, ATOM_TYPE_UNDEFINED])
1304 }
1305 fn as_execute(&self) -> Option<&dyn CustomExecute> {
1306 Some(self)
1307 }
1308 }
1309
1310 impl CustomExecute for ErrorOp {
1311 fn execute(&self, _args: &[Atom]) -> Result<Vec<Atom>, ExecError> {
1312 Err("TestError".into())
1313 }
1314 }
1315
1316 #[test]
1317 fn metta_stop_run_after_error() {
1318 let program = "
1319 (= (foo) ok)
1320 !(error)
1321 !(foo)
1322 ";
1323
1324 let metta = Metta::new(Some(EnvBuilder::test_env()));
1325 metta.tokenizer().borrow_mut().register_token_with_regex_str("error",
1326 |_| Atom::gnd(ErrorOp{}));
1327 let result = metta.run(SExprParser::new(program));
1328
1329 assert_eq!(result, Ok(vec![vec![expr!("Error" ({ErrorOp{}}) "TestError")]]));
1330 }
1331
1332 #[test]
1333 fn metta_stop_after_type_check_fails_on_add() {
1334 let program = "
1335 (: foo (-> A B))
1336 (: a A)
1337 (: b B)
1338 (foo b)
1339 !(foo a)
1340 ";
1341
1342 let metta = Metta::new_core(None, Some(EnvBuilder::test_env()));
1343 metta.settings().set("type-check".into(), sym!("auto"));
1344 let result = metta.run(SExprParser::new(program));
1345 assert_eq!(result, Ok(vec![vec![expr!("Error" ("foo" "b") ("BadArgType" {Number::Integer(1)} "A" "B"))]]));
1346 }
1347
1348 #[test]
1349 fn metta_stop_after_error_happens_inside_tuple() {
1350 let metta = Metta::new_core(None, Some(EnvBuilder::test_env()));
1351 let program = "
1352 !(a b c (Error e SomeError))
1353 ";
1354 let result = metta.run(SExprParser::new(program));
1355 assert_eq!(result, Ok(vec![vec![expr!("Error" "e" "SomeError")]]));
1356
1357 let metta = Metta::new_core(None, Some(EnvBuilder::test_env()));
1358 let program = "
1359 !((Error e SomeError) a b c)
1360 ";
1361 let result = metta.run(SExprParser::new(program));
1362 assert_eq!(result, Ok(vec![vec![expr!("Error" "e" "SomeError")]]));
1363
1364 let metta = Metta::new_core(None, Some(EnvBuilder::test_env()));
1365 let program = "
1366 (: foo (-> A B))
1367 (: b B)
1368 !(s (foo b))
1369 ";
1370 let result = metta.run(SExprParser::new(program));
1371 assert_eq!(result, Ok(vec![vec![expr!("Error" ("foo" "b") ("BadArgType" {Number::Integer(1)} "A" "B"))]]));
1372 }
1373
1374 #[test]
1375 fn metta_first_call_in_the_tuple_has_incorrect_typing() {
1376 let metta = Metta::new_core(None, Some(EnvBuilder::test_env()));
1377 let program = "
1378 (: foo (-> A B))
1379 (: b B)
1380 !((foo b) s)
1381 ";
1382 let result = metta.run(SExprParser::new(program));
1383 assert_eq!(result, Ok(vec![vec![expr!("Error" ("foo" "b") ("BadArgType" {Number::Integer(1)} "A" "B"))]]));
1384 }
1385
1386
1387 #[derive(Clone, PartialEq, Debug)]
1388 struct ReturnAtomOp(Atom);
1389
1390 impl std::fmt::Display for ReturnAtomOp {
1391 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1392 write!(f, "return-atom {}", self.0)
1393 }
1394 }
1395
1396 impl Grounded for ReturnAtomOp {
1397 fn type_(&self) -> Atom {
1398 Atom::expr([ARROW_SYMBOL, ATOM_TYPE_UNDEFINED])
1399 }
1400 fn as_execute(&self) -> Option<&dyn CustomExecute> {
1401 Some(self)
1402 }
1403 }
1404
1405 impl CustomExecute for ReturnAtomOp {
1406 fn execute(&self, _args: &[Atom]) -> Result<Vec<Atom>, ExecError> {
1407 Ok(vec![self.0.clone()])
1408 }
1409 }
1410
1411 #[test]
1412 fn metta_no_crash_on_empty_expression_returned() {
1413 let program = "
1414 !(empty)
1415 ";
1416
1417 let metta = Metta::new(Some(EnvBuilder::test_env()));
1418 metta.tokenizer().borrow_mut().register_token_with_regex_str("empty",
1419 |_| Atom::gnd(ReturnAtomOp(expr!())));
1420 let result = metta.run(SExprParser::new(program));
1421
1422 assert_eq!(result, Ok(vec![vec![expr!()]]));
1423 }
1424
1425 #[test]
1426 fn metta_empty_results_issue_481() {
1427 let metta = Metta::new(Some(EnvBuilder::test_env()));
1428
1429 let program = "
1430 !(== () (collapse
1431 (let* (($L ()) ($x (superpose $L))) $x) ))
1432 ";
1433 let result = metta.run(SExprParser::new(program));
1434 assert_eq!(result, Ok(vec![vec![Atom::gnd(Bool(true))]]));
1435
1436 let program = "!(let $x (empty) OK)";
1437 let result = metta.run(SExprParser::new(program));
1438 assert_eq!(result, Ok(vec![vec![]]));
1439
1440 let program = "!(let* (($x (empty))) OK)";
1441 let result = metta.run(SExprParser::new(program));
1442 assert_eq!(result, Ok(vec![vec![]]));
1443 }
1444
1445 #[test]
1446 fn metta_no_config_dir_by_default() {
1447 let metta = Metta::new(None);
1448 assert_eq!(metta.environment().config_dir(), None);
1449 }
1450
1451 #[test]
1452 fn metta_enable_auto_type_check() {
1453 let metta = Metta::new(Some(EnvBuilder::test_env()));
1454
1455 let program = "
1456 (: a A)
1457 (: b B)
1458 (: foo (-> A A))
1459 (= (foo $x) $x)
1460
1461 !(pragma! type-check auto)
1462 !(foo a)
1463 !(foo b)
1464 ";
1465 let result = metta.run(SExprParser::new(program));
1466 assert_eq!(result, Ok(vec![
1467 vec![UNIT_ATOM],
1468 vec![metta!(a)],
1469 vec![metta!((Error (foo b) (BadArgType 1 A B)))]
1470 ]));
1471 }
1472}