Remove unused system library and simplify environment initialization
The `system.myc` file, containing macros and core utilities, has been removed as its functionality is now handled by an embedded string. This simplifies the build process and eliminates a file that was no longer strictly necessary. Additionally, the `with_cwd()` method on the `Environment` has been removed. The environment now automatically adds the current working directory and its `rtl` subdirectory to the search paths during initialization. This streamlines the setup for file-based usage and ensures standard search paths are always considered.
This commit is contained in:
@@ -1,19 +0,0 @@
|
||||
;; Myc System Library
|
||||
;; Standard macros and core utilities.
|
||||
|
||||
(do
|
||||
(macro while [cond body]
|
||||
`((fn [] (if ~cond
|
||||
(do ~body (again))
|
||||
)))
|
||||
)
|
||||
|
||||
;; Creates a stateful cache (Series) from a stateless stream.
|
||||
(macro cache [lookback type src]
|
||||
`(do
|
||||
(def data (series ~lookback ~type))
|
||||
(pipe [~src] (fn [s] (do (push data s))))
|
||||
data
|
||||
)
|
||||
)
|
||||
)
|
||||
+31
-25
@@ -19,7 +19,6 @@ use crate::ast::compiler::macros::{MacroEvaluator, MacroExpander, MacroRegistry}
|
||||
use crate::ast::compiler::optimizer::Optimizer;
|
||||
use crate::ast::compiler::specializer::{FunctionRegistry, MonoCache, Specializer};
|
||||
use crate::ast::compiler::tco::{ExecNode, TCO};
|
||||
use crate::ast::rtl;
|
||||
use crate::ast::rtl::intrinsics;
|
||||
use crate::ast::types::{
|
||||
Identity, NodeIdentity, Object, Purity, SourceLocation, StaticType, Value,
|
||||
@@ -28,6 +27,9 @@ use crate::ast::types::{
|
||||
use crate::ast::diagnostics::{DiagnosticLevel, Diagnostics};
|
||||
pub type PipelineGenerator = Box<dyn FnMut() -> bool>;
|
||||
|
||||
const SYSTEM_LIB_SOURCE: &str = include_str!("system.myc");
|
||||
const SYSTEM_LIB_PATH: &str = "<embedded>/system.myc";
|
||||
|
||||
pub struct CompilationResult {
|
||||
pub ast: Option<TypedNode>,
|
||||
pub diagnostics: Diagnostics,
|
||||
@@ -169,22 +171,18 @@ impl Environment {
|
||||
search_paths: Rc::new(RefCell::new(Vec::new())),
|
||||
loaded_modules: Rc::new(RefCell::new(HashSet::new())),
|
||||
};
|
||||
env.register_stdlib();
|
||||
env
|
||||
}
|
||||
crate::ast::rtl::register(&env);
|
||||
|
||||
/// Adds the current working directory to the global search paths.
|
||||
/// This is a builder method to easily initialize an environment for file-based usage.
|
||||
pub fn with_cwd(self) -> Self {
|
||||
// Automatically add standard search paths (CWD and CWD/rtl)
|
||||
if let Ok(cwd) = std::env::current_dir() {
|
||||
self.add_search_path(&cwd);
|
||||
// Also add the rtl subdirectory if it exists
|
||||
env.add_search_path(&cwd);
|
||||
let rtl_path = cwd.join("rtl");
|
||||
if rtl_path.exists() {
|
||||
self.add_search_path(rtl_path);
|
||||
env.add_search_path(rtl_path);
|
||||
}
|
||||
}
|
||||
self
|
||||
|
||||
env
|
||||
}
|
||||
|
||||
pub fn add_search_path(&self, path: impl AsRef<Path>) {
|
||||
@@ -276,16 +274,7 @@ impl Environment {
|
||||
base_path: &Path,
|
||||
all_files: &mut Vec<(PathBuf, Node<UntypedKind>)>,
|
||||
) -> Result<(), String> {
|
||||
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());
|
||||
}
|
||||
let directives = self.extract_use_directives(source);
|
||||
|
||||
for module_path in directives {
|
||||
let abs_paths = self.resolve_module_paths(&module_path, base_path)?;
|
||||
@@ -353,6 +342,22 @@ impl Environment {
|
||||
let base_path = file_path.and_then(|p| p.parent()).unwrap_or_else(|| Path::new("."));
|
||||
let mut files = Vec::new();
|
||||
|
||||
// 1. Always load the embedded system library first as a virtual module
|
||||
let system_path = PathBuf::from(SYSTEM_LIB_PATH);
|
||||
if !self.loaded_modules.borrow().contains(&system_path) {
|
||||
self.loaded_modules.borrow_mut().insert(system_path.clone());
|
||||
let mut parser = Parser::new(SYSTEM_LIB_SOURCE);
|
||||
let untyped_ast = parser.parse_expression();
|
||||
if parser.diagnostics.has_errors() {
|
||||
return Err(format!(
|
||||
"Failed to parse embedded system library:\n{}",
|
||||
parser.diagnostics.items[0].message
|
||||
));
|
||||
}
|
||||
files.push((system_path, untyped_ast));
|
||||
}
|
||||
|
||||
// 2. Collect dependencies from the main source
|
||||
self.collect_dependencies(source, base_path, &mut files)?;
|
||||
|
||||
// Pass 1: Discovery (Globals and Macros)
|
||||
@@ -463,7 +468,7 @@ impl Environment {
|
||||
Some(checker.check(&wrapped_ast, &[], diagnostics))
|
||||
}
|
||||
|
||||
pub fn compile_untyped(&self, untyped_ast: Node<UntypedKind>) -> Result<TypedNode, String> {
|
||||
fn compile_untyped(&self, untyped_ast: Node<UntypedKind>) -> Result<TypedNode, String> {
|
||||
let mut diagnostics = Diagnostics::new();
|
||||
|
||||
let typed_ast_opt = self.compile_pipeline(untyped_ast, &mut diagnostics);
|
||||
@@ -530,9 +535,6 @@ impl Environment {
|
||||
values.push(val);
|
||||
}
|
||||
|
||||
fn register_stdlib(&self) {
|
||||
rtl::register(self);
|
||||
}
|
||||
|
||||
pub fn dump_ast(&self, source: &str) -> Result<String, String> {
|
||||
self.preload_dependencies(source, None)?;
|
||||
@@ -542,6 +544,10 @@ impl Environment {
|
||||
}
|
||||
|
||||
pub fn compile(&self, source: &str) -> CompilationResult {
|
||||
if let Err(e) = self.preload_dependencies(source, None) {
|
||||
return CompilationResult::error(format!("Dependency Error: {}", e));
|
||||
}
|
||||
|
||||
let mut parser = Parser::new(source);
|
||||
let untyped_ast = parser.parse_expression();
|
||||
|
||||
|
||||
+1
-11
@@ -42,7 +42,7 @@ struct Cli {
|
||||
|
||||
fn main() {
|
||||
let cli = Cli::parse();
|
||||
let mut env = Environment::new().with_cwd();
|
||||
let mut env = Environment::new();
|
||||
env.optimization = !cli.no_opt;
|
||||
|
||||
// Load libraries (Now just search paths)
|
||||
@@ -74,11 +74,6 @@ fn main() {
|
||||
}
|
||||
|
||||
if let Some(script_str) = cli.eval {
|
||||
if let Err(e) = env.preload_dependencies(&script_str, None) {
|
||||
eprintln!("❌ Error resolving dependencies: {}", e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
if cli.dump {
|
||||
match env.dump_ast(&script_str) {
|
||||
Ok(dump) => println!("{}", dump),
|
||||
@@ -92,11 +87,6 @@ fn main() {
|
||||
} else if let Some(file_path) = cli.file {
|
||||
match fs::read_to_string(&file_path) {
|
||||
Ok(content) => {
|
||||
if let Err(e) = env.preload_dependencies(&content, Some(&file_path)) {
|
||||
eprintln!("❌ Error resolving dependencies for {:?}:\n{}", file_path, e);
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
if cli.dump {
|
||||
match env.dump_ast(&content) {
|
||||
Ok(dump) => println!("{}", dump),
|
||||
|
||||
@@ -578,7 +578,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_record_inlining_in_while_loop() {
|
||||
let env_ast = Environment::new().with_cwd();
|
||||
let env_ast = Environment::new();
|
||||
// Ensure that constants (like the config record) are inherited into inner lambda scopes (like the body of a while loop).
|
||||
let source = r#"
|
||||
(do
|
||||
@@ -603,7 +603,7 @@ mod tests {
|
||||
);
|
||||
|
||||
// The result of running it should obviously still be correct.
|
||||
let env_run = Environment::new().with_cwd();
|
||||
let env_run = Environment::new();
|
||||
let res = env_run.run_script(source).unwrap();
|
||||
assert_eq!(format!("{}", res), "10");
|
||||
}
|
||||
|
||||
+3
-12
@@ -61,7 +61,7 @@ impl Default for CompilerApp {
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let env = Environment::new().with_cwd();
|
||||
let env = Environment::new();
|
||||
|
||||
Self {
|
||||
source_code: String::from(
|
||||
@@ -96,14 +96,10 @@ impl CompilerApp {
|
||||
self.trace_logs.clear();
|
||||
|
||||
// Reset environment for a fresh run
|
||||
self.env = Environment::new().with_cwd();
|
||||
self.env = Environment::new();
|
||||
self.env.optimization = true;
|
||||
|
||||
let res = (|| -> Result<(myc::ast::types::Value, std::time::Duration), String> {
|
||||
if let Err(e) = self.env.preload_dependencies(&self.source_code, self.current_example_path.as_deref()) {
|
||||
return Err(format!("Dependency Error: {}", e));
|
||||
}
|
||||
|
||||
let start_run = std::time::Instant::now();
|
||||
let result = if self.debug_enabled {
|
||||
let (res, logs) = self.env.run_debug(&self.source_code)?;
|
||||
@@ -162,14 +158,9 @@ impl CompilerApp {
|
||||
}
|
||||
|
||||
fn dump_ast(&mut self) {
|
||||
self.env = Environment::new().with_cwd();
|
||||
self.env = Environment::new();
|
||||
self.env.optimization = true; // Enable optimization for AST dump
|
||||
|
||||
if let Err(e) = self.env.preload_dependencies(&self.source_code, self.current_example_path.as_deref()) {
|
||||
self.output_log = format!("Dependency Error: {}", e);
|
||||
return;
|
||||
}
|
||||
|
||||
match self.env.dump_ast(&self.source_code) {
|
||||
Ok(dump) => {
|
||||
self.output_log = format!("--- BOUND AST DUMP ---\n\n{}", dump);
|
||||
|
||||
+4
-28
@@ -27,7 +27,7 @@ pub fn run_functional_tests_with_optimization(enabled: bool) -> Vec<TestResult>
|
||||
let output_re = Regex::new(r";; Output: (.*)").unwrap();
|
||||
|
||||
for entry in entries.filter_map(|e| e.ok()) {
|
||||
let mut env = Environment::new().with_cwd(); // Fresh environment per test file
|
||||
let mut env = Environment::new(); // Fresh environment per test file
|
||||
env.optimization = enabled;
|
||||
let path = entry.path();
|
||||
if path.extension().is_some_and(|ext| ext == "myc") {
|
||||
@@ -39,15 +39,6 @@ pub fn run_functional_tests_with_optimization(enabled: bool) -> Vec<TestResult>
|
||||
.map(|m| m.get(1).unwrap().as_str().trim().to_string());
|
||||
|
||||
if let Some(expected) = expected_output {
|
||||
if let Err(e) = env.preload_dependencies(&content, Some(&path)) {
|
||||
results.push(TestResult {
|
||||
name,
|
||||
success: false,
|
||||
message: format!("Dependency Error: {}", e),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
match env.run_script(&content) {
|
||||
Ok(val) => {
|
||||
let val_str = format!("{}", val);
|
||||
@@ -120,20 +111,8 @@ pub fn run_benchmarks(update: bool, filter: Option<&str>) -> Vec<BenchmarkResult
|
||||
.unwrap_or(1);
|
||||
|
||||
// Compile once for this file (symbols/types are compatible with all fresh environments)
|
||||
let initial_env = Environment::new().with_cwd();
|
||||
|
||||
if let Err(e) = initial_env.preload_dependencies(&content, Some(&path)) {
|
||||
results.push(BenchmarkResult {
|
||||
name,
|
||||
median: Duration::ZERO,
|
||||
baseline: None,
|
||||
diff_pct: None,
|
||||
status: format!("DEPENDENCY ERROR: {}", e),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
let compiled_once = match initial_env.compile(&content).into_result() {
|
||||
let env = Environment::new();
|
||||
let compiled_once = match env.compile(&content).into_result() {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
results.push(BenchmarkResult {
|
||||
@@ -150,10 +129,7 @@ pub fn run_benchmarks(update: bool, filter: Option<&str>) -> Vec<BenchmarkResult
|
||||
// Helper to measure sum of VM execution times over N executions in one environment
|
||||
let measure_sum =
|
||||
|n: u32, node: &crate::ast::compiler::TypedNode| -> Result<Duration, String> {
|
||||
let env = Environment::new().with_cwd();
|
||||
if let Err(e) = env.preload_dependencies(&content, Some(&path)) {
|
||||
return Err(format!("Dependency Error in measurement: {}", e));
|
||||
}
|
||||
let env = Environment::new();
|
||||
|
||||
// Link once per sample
|
||||
let linked = env.link(node.clone());
|
||||
|
||||
Reference in New Issue
Block a user