Refactor: Introduce system library

- Add `rtl/system.myc` as the system library, containing core utilities
  like `while` and `cache`.
- Remove the duplicate `prelude.myc` from `src/ast/rtl/`.
- Modify `Environment::collect_dependencies` to implicitly add `#use
  system` when necessary.
- Update `Environment::with_cwd` to also add the `rtl` subdirectory to
  search paths.
- Add `target/` to `.geminiignore` to exclude build artifacts.
- Adjust example `sma.myc` to use the new `cache` macro and reduce
  sample data size.
- Update `rtl/sma.myc` to correctly initialize the `history` series with
  its `length`.
- Add `preload_dependencies` calls to `dump_ast` and `run_script` for
  proper module loading.
This commit is contained in:
Michael Schimmel
2026-03-08 12:09:32 +01:00
parent 595bcf09e5
commit 4dfdc75545
7 changed files with 56 additions and 63 deletions
+19 -13
View File
@@ -177,7 +177,12 @@ impl Environment {
/// This is a builder method to easily initialize an environment for file-based usage.
pub fn with_cwd(self) -> Self {
if let Ok(cwd) = std::env::current_dir() {
self.add_search_path(cwd);
self.add_search_path(&cwd);
// Also add the rtl subdirectory if it exists
let rtl_path = cwd.join("rtl");
if rtl_path.exists() {
self.add_search_path(rtl_path);
}
}
self
}
@@ -213,15 +218,6 @@ impl Environment {
MacroExpander::new(self.macro_registry.borrow().clone(), evaluator)
}
fn eval_prelude(&self, source: &str) {
let mut parser = crate::ast::parser::Parser::new(source);
let untyped_ast = parser.parse_expression();
let mut expander = self.get_expander();
let _ = expander
.expand(untyped_ast)
.expect("Failed to expand prelude");
*self.macro_registry.borrow_mut() = expander.into_registry();
}
/// Resolves a #use module path relative to a base path, then falls back to search paths.
/// Returns a list of all matching .myc files (single file, or all files in a directory).
@@ -274,14 +270,22 @@ impl Environment {
Err(format!("Could not find module or directory '{}'", module_path))
}
/// Recursively collects all dependencies starting from a given source string.
fn collect_dependencies(
&self,
source: &str,
base_path: &Path,
all_files: &mut Vec<(PathBuf, Node<UntypedKind>)>,
) -> Result<(), String> {
let directives = self.extract_use_directives(source);
let mut directives = self.extract_use_directives(source);
// Implicitly add #use system if it's not already there and we can resolve it.
// This is only done for the root script (when loaded_modules is empty) to avoid redundancy.
if !directives.contains(&"system".to_string())
&& self.loaded_modules.borrow().is_empty()
&& self.resolve_module_paths("system", base_path).is_ok()
{
directives.insert(0, "system".to_string());
}
for module_path in directives {
let abs_paths = self.resolve_module_paths(&module_path, base_path)?;
@@ -528,10 +532,10 @@ impl Environment {
fn register_stdlib(&self) {
rtl::register(self);
self.eval_prelude(include_str!("rtl/prelude.myc"));
}
pub fn dump_ast(&self, source: &str) -> Result<String, String> {
self.preload_dependencies(source, None)?;
let compiled = self.compile(source).into_result()?;
let linked = self.link(compiled);
Ok(Dumper::dump(&linked))
@@ -717,6 +721,7 @@ impl Environment {
}
pub fn run_script(&self, source: &str) -> Result<Value, String> {
self.preload_dependencies(source, None)?;
if self.debug_mode {
let (res, logs) = self.run_debug(source)?;
for line in logs {
@@ -739,6 +744,7 @@ impl Environment {
}
pub fn run_debug(&self, source: &str) -> Result<(Result<Value, String>, Vec<String>), String> {
self.preload_dependencies(source, None)?;
let compiled = self.compile(source).into_result()?;
let linked = self.link(compiled);
let mut vm = VM::new(self.global_values.clone());