Clean up and refactor slightly
This commit is contained in:
parent
7b25b593ef
commit
72a019cfe5
@ -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) => {
|
||||||
|
@ -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,
|
||||||
|
@ -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"),
|
||||||
(
|
(
|
||||||
|
@ -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();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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!(
|
||||||
|
Loading…
Reference in New Issue
Block a user