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
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
+32
-26
@@ -19,7 +19,6 @@ use crate::ast::compiler::macros::{MacroEvaluator, MacroExpander, MacroRegistry}
|
|||||||
use crate::ast::compiler::optimizer::Optimizer;
|
use crate::ast::compiler::optimizer::Optimizer;
|
||||||
use crate::ast::compiler::specializer::{FunctionRegistry, MonoCache, Specializer};
|
use crate::ast::compiler::specializer::{FunctionRegistry, MonoCache, Specializer};
|
||||||
use crate::ast::compiler::tco::{ExecNode, TCO};
|
use crate::ast::compiler::tco::{ExecNode, TCO};
|
||||||
use crate::ast::rtl;
|
|
||||||
use crate::ast::rtl::intrinsics;
|
use crate::ast::rtl::intrinsics;
|
||||||
use crate::ast::types::{
|
use crate::ast::types::{
|
||||||
Identity, NodeIdentity, Object, Purity, SourceLocation, StaticType, Value,
|
Identity, NodeIdentity, Object, Purity, SourceLocation, StaticType, Value,
|
||||||
@@ -28,6 +27,9 @@ use crate::ast::types::{
|
|||||||
use crate::ast::diagnostics::{DiagnosticLevel, Diagnostics};
|
use crate::ast::diagnostics::{DiagnosticLevel, Diagnostics};
|
||||||
pub type PipelineGenerator = Box<dyn FnMut() -> bool>;
|
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 struct CompilationResult {
|
||||||
pub ast: Option<TypedNode>,
|
pub ast: Option<TypedNode>,
|
||||||
pub diagnostics: Diagnostics,
|
pub diagnostics: Diagnostics,
|
||||||
@@ -169,22 +171,18 @@ impl Environment {
|
|||||||
search_paths: Rc::new(RefCell::new(Vec::new())),
|
search_paths: Rc::new(RefCell::new(Vec::new())),
|
||||||
loaded_modules: Rc::new(RefCell::new(HashSet::new())),
|
loaded_modules: Rc::new(RefCell::new(HashSet::new())),
|
||||||
};
|
};
|
||||||
env.register_stdlib();
|
crate::ast::rtl::register(&env);
|
||||||
env
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds the current working directory to the global search paths.
|
// Automatically add standard search paths (CWD and CWD/rtl)
|
||||||
/// 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() {
|
if let Ok(cwd) = std::env::current_dir() {
|
||||||
self.add_search_path(&cwd);
|
env.add_search_path(&cwd);
|
||||||
// Also add the rtl subdirectory if it exists
|
|
||||||
let rtl_path = cwd.join("rtl");
|
let rtl_path = cwd.join("rtl");
|
||||||
if rtl_path.exists() {
|
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>) {
|
pub fn add_search_path(&self, path: impl AsRef<Path>) {
|
||||||
@@ -276,16 +274,7 @@ impl Environment {
|
|||||||
base_path: &Path,
|
base_path: &Path,
|
||||||
all_files: &mut Vec<(PathBuf, Node<UntypedKind>)>,
|
all_files: &mut Vec<(PathBuf, Node<UntypedKind>)>,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
let mut directives = self.extract_use_directives(source);
|
let 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 {
|
for module_path in directives {
|
||||||
let abs_paths = self.resolve_module_paths(&module_path, base_path)?;
|
let abs_paths = self.resolve_module_paths(&module_path, base_path)?;
|
||||||
@@ -352,7 +341,23 @@ impl Environment {
|
|||||||
pub fn preload_dependencies(&self, source: &str, file_path: Option<&Path>) -> Result<(), String> {
|
pub fn preload_dependencies(&self, source: &str, file_path: Option<&Path>) -> Result<(), String> {
|
||||||
let base_path = file_path.and_then(|p| p.parent()).unwrap_or_else(|| Path::new("."));
|
let base_path = file_path.and_then(|p| p.parent()).unwrap_or_else(|| Path::new("."));
|
||||||
let mut files = Vec::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)?;
|
self.collect_dependencies(source, base_path, &mut files)?;
|
||||||
|
|
||||||
// Pass 1: Discovery (Globals and Macros)
|
// Pass 1: Discovery (Globals and Macros)
|
||||||
@@ -463,7 +468,7 @@ impl Environment {
|
|||||||
Some(checker.check(&wrapped_ast, &[], diagnostics))
|
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 mut diagnostics = Diagnostics::new();
|
||||||
|
|
||||||
let typed_ast_opt = self.compile_pipeline(untyped_ast, &mut diagnostics);
|
let typed_ast_opt = self.compile_pipeline(untyped_ast, &mut diagnostics);
|
||||||
@@ -530,9 +535,6 @@ impl Environment {
|
|||||||
values.push(val);
|
values.push(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_stdlib(&self) {
|
|
||||||
rtl::register(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dump_ast(&self, source: &str) -> Result<String, String> {
|
pub fn dump_ast(&self, source: &str) -> Result<String, String> {
|
||||||
self.preload_dependencies(source, None)?;
|
self.preload_dependencies(source, None)?;
|
||||||
@@ -542,6 +544,10 @@ impl Environment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(&self, source: &str) -> CompilationResult {
|
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 mut parser = Parser::new(source);
|
||||||
let untyped_ast = parser.parse_expression();
|
let untyped_ast = parser.parse_expression();
|
||||||
|
|
||||||
|
|||||||
+1
-11
@@ -42,7 +42,7 @@ struct Cli {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
let mut env = Environment::new().with_cwd();
|
let mut env = Environment::new();
|
||||||
env.optimization = !cli.no_opt;
|
env.optimization = !cli.no_opt;
|
||||||
|
|
||||||
// Load libraries (Now just search paths)
|
// Load libraries (Now just search paths)
|
||||||
@@ -74,11 +74,6 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(script_str) = cli.eval {
|
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 {
|
if cli.dump {
|
||||||
match env.dump_ast(&script_str) {
|
match env.dump_ast(&script_str) {
|
||||||
Ok(dump) => println!("{}", dump),
|
Ok(dump) => println!("{}", dump),
|
||||||
@@ -92,11 +87,6 @@ fn main() {
|
|||||||
} else if let Some(file_path) = cli.file {
|
} else if let Some(file_path) = cli.file {
|
||||||
match fs::read_to_string(&file_path) {
|
match fs::read_to_string(&file_path) {
|
||||||
Ok(content) => {
|
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 {
|
if cli.dump {
|
||||||
match env.dump_ast(&content) {
|
match env.dump_ast(&content) {
|
||||||
Ok(dump) => println!("{}", dump),
|
Ok(dump) => println!("{}", dump),
|
||||||
|
|||||||
@@ -578,7 +578,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_record_inlining_in_while_loop() {
|
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).
|
// Ensure that constants (like the config record) are inherited into inner lambda scopes (like the body of a while loop).
|
||||||
let source = r#"
|
let source = r#"
|
||||||
(do
|
(do
|
||||||
@@ -603,7 +603,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// The result of running it should obviously still be correct.
|
// 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();
|
let res = env_run.run_script(source).unwrap();
|
||||||
assert_eq!(format!("{}", res), "10");
|
assert_eq!(format!("{}", res), "10");
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-12
@@ -61,7 +61,7 @@ impl Default for CompilerApp {
|
|||||||
})
|
})
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let env = Environment::new().with_cwd();
|
let env = Environment::new();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
source_code: String::from(
|
source_code: String::from(
|
||||||
@@ -96,14 +96,10 @@ impl CompilerApp {
|
|||||||
self.trace_logs.clear();
|
self.trace_logs.clear();
|
||||||
|
|
||||||
// Reset environment for a fresh run
|
// Reset environment for a fresh run
|
||||||
self.env = Environment::new().with_cwd();
|
self.env = Environment::new();
|
||||||
self.env.optimization = true;
|
self.env.optimization = true;
|
||||||
|
|
||||||
let res = (|| -> Result<(myc::ast::types::Value, std::time::Duration), String> {
|
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 start_run = std::time::Instant::now();
|
||||||
let result = if self.debug_enabled {
|
let result = if self.debug_enabled {
|
||||||
let (res, logs) = self.env.run_debug(&self.source_code)?;
|
let (res, logs) = self.env.run_debug(&self.source_code)?;
|
||||||
@@ -162,14 +158,9 @@ impl CompilerApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn dump_ast(&mut self) {
|
fn dump_ast(&mut self) {
|
||||||
self.env = Environment::new().with_cwd();
|
self.env = Environment::new();
|
||||||
self.env.optimization = true; // Enable optimization for AST dump
|
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) {
|
match self.env.dump_ast(&self.source_code) {
|
||||||
Ok(dump) => {
|
Ok(dump) => {
|
||||||
self.output_log = format!("--- BOUND AST DUMP ---\n\n{}", 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();
|
let output_re = Regex::new(r";; Output: (.*)").unwrap();
|
||||||
|
|
||||||
for entry in entries.filter_map(|e| e.ok()) {
|
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;
|
env.optimization = enabled;
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
if path.extension().is_some_and(|ext| ext == "myc") {
|
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());
|
.map(|m| m.get(1).unwrap().as_str().trim().to_string());
|
||||||
|
|
||||||
if let Some(expected) = expected_output {
|
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) {
|
match env.run_script(&content) {
|
||||||
Ok(val) => {
|
Ok(val) => {
|
||||||
let val_str = format!("{}", val);
|
let val_str = format!("{}", val);
|
||||||
@@ -120,20 +111,8 @@ pub fn run_benchmarks(update: bool, filter: Option<&str>) -> Vec<BenchmarkResult
|
|||||||
.unwrap_or(1);
|
.unwrap_or(1);
|
||||||
|
|
||||||
// Compile once for this file (symbols/types are compatible with all fresh environments)
|
// Compile once for this file (symbols/types are compatible with all fresh environments)
|
||||||
let initial_env = Environment::new().with_cwd();
|
let env = Environment::new();
|
||||||
|
let compiled_once = match env.compile(&content).into_result() {
|
||||||
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() {
|
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
results.push(BenchmarkResult {
|
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
|
// Helper to measure sum of VM execution times over N executions in one environment
|
||||||
let measure_sum =
|
let measure_sum =
|
||||||
|n: u32, node: &crate::ast::compiler::TypedNode| -> Result<Duration, String> {
|
|n: u32, node: &crate::ast::compiler::TypedNode| -> Result<Duration, String> {
|
||||||
let env = Environment::new().with_cwd();
|
let env = Environment::new();
|
||||||
if let Err(e) = env.preload_dependencies(&content, Some(&path)) {
|
|
||||||
return Err(format!("Dependency Error in measurement: {}", e));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Link once per sample
|
// Link once per sample
|
||||||
let linked = env.link(node.clone());
|
let linked = env.link(node.clone());
|
||||||
|
|||||||
Reference in New Issue
Block a user