From 7ab1ac8842c0b7dce3e29cb380ac7923b416bbcf Mon Sep 17 00:00:00 2001 From: zxq5 Date: Mon, 23 Feb 2026 09:04:30 +0000 Subject: [PATCH] added logging to builder trait and implemented for compiler and assembler crates. --- assembler/src/assembler/assembler.rs | 5 ++- assembler/src/assembler/mod.rs | 46 ++++++++++++-------- assembler/src/assembler/resolver.rs | 5 +-- assembler/src/util/logging.rs | 20 ++++----- common/src/build.rs | 2 + common/src/logging.rs | 65 +++++++++++++++++++++++++++- compiler/src/frontend/dsc/mod.rs | 15 +++---- compiler/src/frontend/mod.rs | 10 ++++- compiler/src/lib.rs | 17 +++++--- compiler/src/main.rs | 4 +- dsx_server/src/common/builder/mod.rs | 8 ---- 11 files changed, 137 insertions(+), 60 deletions(-) diff --git a/assembler/src/assembler/assembler.rs b/assembler/src/assembler/assembler.rs index 5ba9e1c..294ed0b 100644 --- a/assembler/src/assembler/assembler.rs +++ b/assembler/src/assembler/assembler.rs @@ -8,7 +8,7 @@ use std::{ use crate::assembler::{AssembleError, Token, expand_pseudo_ops, lexer, quick_hash}; use crate::assembler::{Node, Parser, resolve_dependencies}; -use crate::util::logging::Logger; +// use crate::util::logging::Logger; // pub fn new_assemble(path: &Path) { // let program = Program::new(); @@ -144,7 +144,8 @@ impl Module { } pub fn build(path: PathBuf, program: ProgramRef) -> Result { - // Spawn a thread that creates the main function and executes the lexer and parser. + // Spawn a thread that creates the main function and executes the lexer and + // parser. let handle = thread::spawn(move || { let mut module = Self::new(path.clone(), quick_hash(&path), Vec::new(), program.clone()); diff --git a/assembler/src/assembler/mod.rs b/assembler/src/assembler/mod.rs index 862187a..f70a288 100644 --- a/assembler/src/assembler/mod.rs +++ b/assembler/src/assembler/mod.rs @@ -5,13 +5,16 @@ use std::{ fmt, fs, hash::{DefaultHasher, Hash, Hasher}, path::{Path, PathBuf}, - sync::{Arc, Mutex, mpsc}, + sync::{ + Arc, Mutex, + mpsc::{self, Receiver, Sender}, + }, thread, }; -pub use common::logging::log; use common::{ build::{BuildError, Builder}, + logging::{LogReceiver, Logger}, prelude::Instruction, }; @@ -20,7 +23,7 @@ use common::{ pub mod macros; #[allow(clippy::module_inception)] -pub mod assembler; +// pub mod assembler; pub mod codegen; pub mod expand; pub mod lexer; @@ -38,13 +41,13 @@ pub use self::{ resolver::{create_sections, resolve_dependencies, resolve_symbols}, }; -use crate::util::logging::{Entry, Logger}; - pub struct Assembler { src_path: PathBuf, result_tx: mpsc::Sender, AssembleError>>, result_rx: Option, AssembleError>>>, is_running: bool, + + logs_rx: LogReceiver, } impl From for BuildError { @@ -56,6 +59,10 @@ impl From for BuildError { impl Builder for Assembler { type Output = Vec; + fn logs(&self) -> Vec { + self.logs_rx.logs() + } + #[must_use] fn new(src_path: impl Into) -> Self { let (tx, rx) = mpsc::channel(); @@ -64,6 +71,9 @@ impl Builder for Assembler { result_tx: tx, result_rx: Some(rx), is_running: false, + + // for logging + logs_rx: LogReceiver::new(true), } } @@ -75,9 +85,10 @@ impl Builder for Assembler { let src = self.src_path.clone(); let tx = self.result_tx.clone(); + let logger = self.logs_rx.logger(); thread::spawn(move || { - if let Ok(res) = assemble(&src) { + if let Ok(res) = assemble(&src, &logger) { let buffer: Vec = res .iter() .flat_map(|instruction| instruction.encode().to_be_bytes()) @@ -136,7 +147,7 @@ impl Builder for Assembler { impl Assembler {} -fn assemble(src: &Path) -> Result, AssembleError> { +fn assemble(src: &Path, logger: &Logger) -> Result, AssembleError> { let mut modules = HashSet::new(); let mut program = Program::new(); @@ -146,18 +157,18 @@ fn assemble(src: &Path) -> Result, AssembleError> { return Ok(vec![]); } - prepare_dependency(src, &mut modules, &mut program)?; + prepare_dependency(src, &mut modules, &mut program, &logger)?; let mut nodes = program.nodes.clone(); create_sections(&mut nodes)?; resolve_symbols(&mut nodes)?; - log("Generating assembly output..."); + logger.info("Generating assembly output..."); let instructions = codegen(nodes)?; - log("Compilation Successful"); + logger.info("Compilation Successful"); Ok(instructions) } @@ -165,6 +176,7 @@ fn prepare_dependency( path: &Path, modules: &mut HashSet, program: &mut Program, + logger: &Logger, ) -> Result<(), AssembleError> { let filename = path .file_name() @@ -172,7 +184,7 @@ fn prepare_dependency( .expect("Failed to get file name from path"); if let Ok(path) = path.canonicalize() { - log(&format!( + logger.info(&format!( "{:20} {:20} [{}]", "Building", filename, @@ -184,13 +196,13 @@ fn prepare_dependency( .map_err(|_| AssembleError::InvalidFile(path.to_path_buf()))?; let file_hash = quick_hash(path); - log(&format!("{:20} {:20}", "Tokenising", filename)); + logger.info(&format!("{:20} {:20}", "Tokenising", filename)); let tokens = lexer::lexer(src, file_hash)?; - log(&format!("{:20} {:20}", "Parsing", filename)); + logger.info(&format!("{:20} {:20}", "Parsing", filename)); let parsed = Parser::parse_nodes(tokens)?; - log(&format!("{:20} {:20}", "Resolving Deps", filename)); + logger.info(&format!("{:20} {:20}", "Resolving Deps", filename)); // Get the parent directory of the source file to use as the base directory let base_dir = path .parent() @@ -200,7 +212,7 @@ fn prepare_dependency( let deps = Parser::get_dependencies(&nodes, path)?; - log(&format!("{:20} {:20}", "Expanding Pseudo-ops", filename)); + logger.info(&format!("{:20} {:20}", "Expanding Pseudo-ops", filename)); // add a section instruction nodes.insert( @@ -215,7 +227,7 @@ fn prepare_dependency( program.add_module(nodes); for dep in deps { - log(&format!( + logger.info(&format!( "{:20} {:20}", "Including", dep.file_name() @@ -225,7 +237,7 @@ fn prepare_dependency( let dep_hash = quick_hash(&dep); if modules.insert(dep_hash) { - prepare_dependency(dep.as_path(), modules, program)?; + prepare_dependency(dep.as_path(), modules, program, logger)?; } } diff --git a/assembler/src/assembler/resolver.rs b/assembler/src/assembler/resolver.rs index 626a045..c795e87 100644 --- a/assembler/src/assembler/resolver.rs +++ b/assembler/src/assembler/resolver.rs @@ -6,11 +6,8 @@ use std::{ use common::prelude::Register; +use crate::assembler::model::{Module, Node, Opcode, Symbol, Token}; use crate::assembler::quick_hash; -use crate::assembler::{ - log, - model::{Module, Node, Opcode, Symbol, Token}, -}; use crate::{assembler::AssembleError, node}; pub fn resolve_symbols(nodes: &mut [Node]) -> Result<(), AssembleError> { diff --git a/assembler/src/util/logging.rs b/assembler/src/util/logging.rs index 93c37e1..4867739 100644 --- a/assembler/src/util/logging.rs +++ b/assembler/src/util/logging.rs @@ -2,18 +2,18 @@ #![allow(unused)] use std::{fmt, sync::mpsc::Sender}; -pub struct Logger {} +// pub struct Logger {} -impl Logger { - pub const fn new() -> Self { - Self {} - } +// impl Logger { +// pub const fn new() -> Self { +// Self {} +// } - pub fn log(&self, message: &str) { - _ = self; - println!("\x1b[32mINFO:\x1b[0m {message}"); - } -} +// pub fn log(&self, message: &str) { +// _ = self; +// println!("\x1b[32mINFO:\x1b[0m {message}"); +// } +// } // #[derive(Debug)]= // pub struct Logger { diff --git a/common/src/build.rs b/common/src/build.rs index c04a321..ee14c70 100644 --- a/common/src/build.rs +++ b/common/src/build.rs @@ -49,4 +49,6 @@ pub trait Builder { std::fs::write(path.as_ref(), output) .map_err(|e| BuildError::IoError(e.to_string())) } + + fn logs(&self) -> Vec; } diff --git a/common/src/logging.rs b/common/src/logging.rs index e14cb68..b29147f 100644 --- a/common/src/logging.rs +++ b/common/src/logging.rs @@ -1,4 +1,65 @@ -// TODO: Use an actual logging or tracing library for pretty (scoped) output. -pub fn log(message: &str) { +use std::sync::{Arc, mpsc}; + +pub fn info(message: &str) { println!("\x1b[32mINFO:\x1b[0m {message}"); } + +#[derive(Debug)] +pub struct LogReceiver { + logs_rx: mpsc::Receiver, + sender: Logger, + use_stdio: bool, +} + +#[derive(Debug, Clone)] +pub struct Logger { + use_stdio: bool, + logs_tx: Arc>, +} + +impl Logger { + #[must_use] + pub fn new(logs_tx: mpsc::Sender, use_stdio: bool) -> Self { + Self { + use_stdio: true, + logs_tx: Arc::new(logs_tx), + } + } + + pub fn info(&self, message: &str) { + let res = format!("\x1b[32mINFO:\x1b[0m {message}"); + if self.use_stdio { + println!("{res}"); + } + + self.logs_tx.send(res).expect("Failed to send log message"); + } +} + +impl LogReceiver { + #[must_use] + pub fn new(use_stdio: bool) -> Self { + let (logs_tx, logs_rx) = mpsc::channel(); + Self { + use_stdio, + logs_rx, + sender: Logger::new(logs_tx, use_stdio), + } + } + + #[must_use] + pub fn logs(&self) -> Vec { + self.logs_rx.try_iter().collect() + } + + #[must_use] + pub fn logger(&self) -> Logger { + self.sender.clone() + } +} + +impl Default for LogReceiver { + fn default() -> Self { + Self::new(true) + } +} diff --git a/compiler/src/frontend/dsc/mod.rs b/compiler/src/frontend/dsc/mod.rs index 7778fa8..7448a19 100644 --- a/compiler/src/frontend/dsc/mod.rs +++ b/compiler/src/frontend/dsc/mod.rs @@ -1,6 +1,5 @@ -use common::logging::log; - use crate::model::{CompilerError, Program}; +use common::logging::Logger; use parser::{ParseResult, Parser}; // use semantic_analyser::Analyser; @@ -8,14 +7,14 @@ pub mod lexer; pub mod parser; // pub mod semantic_analyser; -pub fn generate_ast(input: &str) -> Result { - log("Tokenising Input..."); +pub fn generate_ast(input: &str, logger: &Logger) -> Result { + logger.info("Tokenising Input..."); let lexer = lexer::Lexer::new(&input); let tokens = lexer.collect::>(); println!("{tokens:#?}"); - log(&format!("Parsing {} Tokens...", tokens.len())); + logger.info(&format!("Parsing {} Tokens...", tokens.len())); let mut parser = Parser::new(tokens); let ast = match parser.parse() { @@ -27,12 +26,12 @@ pub fn generate_ast(input: &str) -> Result { }; // println!("{ast:#?}"); - log("Analyzing AST..."); - log("Checking Type Information..."); + logger.info("Analyzing AST..."); + logger.info("Checking Type Information..."); // let mut analyser = Analyser::new(); // analyser.analyse(ast.clone()).unwrap(); - log("Type Checking Complete..."); + logger.info("Type Checking Complete..."); Ok(ast) } diff --git a/compiler/src/frontend/mod.rs b/compiler/src/frontend/mod.rs index a9ee921..109d9e2 100644 --- a/compiler/src/frontend/mod.rs +++ b/compiler/src/frontend/mod.rs @@ -1,11 +1,17 @@ +use common::logging::Logger; + use crate::model::{CompilerError, Program}; // mod c; mod dsc; -pub fn compiler_frontend(ext: &str, data: &str) -> Result { +pub fn compiler_frontend( + ext: &str, + data: &str, + logger: &Logger, +) -> Result { match ext { - "dsc" => Ok(dsc::generate_ast(&data)?), + "dsc" => Ok(dsc::generate_ast(&data, &logger)?), // "c" => Ok(c::generate_ast(&data)?), _ => Err(CompilerError::Generic(format!( "File type {} not supported", diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs index fddb7da..31e378d 100644 --- a/compiler/src/lib.rs +++ b/compiler/src/lib.rs @@ -4,7 +4,7 @@ use std::path::{Path, PathBuf}; use common::{ build::{BuildError, Builder}, - logging::log, + logging::LogReceiver, }; use crate::{model::CompilerError, specialised::build_specialised}; @@ -17,6 +17,7 @@ mod specialised; pub struct Compiler { src_path: PathBuf, result: Option>, + logger: LogReceiver, } impl Compiler { @@ -36,10 +37,11 @@ impl Compiler { } // Parse the input using the frontend, providing the file extension and data. - let ast = match frontend::compiler_frontend(input_ext, &input) { - Ok(ast) => ast, - Err(err) => return Err(format!("Compilation failed: {err:?}").into()), - }; + let ast = + match frontend::compiler_frontend(input_ext, &input, &self.logger.logger()) { + Ok(ast) => ast, + Err(err) => return Err(format!("Compilation failed: {err:?}").into()), + }; // println!("Parsed AST: {:#?}", ast); @@ -60,6 +62,7 @@ impl Builder for Compiler { Self { src_path: src_path.into(), result: None, + logger: LogReceiver::new(true), } } @@ -79,6 +82,10 @@ impl Builder for Compiler { "Compiler was never started", )))? } + + fn logs(&self) -> Vec { + todo!() + } } pub fn error(msg: impl Into) -> CompilerError { diff --git a/compiler/src/main.rs b/compiler/src/main.rs index fa2bb43..efeebe6 100644 --- a/compiler/src/main.rs +++ b/compiler/src/main.rs @@ -1,6 +1,6 @@ use std::path::{Path, PathBuf}; -use common::{build::Builder, logging::log}; +use common::{build::Builder, logging::info}; use compiler::Compiler; fn main() { @@ -25,7 +25,7 @@ fn main() { std::fs::write(output_file, &result).expect("Failed to write output"); - log(&format!( + info(&format!( "Compilation Successful ✅ \n\tSource: {}\n\tOutput: {}\n", input_file, output_file, )); diff --git a/dsx_server/src/common/builder/mod.rs b/dsx_server/src/common/builder/mod.rs index 236b189..62b0d15 100644 --- a/dsx_server/src/common/builder/mod.rs +++ b/dsx_server/src/common/builder/mod.rs @@ -31,14 +31,6 @@ pub fn build_project(cwd: &Path) -> Result<(), BuildError> { ))); } - // check is redundant as we're already checking for main files. - // if !has_dsc && !has_dsa { - // return Err(io::Error::new( - // io::ErrorKind::NotFound, - // "No .dsc or .dsa source found in src directory.", - // )); - // } - // detect src. let (has_dsa, has_dsc) = detect_source_language(&src_dir);