diff --git a/src/ast/environment.rs b/src/ast/environment.rs index 279bb75..66489e3 100644 --- a/src/ast/environment.rs +++ b/src/ast/environment.rs @@ -5,7 +5,7 @@ use crate::ast::compiler::{CapturePass, TypeChecker, TypedNode}; use crate::ast::nodes::{AnalyzedPhase, BoundPhase, Symbol, SyntaxKind, SyntaxNode}; use crate::ast::parser::Parser; use crate::ast::closure::Closure; -use crate::ast::vm::{self, GlobalStore, TracingObserver, VM}; +use crate::ast::vm::{GlobalStore, TracingObserver, VM}; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::path::{Path, PathBuf}; @@ -334,23 +334,20 @@ impl Environment { /// Used to pre-load all dependencies of a script before compiling it. 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 mut all_forms: Vec> = 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 forms = parser.parse_program(); + let program = parser.parse_program(); if parser.diagnostics.has_errors() { return Err(format!( "Failed to parse embedded system library:\n{}", parser.diagnostics.items[0].message )); } - for form in forms { - all_forms.push(Rc::new(form)); - } + self.run_program(program)?; } // 2. Collect user dependencies (file I/O + parse, topological order) @@ -358,43 +355,38 @@ impl Environment { Rc::clone(&self.search_paths), Rc::clone(&self.loaded_modules), ); - for (_, syntax_ast) in loader.collect_dependency_files(source, base_path)? { - all_forms.push(Rc::new(syntax_ast)); + for (path, syntax_ast) in loader.collect_dependency_files(source, base_path)? { + let compiled = self.compile_pipeline(syntax_ast, &mut Diagnostics::new()) + .ok_or_else(|| format!("Compilation error in {}", path.display()))?; + self.run_script_compiled(compiled).map_err(|e| { + format!("Initialization error in {}:\n{}", path.display(), e) + })?; } - // Compile and initialize all forms as a single program (no scope boundary) - if !all_forms.is_empty() { - let block = SyntaxNode { - identity: NodeIdentity::anonymous(), - kind: SyntaxKind::Program { exprs: all_forms }, - ty: (), - comments: Rc::from([]), - }; - let mut diagnostics = Diagnostics::new(); + Ok(()) + } - // 1. Expand macros - let expanded = self.expand(block, &mut diagnostics) - .ok_or_else(|| diagnostics.format_errors())?; + /// Compiles and executes a `Program` node without lambda wrapping. + /// Definitions at the top level receive `Address::Global` and persist + /// in the GlobalStore for subsequent compilation units. + fn run_program(&self, program: SyntaxNode) -> Result<(), String> { + let mut diagnostics = Diagnostics::new(); - // 2. Bind names and update root scopes - let bound = self.bind_and_update(&expanded, &mut diagnostics) - .ok_or_else(|| diagnostics.format_errors())?; + let expanded = self.expand(program, &mut diagnostics) + .ok_or_else(|| diagnostics.format_errors())?; - // 3. Type-check (without lambda wrapping) - let typed = self.type_check(&bound, &mut diagnostics); + let bound = self.bind_and_update(&expanded, &mut diagnostics) + .ok_or_else(|| diagnostics.format_errors())?; - if diagnostics.has_errors() { - return Err(diagnostics.format_errors()); - } + let typed = self.type_check(&bound, &mut diagnostics); - // 4. Link and execute - let linked = self.link(typed); - let mut vm = self.create_vm(); - let stack = vec![Value::Void; linked.ty.stack_size as usize]; - let result = vm.eval_in_frame(&mut vm::NoOpObserver, &linked, stack)?; - vm.resolve_tail_calls(&mut vm::NoOpObserver, Ok(result))?; + if diagnostics.has_errors() { + return Err(diagnostics.format_errors()); } + let linked = self.link(typed); + let mut vm = self.create_vm(); + vm.run(&linked)?; Ok(()) } diff --git a/src/ast/parser.rs b/src/ast/parser.rs index 15ca0e4..d579ccd 100644 --- a/src/ast/parser.rs +++ b/src/ast/parser.rs @@ -119,13 +119,20 @@ impl<'a> Parser<'a> { matches!(self.current_token.kind, TokenKind::EOF) } - /// Parses a complete program as a sequence of top-level expressions. - pub fn parse_program(&mut self) -> Vec { + /// Parses a complete program as a sequence of top-level expressions + /// wrapped in a `Program` node. + pub fn parse_program(&mut self) -> SyntaxNode { + let identity = NodeIdentity::new(SourceLocation { line: 1, col: 1 }); let mut expressions = Vec::new(); while !self.at_eof() { - expressions.push(self.parse_expression()); + expressions.push(Rc::new(self.parse_expression())); + } + SyntaxNode { + identity, + kind: SyntaxKind::Program { exprs: expressions }, + ty: (), + comments: Rc::from([]), } - expressions } fn synchronize(&mut self) { diff --git a/src/ast/vm.rs b/src/ast/vm.rs index 46ae9da..af782d9 100644 --- a/src/ast/vm.rs +++ b/src/ast/vm.rs @@ -266,27 +266,23 @@ impl VM { self.resolve_tail_calls(observer, result) } - pub fn eval_in_frame(&mut self, observer: &mut O, root: &ExecNode, stack: Vec) -> Result { - self.stack = stack; - self.frames.clear(); - self.frames.push(CallFrame { - stack_base: 0, - closure: None, - }); - let result = self.eval_internal(observer, root); - self.frames.pop(); - result - } pub fn run_with_observer( &mut self, observer: &mut O, root: &ExecNode, ) -> Result { - let mut stack = Vec::new(); - stack.resize(root.ty.stack_size as usize, Value::Void); + self.stack.clear(); + self.frames.clear(); - let result = self.eval_in_frame(observer, root, stack); + self.stack.resize(root.ty.stack_size as usize, Value::Void); + + self.frames.push(CallFrame { + stack_base: 0, + closure: None, + }); + let result = self.eval_internal(observer, root); + self.frames.pop(); self.resolve_tail_calls(observer, result) } diff --git a/src/main.rs b/src/main.rs index 8ced4a4..d54e2d6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ use eframe::egui; use egui_extras::{Column, TableBuilder}; use myc::ast::compiler::emitter; use myc::ast::environment::Environment; +use myc::ast::nodes::SyntaxKind; use myc::ast::parser::Parser; use std::path::PathBuf; @@ -198,7 +199,12 @@ impl CompilerApp { self.active_tab = AppTab::Output; return; } - self.source_code = expressions.iter().map(emitter::emit).collect::>().join("\n"); + let exprs = if let SyntaxKind::Program { exprs } = &expressions.kind { + exprs.as_slice() + } else { + &[] + }; + self.source_code = exprs.iter().map(|e| emitter::emit(e)).collect::>().join("\n"); self.output_log = "Roundtrip complete — source reformatted.".to_string(); self.active_tab = AppTab::Output; }