From a2408cd14317e1c0969953f8745034d78b2b9bcf Mon Sep 17 00:00:00 2001
From: Ben Bridle <ben@derelict.engineering>
Date: Mon, 3 Feb 2025 09:51:32 +1300
Subject: Use log crate for printing info and error messages

---
 src/bin/br.rs                            | 86 +++++++++++---------------------
 src/debug.rs                             | 11 +---
 src/devices/file_device/buffered_file.rs |  4 +-
 src/emulators/graphical_emulator.rs      |  8 +--
 src/emulators/headless_emulator.rs       |  6 +--
 src/lib.rs                               |  7 ---
 6 files changed, 37 insertions(+), 85 deletions(-)

(limited to 'src')

diff --git a/src/bin/br.rs b/src/bin/br.rs
index 8eb4135..8218286 100644
--- a/src/bin/br.rs
+++ b/src/bin/br.rs
@@ -6,28 +6,7 @@ use std::io::{Read, Write};
 use std::path::{Path, PathBuf};
 use std::process::exit;
 
-
-const NORMAL: &str = "\x1b[0m";
-const BOLD:   &str = "\x1b[1m";
-const WHITE:  &str = "\x1b[37m";
-const RED:    &str = "\x1b[31m";
-const BLUE:   &str = "\x1b[34m";
-
-static mut VERBOSE: bool = false;
-
-macro_rules! verbose {
-    ($($tokens:tt)*) => { if unsafe { VERBOSE } {
-        eprint!("{BOLD}{BLUE}[INFO]{NORMAL}: "); eprint!($($tokens)*);
-        eprintln!("{NORMAL}");
-    } };
-}
-macro_rules! error {
-    ($($tokens:tt)*) => {{
-        eprint!("{BOLD}{RED}[ERROR]{WHITE}: "); eprint!($($tokens)*);
-        eprintln!("{NORMAL}");
-    }};
-}
-
+use log::{info, fatal};
 
 fn main() {
     let args = Arguments::from_env_or_exit();
@@ -39,7 +18,7 @@ fn main() {
         std::process::exit(0);
     }
     if args.verbose {
-        unsafe { VERBOSE = true; }
+        log::set_log_level(log::LogLevel::Info);
     }
     match args.subcommand {
         ArgumentsCmd::Run(run) => main_run(run),
@@ -58,7 +37,7 @@ fn main_run(args: Run) {
 
     let metadata = parse_metadata(&bytecode);
     if metadata.is_none() {
-        verbose!("Could not read program metadata");
+        info!("Could not read program metadata");
     }
 
     let mut config = EmulatorConfig {
@@ -75,7 +54,7 @@ fn main_run(args: Run) {
     let phosphor = Phosphor::new();
 
     if phosphor.is_ok() && args.dimensions().is_some() {
-        verbose!("Starting graphical emulator");
+        info!("Starting graphical emulator");
         let mut phosphor = phosphor.unwrap();
         config.dimensions = args.dimensions().unwrap();
         let cursor = match config.show_cursor {
@@ -83,7 +62,7 @@ fn main_run(args: Run) {
             false => None,
         };
 
-        let mut graphical = GraphicalEmulator::new(&config, args.debug, unsafe {VERBOSE});
+        let mut graphical = GraphicalEmulator::new(&config, args.debug);
         graphical.load_program(&bytecode);
         if let EmulatorSignal::Promote = graphical.run() {
             let program_name = match &metadata {
@@ -108,8 +87,8 @@ fn main_run(args: Run) {
             phosphor.run().unwrap();
         }
     } else {
-        verbose!("Starting headless emulator");
-        let mut headless = HeadlessEmulator::new(&config, args.debug, unsafe {VERBOSE});
+        info!("Starting headless emulator");
+        let mut headless = HeadlessEmulator::new(&config, args.debug);
         headless.load_program(&bytecode);
         headless.run(args.debug);
     };
@@ -123,26 +102,24 @@ fn load_bytecode(path: Option<&Path>) -> Bytecode {
         if let Ok(bytecode) = load_bytecode_from_file(path) {
             let length = bytecode.bytes.len();
             let path = bytecode.path();
-            verbose!("Loaded program from {path:?} ({length} bytes)");
+            info!("Loaded program from {path:?} ({length} bytes)");
             return bytecode;
         } else if let Some(bytecode) = load_bytecode_from_bedrock_path(path) {
             let length = bytecode.bytes.len();
             let path = bytecode.path();
-            verbose!("Loaded program from {path:?} ({length} bytes)");
+            info!("Loaded program from {path:?} ({length} bytes)");
             return bytecode;
         } else {
-            error!("Could not read program from {path:?}, exiting");
-            exit(1);
+            fatal!("Could not read program from {path:?}");
         }
     } else {
-        verbose!("Reading program from standard input...");
+        info!("Reading program from standard input...");
         if let Ok(bytecode) = load_bytecode_from_stdin() {
             let length = bytecode.bytes.len();
-            verbose!("Loaded program from standard input ({length} bytes)");
+            info!("Loaded program from standard input ({length} bytes)");
             return bytecode;
         } else {
-            error!("Could not read program from standard input, exiting");
-            exit(1);
+            fatal!("Could not read program from standard input");
         }
     }
 }
@@ -154,13 +131,13 @@ fn load_bytecode_from_bedrock_path(path: &Path) -> Option<Bytecode> {
             let mut base_path = PathBuf::from(base_path);
             if !base_path.is_absolute() { continue; }
             base_path.push(path);
-            verbose!("Attempting to load program from {base_path:?}");
+            info!("Attempting to load program from {base_path:?}");
             if let Ok(bytecode) = load_bytecode_from_file(&base_path) {
                 return Some(bytecode);
             }
             if path.extension().is_some() { continue; }
             base_path.set_extension("br");
-            verbose!("Attempting to load program from {base_path:?}");
+            info!("Attempting to load program from {base_path:?}");
             if let Ok(bytecode) = load_bytecode_from_file(&base_path) {
                 return Some(bytecode);
             }
@@ -220,29 +197,26 @@ fn main_asm(args: Asm) {
             Ok(source_unit) => SymbolResolver::from_source_unit(source_unit),
             Err(err) => {
                 match err {
-                    ParseError::InvalidExtension => error!(
+                    ParseError::InvalidExtension => fatal!(
                         "File {path:?} has invalid extension, must be '.{ext}'"),
-                    ParseError::NotFound => error!(
+                    ParseError::NotFound => fatal!(
                         "File {path:?} was not found"),
-                    ParseError::InvalidUtf8 => error!(
+                    ParseError::InvalidUtf8 => fatal!(
                         "File {path:?} does not contain valid UTF-8 text"),
-                    ParseError::NotReadable => error!(
+                    ParseError::NotReadable => fatal!(
                         "File {path:?} is not readable"),
-                    ParseError::IsADirectory => error!(
+                    ParseError::IsADirectory => fatal!(
                         "File {path:?} is a directory"),
-                    ParseError::Unknown => error!(
+                    ParseError::Unknown => fatal!(
                         "Unknown error while attempting to read from {path:?}")
                 };
-                exit(1);
             }
         }
     } else {
         let mut source_code = String::new();
-        verbose!("Reading program source from standard input");
+        info!("Reading program source from standard input");
         if let Err(err) = std::io::stdin().read_to_string(&mut source_code) {
-            error!("Could not read from standard input");
-            eprintln!("{err:?}");
-            exit(1);
+            fatal!("Could not read from standard input\n{err:?}");
         }
         let path = "<standard input>";
         let source_unit = SourceUnit::from_source_code(source_code, path);
@@ -300,17 +274,17 @@ fn main_asm(args: Asm) {
             symbols_path.set_extension("br.sym");
             let symbols = generate_symbols_file(&semantic_tokens);
             if let Err(err) = std::fs::write(&symbols_path, symbols) {
-                verbose!("Could not write to symbols path {symbols_path:?}");
+                info!("Could not write to symbols path {symbols_path:?}");
                 eprintln!("{err:?}");
             } else {
-                verbose!("Saved debug symbols to {symbols_path:?}");
+                info!("Saved debug symbols to {symbols_path:?}");
             }
         }
     }
 
     let length = bytecode.len();
     let percentage = (length as f32 / 65536.0 * 100.0).round() as u16;
-    verbose!("Assembled program in {length} bytes ({percentage}% of maximum)");
+    info!("Assembled program in {length} bytes ({percentage}% of maximum)");
 
     if !args.check {
         write_bytes_and_exit(&bytecode, args.output.as_ref());
@@ -320,15 +294,11 @@ fn main_asm(args: Asm) {
 fn write_bytes_and_exit<P: AsRef<Path>>(bytes: &[u8], path: Option<&P>) -> ! {
     if let Some(path) = path {
         if let Err(err) = std::fs::write(path, bytes) {
-            error!("Could not write to path {:?}", path.as_ref());
-            eprintln!("{err:?}");
-            exit(1);
+            fatal!("Could not write to path {:?}\n{err:?}", path.as_ref());
         }
     } else {
         if let Err(err) = std::io::stdout().write_all(bytes) {
-            error!("Could not write to standard output");
-            eprintln!("{err:?}");
-            exit(1);
+            fatal!("Could not write to standard output\n{err:?}");
         }
     }
     exit(0);
diff --git a/src/debug.rs b/src/debug.rs
index 6270948..7fd4ea5 100644
--- a/src/debug.rs
+++ b/src/debug.rs
@@ -5,7 +5,6 @@ use std::time::Instant;
 
 
 const NORMAL: &str = "\x1b[0m";
-const BOLD:   &str = "\x1b[1m";
 const DIM:    &str = "\x1b[2m";
 const YELLOW: &str = "\x1b[33m";
 const BLUE:   &str = "\x1b[34m";
@@ -13,29 +12,21 @@ const BLUE:   &str = "\x1b[34m";
 
 pub struct DebugState {
     pub enabled: bool,
-    pub verbose: bool,
     last_cycle: usize,
     last_mark: Instant,
     symbols: DebugSymbols,
 }
 
 impl DebugState {
-    pub fn new<P: AsRef<Path>>(enabled: bool, verbose: bool, symbols_path: Option<P>) -> Self {
+    pub fn new<P: AsRef<Path>>(enabled: bool, symbols_path: Option<P>) -> Self {
         Self {
             enabled,
-            verbose,
             last_cycle: 0,
             last_mark: Instant::now(),
             symbols: DebugSymbols::from_path_opt(symbols_path),
         }
     }
 
-    pub fn info(&self, string: &str) {
-        if self.verbose {
-            eprintln!("{BOLD}{BLUE}[INFO]{NORMAL}: {string}{NORMAL}");
-        }
-    }
-
     pub fn debug_summary(&mut self, core: &BedrockCore) {
         if self.enabled {
             let prev_pc = core.mem.pc.wrapping_sub(1);
diff --git a/src/devices/file_device/buffered_file.rs b/src/devices/file_device/buffered_file.rs
index f965950..29e1fa3 100644
--- a/src/devices/file_device/buffered_file.rs
+++ b/src/devices/file_device/buffered_file.rs
@@ -3,8 +3,6 @@ use std::io::{BufReader, BufWriter};
 use std::io::{Read, Write};
 use std::io::{ErrorKind, Seek, SeekFrom};
 
-use crate::*;
-
 
 pub struct BufferedFile {
     file: AccessMode,
@@ -42,7 +40,7 @@ impl BufferedFile {
             Ok(_) => buffer[0],
             Err(error) => match error.kind() {
                 ErrorKind::UnexpectedEof => 0,
-                _ => { error!("BufferedFile::read", "{error:?}"); 0 },
+                _ => { log::error!("BufferedFile::read: {error:?}"); 0 },
             }
         }
     }
diff --git a/src/emulators/graphical_emulator.rs b/src/emulators/graphical_emulator.rs
index 14848c6..1c58a34 100644
--- a/src/emulators/graphical_emulator.rs
+++ b/src/emulators/graphical_emulator.rs
@@ -111,11 +111,11 @@ pub struct GraphicalEmulator {
 }
 
 impl GraphicalEmulator {
-    pub fn new(config: &EmulatorConfig, debug: bool, verbose: bool) -> Self {
+    pub fn new(config: &EmulatorConfig, debug: bool) -> Self {
         let devices = GraphicalDeviceBus::new(config);
         Self {
             br: BedrockEmulator::new(devices),
-            debug: DebugState::new(debug, verbose, config.symbols_path.as_ref()),
+            debug: DebugState::new(debug, config.symbols_path.as_ref()),
             dimensions: config.dimensions,
             fullscreen: config.fullscreen,
             scale: config.scale,
@@ -147,7 +147,7 @@ impl GraphicalEmulator {
                 }
                 Some(Signal::Halt) => {
                     self.br.dev.loc.flush();
-                    self.debug.info("Program halted, exiting.");
+                    log::info!("Program halted, exiting.");
                     self.debug.debug_summary(&self.br.core);
                     return EmulatorSignal::Halt;
                 }
@@ -286,7 +286,7 @@ impl WindowProgram for GraphicalEmulator {
                 }
                 Some(Signal::Halt) => {
                     self.br.dev.loc.flush();
-                    self.debug.info("Program halted, exiting.");
+                    log::info!("Program halted, exiting.");
                     self.debug.debug_summary(&self.br.core);
                     requests.write(Request::CloseWindow);
                     break;
diff --git a/src/emulators/headless_emulator.rs b/src/emulators/headless_emulator.rs
index f215db3..9207b3d 100644
--- a/src/emulators/headless_emulator.rs
+++ b/src/emulators/headless_emulator.rs
@@ -86,10 +86,10 @@ pub struct HeadlessEmulator {
 }
 
 impl HeadlessEmulator {
-    pub fn new(config: &EmulatorConfig, debug: bool, verbose: bool) -> Self {
+    pub fn new(config: &EmulatorConfig, debug: bool) -> Self {
         Self {
             br: BedrockEmulator::new(HeadlessDeviceBus::new(config)),
-            debug: DebugState::new(debug, verbose, config.symbols_path.as_ref()),
+            debug: DebugState::new(debug, config.symbols_path.as_ref()),
         }
     }
 
@@ -111,7 +111,7 @@ impl HeadlessEmulator {
                 }
                 Some(Signal::Halt) => {
                     self.br.dev.loc.flush();
-                    self.debug.info("Program halted, exiting.");
+                    log::info!("Program halted, exiting.");
                     self.debug.debug_summary(&self.br.core);
                     return EmulatorSignal::Halt;
                 }
diff --git a/src/lib.rs b/src/lib.rs
index 4ff35eb..0df1efb 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -25,10 +25,3 @@ pub const DEFAULT_SCREEN_SCALE: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(
 pub type ScreenPosition = geometry::Point<u16>;
 pub type ScreenDimensions = geometry::Dimensions<u16>;
 
-#[macro_export]
-macro_rules! error {
-    ($source:expr, $($tokens:tt)*) => {{
-        eprint!("[ERROR] [{}]: ", $source);
-        eprintln!($($tokens)*);
-    }};
-}
-- 
cgit v1.2.3-70-g09d2