From 9a245190d7c3610a84a1b4fde0160c779f911042 Mon Sep 17 00:00:00 2001 From: Chris Mounce Date: Sat, 5 Jul 2025 17:07:47 -0700 Subject: [PATCH] Shrink error Context and reduce cloning --- src/error.rs | 83 +++++++++++++++++++++++++++++-------------- src/labels/process.rs | 8 ++--- src/main.rs | 5 +-- 3 files changed, 63 insertions(+), 33 deletions(-) diff --git a/src/error.rs b/src/error.rs index fa79270..6522331 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,56 +1,85 @@ -use std::{cell::RefCell, error::Error, fmt::Display, ops::Range, rc::Rc}; +use std::{cell::RefCell, error::Error, fmt::Display, ops::Range}; use crate::world::World; -#[derive(Clone, Default)] -pub struct Context { - messages: Rc>>, - location: Location, +pub enum Context<'a> { + Base(Box>>), + With(&'a Context<'a>, ContextInfo<'a>), } -impl Context { - pub fn with_file_path(&self, s: &str) -> Self { - let mut result = self.clone(); - result.location.file_path = Some(s.into()); - result +pub enum ContextInfo<'a> { + FilePath(&'a str), + Board(usize), + Stat(usize), + Span(Range), +} + +impl<'a> Context<'a> { + pub fn new() -> Self { + Self::Base(Box::new(RefCell::new(vec![]))) } - pub fn with_board(&self, board: usize) -> Self { - let mut result = self.clone(); - result.location.board = Some(board); - result + pub fn with_file_path(&'a self, s: &'a str) -> Self { + Self::With(self, ContextInfo::FilePath(s)) } - pub fn with_stat(&self, stat: usize) -> Self { - let mut result = self.clone(); - result.location.stat = Some(stat); - result + pub fn with_board(&'a self, i: usize) -> Self { + Self::With(self, ContextInfo::Board(i)) } - pub fn with_span(&self, span: Range) -> Self { - let mut result = self.clone(); - result.location.span = Some(span); - result + pub fn with_stat(&'a self, i: usize) -> Self { + Self::With(self, ContextInfo::Stat(i)) + } + + pub fn with_span(&'a self, r: Range) -> Self { + Self::With(self, ContextInfo::Span(r)) + } + + fn store(&self, mut message: CompileMessage) { + match self { + Context::Base(refcell) => refcell.borrow_mut().push(message), + Context::With(parent, info) => { + let location = &mut message.location; + match info { + ContextInfo::FilePath(s) => { + location.file_path.get_or_insert((*s).into()); + } + ContextInfo::Board(i) => { + location.board.get_or_insert(*i); + } + ContextInfo::Stat(i) => { + location.stat.get_or_insert(*i); + } + ContextInfo::Span(r) => { + location.span.get_or_insert(r.clone()); + } + }; + parent.store(message); + } + } } pub fn error(&self, message: &str) { - self.messages.borrow_mut().push(CompileMessage { + self.store(CompileMessage { level: Level::Error, message: message.into(), - location: self.location.clone(), + location: Location::default(), }); } pub fn warning(&self, message: &str) { - self.messages.borrow_mut().push(CompileMessage { + self.store(CompileMessage { level: Level::Warning, message: message.into(), - location: self.location.clone(), + location: Location::default(), }); } pub fn into_messages(self) -> Vec { - self.messages.take() + match self { + Context::Base(refcell) => refcell.into_inner(), + _ => panic!("into_messages() may only be called on the base context"), + } } } diff --git a/src/labels/process.rs b/src/labels/process.rs index 63976c7..12b6c7e 100644 --- a/src/labels/process.rs +++ b/src/labels/process.rs @@ -259,28 +259,28 @@ mod test { #[test] fn test_label_sanitization() { let mut board = board_from_text("tests/labels/sanitize.txt"); - let _ = process_labels(&mut board, &Context::default()); + let _ = process_labels(&mut board, &Context::new()); assert_snapshot!(board_to_text(board)); } #[test] fn test_anonymous_labels() { let mut board = board_from_text("tests/labels/anonymous.txt"); - let _ = process_labels(&mut board, &Context::default()); + let _ = process_labels(&mut board, &Context::new()); assert_snapshot!(board_to_text(board)); } #[test] fn test_local_labels() { let mut board = board_from_text("tests/labels/local.txt"); - let _ = process_labels(&mut board, &Context::default()); + let _ = process_labels(&mut board, &Context::new()); assert_snapshot!(board_to_text(board)); } #[test] fn test_namespaces() { let mut board = board_from_text("tests/labels/namespaces.txt"); - let _ = process_labels(&mut board, &Context::default()); + let _ = process_labels(&mut board, &Context::new()); assert_snapshot!(board_to_text(board)); } } diff --git a/src/main.rs b/src/main.rs index 212a18d..dadabfb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,14 +38,15 @@ fn main() -> Result<(), Box> { } // Resolve labels to proper ZZT-OOP - let ctx = ErrContext::default().with_file_path(&world_filename); + let base_ctx = ErrContext::new(); + let ctx = base_ctx.with_file_path(&world_filename); for (i, mut board) in world.boards.iter_mut().enumerate() { let ctx = ctx.with_board(i); process_labels(&mut board, &ctx); } // Print diagnostics - let messages = ctx.into_messages(); + let messages = base_ctx.into_messages(); for (i, message) in messages.iter().enumerate() { if i > 0 { println!();