Add module loader and related tests

Introduce `ModuleLoader` to handle `#use` directives and dependency
resolution. This involves adding `tempfile` dependency, modifying
`Cargo.toml` and `Cargo.lock`, creating a new `module_loader.rs` file,
and updating `environment.rs` to use the new module.

Also, add comprehensive tests for `Diagnostics::format_errors`,
`CompilationResult`, and the new `ModuleLoader` functionality. These
tests cover various scenarios including empty diagnostics, multiple
errors, error formatting, compilation success/failure, and complex
dependency loading with topological ordering and search path resolution.
This commit is contained in:
2026-03-27 15:08:28 +01:00
parent 636f5a1814
commit 1f0208af95
8 changed files with 457 additions and 123 deletions
+56
View File
@@ -0,0 +1,56 @@
use myc::ast::compiler::CompilationResult;
use myc::ast::diagnostics::Diagnostics;
use myc::ast::environment::Environment;
// --- Diagnostics::format_errors() ---
#[test]
fn format_errors_empty() {
let diag = Diagnostics::new();
assert_eq!(diag.format_errors(), "");
}
#[test]
fn format_errors_single() {
let mut diag = Diagnostics::new();
diag.push_error("type mismatch", None);
assert_eq!(diag.format_errors(), "type mismatch");
}
#[test]
fn format_errors_multiple_joined_with_newline() {
let mut diag = Diagnostics::new();
diag.push_error("first error", None);
diag.push_error("second error", None);
assert_eq!(diag.format_errors(), "first error\nsecond error");
}
#[test]
fn format_errors_ignores_warnings_and_hints() {
let mut diag = Diagnostics::new();
diag.push_warning("just a warning", None);
diag.push_hint("a hint", None);
diag.push_error("the real error", None);
// Only the error should appear
assert_eq!(diag.format_errors(), "the real error");
}
// --- CompilationResult ---
#[test]
fn compilation_result_error_into_err() {
let result = CompilationResult::error("something went wrong");
let err = result.into_result();
assert!(err.is_err());
assert_eq!(err.unwrap_err(), "something went wrong");
}
#[test]
fn compilation_result_success_into_ok() {
// The success() constructor requires a TypedNode, which is produced by
// the compiler. We verify the happy path via a minimal compile round-trip.
let env = Environment::new();
let result = env.compile("(+ 1 2)");
assert!(!result.diagnostics.has_errors(), "unexpected errors: {}", result.diagnostics.format_errors());
assert!(result.into_result().is_ok());
}