From 9c56258c489eacb3d8532c7f02b7e6473bb63b17 Mon Sep 17 00:00:00 2001 From: zxq5 Date: Sun, 22 Jun 2025 03:51:16 +0100 Subject: [PATCH] assembler changes & brainf##k compiler lmao --- assembler/brainf.bf | 34 +++ assembler/brainf.dsb | Bin 0 -> 3000 bytes assembler/src/assembler/assembler.rs | 205 ++++++++++++++++++ assembler/src/assembler/codegen.rs | 13 +- assembler/src/assembler/macros.rs | 8 + assembler/src/assembler/mod.rs | 146 +++++++------ assembler/src/brainf.rs | 298 +++++++++++++++++++++++++++ assembler/src/lib.rs | 3 +- assembler/src/main.rs | 65 +++--- assembler/src/util/logging.rs | 113 +++++----- 10 files changed, 731 insertions(+), 154 deletions(-) create mode 100644 assembler/brainf.bf create mode 100644 assembler/brainf.dsb create mode 100644 assembler/src/assembler/assembler.rs create mode 100644 assembler/src/brainf.rs diff --git a/assembler/brainf.bf b/assembler/brainf.bf new file mode 100644 index 0000000..42e73cc --- /dev/null +++ b/assembler/brainf.bf @@ -0,0 +1,34 @@ +++++++++++++++++++++++++++++++++++++++++++++ c1v44 : ASCII code of comma +>++++++++++++++++++++++++++++++++ c2v32 : ASCII code of space +>++++++++++++++++ c3v11 : quantity of numbers to be calculated +> c4v0 : zeroth Fibonacci number (will not be printed) +>+ c5v1 : first Fibonacci number +<< c3 : loop counter +[ block : loop to print (i)th number and calculate next one +>> c5 : the number to be printed + + block : divide c5 by 10 (preserve c5) +> c6v0 : service zero +>++++++++++ c7v10 : divisor +<< c5 : back to dividend +[->+>-[>+>>]>[+[-<+>]>+>>]<<<<<<] c5v0 : divmod algo; results in 0 n d_n%d n%d n/d +>[<+>-] c5 : move dividend back to c5 and clear c6 +>[-] c7v0 : clear c7 + +>> block : c9 can have two digits; divide it by ten again +>++++++++++ c10v10: divisor +< c9 : back to dividend +[->-[>+>>]>[+[-<+>]>+>>]<<<<<] c9v0 : another divmod algo; results in 0 d_n%d n%d n/d +>[-] c10v0 : clear c10 +>>[++++++++++++++++++++++++++++++++++++++++++++++++.[-]]c12v0 : print nonzero n/d (first digit) and clear c12 +<[++++++++++++++++++++++++++++++++++++++++++++++++.[-]] c11v0 : print nonzero n%d (second digit) and clear c11 + +<<<++++++++++++++++++++++++++++++++++++++++++++++++.[-] c8v0 : print any n%d (last digit) and clear c8 +<<<<<<<.>. c1c2 : print comma and space + block : actually calculate next Fibonacci in c6 +>>[>>+<<-] c4v0 : move c4 to c6 (don't need to preserve it) +>[>+<<+>-] c5v0 : move c5 to c6 and c4 (need to preserve it) +>[<+>-] c6v0 : move c6 with sum to c5 +<<<- c3 : decrement loop counter +] +<<++... c1 : output three dots diff --git a/assembler/brainf.dsb b/assembler/brainf.dsb new file mode 100644 index 0000000000000000000000000000000000000000..c748cf895f8113e0d3484e6193d250944b48b3de GIT binary patch literal 3000 zcmdT`y-or_5dMJWIFQChEs#iOP*l)BLP4yJg<5!tm5*R&;{#ZtK@+Wf03U$D!otEg zI1394OG^_P3NyDmGOYX@NFo*&X6I(U`R1G5J<2}PZ2*V@YaUSY5OKV76g;5lA$B<5 z#D9A7Dd1`cYH<&L&U=zvB$l*kHnhGmJxlvwu8FFj`i!=84C^BE``KYoaFw(|a8seX_aQv63(4)ck1O&M~!j$xr!ay&$=;UN*kL{ID_YxE?%SIft>O z9;4cZ$1!8FR;HJC_H!+pA8T6kV@;0j#!zYUi@3HOCwr7O)e7^-o;B}ygKJ7W=1}$3 z81q+s<{!7_A0J`g$4b6k*rn)?pJZMZgx;Qr?`R`V0Vp3vGj z-)Ek+k!M!gVYp0l%y6BOneIK54DLs%!KCa#T&M=$(_!Oej^5j;pcmm|B?O7ZvaN{J?Ynr^mpn;etbJ+9Mz&{koM!g zyKEWUeZZ;Ik==&7T7kP!0WvvYDFQTdh!k3Ii!ESz9iac>*^<8NvYYz1d, + modules: Vec, + tasks: Vec, + logger: Logger, +} + +impl Program { + pub fn new() -> Self { + Self { + registry: HashSet::new(), + modules: Vec::new(), + tasks: Vec::new(), + main_path: PathBuf::new(), + logger: Logger::new(), + } + } + + pub fn add_task(&mut self, task: Task) { + self.tasks.push(task); + } +} + +impl Default for Program { + fn default() -> Self { + Self::new() + } +} + +struct ProgramRef { + program: Arc>, +} + +impl ProgramRef { + pub fn new(program: Program) -> Self { + Self { + program: Arc::new(Mutex::new(program)), + } + } + + pub fn register(&self, path: &Path) { + self.program + .lock() + .unwrap() + .registry + .insert(quick_hash(path)); + } + + pub fn is_registered(&self, path: &Path) -> bool { + self.program + .lock() + .unwrap() + .registry + .contains(&quick_hash(path)) + } + + // pub fn get_tasks(&self) -> Vec<&Task> { + // self.program.lock().unwrap().tasks.iter().collect() + // } + + pub fn add_task(&self, task: Task) { + self.program.lock().unwrap().add_task(task); + } + + pub fn add_module(&self, module: Module) { + self.program.lock().unwrap().modules.push(module); + } + + pub fn log(&self, message: &str) { + self.program.lock().unwrap().logger.log(message); + } +} + +impl Clone for ProgramRef { + fn clone(&self) -> Self { + Self { + program: self.program.clone(), + } + } +} + +pub struct Module { + pub path: PathBuf, + pub hash: u64, + pub nodes: Vec, + program: ProgramRef, +} + +impl Module { + pub fn new(path: PathBuf, hash: u64, nodes: Vec, program: ProgramRef) -> Self { + Self { + path, + hash, + nodes, + program, + } + } + + pub fn build(path: PathBuf, program: ProgramRef) -> Task { + // spawn a thread that creates the main function and executes the lexer and parser. + let handle = thread::spawn(move || { + let mut module = + Module::new(path.clone(), quick_hash(&path), Vec::new(), program.clone()); + + let tokens = module.lex(); + module.parse(tokens); + module.expand(); + module.prepare_dependencies(); + module + }); + + Task { module: handle } + } + + fn lex(&mut self) -> Vec { + if let Ok(path) = self.path.canonicalize() { + self.program.log(&format!( + "{:20} {:20} [{}]", + "Building", + self.get_filename(), + path.display() + )); + } + + let src = fs::read_to_string(&self.path) + .map_err(|_| AssembleError::InvalidFile(self.path.to_path_buf())) + .unwrap(); + let file_hash = quick_hash(&self.path); + + self.program + .log(&format!("{:20} {:20}", "Tokenising", self.get_filename())); + lexer::lexer(src, file_hash).unwrap() + } + + fn parse(&mut self, tokens: Vec) { + self.program + .log(&format!("{:20} {:20}", "Parsing", self.get_filename())); + let parsed = Parser::parse_nodes(tokens).unwrap(); + self.nodes = parsed; + } + + fn expand(&mut self) { + self.program + .log(&format!("{:20} {:20}", "Expanding", self.get_filename())); + let expanded = expand_pseudo_ops(self.nodes.clone(), self.hash).unwrap(); + self.nodes = expanded; + } + + fn prepare_dependencies(&mut self) { + let nodes = resolve_dependencies(self.nodes.clone(), self.path.parent().unwrap()) + .unwrap(); + + let dependencies = Parser::get_dependencies(&nodes, &self.path).unwrap(); + + for dep in dependencies { + if self.program.is_registered(&dep) { + // we have already built this module! + continue; + } + + self.program.register(&dep); + + // create new module + // add the task to the program + let task = Module::build(dep, self.program.clone()); + self.program.add_task(task); + } + } + + // helper functions + fn get_filename(&self) -> &str { + self.path.file_name().unwrap().to_str().unwrap() + } +} + +pub struct Task { + module: JoinHandle, +} diff --git a/assembler/src/assembler/codegen.rs b/assembler/src/assembler/codegen.rs index f3f7a18..5da4219 100644 --- a/assembler/src/assembler/codegen.rs +++ b/assembler/src/assembler/codegen.rs @@ -3,14 +3,23 @@ use common::{args, prelude::*}; use crate::assembler::model::{Node, Opcode}; use crate::{assembler::AssembleError, expect_token}; +fn log(message: &str) { + println!("\x1b[32mINFO:\x1b[0m {message}"); +} + pub fn codegen(nodes: Vec) -> Result, AssembleError> { let mut instructions = vec![]; for node in nodes { - println!("node {node}"); - instructions.push(build_instruction(node)?); + instructions.push( + build_instruction(node.clone()) + .expect(format!("Failed to build instruction: {:?}", node).as_str()), + ); } + println!("------------------------"); + log("Compilation Success ✅"); + Ok(instructions) } diff --git a/assembler/src/assembler/macros.rs b/assembler/src/assembler/macros.rs index 32e5974..c40fc4c 100644 --- a/assembler/src/assembler/macros.rs +++ b/assembler/src/assembler/macros.rs @@ -45,6 +45,14 @@ macro_rules! node { ) }; + ($symbol: expr, $opcode: expr) => { + $crate::assembler::model::Node::new( + $symbol.clone(), + $opcode.clone(), + Vec::new() + ) + }; + (@convert_token $token: literal) => { $crate::assembler::model::Token::Immediate($token) }; diff --git a/assembler/src/assembler/mod.rs b/assembler/src/assembler/mod.rs index 16c934c..0493013 100644 --- a/assembler/src/assembler/mod.rs +++ b/assembler/src/assembler/mod.rs @@ -5,7 +5,8 @@ use std::{ fmt, fs, hash::{DefaultHasher, Hash, Hasher}, path::{Path, PathBuf}, - sync::mpsc, + sync::{Arc, Mutex, mpsc}, + thread, }; use common::prelude::Instruction; @@ -19,6 +20,7 @@ fn log(message: &str) { #[macro_use] pub mod macros; +pub mod assembler; pub mod codegen; pub mod expand; pub mod lexer; @@ -39,72 +41,95 @@ pub use self::{ use crate::util::logging::{Entry, Logger}; pub struct CompilerEngine { - modules: HashSet, - program: Program, - logger: Option, - receiver: Option>, - result: Option, AssembleError>>, + result_tx: mpsc::Sender, AssembleError>>, + result_rx: Option, AssembleError>>>, + is_running: bool, } impl CompilerEngine { - pub fn new() -> CompilerEngine { - let (tx, rx) = mpsc::channel::(); - CompilerEngine { - program: Program::new(), - modules: HashSet::new(), - logger: Some(Logger::new(tx)), - receiver: Some(rx), - result: None, + pub fn new() -> Self { + let (tx, rx) = mpsc::channel(); + Self { + result_tx: tx, + result_rx: Some(rx), + is_running: false, } } - pub fn get_log() -> Option { - None - } - - pub fn get_logs() -> Vec { - vec![] - } - - pub fn is_ready(&self) -> bool { - self.result.is_some() - } - - pub fn result(&self) -> Option, AssembleError>> { - self.result.clone() - } - - pub fn assemble(&mut self, src: &Path) -> Result<(), AssembleError> { - let hash = quick_hash(src); - - if self.modules.contains(&hash) { - return Ok(()); + /// Start the compilation process in a separate thread + pub fn start_compilation(&mut self, src: &Path) { + if self.is_running { + return; } - prepare_dependency(src, &mut self.modules, &mut self.program)?; + let src = src.to_path_buf(); + let tx = self.result_tx.clone(); - self.result = Some(self.build()); + thread::spawn(move || { + let result = assemble(&src); + tx.send(result).unwrap(); + }); - Ok(()) + self.is_running = true; } - fn load_module(&mut self, path: &Path) -> Result<(), AssembleError> { - Ok(()) - } - - fn build(&self) -> Result, AssembleError> { - let mut nodes = self.program.nodes.clone(); - - create_sections(&mut nodes)?; - resolve_symbols(&mut nodes)?; - - let instructions = codegen(nodes)?; - for inst in instructions.iter() { - println!("{inst}"); + /// Check if compilation is complete and get the result + pub fn try_get_result(&mut self) -> Option, AssembleError>> { + if !self.is_running { + return None; } - Ok(instructions) + match self.result_rx.as_ref().unwrap().try_recv() { + Ok(result) => { + self.is_running = false; + Some(result) + } + Err(mpsc::TryRecvError::Empty) => None, + Err(mpsc::TryRecvError::Disconnected) => { + self.is_running = false; + Some(Err(AssembleError::Generic)) + } + } } + + /// Block until compilation is complete and return the result + pub fn wait_for_result(&mut self) -> Result, AssembleError> { + if !self.is_running { + return Err(AssembleError::Generic); + } + + match self.result_rx.take().unwrap().recv() { + Ok(result) => { + self.is_running = false; + result + } + Err(_) => { + self.is_running = false; + Err(AssembleError::Generic) + } + } + } +} + +fn assemble(src: &Path) -> Result, AssembleError> { + let mut modules = HashSet::new(); + let mut program = Program::new(); + + let hash = quick_hash(src); + + if modules.contains(&hash) { + return Ok(vec![]); + } + + prepare_dependency(src, &mut modules, &mut program)?; + + let mut nodes = program.nodes.clone(); + + create_sections(&mut nodes)?; + resolve_symbols(&mut nodes)?; + + let instructions = codegen(nodes)?; + Ok(instructions) } impl Default for CompilerEngine { @@ -143,7 +168,8 @@ fn prepare_dependency( let base_dir = path .parent() .ok_or_else(|| AssembleError::InvalidFile(path.to_path_buf()))?; - let nodes = resolve_dependencies(parsed, base_dir)?; + let mut nodes = expand_pseudo_ops(parsed, file_hash)?; + nodes = resolve_dependencies(nodes, base_dir)?; let deps = Parser::get_dependencies(&nodes, path)?; @@ -151,7 +177,6 @@ fn prepare_dependency( "{:20} {:20}", "Expanding PseudoInstructions", filename )); - let mut nodes = expand_pseudo_ops(nodes, file_hash)?; // add a section instruction nodes.insert( @@ -181,19 +206,6 @@ fn prepare_dependency( Ok(()) } -fn _build(_src: Vec) -> Result, AssembleError> { - Ok(vec![]) -} - -/// TODO: disassembling functionality -/// - We probably don't need to implement this for a while yet. -/// - This method should recover symbols such as labels and variables from the human -/// written assembly, recognising sequences that are expansions of pseudo-instructions -/// and reversing this to produce near enough the original source code. -pub fn disassemble(_: Vec) -> String { - todo!() -} - #[derive(Debug, Clone)] pub enum AssembleError { Generic, diff --git a/assembler/src/brainf.rs b/assembler/src/brainf.rs new file mode 100644 index 0000000..7e89dcd --- /dev/null +++ b/assembler/src/brainf.rs @@ -0,0 +1,298 @@ +use std::{ + fs, + path::{self, Path}, +}; + +use common::prelude::{Instruction, Register}; + +use crate::{ + assembler::{ + Module, Node, Opcode, Symbol, Token, codegen, create_sections, expand_pseudo_ops, + resolve_symbols, + }, + node, +}; + +pub fn build(src: &Path) -> Vec { + let src = fs::read_to_string(src).unwrap(); + let mut nodes = parse(src); + + // we need to expand pseudoinstructions etc now + nodes = expand_pseudo_ops(nodes, 0).unwrap(); + + create_sections(&mut nodes).unwrap(); + + for n in nodes.iter() { + println!("{}", n); + } + + resolve_symbols(&mut nodes).unwrap(); + + codegen(nodes).unwrap() +} + +pub fn parse(src: String) -> Vec { + let stack = Token::Immediate(0x10000); + let acc = Token::Register(Register::Acc); + let rga = Token::Register(Register::Rga); + + let bpr = Token::Register(Register::Bpr); + let spr = Token::Register(Register::Spr); + let mut nodes = Vec::::new(); + + // Define symbols + let print_start = Symbol { + name: "print".to_string(), + module: Module::Resolved(0), + }; + + let tokens = lex(src); + + let mut id = 0; + let mut idstack = Vec::::new(); + + nodes.extend(vec![ + // set up a stack + node!(None, Opcode::Lwi, stack, bpr), + node!(None, Opcode::Mov, bpr, spr), + // set up the data pointer + node!( + Some(Symbol { + name: "main".to_string(), + module: Module::Resolved(0) + }), + Opcode::Lwi, + Token::Immediate(0x30000), + rga + ), + ]); + + for (id, tok) in tokens.iter().enumerate() { + match tok { + BfToken::Inc => { + // inc acc + nodes.extend(vec![node!(None, Opcode::Inc, acc)]); + } + BfToken::Dec => { + // dec acc + nodes.extend(vec![node!(None, Opcode::Dec, acc)]); + } + BfToken::IncPtr => { + // stb acc, rga + // add rga, 4 + // ldb rga, acc + nodes.extend(vec![ + node!(None, Opcode::Stw, acc, rga, 0), + node!(None, Opcode::AddI, rga, 4, rga), + node!(None, Opcode::Ldw, rga, acc, 0), + ]); + } + BfToken::DecPtr => { + // stb acc, rga + // sub rga, 4 + // ldb rga, acc + nodes.extend(vec![ + node!(None, Opcode::Stw, acc, rga, 0), + node!(None, Opcode::SubI, rga, 4, rga), + node!(None, Opcode::Ldw, rga, acc, 0), + ]); + } + BfToken::Out => { + // push rga + // call print + // pop zero + nodes.extend(vec![ + node!(None, Opcode::Push, acc), + node!(None, Opcode::Call, Token::Symbol(print_start.clone())), + node!(None, Opcode::Pop, Token::Register(Register::Zero)), + ]); + } + BfToken::In => { + // Read a byte from input and store it at the current data pointer + // Assuming we have an input function mapped to a specific memory location or I/O port + nodes.extend(vec![ + // Read input (assuming input is mapped to memory address 0x40000) + node!(None, Opcode::Ldw, Token::Immediate(0x40000), acc, 0), + // Store the input byte at the current data pointer + ]); + } + BfToken::Forward => { + // Start of loop [ + let loop_start = format!("loop_start_{}", id); + let loop_end = format!("loop_end_{}", id); + + // Push the current position for the matching ] + idstack.push(id as u32); + + // Load current cell value and check if zero + nodes.extend(vec![ + // Compare with zero + node!(None, Opcode::Cmp, acc, Token::Register(Register::Zero)), + // If zero, jump to end of loop + node!( + None, + Opcode::Jeq, + Token::Symbol(Symbol { + name: loop_end, + module: Module::Resolved(0), + }), + Token::Register(Register::Zero) + ), + ]); + + // Add label for loop start + nodes.push(node!( + Some(Symbol { + name: loop_start, + module: Module::Resolved(0), + }), + Opcode::Nop + )); + } + BfToken::Back => { + // End of loop ] + if let Some(start_id) = idstack.pop() { + let loop_start = format!("loop_start_{}", start_id); + let loop_end = format!("loop_end_{}", start_id); + + // Jump back to the start of the loop + nodes.extend(vec![ + // Compare with zero + node!(None, Opcode::Cmp, acc, Token::Register(Register::Zero)), + // If not zero, jump back to start of loop + node!( + None, + Opcode::Jne, + Token::Symbol(Symbol { + name: loop_start, + module: Module::Resolved(0), + }), + Token::Register(Register::Zero) + ), + // Add label for loop end + node!( + Some(Symbol { + name: loop_end, + module: Module::Resolved(0), + }), + Opcode::Nop + ), + ]); + } else { + // Unmatched closing bracket - could add error handling here + eprintln!("Warning: Unmatched ']' at position {}", id); + } + } + } + } + + nodes.push(node!(None, Opcode::Hlt)); + + insert_lib(&mut nodes); + + nodes +} + +fn insert_lib(nodes: &mut Vec) { + let bpr = Token::Register(Register::Bpr); + let spr = Token::Register(Register::Spr); + let rg0 = Token::Register(Register::Rg0); + let rg1 = Token::Register(Register::Rg1); + + let print_start = Symbol { + name: "print".to_string(), + module: Module::Resolved(0), + }; + let current = Symbol { + name: "current".to_string(), + module: Module::Resolved(0), + }; + // set up the program framework. + nodes.extend(vec![ + // set display to 0x20000 + node!( + None, + Opcode::Dw, + Token::Symbol(current.clone()), + Token::Immediate(0x20000) + ), + // print function + // initialisation + node!(Some(print_start.clone()), Opcode::Push, bpr.clone()), + node!(None, Opcode::Mov, spr.clone(), bpr.clone()), + // function body + node!( + None, + Opcode::Ldw, + bpr.clone(), + rg0.clone(), + Token::Immediate(8) + ), + node!( + None, + Opcode::Ldw, + Token::Symbol(current.clone()), // Load address of current + rg1.clone(), + Token::Immediate(0) + ), + node!( + None, + Opcode::Stb, + rg0.clone(), + rg1.clone(), + Token::Immediate(0) + ), + node!( + None, + Opcode::AddI, + rg1.clone(), + Token::Immediate(1), + rg1.clone() + ), + // function return according to spec. + node!( + None, + Opcode::Stw, + rg1.clone(), + Token::Symbol(current.clone()), // Store back to current + Token::Immediate(0) + ), + node!(None, Opcode::Mov, bpr.clone(), spr.clone()), + node!(None, Opcode::Pop, bpr.clone()), + node!(None, Opcode::Return), + ]); +} + +enum BfToken { + Inc, + Dec, + IncPtr, + DecPtr, + Out, + In, + Forward, + Back, +} + +fn lex(src: String) -> Vec { + src.chars() + .filter_map(|c| match c { + '+' => Some(BfToken::Inc), + '-' => Some(BfToken::Dec), + '>' => Some(BfToken::IncPtr), + '<' => Some(BfToken::DecPtr), + '.' => Some(BfToken::Out), + ',' => Some(BfToken::In), + '[' => Some(BfToken::Forward), + ']' => Some(BfToken::Back), + _ => None, + }) + .collect() +} + +fn create_symbol(id: u32) -> Symbol { + Symbol { + name: format!("label_{}", id), + module: Module::Resolved(0), + } +} diff --git a/assembler/src/lib.rs b/assembler/src/lib.rs index 45d7389..2c74cb3 100644 --- a/assembler/src/lib.rs +++ b/assembler/src/lib.rs @@ -1,8 +1,9 @@ pub mod assembler; +pub mod brainf; pub mod tooling; mod util; pub mod prelude { pub use crate::assembler::CompilerEngine; - pub use crate::assembler::disassemble; + pub use crate::tooling::project; } diff --git a/assembler/src/main.rs b/assembler/src/main.rs index 0d4f523..aee5ff3 100644 --- a/assembler/src/main.rs +++ b/assembler/src/main.rs @@ -1,4 +1,4 @@ -use assembler::prelude::*; +use assembler::{brainf, prelude::*}; use std::{fs, io::Write, path::PathBuf}; fn main() { @@ -6,7 +6,29 @@ fn main() { let args: Vec = std::env::args().collect(); if args.len() == 2 && args[1] == "init" { - assembler::tooling::project::tool_libcreate(); + project::tool_libcreate(); + std::process::exit(0); + } + + if args.len() == 2 && args[1] == "brainf" { + let src = PathBuf::from("brainf.bf"); + let result = brainf::build(&src); + + let mut file = match fs::File::create("brainf.dsb") { + Err(e) => { + eprintln!("Failed to create output file: {}", e); + std::process::exit(1); + } + Ok(file) => file, + }; + + for instruction in result { + if let Err(e) = file.write(&instruction.encode().to_be_bytes()) { + eprintln!("Failed to write to output file: {}", e); + std::process::exit(1); + } + } + std::process::exit(0); } @@ -19,41 +41,16 @@ fn main() { let output_path = &args[4]; let src = PathBuf::from(input_path); - // Create the output file - let mut output_file = match fs::File::create(output_path) { - Ok(file) => file, - Err(e) => { - eprintln!("Failed to create output file: {}", e); - std::process::exit(1); - } - }; - // Initialize the compiler engine - let mut engine = CompilerEngine::new(); + let mut compiler = CompilerEngine::new(); + compiler.start_compilation(&src); - // Assemble the source file - if let Err(e) = engine.assemble(&src) { - eprintln!("Assembly error: {}", e); - std::process::exit(1); - } + // Or block until done + let result = compiler.wait_for_result().unwrap(); - // Build and write the output - match engine.result() { - Some(Ok(instructions)) => { - for instruction in instructions { - if let Err(e) = output_file.write_all(&instruction.encode().to_le_bytes()) - { - eprintln!("Failed to write to output file: {}", e); - std::process::exit(1); - } - } - } - Some(Err(e)) => { - eprintln!("Build error: {}", e); - std::process::exit(1); - } - None => { - eprintln!("Build error: No result available"); + for instruction in result { + if let Err(e) = fs::write(output_path, instruction.encode().to_be_bytes()) { + eprintln!("Failed to write to output file: {}", e); std::process::exit(1); } } diff --git a/assembler/src/util/logging.rs b/assembler/src/util/logging.rs index ab6645a..16cff31 100644 --- a/assembler/src/util/logging.rs +++ b/assembler/src/util/logging.rs @@ -1,62 +1,75 @@ +#![allow(dead_code)] +#![allow(unused)] use std::{fmt, sync::mpsc::Sender}; -#[allow(dead_code)] -#[derive(Debug)] -pub struct Logger { - pub sender: Sender, -} +pub struct Logger {} impl Logger { - pub fn new(sender: Sender) -> Self { - Self { sender } + pub fn new() -> Self { + Self {} } - pub fn debug(&self, message: T) { - self.sender - .send(Entry { - etype: EntryType::Debug, - message: message.to_string(), - }) - .unwrap(); - } - - pub fn info(&self, message: T) { - self.sender - .send(Entry { - etype: EntryType::Info, - message: message.to_string(), - }) - .unwrap(); - } - - pub fn warn(&self, message: T) { - self.sender - .send(Entry { - etype: EntryType::Warn, - message: message.to_string(), - }) - .unwrap(); - } - - pub fn error(&self, message: T) { - self.sender - .send(Entry { - etype: EntryType::Error, - message: message.to_string(), - }) - .unwrap(); - } - - pub fn fatal(&self, message: T) { - self.sender - .send(Entry { - etype: EntryType::Fatal, - message: message.to_string(), - }) - .unwrap(); + pub fn log(&self, message: &str) { + println!("\x1b[32mINFO:\x1b[0m {message}"); } } +// #[derive(Debug)]= +// pub struct Logger { +// pub sender: Sender, +// } + +// impl Logger { +// pub fn new(sender: Sender) -> Self { +// Self { sender } +// } + +// pub fn debug(&self, message: T) { +// self.sender +// .send(Entry { +// etype: EntryType::Debug, +// message: message.to_string(), +// }) +// .unwrap(); +// } + +// pub fn info(&self, message: T) { +// self.sender +// .send(Entry { +// etype: EntryType::Info, +// message: message.to_string(), +// }) +// .unwrap(); +// } + +// pub fn warn(&self, message: T) { +// self.sender +// .send(Entry { +// etype: EntryType::Warn, +// message: message.to_string(), +// }) +// .unwrap(); +// } + +// pub fn error(&self, message: T) { +// self.sender +// .send(Entry { +// etype: EntryType::Error, +// message: message.to_string(), +// }) +// .unwrap(); +// } + +// pub fn fatal(&self, message: T) { +// self.sender +// .send(Entry { +// etype: EntryType::Fatal, +// message: message.to_string(), +// }) +// .unwrap(); +// } +// } + pub struct Entry { etype: EntryType, pub message: String,