Shrink error Context and reduce cloning

This commit is contained in:
2025-07-05 17:07:47 -07:00
parent 2b35fe30e9
commit 9a245190d7
3 changed files with 63 additions and 33 deletions
+56 -27
View File
@@ -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; use crate::world::World;
#[derive(Clone, Default)] pub enum Context<'a> {
pub struct Context { Base(Box<RefCell<Vec<CompileMessage>>>),
messages: Rc<RefCell<Vec<CompileMessage>>>, With(&'a Context<'a>, ContextInfo<'a>),
location: Location,
} }
impl Context { pub enum ContextInfo<'a> {
pub fn with_file_path(&self, s: &str) -> Self { FilePath(&'a str),
let mut result = self.clone(); Board(usize),
result.location.file_path = Some(s.into()); Stat(usize),
result Span(Range<usize>),
} }
pub fn with_board(&self, board: usize) -> Self { impl<'a> Context<'a> {
let mut result = self.clone(); pub fn new() -> Self {
result.location.board = Some(board); Self::Base(Box::new(RefCell::new(vec![])))
result
} }
pub fn with_stat(&self, stat: usize) -> Self { pub fn with_file_path(&'a self, s: &'a str) -> Self {
let mut result = self.clone(); Self::With(self, ContextInfo::FilePath(s))
result.location.stat = Some(stat);
result
} }
pub fn with_span(&self, span: Range<usize>) -> Self { pub fn with_board(&'a self, i: usize) -> Self {
let mut result = self.clone(); Self::With(self, ContextInfo::Board(i))
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<usize>) -> 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) { pub fn error(&self, message: &str) {
self.messages.borrow_mut().push(CompileMessage { self.store(CompileMessage {
level: Level::Error, level: Level::Error,
message: message.into(), message: message.into(),
location: self.location.clone(), location: Location::default(),
}); });
} }
pub fn warning(&self, message: &str) { pub fn warning(&self, message: &str) {
self.messages.borrow_mut().push(CompileMessage { self.store(CompileMessage {
level: Level::Warning, level: Level::Warning,
message: message.into(), message: message.into(),
location: self.location.clone(), location: Location::default(),
}); });
} }
pub fn into_messages(self) -> Vec<CompileMessage> { pub fn into_messages(self) -> Vec<CompileMessage> {
self.messages.take() match self {
Context::Base(refcell) => refcell.into_inner(),
_ => panic!("into_messages() may only be called on the base context"),
}
} }
} }
+4 -4
View File
@@ -259,28 +259,28 @@ mod test {
#[test] #[test]
fn test_label_sanitization() { fn test_label_sanitization() {
let mut board = board_from_text("tests/labels/sanitize.txt"); 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)); assert_snapshot!(board_to_text(board));
} }
#[test] #[test]
fn test_anonymous_labels() { fn test_anonymous_labels() {
let mut board = board_from_text("tests/labels/anonymous.txt"); 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)); assert_snapshot!(board_to_text(board));
} }
#[test] #[test]
fn test_local_labels() { fn test_local_labels() {
let mut board = board_from_text("tests/labels/local.txt"); 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)); assert_snapshot!(board_to_text(board));
} }
#[test] #[test]
fn test_namespaces() { fn test_namespaces() {
let mut board = board_from_text("tests/labels/namespaces.txt"); 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)); assert_snapshot!(board_to_text(board));
} }
} }
+3 -2
View File
@@ -38,14 +38,15 @@ fn main() -> Result<(), Box<dyn Error>> {
} }
// Resolve labels to proper ZZT-OOP // 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() { for (i, mut board) in world.boards.iter_mut().enumerate() {
let ctx = ctx.with_board(i); let ctx = ctx.with_board(i);
process_labels(&mut board, &ctx); process_labels(&mut board, &ctx);
} }
// Print diagnostics // Print diagnostics
let messages = ctx.into_messages(); let messages = base_ctx.into_messages();
for (i, message) in messages.iter().enumerate() { for (i, message) in messages.iter().enumerate() {
if i > 0 { if i > 0 {
println!(); println!();