Improve constructors

This commit is contained in:
Jeff 2024-08-23 11:44:47 -04:00
parent de3c83a6f5
commit 6a488c2245
6 changed files with 294 additions and 211 deletions

View File

@ -82,9 +82,11 @@ impl<'a> Analyzer<'a> {
fn analyze_statement(&mut self, statement: &Statement) {
match statement {
Statement::Expression(expression) => self.analyze_expression(expression),
Statement::Expression(expression) => {
self.analyze_expression(expression, statement.position())
}
Statement::ExpressionNullified(expression_node) => {
self.analyze_expression(&expression_node.inner);
self.analyze_expression(&expression_node.inner, statement.position());
}
Statement::Let(let_statement) => match &let_statement.inner {
LetStatement::Let { identifier, value }
@ -118,7 +120,7 @@ impl<'a> Analyzer<'a> {
});
}
self.analyze_expression(value);
self.analyze_expression(value, statement.position());
}
LetStatement::LetType { .. } => todo!(),
LetStatement::LetMutType { .. } => todo!(),
@ -130,7 +132,7 @@ impl<'a> Analyzer<'a> {
StructType::Unit {
name: name.inner.clone(),
},
name.position,
statement.position(),
),
StructDefinition::Tuple { name, items } => {
let fields = items.iter().map(|item| item.inner.clone()).collect();
@ -141,7 +143,7 @@ impl<'a> Analyzer<'a> {
name: name.inner.clone(),
fields,
},
name.position,
statement.position(),
)
}
StructDefinition::Fields { name, fields } => {
@ -158,7 +160,7 @@ impl<'a> Analyzer<'a> {
name: name.inner.clone(),
fields,
},
name.position,
statement.position(),
)
}
};
@ -173,69 +175,96 @@ impl<'a> Analyzer<'a> {
}
}
fn analyze_expression(&mut self, expression: &Expression) {
fn analyze_expression(&mut self, expression: &Expression, statement_position: Span) {
match expression {
Expression::Block(block_expression) => self.analyze_block(&block_expression.inner),
Expression::Break(break_node) => {
if let Some(expression) = &break_node.inner {
self.analyze_expression(expression);
self.analyze_expression(expression, statement_position);
}
}
Expression::Call(call_expression) => {
let CallExpression { invoker, arguments } = call_expression.inner.as_ref();
self.analyze_expression(invoker);
self.analyze_expression(invoker, statement_position);
for argument in arguments {
self.analyze_expression(argument);
self.analyze_expression(argument, statement_position);
}
}
Expression::FieldAccess(field_access_expression) => {
let FieldAccessExpression { container, .. } =
let FieldAccessExpression { container, field } =
field_access_expression.inner.as_ref();
self.analyze_expression(container);
}
Expression::Grouped(expression) => {
self.analyze_expression(expression.inner.as_ref());
}
Expression::Identifier(identifier) => {
let found = self
.context
.update_last_position(&identifier.inner, identifier.position)
.map_err(|error| {
self.errors.push(AnalysisError::ContextError {
error,
position: identifier.position,
})
let container_type = match container.return_type(&self.context) {
Ok(Some(r#type)) => r#type,
Ok(None) => {
self.errors
.push(AnalysisError::ExpectedValueFromExpression {
expression: container.clone(),
});
if let Ok(false) = found {
return;
}
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
if !container_type.has_field(&field.inner) {
self.errors.push(AnalysisError::UndefinedFieldIdentifier {
identifier: field.clone(),
container: container.clone(),
});
}
self.analyze_expression(container, statement_position);
}
Expression::Grouped(expression) => {
self.analyze_expression(expression.inner.as_ref(), statement_position);
}
Expression::Identifier(identifier) => {
let find_identifier = self
.context
.update_last_position(&identifier.inner, statement_position);
if let Ok(false) = find_identifier {
self.errors.push(AnalysisError::UndefinedVariable {
identifier: identifier.clone(),
});
}
if let Err(context_error) = find_identifier {
self.errors.push(AnalysisError::ContextError {
error: context_error,
position: identifier.position,
});
}
}
Expression::If(if_expression) => {
self.analyze_if(&if_expression.inner, statement_position)
}
Expression::If(if_expression) => self.analyze_if(&if_expression.inner),
Expression::List(list_expression) => match list_expression.inner.as_ref() {
ListExpression::AutoFill {
repeat_operand,
length_operand,
} => {
self.analyze_expression(repeat_operand);
self.analyze_expression(length_operand);
self.analyze_expression(repeat_operand, statement_position);
self.analyze_expression(length_operand, statement_position);
}
ListExpression::Ordered(expressions) => {
for expression in expressions {
self.analyze_expression(expression);
self.analyze_expression(expression, statement_position);
}
}
},
Expression::ListIndex(list_index_expression) => {
let ListIndexExpression { list, index } = list_index_expression.inner.as_ref();
self.analyze_expression(list);
self.analyze_expression(index);
self.analyze_expression(list, statement_position);
self.analyze_expression(index, statement_position);
let list_type = match list.return_type(&self.context) {
Ok(Some(r#type)) => r#type,
@ -253,7 +282,7 @@ impl<'a> Analyzer<'a> {
return;
}
};
let index_type = match list.return_type(&self.context) {
let index_type = match index.return_type(&self.context) {
Ok(Some(r#type)) => r#type,
Ok(None) => {
self.errors
@ -301,6 +330,22 @@ impl<'a> Analyzer<'a> {
index_value: integer,
});
}
} else if let Type::Integer
| Type::Range {
r#type: RangeableType::Integer,
} = index_type
{
} else {
self.errors.push(AnalysisError::ExpectedTypeMultiple {
expected: vec![
Type::Integer,
Type::Range {
r#type: RangeableType::Integer,
},
],
actual: index_type.clone(),
actual_expression: index.clone(),
});
}
}
@ -329,13 +374,13 @@ impl<'a> Analyzer<'a> {
Expression::Loop(loop_expression) => match loop_expression.inner.as_ref() {
LoopExpression::Infinite { block } => self.analyze_block(&block.inner),
LoopExpression::While { condition, block } => {
self.analyze_expression(condition);
self.analyze_expression(condition, statement_position);
self.analyze_block(&block.inner);
}
LoopExpression::For {
iterator, block, ..
} => {
self.analyze_expression(iterator);
self.analyze_expression(iterator, statement_position);
self.analyze_block(&block.inner);
}
},
@ -343,23 +388,23 @@ impl<'a> Analyzer<'a> {
let MapExpression { pairs } = map_expression.inner.as_ref();
for (_, expression) in pairs {
self.analyze_expression(expression);
self.analyze_expression(expression, statement_position);
}
}
Expression::Operator(operator_expression) => match operator_expression.inner.as_ref() {
OperatorExpression::Assignment { assignee, value } => {
self.analyze_expression(assignee);
self.analyze_expression(value);
self.analyze_expression(assignee, statement_position);
self.analyze_expression(value, statement_position);
}
OperatorExpression::Comparison { left, right, .. } => {
self.analyze_expression(left);
self.analyze_expression(right);
self.analyze_expression(left, statement_position);
self.analyze_expression(right, statement_position);
}
OperatorExpression::CompoundAssignment {
assignee, modifier, ..
} => {
self.analyze_expression(assignee);
self.analyze_expression(modifier);
self.analyze_expression(assignee, statement_position);
self.analyze_expression(modifier, statement_position);
let (expected_type, actual_type) = match (
assignee.return_type(&self.context),
@ -413,14 +458,14 @@ impl<'a> Analyzer<'a> {
}
OperatorExpression::ErrorPropagation(_) => todo!(),
OperatorExpression::Negation(expression) => {
self.analyze_expression(expression);
self.analyze_expression(expression, statement_position);
}
OperatorExpression::Not(expression) => {
self.analyze_expression(expression);
self.analyze_expression(expression, statement_position);
}
OperatorExpression::Math { left, right, .. } => {
self.analyze_expression(left);
self.analyze_expression(right);
self.analyze_expression(left, statement_position);
self.analyze_expression(right, statement_position);
let (left_type, right_type) = match (
left.return_type(&self.context),
@ -506,8 +551,8 @@ impl<'a> Analyzer<'a> {
}
}
OperatorExpression::Logic { left, right, .. } => {
self.analyze_expression(left);
self.analyze_expression(right);
self.analyze_expression(left, statement_position);
self.analyze_expression(right, statement_position);
let (left_type, right_type) = match (
left.return_type(&self.context),
@ -560,19 +605,19 @@ impl<'a> Analyzer<'a> {
},
Expression::Range(range_expression) => match range_expression.inner.as_ref() {
RangeExpression::Exclusive { start, end } => {
self.analyze_expression(start);
self.analyze_expression(end);
self.analyze_expression(start, statement_position);
self.analyze_expression(end, statement_position);
}
RangeExpression::Inclusive { start, end } => {
self.analyze_expression(start);
self.analyze_expression(end);
self.analyze_expression(start, statement_position);
self.analyze_expression(end, statement_position);
}
},
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
StructExpression::Fields { name, fields } => {
let update_position = self
.context
.update_last_position(&name.inner, name.position);
.update_last_position(&name.inner, statement_position);
if let Err(error) = update_position {
self.errors.push(AnalysisError::ContextError {
@ -584,14 +629,14 @@ impl<'a> Analyzer<'a> {
}
for (_, expression) in fields {
self.analyze_expression(expression);
self.analyze_expression(expression, statement_position);
}
}
},
Expression::TupleAccess(tuple_access) => {
let TupleAccessExpression { tuple, .. } = tuple_access.inner.as_ref();
self.analyze_expression(tuple);
self.analyze_expression(tuple, statement_position);
}
}
}
@ -611,13 +656,13 @@ impl<'a> Analyzer<'a> {
}
}
fn analyze_if(&mut self, if_expression: &IfExpression) {
fn analyze_if(&mut self, if_expression: &IfExpression, statement_position: Span) {
match if_expression {
IfExpression::If {
condition,
if_block,
} => {
self.analyze_expression(condition);
self.analyze_expression(condition, statement_position);
self.analyze_block(&if_block.inner);
}
IfExpression::IfElse {
@ -625,7 +670,7 @@ impl<'a> Analyzer<'a> {
if_block,
r#else,
} => {
self.analyze_expression(condition);
self.analyze_expression(condition, statement_position);
self.analyze_block(&if_block.inner);
match r#else {
@ -633,7 +678,7 @@ impl<'a> Analyzer<'a> {
self.analyze_block(&block_expression.inner);
}
ElseExpression::If(if_expression) => {
self.analyze_if(&if_expression.inner);
self.analyze_if(&if_expression.inner, statement_position);
}
}
}
@ -691,9 +736,9 @@ pub enum AnalysisError {
actual_type: Type,
expected: Type,
},
UndefinedField {
identifier: Expression,
expression: Expression,
UndefinedFieldIdentifier {
identifier: Node<Identifier>,
container: Expression,
},
UndefinedType {
identifier: Node<Identifier>,
@ -736,7 +781,7 @@ impl AnalysisError {
AnalysisError::TypeConflict {
actual_expression, ..
} => actual_expression.position(),
AnalysisError::UndefinedField { identifier, .. } => identifier.position(),
AnalysisError::UndefinedFieldIdentifier { identifier, .. } => identifier.position,
AnalysisError::UndefinedType { identifier } => identifier.position,
AnalysisError::UndefinedVariable { identifier } => identifier.position,
AnalysisError::UnexpectedIdentifier { identifier } => identifier.position,
@ -826,11 +871,15 @@ impl Display for AnalysisError {
expected, actual_statement, actual_type
)
}
AnalysisError::UndefinedField {
AnalysisError::UndefinedFieldIdentifier {
identifier,
expression: map,
container,
} => {
write!(f, "Undefined field {} in map {}", identifier, map)
write!(
f,
"Undefined field {} in container {}",
identifier, container
)
}
AnalysisError::UndefinedType { identifier } => {
write!(f, "Undefined type {}", identifier)
@ -850,6 +899,7 @@ impl Display for AnalysisError {
#[cfg(test)]
mod tests {
use crate::RangeableType;
use super::*;
@ -963,43 +1013,21 @@ mod tests {
}
#[test]
fn nonexistant_field_identifier() {
let source = "{ x = 1 }.y";
fn nonexistant_map_field_identifier() {
let source = "map { x = 1 }.y";
assert_eq!(
analyze(source),
Err(DustError::Analysis {
analysis_errors: vec![AnalysisError::UndefinedField {
identifier: Expression::identifier(Identifier::new("y"), (11, 12)),
expression: Expression::map(
analysis_errors: vec![AnalysisError::UndefinedFieldIdentifier {
container: Expression::map(
[(
Node::new(Identifier::new("x"), (2, 3)),
Expression::literal(1, (6, 7))
Node::new(Identifier::new("x"), (6, 7)),
Expression::literal(1, (10, 11))
)],
(0, 11)
),
}],
source,
})
);
}
#[test]
fn nonexistant_field_string() {
let source = "{ x = 1 }.'y'";
assert_eq!(
analyze(source),
Err(DustError::Analysis {
analysis_errors: vec![AnalysisError::UndefinedField {
identifier: Expression::literal("y", (11, 14)),
expression: Expression::map(
[(
Node::new(Identifier::new("x"), (2, 3)),
Expression::literal(1, (6, 7))
)],
(0, 11)
(0, 13)
),
identifier: Node::new(Identifier::new("y"), (14, 15)),
}],
source,
})
@ -1030,7 +1058,7 @@ mod tests {
#[test]
fn malformed_field_access() {
let source = "{ x = 1 }.0";
let source = "struct Foo { x: int } Foo { x: 1 }.0";
assert_eq!(
analyze(source),
@ -1079,14 +1107,14 @@ mod tests {
#[test]
fn nonexistant_field() {
let source = "'hello'.foo";
let source = "\"hello\".foo";
assert_eq!(
analyze(source),
Err(DustError::Analysis {
analysis_errors: vec![AnalysisError::UndefinedField {
expression: Expression::literal("hello", (0, 7)),
identifier: Expression::identifier(Identifier::new("foo"), (8, 11)),
analysis_errors: vec![AnalysisError::UndefinedFieldIdentifier {
container: Expression::literal("hello", (0, 7)),
identifier: Node::new(Identifier::new("foo"), (8, 11)),
}],
source,
})

View File

@ -5,60 +5,103 @@ use std::{
use serde::{Deserialize, Serialize};
use crate::{Identifier, Struct, Value};
use crate::{Identifier, Struct, StructType, TypeConflict, Value};
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum Constructor {
Unit(UnitConstructor),
Tuple(TupleConstructor),
Fields(FieldsConstructor),
pub struct Constructor {
pub struct_type: StructType,
}
impl Display for Constructor {
impl Constructor {
pub fn construct_unit(&self) -> Result<Value, ConstructError> {
if let StructType::Unit { name } = &self.struct_type {
Ok(Value::r#struct(Struct::Unit { name: name.clone() }))
} else {
Err(ConstructError::ExpectedUnit)
}
}
pub fn construct_tuple(&self, fields: Vec<Value>) -> Result<Value, ConstructError> {
if let StructType::Tuple {
name: expected_name,
fields: expected_fields,
} = &self.struct_type
{
if fields.len() != expected_fields.len() {
return Err(ConstructError::FieldCountMismatch);
}
for (i, value) in fields.iter().enumerate() {
let expected_type = expected_fields.get(i).unwrap();
let actual_type = value.r#type();
expected_type.check(&actual_type)?;
}
Ok(Value::r#struct(Struct::Tuple {
name: expected_name.clone(),
fields,
}))
} else {
Err(ConstructError::ExpectedTuple)
}
}
pub fn construct_fields(
&self,
fields: HashMap<Identifier, Value>,
) -> Result<Value, ConstructError> {
if let StructType::Fields {
name: expected_name,
fields: expected_fields,
} = &self.struct_type
{
if fields.len() != expected_fields.len() {
return Err(ConstructError::FieldCountMismatch);
}
for (field_name, field_value) in fields.iter() {
let expected_type = expected_fields.get(field_name).unwrap();
let actual_type = field_value.r#type();
expected_type.check(&actual_type)?;
}
Ok(Value::r#struct(Struct::Fields {
name: expected_name.clone(),
fields,
}))
} else {
Err(ConstructError::ExpectedFields)
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum ConstructError {
FieldCountMismatch,
ExpectedUnit,
ExpectedTuple,
ExpectedFields,
TypeConflict(TypeConflict),
}
impl From<TypeConflict> for ConstructError {
fn from(conflict: TypeConflict) -> Self {
Self::TypeConflict(conflict)
}
}
impl Display for ConstructError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Constructor::Unit(unit) => write!(f, "{}", unit.name),
Constructor::Tuple(tuple) => write!(f, "{}", tuple.name),
Constructor::Fields(fields) => write!(f, "{}", fields.name),
ConstructError::FieldCountMismatch => write!(f, "Field count mismatch"),
ConstructError::ExpectedUnit => write!(f, "Expected unit struct"),
ConstructError::ExpectedTuple => write!(f, "Expected tuple struct"),
ConstructError::ExpectedFields => write!(f, "Expected fields struct"),
ConstructError::TypeConflict(TypeConflict { expected, actual }) => {
write!(f, "Type conflict: expected {}, got {}", expected, actual)
}
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct UnitConstructor {
pub name: Identifier,
}
impl UnitConstructor {
pub fn construct(self) -> Value {
Value::r#struct(Struct::Unit { name: self.name })
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct TupleConstructor {
pub name: Identifier,
}
impl TupleConstructor {
pub fn construct(self, fields: Vec<Value>) -> Value {
Value::r#struct(Struct::Tuple {
name: self.name,
fields,
})
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct FieldsConstructor {
pub name: Identifier,
}
impl FieldsConstructor {
pub fn construct(self, fields: HashMap<Identifier, Value>) -> Value {
Value::r#struct(Struct::Fields {
name: self.name,
fields,
})
}
}

View File

@ -172,7 +172,7 @@ impl Context {
identifier: Identifier,
constructor: Constructor,
) -> Result<(), ContextError> {
log::trace!("Setting {identifier} to constructor {constructor}");
log::trace!("Setting {identifier} to constructor {constructor:?}");
let mut associations = self.associations.write()?;

View File

@ -204,14 +204,10 @@ impl<'src> Parser<'src> {
self.next_token()?;
if let Token::Semicolon = self.current_token {
break;
} else {
return Err(ParseError::ExpectedToken {
expected: TokenKind::Semicolon,
actual: self.current_token.to_owned(),
position: self.current_position,
});
self.next_token()?;
}
break;
}
let type_node = self.parse_type()?;
@ -227,8 +223,6 @@ impl<'src> Parser<'src> {
let position = (start_position.0, self.current_position.1);
self.next_token()?;
return if types.is_empty() {
Ok(Statement::struct_definition(
StructDefinition::Unit { name },
@ -249,6 +243,8 @@ impl<'src> Parser<'src> {
loop {
if let Token::RightCurlyBrace = self.current_token {
self.next_token()?;
if let Token::Semicolon = self.current_token {
self.next_token()?;
}
@ -281,8 +277,6 @@ impl<'src> Parser<'src> {
let position = (start_position.0, self.current_position.1);
self.next_token()?;
return if fields.is_empty() {
Ok(Statement::struct_definition(
StructDefinition::Unit { name },

View File

@ -17,10 +17,7 @@ use std::{
use serde::{Deserialize, Serialize};
use crate::{
constructor::{FieldsConstructor, TupleConstructor, UnitConstructor},
Constructor, Identifier,
};
use crate::{constructor::Constructor, Identifier};
/// Description of a kind of value.
///
@ -234,6 +231,28 @@ impl Type {
expected: self.clone(),
})
}
pub fn has_field(&self, field: &Identifier) -> bool {
match field.as_str() {
"to_string" => true,
"length" => {
matches!(
self,
Type::List { .. }
| Type::ListOf { .. }
| Type::ListEmpty
| Type::Map { .. }
| Type::String { .. }
)
}
"is_even" | "is_odd" => matches!(self, Type::Integer | Type::Float),
_ => match self {
Type::Struct(StructType::Fields { fields, .. }) => fields.contains_key(field),
Type::Map { pairs } => pairs.contains_key(field),
_ => false,
},
}
}
}
impl Display for Type {
@ -445,14 +464,8 @@ impl StructType {
}
pub fn constructor(&self) -> Constructor {
match self {
StructType::Unit { name } => Constructor::Unit(UnitConstructor { name: name.clone() }),
StructType::Tuple { name, .. } => {
Constructor::Tuple(TupleConstructor { name: name.clone() })
}
StructType::Fields { name, .. } => {
Constructor::Fields(FieldsConstructor { name: name.clone() })
}
Constructor {
struct_type: self.clone(),
}
}
}

View File

@ -20,6 +20,7 @@ use crate::{
OperatorExpression, PrimitiveValueExpression, RangeExpression, Span, Statement,
StructDefinition, StructExpression,
},
constructor::ConstructError,
core_library, parse, Analyzer, BuiltInFunctionError, Constructor, Context, ContextData,
ContextError, DustError, Expression, Function, FunctionCallError, Identifier, ParseError,
StructType, Type, Value, ValueData, ValueError,
@ -313,18 +314,23 @@ impl Vm {
}
if let Some(ContextData::Constructor(constructor)) = get_data {
if let Constructor::Unit(unit_constructor) = constructor {
return Ok(Evaluation::Return(Some(unit_constructor.construct())));
}
let construct_result = constructor.construct_unit();
return Ok(Evaluation::Constructor(constructor));
match construct_result {
Ok(value) => Ok(Evaluation::Return(Some(value))),
Err(ConstructError::ExpectedUnit) => Ok(Evaluation::Constructor(constructor)),
Err(error) => Err(RuntimeError::ConstructError {
error,
position: identifier.position,
}),
}
} else {
Err(RuntimeError::UnassociatedIdentifier {
identifier: identifier.inner,
position: identifier.position,
})
}
}
fn run_struct(
&self,
@ -340,7 +346,6 @@ impl Vm {
.map_err(|error| RuntimeError::ContextError { error, position })?;
if let Some(constructor) = constructor {
if let Constructor::Fields(fields_constructor) = constructor {
let mut arguments = HashMap::with_capacity(fields.len());
for (identifier, expression) in fields {
@ -352,12 +357,11 @@ impl Vm {
arguments.insert(identifier.inner, value);
}
Ok(Evaluation::Return(Some(
fields_constructor.construct(arguments),
)))
} else {
Err(RuntimeError::ExpectedFieldsConstructor { position })
}
let value = constructor
.construct_fields(arguments.clone())
.map_err(|error| RuntimeError::ConstructError { error, position })?;
Ok(Evaluation::Return(Some(value)))
} else {
Err(RuntimeError::ExpectedConstructor { position })
}
@ -803,32 +807,28 @@ impl Vm {
let run_invoker = self.run_expression(invoker, collect_garbage)?;
match run_invoker {
Evaluation::Constructor(constructor) => match constructor {
Constructor::Unit(unit_constructor) => {
Ok(Evaluation::Return(Some(unit_constructor.construct())))
}
Constructor::Tuple(tuple_constructor) => {
Evaluation::Constructor(constructor) => {
let mut fields = Vec::new();
for argument in arguments {
let position = argument.position();
if let Some(value) = self.run_expression(argument, collect_garbage)?.value()
{
if let Some(value) = self.run_expression(argument, collect_garbage)?.value() {
fields.push(value);
} else {
return Err(RuntimeError::ExpectedValue { position });
}
}
let tuple = tuple_constructor.construct(fields);
let value = constructor.construct_tuple(fields).map_err(|error| {
RuntimeError::ConstructError {
error,
position: invoker_position,
}
})?;
Ok(Evaluation::Return(Some(tuple)))
Ok(Evaluation::Return(Some(value)))
}
Constructor::Fields(_) => {
todo!("Return an error")
}
},
Evaluation::Return(Some(value)) => {
let function = match value {
Value::Raw(ValueData::Function(function)) => function,
@ -1091,6 +1091,10 @@ impl Evaluation {
#[derive(Clone, Debug, PartialEq)]
pub enum RuntimeError {
ConstructError {
error: ConstructError,
position: Span,
},
ContextError {
error: ContextError,
position: Span,
@ -1113,9 +1117,6 @@ pub enum RuntimeError {
left_position: Span,
right_position: Span,
},
// Anaylsis Failures
// These should be prevented by running the analyzer before the VM
BuiltInFunctionError {
error: BuiltInFunctionError,
position: Span,
@ -1192,6 +1193,7 @@ pub enum RuntimeError {
impl RuntimeError {
pub fn position(&self) -> Span {
match self {
Self::ConstructError { position, .. } => *position,
Self::ContextError { position, .. } => *position,
Self::BuiltInFunctionError { position, .. } => *position,
Self::FunctionCall { position, .. } => *position,
@ -1242,6 +1244,9 @@ impl From<ParseError> for RuntimeError {
impl Display for RuntimeError {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::ConstructError { error, position } => {
write!(f, "Constructor error at {:?}: {}", position, error)
}
Self::ContextError { error, position } => {
write!(f, "Context error at {:?}: {}", position, error)
}