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

View File

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

View File

@ -8,6 +8,7 @@ pub use statement::*;
use std::{ use std::{
collections::VecDeque, collections::VecDeque,
fmt::{self, Display, Formatter}, fmt::{self, Display, Formatter},
num::TryFromIntError,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -62,21 +63,49 @@ impl<T: Display> Display for Node<T> {
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum AstError { pub enum AstError {
ContextError { error: ContextError, position: Span }, ContextError {
ExpectedType { position: Span }, error: ContextError,
ExpectedTupleType { position: Span }, position: Span,
ExpectedNonEmptyList { position: Span }, },
ExpectedRangeableType { 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 { impl AstError {
pub fn position(&self) -> Span { pub fn position(&self) -> Span {
match self { match self {
AstError::ContextError { position, .. } => *position, AstError::ContextError { position, .. } => *position,
AstError::ExpectedType { position } => *position, AstError::ExpectedInteger { position } => *position,
AstError::ExpectedTupleType { position } => *position, AstError::ExpectedListType { position } => *position,
AstError::ExpectedNonEmptyEvaluation { position } => *position,
AstError::ExpectedNonEmptyList { position } => *position, AstError::ExpectedNonEmptyList { position } => *position,
AstError::ExpectedRangeableType { 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 } => { AstError::ContextError { error, position } => {
write!(f, "Context error at {:?}: {}", position, error) 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 } => { AstError::ExpectedTupleType { position } => {
write!(f, "Expected a tuple type at {:?}", position) write!(f, "Expected a tuple type at {:?}", position)
} }
AstError::ExpectedNonEmptyEvaluation { position } => {
write!(f, "Expected a type at {:?}", position)
}
AstError::ExpectedNonEmptyList { position } => { AstError::ExpectedNonEmptyList { position } => {
write!(f, "Expected a non-empty list at {:?}", position) write!(f, "Expected a non-empty list at {:?}", position)
} }
AstError::ExpectedRangeableType { position } => { AstError::ExpectedRangeableType { position } => {
write!(f, "Expected a rangeable type at {:?}", 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 serde::{Deserialize, Serialize};
use crate::{Context, Identifier, Type}; use crate::{Context, Identifier, Type, TypeEvaluation};
use super::{AstError, Expression, Node, Span}; 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 { match self {
Statement::Expression(expression) => expression.return_type(context), Statement::Expression(expression) => expression.type_evaluation(context),
Statement::ExpressionNullified(_) => Ok(None), Statement::ExpressionNullified(expression_node) => {
Statement::Let(_) => Ok(None), let type_evaluation = expression_node.inner.type_evaluation(context)?;
Statement::StructDefinition(_) => Ok(None),
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 context;
pub mod core_library; pub mod core_library;
pub mod dust_error; pub mod dust_error;
pub mod evaluation;
pub mod identifier; pub mod identifier;
pub mod lexer; pub mod lexer;
pub mod parser; pub mod parser;
@ -37,6 +38,7 @@ pub use constructor::Constructor;
pub use context::{Context, ContextData, ContextError}; pub use context::{Context, ContextData, ContextError};
pub use core_library::core_library; pub use core_library::core_library;
pub use dust_error::DustError; pub use dust_error::DustError;
pub use evaluation::{Evaluation, TypeEvaluation};
pub use identifier::Identifier; pub use identifier::Identifier;
pub use lexer::{lex, LexError, Lexer}; pub use lexer::{lex, LexError, Lexer};
pub use parser::{parse, ParseError, Parser}; pub use parser::{parse, ParseError, Parser};

View File

@ -21,8 +21,8 @@ use crate::{
StructDefinition, StructExpression, StructDefinition, StructExpression,
}, },
constructor::ConstructError, constructor::ConstructError,
core_library, parse, Analyzer, BuiltInFunctionError, Constructor, Context, ContextData, core_library, parse, Analyzer, BuiltInFunctionError, Context, ContextData, ContextError,
ContextError, DustError, Expression, Function, FunctionCallError, Identifier, ParseError, DustError, Evaluation, Expression, Function, FunctionCallError, Identifier, ParseError,
StructType, Type, Value, ValueData, ValueError, 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)] #[derive(Clone, Debug, PartialEq)]
pub enum RuntimeError { pub enum RuntimeError {
ConstructError { ConstructError {