Improve built-in values and errors

This commit is contained in:
Jeff 2024-03-17 18:03:43 -04:00
parent bc5cadc446
commit 791610b350
4 changed files with 62 additions and 25 deletions

View File

@ -34,7 +34,10 @@ impl AbstractTree for Index {
expression.node.expected_type(_context) expression.node.expected_type(_context)
} else { } 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::CannotIndexWith(left_type, right_type))
} }
} }
_ => Err(ValidationError::CannotIndex(left_type)), _ => Err(ValidationError::CannotIndex {
r#type: left_type,
position: self.left.position,
}),
} }
} }

View File

@ -6,7 +6,7 @@ use std::{
use crate::{ use crate::{
abstract_tree::{Identifier, Type}, abstract_tree::{Identifier, Type},
error::RwLockPoisonError, error::RwLockPoisonError,
value::BuiltInFunction, value::{BuiltInFunction, BuiltInValue},
Value, Value,
}; };
@ -53,7 +53,14 @@ impl Context {
} }
pub fn contains(&self, identifier: &Identifier) -> Result<bool, RwLockPoisonError> { pub fn contains(&self, identifier: &Identifier) -> Result<bool, RwLockPoisonError> {
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<Option<Type>, RwLockPoisonError> { pub fn get_type(&self, identifier: &Identifier) -> Result<Option<Type>, RwLockPoisonError> {
@ -67,6 +74,7 @@ impl Context {
} }
let r#type = match identifier.as_str() { let r#type = match identifier.as_str() {
"io" => BuiltInValue::Io.r#type(),
"output" => BuiltInFunction::Output.r#type(), "output" => BuiltInFunction::Output.r#type(),
_ => return Ok(None), _ => return Ok(None),
}; };
@ -79,6 +87,7 @@ impl Context {
Ok(Some(value.clone())) Ok(Some(value.clone()))
} else { } else {
let value = match identifier.as_str() { let value = match identifier.as_str() {
"io" => BuiltInValue::Io.value(),
"output" => Value::built_in_function(BuiltInFunction::Output), "output" => Value::built_in_function(BuiltInFunction::Output),
_ => return Ok(None), _ => return Ok(None),
}; };

View File

@ -1,6 +1,6 @@
use std::{io, ops::Range, sync::PoisonError}; use std::{io, ops::Range, sync::PoisonError};
use ariadne::{Label, ReportBuilder}; use ariadne::{Color, Fmt, Label, ReportBuilder};
use chumsky::{prelude::Rich, span::Span}; use chumsky::{prelude::Rich, span::Span};
use crate::{ use crate::{
@ -33,6 +33,8 @@ impl Error {
self, self,
mut builder: ReportBuilder<'_, Range<usize>>, mut builder: ReportBuilder<'_, Range<usize>>,
) -> ReportBuilder<'_, Range<usize>> { ) -> ReportBuilder<'_, Range<usize>> {
let type_color = Color::Green;
match self { match self {
Error::Parse { expected, span } => { Error::Parse { expected, span } => {
let message = match expected.as_str() { let message = match expected.as_str() {
@ -66,16 +68,18 @@ impl Error {
}, },
Error::Validation { error, position } => match error { Error::Validation { error, position } => match error {
ValidationError::ExpectedBoolean { actual, position } => { ValidationError::ExpectedBoolean { actual, position } => {
builder.add_label( builder.add_label(Label::new(position.0..position.1).with_message(format!(
Label::new(position.0..position.1) "Expected {} but got {}.",
.with_message(format!("Expected boolean but got {actual}.")), "boolean".fg(type_color),
); actual.fg(type_color)
)));
} }
ValidationError::ExpectedIntegerOrFloat => { ValidationError::ExpectedIntegerOrFloat => {
builder.add_label( builder.add_label(Label::new(position.0..position.1).with_message(format!(
Label::new(position.0..position.1) "Expected {} or {}.",
.with_message("Expected integer or float."), "integer".fg(type_color),
); "float".fg(type_color)
)));
} }
ValidationError::RwLockPoison(_) => todo!(), ValidationError::RwLockPoison(_) => todo!(),
ValidationError::TypeCheck { ValidationError::TypeCheck {
@ -86,10 +90,12 @@ impl Error {
let TypeConflict { actual, expected } = conflict; let TypeConflict { actual, expected } = conflict;
builder.add_labels([ builder.add_labels([
Label::new(expected_postion.0..expected_postion.1) Label::new(expected_postion.0..expected_postion.1).with_message(format!(
.with_message(format!("Type {expected} established here.")), "Type {} established here.",
expected.fg(type_color)
)),
Label::new(actual_position.0..actual_position.1) 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) => { ValidationError::VariableNotFound(identifier) => {
@ -99,7 +105,10 @@ impl Error {
.with_priority(1), .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::CannotIndexWith(_, _) => todo!(),
ValidationError::InterpreterExpectedReturn => todo!(), ValidationError::InterpreterExpectedReturn => todo!(),
ValidationError::ExpectedFunction { .. } => todo!(), ValidationError::ExpectedFunction { .. } => todo!(),
@ -169,7 +178,10 @@ impl PartialEq for RuntimeError {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum ValidationError { pub enum ValidationError {
CannotIndex(Type), CannotIndex {
r#type: Type,
position: SourcePosition,
},
CannotIndexWith(Type, Type), CannotIndexWith(Type, Type),
ExpectedBoolean { ExpectedBoolean {
actual: Type, actual: Type,

View File

@ -377,24 +377,34 @@ impl BuiltInFunction {
impl Display for BuiltInFunction { impl Display for BuiltInFunction {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
BuiltInFunction::Output => write!(f, "(to_output : any) : none rust_magic();"), BuiltInFunction::Output => write!(f, "(to_output : any) : none {{ *MAGIC* }}"),
BuiltInFunction::ReadLine => todo!(), BuiltInFunction::ReadLine => write!(f, "() : str {{ *MAGIC* }}"),
} }
} }
} }
static IO: OnceLock<Value> = OnceLock::new();
pub enum BuiltInValue { pub enum BuiltInValue {
Io, Io,
} }
impl BuiltInValue { impl BuiltInValue {
pub fn io() -> Value { pub fn value(self) -> Value {
static IO: OnceLock<Value> = OnceLock::new(); 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,
}
} }
} }