Clean up and refactor slightly

This commit is contained in:
Jeff 2024-09-05 11:32:31 -04:00
parent 7b25b593ef
commit 72a019cfe5
6 changed files with 52 additions and 54 deletions

View File

@ -176,7 +176,10 @@ impl<'a> Analyzer<'a> {
expression: &Expression, expression: &Expression,
context: &Context, context: &Context,
) -> Result<(), ContextError> { ) -> Result<(), ContextError> {
log::trace!("Analyzing expression {expression}"); log::trace!(
"Analyzing expression {expression} at {:?}",
expression.position()
);
match expression { match expression {
Expression::Block(block_expression) => { Expression::Block(block_expression) => {

View File

@ -25,6 +25,17 @@ impl Context {
inner: Arc::new(ContextInner { inner: Arc::new(ContextInner {
associations: RwLock::new(data), associations: RwLock::new(data),
parent: None, parent: None,
is_immutable: false,
}),
}
}
pub fn with_data_immutable(data: Associations) -> Self {
Self {
inner: Arc::new(ContextInner {
associations: RwLock::new(data),
parent: None,
is_immutable: true,
}), }),
} }
} }
@ -45,6 +56,7 @@ impl Context {
inner: Arc::new(ContextInner { inner: Arc::new(ContextInner {
associations: RwLock::new(HashMap::new()), associations: RwLock::new(HashMap::new()),
parent: Some(Arc::downgrade(&self.inner)), parent: Some(Arc::downgrade(&self.inner)),
is_immutable: false,
}), }),
} }
} }
@ -158,20 +170,19 @@ impl Context {
/// Recovers the context from a poisoned state by recovering data from an error. /// Recovers the context from a poisoned state by recovering data from an error.
/// ///
/// This method is not used. /// This method is not used.
pub fn _recover_from_poison(&mut self, error: &ContextError) { pub fn _recover_from_poison(&mut self, recovered: &RwLockReadGuard<Associations>) {
log::debug!("Context is recovering from poison error"); log::debug!("Context is recovering from poison error");
let ContextError::PoisonErrorRecovered(recovered) = error;
let mut new_associations = HashMap::new(); let mut new_associations = HashMap::new();
for (identifier, (context_data, position)) in recovered.as_ref() { for (identifier, (context_data, position)) in recovered.iter() {
new_associations.insert(identifier.clone(), (context_data.clone(), *position)); new_associations.insert(identifier.clone(), (context_data.clone(), *position));
} }
self.inner = Arc::new(ContextInner { self.inner = Arc::new(ContextInner {
associations: RwLock::new(new_associations), associations: RwLock::new(new_associations),
parent: None, parent: None,
is_immutable: false,
}); });
} }
} }
@ -184,18 +195,12 @@ impl Default for Context {
#[derive(Debug)] #[derive(Debug)]
pub struct ContextInner { pub struct ContextInner {
pub associations: RwLock<Associations>, associations: RwLock<Associations>,
pub parent: Option<Weak<ContextInner>>, parent: Option<Weak<ContextInner>>,
is_immutable: bool,
} }
impl ContextInner { impl ContextInner {
pub fn new(associations: RwLock<Associations>, parent: Option<Weak<ContextInner>>) -> Self {
Self {
associations,
parent,
}
}
/// Returns the number of associated identifiers in the context. /// Returns the number of associated identifiers in the context.
pub fn association_count(&self) -> Result<usize, ContextError> { pub fn association_count(&self) -> Result<usize, ContextError> {
Ok(self.associations.read()?.len()) Ok(self.associations.read()?.len())
@ -329,6 +334,10 @@ impl ContextInner {
identifier: Identifier, identifier: Identifier,
r#type: Type, r#type: Type,
) -> Result<(), ContextError> { ) -> Result<(), ContextError> {
if self.is_immutable {
return Err(ContextError::CannotMutateImmutableContext);
}
log::trace!("Setting {identifier} to type {type}."); log::trace!("Setting {identifier} to type {type}.");
let mut associations = self.associations.write()?; let mut associations = self.associations.write()?;
@ -351,6 +360,10 @@ impl ContextInner {
identifier: Identifier, identifier: Identifier,
value: Value, value: Value,
) -> Result<(), ContextError> { ) -> Result<(), ContextError> {
if self.is_immutable {
return Err(ContextError::CannotMutateImmutableContext);
}
log::trace!("Setting {identifier} to value {value}"); log::trace!("Setting {identifier} to value {value}");
let mut associations = self.associations.write()?; let mut associations = self.associations.write()?;
@ -373,6 +386,10 @@ impl ContextInner {
identifier: Identifier, identifier: Identifier,
constructor: Constructor, constructor: Constructor,
) -> Result<(), ContextError> { ) -> Result<(), ContextError> {
if self.is_immutable {
return Err(ContextError::CannotMutateImmutableContext);
}
log::trace!("Setting {identifier} to constructor {constructor:?}"); log::trace!("Setting {identifier} to constructor {constructor:?}");
let mut associations = self.associations.write()?; let mut associations = self.associations.write()?;
@ -396,6 +413,10 @@ impl ContextInner {
identifier: Identifier, identifier: Identifier,
struct_type: StructType, struct_type: StructType,
) -> Result<(), ContextError> { ) -> Result<(), ContextError> {
if self.is_immutable {
return Err(ContextError::CannotMutateImmutableContext);
}
log::trace!("Setting {identifier} to constructor of type {struct_type}"); log::trace!("Setting {identifier} to constructor of type {struct_type}");
let mut variables = self.associations.write()?; let mut variables = self.associations.write()?;
@ -490,6 +511,7 @@ pub enum ContextData {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum ContextError { pub enum ContextError {
CannotMutateImmutableContext,
PoisonErrorRecovered(Arc<Associations>), PoisonErrorRecovered(Arc<Associations>),
} }
@ -512,9 +534,11 @@ impl From<PoisonError<RwLockReadGuard<'_, Associations>>> for ContextError {
impl PartialEq for ContextError { impl PartialEq for ContextError {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
match (self, other) { match (self, other) {
(Self::CannotMutateImmutableContext, Self::CannotMutateImmutableContext) => true,
(Self::PoisonErrorRecovered(left), Self::PoisonErrorRecovered(right)) => { (Self::PoisonErrorRecovered(left), Self::PoisonErrorRecovered(right)) => {
Arc::ptr_eq(left, right) Arc::ptr_eq(left, right)
} }
_ => false,
} }
} }
} }
@ -522,6 +546,7 @@ impl PartialEq for ContextError {
impl Display for ContextError { impl Display for ContextError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
Self::CannotMutateImmutableContext => write!(f, "Cannot mutate immutable context"),
Self::PoisonErrorRecovered(associations) => { Self::PoisonErrorRecovered(associations) => {
write!( write!(
f, f,

View File

@ -6,7 +6,7 @@ static CORE_LIBRARY: OnceLock<Context> = OnceLock::new();
pub fn core_library<'a>() -> &'a Context { pub fn core_library<'a>() -> &'a Context {
CORE_LIBRARY.get_or_init(|| { CORE_LIBRARY.get_or_init(|| {
Context::with_data(HashMap::from([ Context::with_data_immutable(HashMap::from([
( (
Identifier::new("to_string"), Identifier::new("to_string"),
( (

View File

@ -1,8 +1,8 @@
//! Top-level error handling for the Dust language. //! Top-level error handling for the Dust language.
use annotate_snippets::{Level, Message, Renderer, Snippet}; use annotate_snippets::{Level, Renderer, Snippet};
use std::fmt::Display; use std::fmt::Display;
use crate::{AnalysisError, ContextError, LexError, ParseError, RuntimeError, Span}; use crate::{AnalysisError, ContextError, LexError, ParseError, RuntimeError};
/// An error that occurred during the execution of the Dust language and its /// An error that occurred during the execution of the Dust language and its
/// corresponding source code. /// corresponding source code.
@ -79,43 +79,6 @@ impl<'src> DustError<'src> {
} }
} }
fn footer(&self) -> Vec<(&'static str, Span, String)> {
match self {
DustError::ContextError(_) => vec![],
DustError::Runtime { runtime_error, .. } => {
let mut error_data = vec![(
"Runtime error",
runtime_error.position(),
runtime_error.to_string(),
)];
if let RuntimeError::Expression { error, position } = runtime_error {
error_data.push((
"Error occured at this expression",
*position,
error.to_string(),
));
}
error_data
}
DustError::Analysis {
analysis_errors, ..
} => analysis_errors
.iter()
.map(|error| ("Analysis error", error.position(), error.to_string()))
.collect(),
DustError::Parse { parse_error, .. } => vec![(
"Parse error",
parse_error.position(),
parse_error.to_string(),
)],
DustError::Lex { lex_error, .. } => {
vec![("Lex error", lex_error.position(), lex_error.to_string())]
}
}
}
pub fn report(&self) -> String { pub fn report(&self) -> String {
let mut report = String::new(); let mut report = String::new();
let renderer = Renderer::styled(); let renderer = Renderer::styled();

View File

@ -1022,8 +1022,13 @@ impl Vm {
let mut evaluation = Evaluation::Return(None); let mut evaluation = Evaluation::Return(None);
for statement in ast.statements { for statement in ast.statements {
let position = statement.position();
evaluation = Vm.run_statement(statement, &ast.context, collect_garbage)?; evaluation = Vm.run_statement(statement, &ast.context, collect_garbage)?;
ast.context
.collect_garbage(position.1)
.map_err(|error| RuntimeError::ContextError { error, position })?;
if let Evaluation::Break(_) = evaluation { if let Evaluation::Break(_) = evaluation {
return Ok(evaluation); return Ok(evaluation);
} }

View File

@ -9,6 +9,8 @@ fn block_scope_captures_parent() {
#[test] #[test]
fn block_scope_does_not_capture_child() { fn block_scope_does_not_capture_child() {
env_logger::builder().is_test(true).try_init().unwrap();
let source = "{ let x = 42; } x"; let source = "{ let x = 42; } x";
assert_eq!( assert_eq!(