From 4db3ae7cb89f96eb41c0ff903f8dbaa81c1b0343 Mon Sep 17 00:00:00 2001 From: Jeff Date: Wed, 6 Mar 2024 17:32:31 -0500 Subject: [PATCH] Add more errors --- src/abstract_tree/expression.rs | 6 +++++- src/abstract_tree/identifier.rs | 34 ++++++++++++++++++++++++--------- src/abstract_tree/statement.rs | 7 ++++++- src/error.rs | 34 ++++++++++++++++++++++++++++----- src/lib.rs | 14 ++++++++------ src/value.rs | 26 ++++++++++++++++++++++++- 6 files changed, 98 insertions(+), 23 deletions(-) diff --git a/src/abstract_tree/expression.rs b/src/abstract_tree/expression.rs index 868af79..f5ec37c 100644 --- a/src/abstract_tree/expression.rs +++ b/src/abstract_tree/expression.rs @@ -23,7 +23,11 @@ impl<'src> AbstractTree for Expression<'src> { } fn validate(&self, _context: &Context) -> Result<(), ValidationError> { - todo!() + match self { + Expression::Identifier(identifier) => identifier.validate(_context), + Expression::Logic(logic) => logic.validate(_context), + Expression::Value(value_node) => value_node.validate(_context), + } } fn run(self, context: &Context) -> Result { diff --git a/src/abstract_tree/identifier.rs b/src/abstract_tree/identifier.rs index 22f128d..9a9b653 100644 --- a/src/abstract_tree/identifier.rs +++ b/src/abstract_tree/identifier.rs @@ -1,4 +1,7 @@ -use std::sync::Arc; +use std::{ + fmt::{self, Display, Formatter}, + sync::Arc, +}; use crate::{ context::Context, @@ -22,18 +25,31 @@ impl Identifier { } impl AbstractTree for Identifier { - fn expected_type(&self, _context: &Context) -> Result { - todo!() + fn expected_type(&self, context: &Context) -> Result { + if let Some(value) = context.get(self)? { + Ok(value.r#type()) + } else { + Err(ValidationError::VariableNotFound(self.clone())) + } } - fn validate(&self, _context: &Context) -> Result<(), ValidationError> { - todo!() + fn validate(&self, context: &Context) -> Result<(), ValidationError> { + if let Some(_) = context.get(self)? { + Ok(()) + } else { + Err(ValidationError::VariableNotFound(self.clone())) + } } - fn run(self, _context: &Context) -> Result { - todo!() - // let value = context.get(&self)?.unwrap_or_else(Value::none).clone(); + fn run(self, context: &Context) -> Result { + let value = context.get(&self)?.unwrap_or_else(Value::none).clone(); - // Ok(value) + Ok(value) + } +} + +impl Display for Identifier { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + write!(f, "{}", self.0) } } diff --git a/src/abstract_tree/statement.rs b/src/abstract_tree/statement.rs index 8363812..4d3c449 100644 --- a/src/abstract_tree/statement.rs +++ b/src/abstract_tree/statement.rs @@ -24,7 +24,12 @@ impl<'src> AbstractTree for Statement<'src> { } fn validate(&self, _context: &Context) -> Result<(), ValidationError> { - todo!() + match self { + Statement::Assignment(assignment) => assignment.validate(_context), + Statement::Block(_) => todo!(), + Statement::Expression(expression) => expression.validate(_context), + Statement::Loop(_) => todo!(), + } } fn run(self, _context: &Context) -> Result { diff --git a/src/error.rs b/src/error.rs index a0d2f88..af84cc2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,14 +3,26 @@ use std::sync::PoisonError; use ariadne::{Label, Report, ReportKind}; use chumsky::{prelude::Rich, span::SimpleSpan}; -use crate::{abstract_tree::Type, lexer::Token}; +use crate::{ + abstract_tree::{Identifier, Type}, + lexer::Token, +}; #[derive(Debug, PartialEq)] pub enum Error { - Parse { expected: String, span: SimpleSpan }, - Lex { expected: String, span: SimpleSpan }, + Parse { + expected: String, + span: SimpleSpan, + }, + Lex { + expected: String, + span: SimpleSpan, + }, Runtime(RuntimeError), - Validation(ValidationError), + Validation { + error: ValidationError, + span: SimpleSpan, + }, } impl From> for Error { @@ -60,6 +72,7 @@ pub enum ValidationError { ExpectedBoolean, RwLockPoison(RwLockPoisonError), TypeCheck(TypeCheckError), + VariableNotFound(Identifier), } impl From for ValidationError { @@ -110,7 +123,18 @@ pub fn create_report<'a>(errors: &'a [Error]) -> Report<'a> { ); } Error::Runtime(_) => todo!(), - Error::Validation(_) => todo!(), + Error::Validation { error, span } => match error { + ValidationError::ExpectedBoolean => todo!(), + ValidationError::RwLockPoison(_) => todo!(), + ValidationError::TypeCheck(_) => todo!(), + ValidationError::VariableNotFound(identifier) => { + report = + report + .with_label(Label::new(span.start..span.end).with_message(format!( + "The variable {identifier} does not exist." + ))); + } + }, } } diff --git a/src/lib.rs b/src/lib.rs index 9282dc2..3ada3c1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,12 +26,14 @@ impl Interpreter { let statements = parse(&tokens)?; let errors = statements .iter() - .filter_map(|(statement, _span)| { - if let Some(error) = statement.validate(&self.context).err() { - Some(Error::Validation(error)) - } else { - None - } + .filter_map(|(statement, span)| { + statement + .validate(&self.context) + .map_err(|validation_error| Error::Validation { + error: validation_error, + span: span.clone(), + }) + .err() }) .collect::>(); diff --git a/src/value.rs b/src/value.rs index 98136a3..f0f64cf 100644 --- a/src/value.rs +++ b/src/value.rs @@ -6,7 +6,10 @@ use std::{ sync::{Arc, OnceLock}, }; -use crate::{abstract_tree::Identifier, error::ValidationError}; +use crate::{ + abstract_tree::{Identifier, Type}, + error::ValidationError, +}; pub static NONE: OnceLock = OnceLock::new(); @@ -63,6 +66,27 @@ impl Value { Value(Arc::new(ValueInner::Enum(name, variant))) } + pub fn r#type(&self) -> Type { + match self.0.as_ref() { + ValueInner::Boolean(_) => Type::Boolean, + ValueInner::Float(_) => Type::Float, + ValueInner::Integer(_) => Type::Integer, + ValueInner::List(values) => { + let mut types = Vec::with_capacity(values.len()); + + for value in values { + types.push(value.r#type()); + } + + Type::ListExact(types) + } + ValueInner::Map(_) => Type::Map, + ValueInner::Range(_) => Type::Range, + ValueInner::String(_) => Type::String, + ValueInner::Enum(name, _) => Type::Custom(name.clone()), + } + } + pub fn as_boolean(&self) -> Result { if let ValueInner::Boolean(boolean) = self.0.as_ref() { return Ok(*boolean);