From 791610b350fcf642b1c2973943058da60a3531f9 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sun, 17 Mar 2024 18:03:43 -0400 Subject: [PATCH] Improve built-in values and errors --- src/abstract_tree/index.rs | 10 ++++++++-- src/context.rs | 13 +++++++++++-- src/error.rs | 40 +++++++++++++++++++++++++------------- src/value.rs | 24 ++++++++++++++++------- 4 files changed, 62 insertions(+), 25 deletions(-) diff --git a/src/abstract_tree/index.rs b/src/abstract_tree/index.rs index 18daadf..e3390e4 100644 --- a/src/abstract_tree/index.rs +++ b/src/abstract_tree/index.rs @@ -34,7 +34,10 @@ impl AbstractTree for Index { expression.node.expected_type(_context) } else { - Err(ValidationError::CannotIndex(left_type)) + Err(ValidationError::CannotIndex { + r#type: left_type, + position: self.left.position, + }) } } @@ -53,7 +56,10 @@ impl AbstractTree for Index { Err(ValidationError::CannotIndexWith(left_type, right_type)) } } - _ => Err(ValidationError::CannotIndex(left_type)), + _ => Err(ValidationError::CannotIndex { + r#type: left_type, + position: self.left.position, + }), } } diff --git a/src/context.rs b/src/context.rs index a257090..5f40b26 100644 --- a/src/context.rs +++ b/src/context.rs @@ -6,7 +6,7 @@ use std::{ use crate::{ abstract_tree::{Identifier, Type}, error::RwLockPoisonError, - value::BuiltInFunction, + value::{BuiltInFunction, BuiltInValue}, Value, }; @@ -53,7 +53,14 @@ impl Context { } pub fn contains(&self, identifier: &Identifier) -> Result { - Ok(self.inner.read()?.contains_key(identifier)) + if self.inner.read()?.contains_key(identifier) { + Ok(true) + } else { + match identifier.as_str() { + "io" | "output" => Ok(true), + _ => Ok(false), + } + } } pub fn get_type(&self, identifier: &Identifier) -> Result, RwLockPoisonError> { @@ -67,6 +74,7 @@ impl Context { } let r#type = match identifier.as_str() { + "io" => BuiltInValue::Io.r#type(), "output" => BuiltInFunction::Output.r#type(), _ => return Ok(None), }; @@ -79,6 +87,7 @@ impl Context { Ok(Some(value.clone())) } else { let value = match identifier.as_str() { + "io" => BuiltInValue::Io.value(), "output" => Value::built_in_function(BuiltInFunction::Output), _ => return Ok(None), }; diff --git a/src/error.rs b/src/error.rs index e8335b2..750dd66 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,6 +1,6 @@ use std::{io, ops::Range, sync::PoisonError}; -use ariadne::{Label, ReportBuilder}; +use ariadne::{Color, Fmt, Label, ReportBuilder}; use chumsky::{prelude::Rich, span::Span}; use crate::{ @@ -33,6 +33,8 @@ impl Error { self, mut builder: ReportBuilder<'_, Range>, ) -> ReportBuilder<'_, Range> { + let type_color = Color::Green; + match self { Error::Parse { expected, span } => { let message = match expected.as_str() { @@ -66,16 +68,18 @@ impl Error { }, Error::Validation { error, position } => match error { ValidationError::ExpectedBoolean { actual, position } => { - builder.add_label( - Label::new(position.0..position.1) - .with_message(format!("Expected boolean but got {actual}.")), - ); + builder.add_label(Label::new(position.0..position.1).with_message(format!( + "Expected {} but got {}.", + "boolean".fg(type_color), + actual.fg(type_color) + ))); } ValidationError::ExpectedIntegerOrFloat => { - builder.add_label( - Label::new(position.0..position.1) - .with_message("Expected integer or float."), - ); + builder.add_label(Label::new(position.0..position.1).with_message(format!( + "Expected {} or {}.", + "integer".fg(type_color), + "float".fg(type_color) + ))); } ValidationError::RwLockPoison(_) => todo!(), ValidationError::TypeCheck { @@ -86,10 +90,12 @@ impl Error { let TypeConflict { actual, expected } = conflict; builder.add_labels([ - Label::new(expected_postion.0..expected_postion.1) - .with_message(format!("Type {expected} established here.")), + Label::new(expected_postion.0..expected_postion.1).with_message(format!( + "Type {} established here.", + expected.fg(type_color) + )), Label::new(actual_position.0..actual_position.1) - .with_message(format!("Got type {actual} here.")), + .with_message(format!("Got type {} here.", actual.fg(type_color))), ]); } ValidationError::VariableNotFound(identifier) => { @@ -99,7 +105,10 @@ impl Error { .with_priority(1), ); } - ValidationError::CannotIndex(_) => todo!(), + ValidationError::CannotIndex { r#type, position } => builder.add_label( + Label::new(position.0..position.1) + .with_message(format!("Cannot index into a {}.", r#type.fg(type_color))), + ), ValidationError::CannotIndexWith(_, _) => todo!(), ValidationError::InterpreterExpectedReturn => todo!(), ValidationError::ExpectedFunction { .. } => todo!(), @@ -169,7 +178,10 @@ impl PartialEq for RuntimeError { #[derive(Debug, PartialEq)] pub enum ValidationError { - CannotIndex(Type), + CannotIndex { + r#type: Type, + position: SourcePosition, + }, CannotIndexWith(Type, Type), ExpectedBoolean { actual: Type, diff --git a/src/value.rs b/src/value.rs index ab4e74f..9acf729 100644 --- a/src/value.rs +++ b/src/value.rs @@ -377,24 +377,34 @@ impl BuiltInFunction { impl Display for BuiltInFunction { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { - BuiltInFunction::Output => write!(f, "(to_output : any) : none rust_magic();"), - BuiltInFunction::ReadLine => todo!(), + BuiltInFunction::Output => write!(f, "(to_output : any) : none {{ *MAGIC* }}"), + BuiltInFunction::ReadLine => write!(f, "() : str {{ *MAGIC* }}"), } } } +static IO: OnceLock = OnceLock::new(); + pub enum BuiltInValue { Io, } impl BuiltInValue { - pub fn io() -> Value { - static IO: OnceLock = OnceLock::new(); + pub fn value(self) -> Value { + match self { + BuiltInValue::Io => { + let mut properties = BTreeMap::new(); - let mut properties = BTreeMap::new(); + properties.insert(Identifier::new("read_line"), BuiltInFunction::read_line()); - properties.insert(Identifier::new("read_line"), BuiltInFunction::read_line()); + IO.get_or_init(|| Value::map(properties)).clone() + } + } + } - IO.get_or_init(|| Value::map(properties)).clone() + pub fn r#type(self) -> Type { + match self { + BuiltInValue::Io => Type::Map, + } } }