Clean up and refactor slightly
This commit is contained in:
parent
7b25b593ef
commit
72a019cfe5
@ -176,7 +176,10 @@ impl<'a> Analyzer<'a> {
|
||||
expression: &Expression,
|
||||
context: &Context,
|
||||
) -> Result<(), ContextError> {
|
||||
log::trace!("Analyzing expression {expression}");
|
||||
log::trace!(
|
||||
"Analyzing expression {expression} at {:?}",
|
||||
expression.position()
|
||||
);
|
||||
|
||||
match expression {
|
||||
Expression::Block(block_expression) => {
|
||||
|
@ -25,6 +25,17 @@ impl Context {
|
||||
inner: Arc::new(ContextInner {
|
||||
associations: RwLock::new(data),
|
||||
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 {
|
||||
associations: RwLock::new(HashMap::new()),
|
||||
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.
|
||||
///
|
||||
/// 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");
|
||||
|
||||
let ContextError::PoisonErrorRecovered(recovered) = error;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
self.inner = Arc::new(ContextInner {
|
||||
associations: RwLock::new(new_associations),
|
||||
parent: None,
|
||||
is_immutable: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -184,18 +195,12 @@ impl Default for Context {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ContextInner {
|
||||
pub associations: RwLock<Associations>,
|
||||
pub parent: Option<Weak<ContextInner>>,
|
||||
associations: RwLock<Associations>,
|
||||
parent: Option<Weak<ContextInner>>,
|
||||
is_immutable: bool,
|
||||
}
|
||||
|
||||
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.
|
||||
pub fn association_count(&self) -> Result<usize, ContextError> {
|
||||
Ok(self.associations.read()?.len())
|
||||
@ -329,6 +334,10 @@ impl ContextInner {
|
||||
identifier: Identifier,
|
||||
r#type: Type,
|
||||
) -> Result<(), ContextError> {
|
||||
if self.is_immutable {
|
||||
return Err(ContextError::CannotMutateImmutableContext);
|
||||
}
|
||||
|
||||
log::trace!("Setting {identifier} to type {type}.");
|
||||
|
||||
let mut associations = self.associations.write()?;
|
||||
@ -351,6 +360,10 @@ impl ContextInner {
|
||||
identifier: Identifier,
|
||||
value: Value,
|
||||
) -> Result<(), ContextError> {
|
||||
if self.is_immutable {
|
||||
return Err(ContextError::CannotMutateImmutableContext);
|
||||
}
|
||||
|
||||
log::trace!("Setting {identifier} to value {value}");
|
||||
|
||||
let mut associations = self.associations.write()?;
|
||||
@ -373,6 +386,10 @@ impl ContextInner {
|
||||
identifier: Identifier,
|
||||
constructor: Constructor,
|
||||
) -> Result<(), ContextError> {
|
||||
if self.is_immutable {
|
||||
return Err(ContextError::CannotMutateImmutableContext);
|
||||
}
|
||||
|
||||
log::trace!("Setting {identifier} to constructor {constructor:?}");
|
||||
|
||||
let mut associations = self.associations.write()?;
|
||||
@ -396,6 +413,10 @@ impl ContextInner {
|
||||
identifier: Identifier,
|
||||
struct_type: StructType,
|
||||
) -> Result<(), ContextError> {
|
||||
if self.is_immutable {
|
||||
return Err(ContextError::CannotMutateImmutableContext);
|
||||
}
|
||||
|
||||
log::trace!("Setting {identifier} to constructor of type {struct_type}");
|
||||
|
||||
let mut variables = self.associations.write()?;
|
||||
@ -490,6 +511,7 @@ pub enum ContextData {
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ContextError {
|
||||
CannotMutateImmutableContext,
|
||||
PoisonErrorRecovered(Arc<Associations>),
|
||||
}
|
||||
|
||||
@ -512,9 +534,11 @@ impl From<PoisonError<RwLockReadGuard<'_, Associations>>> for ContextError {
|
||||
impl PartialEq for ContextError {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::CannotMutateImmutableContext, Self::CannotMutateImmutableContext) => true,
|
||||
(Self::PoisonErrorRecovered(left), Self::PoisonErrorRecovered(right)) => {
|
||||
Arc::ptr_eq(left, right)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -522,6 +546,7 @@ impl PartialEq for ContextError {
|
||||
impl Display for ContextError {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::CannotMutateImmutableContext => write!(f, "Cannot mutate immutable context"),
|
||||
Self::PoisonErrorRecovered(associations) => {
|
||||
write!(
|
||||
f,
|
||||
|
@ -6,7 +6,7 @@ static CORE_LIBRARY: OnceLock<Context> = OnceLock::new();
|
||||
|
||||
pub fn core_library<'a>() -> &'a Context {
|
||||
CORE_LIBRARY.get_or_init(|| {
|
||||
Context::with_data(HashMap::from([
|
||||
Context::with_data_immutable(HashMap::from([
|
||||
(
|
||||
Identifier::new("to_string"),
|
||||
(
|
||||
|
@ -1,8 +1,8 @@
|
||||
//! 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 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
|
||||
/// 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 {
|
||||
let mut report = String::new();
|
||||
let renderer = Renderer::styled();
|
||||
|
@ -1022,8 +1022,13 @@ impl Vm {
|
||||
let mut evaluation = Evaluation::Return(None);
|
||||
|
||||
for statement in ast.statements {
|
||||
let position = statement.position();
|
||||
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 {
|
||||
return Ok(evaluation);
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ fn block_scope_captures_parent() {
|
||||
|
||||
#[test]
|
||||
fn block_scope_does_not_capture_child() {
|
||||
env_logger::builder().is_test(true).try_init().unwrap();
|
||||
|
||||
let source = "{ let x = 42; } x";
|
||||
|
||||
assert_eq!(
|
||||
|
Loading…
Reference in New Issue
Block a user