1
0

Replace "return_type" methods in AST with new type_evaluation

This commit is contained in:
Jeff 2024-08-23 13:47:22 -04:00
parent f510cce0ee
commit 8b14d74eba
7 changed files with 395 additions and 228 deletions

View File

@ -91,13 +91,13 @@ impl<'a> Analyzer<'a> {
Statement::Let(let_statement) => match &let_statement.inner {
LetStatement::Let { identifier, value }
| LetStatement::LetMut { identifier, value } => {
let r#type = match value.return_type(&self.context) {
Ok(type_option) => type_option,
let r#type = match value.type_evaluation(&self.context) {
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
None
return;
}
Ok(evaluation) => evaluation.r#type(),
};
if let Some(r#type) = r#type {
@ -196,19 +196,22 @@ impl<'a> Analyzer<'a> {
let FieldAccessExpression { container, field } =
field_access_expression.inner.as_ref();
let container_type = match container.return_type(&self.context) {
Ok(Some(r#type)) => r#type,
Ok(None) => {
let evaluation = match container.type_evaluation(&self.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
let container_type = match evaluation.r#type() {
Some(r#type) => r#type,
None => {
self.errors
.push(AnalysisError::ExpectedValueFromExpression {
expression: container.clone(),
});
return;
}
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
@ -266,25 +269,17 @@ impl<'a> Analyzer<'a> {
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,
Ok(None) => {
self.errors
.push(AnalysisError::ExpectedValueFromExpression {
expression: list.clone(),
});
return;
}
let list_type_evaluation = match list.type_evaluation(&self.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
let index_type = match index.return_type(&self.context) {
Ok(Some(r#type)) => r#type,
Ok(None) => {
let list_type = match list_type_evaluation.r#type() {
Some(r#type) => r#type,
None => {
self.errors
.push(AnalysisError::ExpectedValueFromExpression {
expression: list.clone(),
@ -292,12 +287,26 @@ impl<'a> Analyzer<'a> {
return;
}
};
let index_type_evaluation = match index.type_evaluation(&self.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
let index_type = match index_type_evaluation.r#type() {
Some(r#type) => r#type,
None => {
self.errors
.push(AnalysisError::ExpectedValueFromExpression {
expression: list.clone(),
});
return;
}
};
let literal_type = if let Expression::Literal(Node { inner, .. }) = index {
Some(inner.as_ref().clone())
} else {
@ -406,14 +415,29 @@ impl<'a> Analyzer<'a> {
self.analyze_expression(assignee, statement_position);
self.analyze_expression(modifier, statement_position);
let assignee_type_evaluation = match assignee.type_evaluation(&self.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
let modifier_type_evaluation = match modifier.type_evaluation(&self.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
let (expected_type, actual_type) = match (
assignee.return_type(&self.context),
modifier.return_type(&self.context),
assignee_type_evaluation.r#type(),
modifier_type_evaluation.r#type(),
) {
(Ok(Some(expected_type)), Ok(Some(actual_type))) => {
(expected_type, actual_type)
}
(Ok(None), Ok(None)) => {
(Some(expected_type), Some(actual_type)) => (expected_type, actual_type),
(None, None) => {
self.errors
.push(AnalysisError::ExpectedValueFromExpression {
expression: assignee.clone(),
@ -424,28 +448,20 @@ impl<'a> Analyzer<'a> {
});
return;
}
(Ok(None), _) => {
(None, _) => {
self.errors
.push(AnalysisError::ExpectedValueFromExpression {
expression: assignee.clone(),
});
return;
}
(_, Ok(None)) => {
(_, None) => {
self.errors
.push(AnalysisError::ExpectedValueFromExpression {
expression: modifier.clone(),
});
return;
}
(Err(ast_error), _) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
(_, Err(ast_error)) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
if actual_type != expected_type {
@ -467,12 +483,29 @@ impl<'a> Analyzer<'a> {
self.analyze_expression(left, statement_position);
self.analyze_expression(right, statement_position);
let left_type_evaluation = match left.type_evaluation(&self.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
let right_type_evaluation = match right.type_evaluation(&self.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
let (left_type, right_type) = match (
left.return_type(&self.context),
right.return_type(&self.context),
left_type_evaluation.r#type(),
right_type_evaluation.r#type(),
) {
(Ok(Some(left_type)), Ok(Some(right_type))) => (left_type, right_type),
(Ok(None), Ok(None)) => {
(Some(left_type), Some(right_type)) => (left_type, right_type),
(None, None) => {
self.errors
.push(AnalysisError::ExpectedValueFromExpression {
expression: left.clone(),
@ -483,28 +516,20 @@ impl<'a> Analyzer<'a> {
});
return;
}
(Ok(None), _) => {
(None, _) => {
self.errors
.push(AnalysisError::ExpectedValueFromExpression {
expression: left.clone(),
});
return;
}
(_, Ok(None)) => {
(_, None) => {
self.errors
.push(AnalysisError::ExpectedValueFromExpression {
expression: right.clone(),
});
return;
}
(Err(ast_error), _) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
(_, Err(ast_error)) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
match left_type {
@ -554,12 +579,29 @@ impl<'a> Analyzer<'a> {
self.analyze_expression(left, statement_position);
self.analyze_expression(right, statement_position);
let left_type_evaluation = match left.type_evaluation(&self.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
let right_type_evaluation = match right.type_evaluation(&self.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
let (left_type, right_type) = match (
left.return_type(&self.context),
right.return_type(&self.context),
left_type_evaluation.r#type(),
right_type_evaluation.r#type(),
) {
(Ok(Some(left_type)), Ok(Some(right_type))) => (left_type, right_type),
(Ok(None), Ok(None)) => {
(Some(left_type), Some(right_type)) => (left_type, right_type),
(None, None) => {
self.errors
.push(AnalysisError::ExpectedValueFromExpression {
expression: left.clone(),
@ -570,28 +612,20 @@ impl<'a> Analyzer<'a> {
});
return;
}
(Ok(None), _) => {
(None, _) => {
self.errors
.push(AnalysisError::ExpectedValueFromExpression {
expression: left.clone(),
});
return;
}
(_, Ok(None)) => {
(_, None) => {
self.errors
.push(AnalysisError::ExpectedValueFromExpression {
expression: right.clone(),
});
return;
}
(Err(ast_error), _) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
(_, Err(ast_error)) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
if left_type != right_type {
@ -636,19 +670,23 @@ impl<'a> Analyzer<'a> {
Expression::TupleAccess(tuple_access) => {
let TupleAccessExpression { tuple, index } = tuple_access.inner.as_ref();
let tuple_type = match tuple.return_type(&self.context) {
Ok(Some(tuple_type)) => tuple_type,
Ok(None) => {
let type_evaluation = match tuple.type_evaluation(&self.context) {
Ok(evaluation) => evaluation,
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
let tuple_type = match type_evaluation.r#type() {
Some(tuple_type) => tuple_type,
None => {
self.errors
.push(AnalysisError::ExpectedValueFromExpression {
expression: tuple.clone(),
});
return;
}
Err(ast_error) => {
self.errors.push(AnalysisError::AstError(ast_error));
return;
}
};
if let Type::Tuple {

View File

@ -6,7 +6,10 @@ use std::{
use serde::{Deserialize, Serialize};
use crate::{BuiltInFunction, Context, FunctionType, Identifier, RangeableType, StructType, Type};
use crate::{
BuiltInFunction, Context, FunctionType, Identifier, RangeableType, StructType, Type,
TypeEvaluation,
};
use super::{AstError, Node, Span, Statement};
@ -268,127 +271,172 @@ impl Expression {
}
}
pub fn return_type(&self, context: &Context) -> Result<Option<Type>, AstError> {
pub fn type_evaluation(&self, context: &Context) -> Result<TypeEvaluation, AstError> {
let return_type = match self {
Expression::Block(block_expression) => block_expression.inner.return_type(context)?,
Expression::Block(block_expression) => {
block_expression.inner.type_evaluation(context)?
}
Expression::Break(expression_node) => {
if let Some(expression) = expression_node.inner.as_ref() {
expression.return_type(context)?
let type_evaluation = expression.type_evaluation(context)?;
TypeEvaluation::Break(type_evaluation.r#type())
} else {
None
TypeEvaluation::Break(None)
}
}
Expression::Call(call_expression) => {
let CallExpression { invoker, .. } = call_expression.inner.as_ref();
let invoker_type = invoker.return_type(context)?;
let invoker_type = invoker.type_evaluation(context)?.r#type();
if let Some(Type::Function(FunctionType { return_type, .. })) = invoker_type {
return_type.map(|r#type| *r#type)
} else if let Some(Type::Struct(_)) = invoker_type {
invoker_type
} else {
None
}
let return_type =
if let Some(Type::Function(FunctionType { return_type, .. })) = invoker_type {
return_type.map(|r#type| *r#type)
} else if let Some(Type::Struct(_)) = invoker_type {
invoker_type
} else {
None
};
TypeEvaluation::Return(return_type)
}
Expression::FieldAccess(field_access_expression) => {
let FieldAccessExpression { container, field } =
field_access_expression.inner.as_ref();
let container_type = container.return_type(context)?;
let container_type = container.type_evaluation(context)?.r#type();
if let Some(Type::Struct(StructType::Fields { fields, .. })) = container_type {
fields
let found_type = fields
.into_iter()
.find(|(name, _)| name == &field.inner)
.map(|(_, r#type)| r#type)
.map(|(_, r#type)| r#type);
TypeEvaluation::Return(found_type)
} else {
None
return Err(AstError::ExpectedStructFieldsType {
position: container.position(),
});
}
}
Expression::Grouped(expression) => expression.inner.return_type(context)?,
Expression::Grouped(expression) => expression.inner.type_evaluation(context)?,
Expression::Identifier(identifier) => {
context
.get_type(&identifier.inner)
.map_err(|error| AstError::ContextError {
let type_option = context.get_type(&identifier.inner).map_err(|error| {
AstError::ContextError {
error,
position: identifier.position,
})?
}
})?;
TypeEvaluation::Return(type_option)
}
Expression::If(if_expression) => match if_expression.inner.as_ref() {
IfExpression::If { .. } => None,
IfExpression::IfElse { if_block, .. } => if_block.inner.return_type(context)?,
IfExpression::If { .. } => TypeEvaluation::Return(None),
IfExpression::IfElse { if_block, .. } => if_block.inner.type_evaluation(context)?,
},
Expression::List(list_expression) => match list_expression.inner.as_ref() {
ListExpression::AutoFill { repeat_operand, .. } => {
let item_type = repeat_operand.return_type(context)?;
if let Some(r#type) = item_type {
Some(Type::ListOf {
item_type: Box::new(r#type),
})
} else {
return Err(AstError::ExpectedType {
ListExpression::AutoFill {
repeat_operand,
length_operand,
} => {
let item_type = repeat_operand
.type_evaluation(context)?
.r#type()
.ok_or_else(|| AstError::ExpectedListType {
position: repeat_operand.position(),
});
}
})?;
let list_type = if let Expression::Literal(literal_expression) = length_operand
{
if let Some(index) = literal_expression.inner.as_integer() {
let length = match usize::try_from(index) {
Ok(usize) => usize,
Err(error) => {
return Err(AstError::FromIntError {
error,
position: length_operand.position(),
})
}
};
Type::List {
item_type: Box::new(item_type),
length,
}
} else {
return Err(AstError::ExpectedInteger {
position: literal_expression.position,
});
}
} else {
Type::ListOf {
item_type: Box::new(item_type),
}
};
TypeEvaluation::Return(Some(list_type))
}
ListExpression::Ordered(expressions) => {
if expressions.is_empty() {
return Ok(Some(Type::ListEmpty));
return Ok(TypeEvaluation::Return(Some(Type::ListEmpty)));
}
let item_type = expressions
.first()
.ok_or_else(|| AstError::ExpectedNonEmptyList {
position: self.position(),
})?
.return_type(context)?
.ok_or_else(|| AstError::ExpectedType {
.unwrap()
.type_evaluation(context)?
.r#type()
.ok_or_else(|| AstError::ExpectedNonEmptyEvaluation {
position: expressions.first().unwrap().position(),
})?;
let length = expressions.len();
Some(Type::List {
TypeEvaluation::Return(Some(Type::List {
item_type: Box::new(item_type),
length,
})
}))
}
},
Expression::ListIndex(list_index_expression) => {
let ListIndexExpression { list, .. } = list_index_expression.inner.as_ref();
let list_type =
list.return_type(context)?
.ok_or_else(|| AstError::ExpectedType {
position: list.position(),
})?;
let list_type = list.type_evaluation(context)?.r#type().ok_or_else(|| {
AstError::ExpectedListType {
position: list.position(),
}
})?;
if let Type::List { item_type, .. } = list_type {
Some(*item_type)
TypeEvaluation::Return(Some(*item_type))
} else {
None
return Err(AstError::ExpectedListType {
position: list.position(),
});
}
}
Expression::Literal(literal_expression) => match literal_expression.inner.as_ref() {
LiteralExpression::BuiltInFunction(built_in_function) => {
built_in_function.return_type()
}
LiteralExpression::Primitive(primitive_value) => match primitive_value {
PrimitiveValueExpression::Boolean(_) => Some(Type::Boolean),
PrimitiveValueExpression::Character(_) => Some(Type::Character),
PrimitiveValueExpression::Integer(_) => Some(Type::Integer),
PrimitiveValueExpression::Float(_) => Some(Type::Float),
},
LiteralExpression::String(string) => Some(Type::String {
length: Some(string.len()),
}),
},
Expression::Literal(literal_expression) => {
let type_option = match literal_expression.inner.as_ref() {
LiteralExpression::BuiltInFunction(built_in_function) => {
built_in_function.return_type()
}
LiteralExpression::Primitive(primitive_value) => match primitive_value {
PrimitiveValueExpression::Boolean(_) => Some(Type::Boolean),
PrimitiveValueExpression::Character(_) => Some(Type::Character),
PrimitiveValueExpression::Integer(_) => Some(Type::Integer),
PrimitiveValueExpression::Float(_) => Some(Type::Float),
},
LiteralExpression::String(string) => Some(Type::String {
length: Some(string.len()),
}),
};
TypeEvaluation::Return(type_option)
}
Expression::Loop(loop_expression) => match loop_expression.inner.as_ref() {
LoopExpression::For { block, .. } => block.inner.return_type(context)?,
LoopExpression::Infinite { .. } => None,
LoopExpression::While { block, .. } => block.inner.return_type(context)?,
LoopExpression::For { block, .. } => block.inner.type_evaluation(context)?,
LoopExpression::Infinite { block } => block.inner.type_evaluation(context)?,
LoopExpression::While { block, .. } => block.inner.type_evaluation(context)?,
},
Expression::Map(map_expression) => {
let MapExpression { pairs } = map_expression.inner.as_ref();
@ -396,41 +444,47 @@ impl Expression {
let mut types = HashMap::with_capacity(pairs.len());
for (key, value) in pairs {
let value_type =
value
.return_type(context)?
.ok_or_else(|| AstError::ExpectedType {
position: value.position(),
})?;
let value_type = value.type_evaluation(context)?.r#type().ok_or_else(|| {
AstError::ExpectedNonEmptyEvaluation {
position: value.position(),
}
})?;
types.insert(key.inner.clone(), value_type);
}
Some(Type::Map { pairs: types })
TypeEvaluation::Return(Some(Type::Map { pairs: types }))
}
Expression::Operator(operator_expression) => {
let expected_type = match operator_expression.inner.as_ref() {
OperatorExpression::Assignment { .. } => None,
OperatorExpression::Comparison { .. } => Some(Type::Boolean),
OperatorExpression::CompoundAssignment { .. } => None,
OperatorExpression::ErrorPropagation(expression) => {
expression.type_evaluation(context)?.r#type()
}
OperatorExpression::Negation(expression) => {
expression.type_evaluation(context)?.r#type()
}
OperatorExpression::Not(_) => Some(Type::Boolean),
OperatorExpression::Math { left, .. } => {
left.type_evaluation(context)?.r#type()
}
OperatorExpression::Logic { .. } => Some(Type::Boolean),
};
TypeEvaluation::Return(expected_type)
}
Expression::Operator(operator_expression) => match operator_expression.inner.as_ref() {
OperatorExpression::Assignment { .. } => None,
OperatorExpression::Comparison { .. } => Some(Type::Boolean),
OperatorExpression::CompoundAssignment { .. } => None,
OperatorExpression::ErrorPropagation(expression) => {
expression.return_type(context)?
}
OperatorExpression::Negation(expression) => expression.return_type(context)?,
OperatorExpression::Not(_) => Some(Type::Boolean),
OperatorExpression::Math { left, .. } => left.return_type(context)?,
OperatorExpression::Logic { .. } => Some(Type::Boolean),
},
Expression::Range(range_expression) => {
let start = match range_expression.inner.as_ref() {
RangeExpression::Exclusive { start, .. } => start,
RangeExpression::Inclusive { start, .. } => start,
};
let start_type =
start
.return_type(context)?
.ok_or_else(|| AstError::ExpectedType {
position: start.position(),
})?;
let start_type = start.type_evaluation(context)?.r#type().ok_or_else(|| {
AstError::ExpectedListType {
position: start.position(),
}
})?;
let rangeable_type = match start_type {
Type::Byte => RangeableType::Byte,
Type::Character => RangeableType::Character,
@ -443,44 +497,41 @@ impl Expression {
}
};
Some(Type::Range {
TypeEvaluation::Return(Some(Type::Range {
r#type: rangeable_type,
})
}))
}
Expression::Struct(struct_expression) => match struct_expression.inner.as_ref() {
StructExpression::Fields { name, fields } => {
let mut types = HashMap::with_capacity(fields.len());
for (field, expression) in fields {
let r#type = expression.return_type(context)?.ok_or_else(|| {
AstError::ExpectedType {
position: expression.position(),
}
})?;
let r#type =
expression
.type_evaluation(context)?
.r#type()
.ok_or_else(|| AstError::ExpectedListType {
position: expression.position(),
})?;
types.insert(field.inner.clone(), r#type);
}
Some(Type::Struct(StructType::Fields {
TypeEvaluation::Return(Some(Type::Struct(StructType::Fields {
name: name.inner.clone(),
fields: types,
}))
})))
}
},
Expression::TupleAccess(tuple_access_expression) => {
let TupleAccessExpression { tuple, index } = tuple_access_expression.inner.as_ref();
let tuple_value =
tuple
.return_type(context)?
.ok_or_else(|| AstError::ExpectedType {
position: tuple.position(),
})?;
let tuple_value = tuple.type_evaluation(context)?.r#type();
if let Type::Tuple {
if let Some(Type::Tuple {
fields: Some(fields),
} = tuple_value
}) = tuple_value
{
fields.get(index.inner).cloned()
TypeEvaluation::Return(fields.get(index.inner).cloned())
} else {
Err(AstError::ExpectedTupleType {
position: tuple.position(),
@ -766,6 +817,15 @@ pub enum LiteralExpression {
String(String),
}
impl LiteralExpression {
pub fn as_integer(&self) -> Option<i64> {
match self {
LiteralExpression::Primitive(PrimitiveValueExpression::Integer(value)) => Some(*value),
_ => None,
}
}
}
impl Display for LiteralExpression {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
@ -1051,13 +1111,13 @@ pub enum BlockExpression {
}
impl BlockExpression {
fn return_type(&self, context: &Context) -> Result<Option<Type>, AstError> {
fn type_evaluation(&self, context: &Context) -> Result<TypeEvaluation, AstError> {
match self {
BlockExpression::Async(statements) | BlockExpression::Sync(statements) => {
if let Some(statement) = statements.last() {
statement.return_type(context)
statement.type_evaluation(context)
} else {
Ok(None)
Ok(TypeEvaluation::Return(None))
}
}
}

View File

@ -8,6 +8,7 @@ pub use statement::*;
use std::{
collections::VecDeque,
fmt::{self, Display, Formatter},
num::TryFromIntError,
};
use serde::{Deserialize, Serialize};
@ -62,21 +63,49 @@ impl<T: Display> Display for Node<T> {
#[derive(Debug, Clone, PartialEq)]
pub enum AstError {
ContextError { error: ContextError, position: Span },
ExpectedType { position: Span },
ExpectedTupleType { position: Span },
ExpectedNonEmptyList { position: Span },
ExpectedRangeableType { position: Span },
ContextError {
error: ContextError,
position: Span,
},
ExpectedInteger {
position: Span,
},
ExpectedListType {
position: Span,
},
ExpectedNonEmptyEvaluation {
position: Span,
},
ExpectedNonEmptyList {
position: Span,
},
ExpectedRangeableType {
position: Span,
},
ExpectedStructFieldsType {
position: Span,
},
ExpectedTupleType {
position: Span,
},
FromIntError {
error: TryFromIntError,
position: Span,
},
}
impl AstError {
pub fn position(&self) -> Span {
match self {
AstError::ContextError { position, .. } => *position,
AstError::ExpectedType { position } => *position,
AstError::ExpectedTupleType { position } => *position,
AstError::ExpectedInteger { position } => *position,
AstError::ExpectedListType { position } => *position,
AstError::ExpectedNonEmptyEvaluation { position } => *position,
AstError::ExpectedNonEmptyList { position } => *position,
AstError::ExpectedRangeableType { position } => *position,
AstError::ExpectedStructFieldsType { position } => *position,
AstError::ExpectedTupleType { position } => *position,
AstError::FromIntError { position, .. } => *position,
}
}
}
@ -87,16 +116,30 @@ impl Display for AstError {
AstError::ContextError { error, position } => {
write!(f, "Context error at {:?}: {}", position, error)
}
AstError::ExpectedType { position } => write!(f, "Expected a type at {:?}", position),
AstError::ExpectedInteger { position } => {
write!(f, "Expected an integer at {:?}", position)
}
AstError::ExpectedListType { position } => {
write!(f, "Expected a type at {:?}", position)
}
AstError::ExpectedTupleType { position } => {
write!(f, "Expected a tuple type at {:?}", position)
}
AstError::ExpectedNonEmptyEvaluation { position } => {
write!(f, "Expected a type at {:?}", position)
}
AstError::ExpectedNonEmptyList { position } => {
write!(f, "Expected a non-empty list at {:?}", position)
}
AstError::ExpectedRangeableType { position } => {
write!(f, "Expected a rangeable type at {:?}", position)
}
AstError::ExpectedStructFieldsType { position } => {
write!(f, "Expected a struct type with fields at {:?}", position)
}
AstError::FromIntError { error, position } => {
write!(f, "Integer conversion error at {:?}: {}", position, error)
}
}
}
}

View File

@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter};
use serde::{Deserialize, Serialize};
use crate::{Context, Identifier, Type};
use crate::{Context, Identifier, Type, TypeEvaluation};
use super::{AstError, Expression, Node, Span};
@ -28,12 +28,20 @@ impl Statement {
}
}
pub fn return_type(&self, context: &Context) -> Result<Option<Type>, AstError> {
pub fn type_evaluation(&self, context: &Context) -> Result<TypeEvaluation, AstError> {
match self {
Statement::Expression(expression) => expression.return_type(context),
Statement::ExpressionNullified(_) => Ok(None),
Statement::Let(_) => Ok(None),
Statement::StructDefinition(_) => Ok(None),
Statement::Expression(expression) => expression.type_evaluation(context),
Statement::ExpressionNullified(expression_node) => {
let type_evaluation = expression_node.inner.type_evaluation(context)?;
if let TypeEvaluation::Break(_) = type_evaluation {
Ok(type_evaluation)
} else {
Ok(TypeEvaluation::Return(None))
}
}
Statement::Let(_) => Ok(TypeEvaluation::Return(None)),
Statement::StructDefinition(_) => Ok(TypeEvaluation::Return(None)),
}
}
}

View File

@ -0,0 +1,39 @@
use crate::{Constructor, RuntimeError, Span, Type, Value};
pub enum Evaluation {
Break(Option<Value>),
Constructor(Constructor),
Return(Option<Value>),
}
impl Evaluation {
pub fn value(self) -> Option<Value> {
match self {
Evaluation::Return(value_option) => value_option,
_ => None,
}
}
pub fn expect_value(self, position: Span) -> Result<Value, RuntimeError> {
if let Evaluation::Return(Some(value)) = self {
Ok(value)
} else {
Err(RuntimeError::ExpectedValue { position })
}
}
}
pub enum TypeEvaluation {
Break(Option<Type>),
Constructor(Type),
Return(Option<Type>),
}
impl TypeEvaluation {
pub fn r#type(self) -> Option<Type> {
match self {
TypeEvaluation::Return(type_option) => type_option,
_ => None,
}
}
}

View File

@ -22,6 +22,7 @@ pub mod constructor;
pub mod context;
pub mod core_library;
pub mod dust_error;
pub mod evaluation;
pub mod identifier;
pub mod lexer;
pub mod parser;
@ -37,6 +38,7 @@ pub use constructor::Constructor;
pub use context::{Context, ContextData, ContextError};
pub use core_library::core_library;
pub use dust_error::DustError;
pub use evaluation::{Evaluation, TypeEvaluation};
pub use identifier::Identifier;
pub use lexer::{lex, LexError, Lexer};
pub use parser::{parse, ParseError, Parser};

View File

@ -21,8 +21,8 @@ use crate::{
StructDefinition, StructExpression,
},
constructor::ConstructError,
core_library, parse, Analyzer, BuiltInFunctionError, Constructor, Context, ContextData,
ContextError, DustError, Expression, Function, FunctionCallError, Identifier, ParseError,
core_library, parse, Analyzer, BuiltInFunctionError, Context, ContextData, ContextError,
DustError, Evaluation, Expression, Function, FunctionCallError, Identifier, ParseError,
StructType, Type, Value, ValueData, ValueError,
};
@ -1066,29 +1066,6 @@ impl Vm {
}
}
enum Evaluation {
Break(Option<Value>),
Constructor(Constructor),
Return(Option<Value>),
}
impl Evaluation {
pub fn value(self) -> Option<Value> {
match self {
Evaluation::Return(value_option) => value_option,
_ => None,
}
}
pub fn expect_value(self, position: Span) -> Result<Value, RuntimeError> {
if let Evaluation::Return(Some(value)) = self {
Ok(value)
} else {
Err(RuntimeError::ExpectedValue { position })
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum RuntimeError {
ConstructError {