Improve constructors

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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