Replace "return_type" methods in AST with new type_evaluation
This commit is contained in:
parent
f510cce0ee
commit
8b14d74eba
@ -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 {
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
39
dust-lang/src/evaluation.rs
Normal file
39
dust-lang/src/evaluation.rs
Normal 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,
|
||||
}
|
||||
}
|
||||
}
|
@ -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};
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user