Fix lots of parsing and type inferencing

This commit is contained in:
Jeff 2024-06-19 20:14:51 -04:00
parent e7e5d1c08d
commit 0b8880ae55
10 changed files with 349 additions and 113 deletions

View File

@ -33,7 +33,7 @@ impl Evaluate for As {
_manage_memory: bool,
) -> Result<(), ValidationError> {
match self.constructor {
TypeConstructor::Type(_) => {}
TypeConstructor::Raw(_) => {}
_ => todo!("Create an error for this occurence."),
};

View File

@ -8,7 +8,8 @@ use crate::{
};
use super::{
Evaluate, Evaluation, ExpectedType, Expression, Statement, Type, TypeConstructor, WithPosition,
type_constructor::TypeInvokationConstructor, Evaluate, Evaluation, ExpectedType, Expression,
Statement, Type, TypeConstructor, WithPosition,
};
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
@ -44,21 +45,66 @@ impl Assignment {
impl Evaluate for Assignment {
fn validate(&self, context: &mut Context, manage_memory: bool) -> Result<(), ValidationError> {
let statement_type = self.statement.expected_type(context)?;
if let Some(TypeConstructor::Raw(WithPosition {
node: Type::None,
position,
})) = &self.constructor
{
return Err(ValidationError::CannotAssignToNone(position.clone()));
}
if let Type::None = statement_type {
let relevant_statement = self.statement.last_child_statement();
let statement_type = relevant_statement.expected_type(context)?;
if let Type::None = &statement_type {
return Err(ValidationError::CannotAssignToNone(
self.statement.position(),
));
}
let statement = self
.statement
.last_child_statement()
.unwrap_or(&self.statement);
if let Some(constructor) = &self.constructor {
let r#type = constructor.clone().construct(&context)?;
r#type
.check(&statement_type)
.map_err(|conflict| ValidationError::TypeCheck {
conflict,
actual_position: self.statement.position(),
expected_position: Some(constructor.position()),
})?;
context.set_type(self.identifier.node.clone(), r#type.clone())?;
} else {
context.set_type(self.identifier.node.clone(), statement_type.clone())?;
}
self.statement.validate(context, manage_memory)?;
if let (
Some(TypeConstructor::Invokation(TypeInvokationConstructor {
identifier,
type_arguments,
})),
Statement::Expression(Expression::Value(_)),
Type::Enum {
type_parameters, ..
},
) = (&self.constructor, relevant_statement, &statement_type)
{
if let (Some(parameters), Some(arguments)) = (type_parameters, type_arguments) {
if parameters.len() != arguments.len() {
return Err(ValidationError::FullTypeNotKnown {
identifier: identifier.node.clone(),
position: self.constructor.clone().unwrap().position(),
});
}
}
return Ok(());
}
if let (Some(constructor), Statement::Expression(Expression::FunctionCall(function_call))) =
(&self.constructor, statement)
(&self.constructor, relevant_statement)
{
let declared_type = constructor.clone().construct(context)?;
let function_type = function_call.node.function().expected_type(context)?;
@ -76,6 +122,8 @@ impl Evaluate for Assignment {
if let Some(parameter) = returned_parameter {
context.set_type(parameter, declared_type)?;
return Ok(());
}
}
} else {
@ -84,24 +132,8 @@ impl Evaluate for Assignment {
position: function_call.position,
});
}
} else if let Some(constructor) = &self.constructor {
let r#type = constructor.clone().construct(&context)?;
r#type
.check(&statement_type)
.map_err(|conflict| ValidationError::TypeCheck {
conflict,
actual_position: self.statement.position(),
expected_position: Some(constructor.position()),
})?;
context.set_type(self.identifier.node.clone(), r#type.clone())?;
} else {
context.set_type(self.identifier.node.clone(), statement_type)?;
}
self.statement.validate(context, manage_memory)?;
Ok(())
}

View File

@ -40,11 +40,11 @@ impl Statement {
}
}
pub fn last_child_statement(&self) -> Option<&Self> {
pub fn last_child_statement(&self) -> &Self {
match self {
Statement::Block(block) => Some(block.node.last_statement()),
Statement::Loop(r#loop) => Some(r#loop.node.last_statement()),
_ => None,
Statement::Block(inner) => inner.node.last_statement(),
Statement::Loop(inner) => inner.node.last_statement(),
statement => statement,
}
}
}

View File

@ -16,7 +16,8 @@ pub enum Type {
Any,
Boolean,
Enum {
variants: Vec<(Identifier, Vec<Type>)>,
type_parameters: Option<Vec<Type>>,
variants: Vec<(Identifier, Option<Vec<Type>>)>,
},
Float,
Function {
@ -229,14 +230,20 @@ impl Display for Type {
match self {
Type::Any => write!(f, "any"),
Type::Boolean => write!(f, "bool"),
Type::Enum { variants } => {
write!(f, "enum {{")?;
Type::Enum { variants, .. } => {
write!(f, "enum ")?;
write!(f, " {{")?;
for (identifier, types) in variants {
writeln!(f, "{identifier}(")?;
writeln!(f, "{identifier}")?;
if let Some(types) = types {
write!(f, "(")?;
for r#type in types {
write!(f, "{}", r#type)?
write!(f, "{}", r#type)?;
}
}
write!(f, ")")?;

View File

@ -10,10 +10,10 @@ use super::{SourcePosition, Type, WithPosition};
pub enum TypeConstructor {
Enum(WithPosition<EnumTypeConstructor>),
Function(WithPosition<FunctionTypeConstructor>),
Identifier(WithPosition<Identifier>),
Invokation(TypeInvokationConstructor),
List(WithPosition<ListTypeConstructor>),
ListOf(WithPosition<Box<TypeConstructor>>),
Type(WithPosition<Type>),
Raw(WithPosition<Type>),
}
impl TypeConstructor {
@ -21,17 +21,61 @@ impl TypeConstructor {
match self {
TypeConstructor::Enum(WithPosition { position, .. }) => *position,
TypeConstructor::Function(WithPosition { position, .. }) => *position,
TypeConstructor::Identifier(WithPosition { position, .. }) => *position,
TypeConstructor::Invokation(TypeInvokationConstructor {
identifier,
type_arguments,
}) => {
if let Some(arguments) = type_arguments {
SourcePosition(
identifier.position.0,
arguments.last().unwrap().position().1,
)
} else {
SourcePosition(identifier.position.0, identifier.position.1)
}
}
TypeConstructor::List(WithPosition { position, .. }) => *position,
TypeConstructor::ListOf(WithPosition { position, .. }) => *position,
TypeConstructor::Type(WithPosition { position, .. }) => *position,
TypeConstructor::Raw(WithPosition { position, .. }) => *position,
}
}
pub fn construct(self, context: &Context) -> Result<Type, ValidationError> {
let r#type = match self {
TypeConstructor::Invokation(TypeInvokationConstructor { identifier, .. }) => {
let invoked_type = if let Some(r#type) = context.get_type(&identifier.node)? {
r#type
} else {
return Err(ValidationError::VariableNotFound {
identifier: identifier.node,
position: identifier.position,
});
};
if let Type::Enum {
type_parameters,
variants,
} = invoked_type
{
let mut mapped_variants = Vec::with_capacity(variants.len());
for (variant_name, content) in variants {
mapped_variants.push((variant_name.clone(), content.clone()));
}
Type::Enum {
type_parameters: type_parameters.clone(),
variants: mapped_variants,
}
} else {
invoked_type
}
}
TypeConstructor::Enum(enum_type_constructor) => {
let EnumTypeConstructor { variants, .. } = enum_type_constructor.node;
let EnumTypeConstructor {
type_parameters,
variants,
} = enum_type_constructor.node;
let mut type_variants = Vec::with_capacity(variants.len());
for (variant_name, constructors) in variants {
@ -44,11 +88,22 @@ impl TypeConstructor {
types.push(r#type);
}
type_variants.push((variant_name.node, types));
type_variants.push((variant_name.node, Some(types)));
} else {
type_variants.push((variant_name.node, None))
}
}
Type::Enum {
type_parameters: type_parameters.map(|identifiers| {
identifiers
.into_iter()
.map(|identifier| Type::Generic {
identifier: identifier.node,
concrete_type: None,
})
.collect()
}),
variants: type_variants,
}
}
@ -81,21 +136,6 @@ impl TypeConstructor {
return_type,
}
}
TypeConstructor::Identifier(WithPosition {
node: identifier, ..
}) => {
if let Some(r#type) = context.get_type(&identifier)? {
Type::Generic {
identifier,
concrete_type: Some(Box::new(r#type)),
}
} else {
Type::Generic {
identifier,
concrete_type: None,
}
}
}
TypeConstructor::List(positioned_constructor) => {
let ListTypeConstructor { length, item_type } = positioned_constructor.node;
let constructed_type = item_type.construct(context)?;
@ -110,7 +150,7 @@ impl TypeConstructor {
Type::ListOf(Box::new(item_type))
}
TypeConstructor::Type(r#type) => r#type.node,
TypeConstructor::Raw(r#type) => r#type.node,
};
Ok(r#type)
@ -141,3 +181,9 @@ pub struct ListTypeConstructor {
pub length: usize,
pub item_type: Box<TypeConstructor>,
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct TypeInvokationConstructor {
pub identifier: WithPosition<Identifier>,
pub type_arguments: Option<Vec<TypeConstructor>>,
}

View File

@ -41,12 +41,26 @@ pub enum ValueNode {
impl Evaluate for ValueNode {
fn validate(&self, context: &mut Context, _manage_memory: bool) -> Result<(), ValidationError> {
if let ValueNode::EnumInstance { type_name, .. } = self {
if let Some(_) = context.get_type(&type_name.node)? {
if let ValueNode::EnumInstance {
type_name, variant, ..
} = self
{
if let Some(Type::Enum { variants, .. }) = context.get_type(&type_name.node)? {
if variants
.iter()
.find(|(identifier, _)| identifier == &variant.node)
.is_none()
{
return Err(ValidationError::EnumVariantNotFound {
identifier: variant.node.clone(),
position: variant.position,
});
}
} else {
return Err(ValidationError::EnumDefinitionNotFound(
type_name.node.clone(),
));
return Err(ValidationError::EnumDefinitionNotFound {
identifier: type_name.node.clone(),
position: Some(type_name.position),
});
}
}
@ -231,17 +245,28 @@ impl Evaluate for ValueNode {
return_type,
body,
} => {
let type_parameters =
type_parameters.map(|parameter_list| parameter_list.into_iter().collect());
let function_context = context.create_child();
let mut value_parameters = Vec::with_capacity(constructors.len());
for (identifier, constructor) in constructors {
let r#type = constructor.construct(&context)?;
let r#type = constructor.construct(&function_context)?;
value_parameters.push((identifier, r#type));
}
let return_type = return_type.construct(&context)?;
if let Some(identifiers) = &type_parameters {
for identifier in identifiers {
function_context.set_type(
identifier.clone(),
Type::Generic {
identifier: identifier.clone(),
concrete_type: None,
},
)?;
}
}
let return_type = return_type.construct(&function_context)?;
Value::function(type_parameters, value_parameters, return_type, body.node)
}
@ -401,9 +426,10 @@ impl ExpectedType for ValueNode {
if let Some(r#type) = context.get_type(&type_name.node)? {
r#type
} else {
return Err(ValidationError::EnumDefinitionNotFound(
type_name.node.clone(),
));
return Err(ValidationError::EnumDefinitionNotFound {
identifier: type_name.node.clone(),
position: Some(type_name.position),
});
}
}
ValueNode::Float(_) => Type::Float,

View File

@ -132,6 +132,10 @@ pub enum ValidationError {
position: SourcePosition,
},
ExpectedValue(SourcePosition),
FullTypeNotKnown {
identifier: Identifier,
position: SourcePosition,
},
InterpreterExpectedReturn(SourcePosition),
RwLockPoison(RwLockPoisonError),
TypeCheck {
@ -160,7 +164,14 @@ pub enum ValidationError {
identifier: Identifier,
position: SourcePosition,
},
EnumDefinitionNotFound(Identifier),
EnumDefinitionNotFound {
identifier: Identifier,
position: Option<SourcePosition>,
},
EnumVariantNotFound {
identifier: Identifier,
position: SourcePosition,
},
}
impl From<RwLockPoisonError> for ValidationError {

View File

@ -335,6 +335,17 @@ impl InterpreterError {
)),
);
}
ValidationError::FullTypeNotKnown {
identifier,
position,
} => builder.add_label(
Label::new((self.source_id.clone(), position.0..position.1)).with_message(
format!(
"The full type for {} must be known.",
identifier.fg(identifier_color)
),
),
),
ValidationError::RwLockPoison(_) => todo!(),
ValidationError::TypeCheck {
conflict,
@ -425,7 +436,25 @@ impl InterpreterError {
)
}
ValidationError::ExpectedString { .. } => todo!(),
ValidationError::EnumDefinitionNotFound(_) => todo!(),
ValidationError::EnumDefinitionNotFound {
identifier,
position,
} => {
let message = format!(
"The enum {} does not exist in this context.",
identifier.fg(identifier_color),
);
if let Some(position) = position {
builder.add_label(
Label::new((self.source_id.clone(), position.0..position.1))
.with_message(message),
)
} else {
builder = builder.with_message(message);
}
}
ValidationError::EnumVariantNotFound { .. } => todo!(),
}
}

View File

@ -9,6 +9,8 @@ use crate::{
lexer::{Control, Keyword, Operator, Token},
};
use self::type_constructor::TypeInvokationConstructor;
pub type ParserInput<'src> =
SpannedInput<Token<'src>, SimpleSpan, &'src [(Token<'src>, SimpleSpan)]>;
@ -79,7 +81,7 @@ pub fn parser<'src>(
just(Token::Keyword(Keyword::Range)).to(Type::Range),
just(Token::Keyword(Keyword::Str)).to(Type::String),
))
.map_with(|r#type, state| TypeConstructor::Type(r#type.with_position(state.span())));
.map_with(|r#type, state| TypeConstructor::Raw(r#type.with_position(state.span())));
let function_type = just(Token::Keyword(Keyword::Fn))
.ignore_then(
@ -147,10 +149,6 @@ pub fn parser<'src>(
TypeConstructor::ListOf(Box::new(item_type).with_position(state.span()))
});
let identifier_type = positioned_identifier
.clone()
.map(|identifier| TypeConstructor::Identifier(identifier));
let enum_variant = positioned_identifier.clone().then(
type_constructor
.clone()
@ -196,12 +194,34 @@ pub fn parser<'src>(
)
});
let type_invokation = positioned_identifier
.clone()
.then(
type_constructor
.clone()
.separated_by(just(Token::Control(Control::Comma)))
.at_least(1)
.allow_trailing()
.collect()
.delimited_by(
just(Token::Control(Control::ParenOpen)),
just(Token::Control(Control::ParenClose)),
)
.or_not(),
)
.map(|(identifier, type_arguments)| {
TypeConstructor::Invokation(TypeInvokationConstructor {
identifier,
type_arguments,
})
});
choice((
type_invokation,
function_type,
list_type,
list_of_type,
primitive_type,
identifier_type,
enum_type,
))
});
@ -703,10 +723,10 @@ pub fn parser<'src>(
.repeated()
.or_not()
.ignore_then(choice((
async_block,
if_else,
assignment,
expression_statement,
async_block,
if_else,
r#break,
block_statement,
r#loop,
@ -725,6 +745,53 @@ mod tests {
use super::*;
#[test]
fn type_invokation() {
assert_eq!(
parse(&lex("x: Foo(int) = Foo::Bar(42)").unwrap()).unwrap()[0],
Statement::Assignment(
Assignment::new(
Identifier::new("x").with_position((0, 1)),
Some(TypeConstructor::Invokation(TypeInvokationConstructor {
identifier: Identifier::new("Foo").with_position((3, 6)),
type_arguments: Some(vec![TypeConstructor::Raw(
Type::Integer.with_position((7, 10))
)]),
})),
AssignmentOperator::Assign,
Statement::Expression(Expression::Value(
ValueNode::EnumInstance {
type_name: Identifier::new("Foo").with_position((14, 17)),
variant: Identifier::new("Bar").with_position((19, 22)),
content: Some(vec![Expression::Value(
ValueNode::Integer(42).with_position((23, 25))
)])
}
.with_position((14, 26))
))
)
.with_position((0, 26))
)
);
}
#[test]
fn enum_instance() {
assert_eq!(
parse(&lex("Foo::Bar(42)").unwrap()).unwrap()[0],
Statement::Expression(Expression::Value(
ValueNode::EnumInstance {
type_name: Identifier::new("Foo").with_position((0, 3)),
variant: Identifier::new("Bar").with_position((5, 8)),
content: Some(vec![Expression::Value(
ValueNode::Integer(42).with_position((9, 11))
)])
}
.with_position((0, 12))
))
);
}
#[test]
fn enum_type_empty() {
assert_eq!(
@ -762,15 +829,13 @@ mod tests {
(
Identifier::new("X").with_position((21, 22)),
Some(vec![
TypeConstructor::Type(Type::String.with_position((23, 26))),
TypeConstructor::Type(
Type::Integer.with_position((28, 31))
)
TypeConstructor::Raw(Type::String.with_position((23, 26))),
TypeConstructor::Raw(Type::Integer.with_position((28, 31)))
])
),
(
Identifier::new("Y").with_position((34, 35)),
Some(vec![TypeConstructor::Type(
Some(vec![TypeConstructor::Raw(
Type::Integer.with_position((36, 39))
)])
)
@ -800,14 +865,22 @@ mod tests {
variants: vec![
(
Identifier::new("X").with_position((28, 29)),
Some(vec![TypeConstructor::Identifier(
Identifier::new("T").with_position((30, 31))
Some(vec![TypeConstructor::Invokation(
TypeInvokationConstructor {
identifier: Identifier::new("T")
.with_position((30, 31)),
type_arguments: None,
}
)])
),
(
Identifier::new("Y").with_position((34, 35)),
Some(vec![TypeConstructor::Identifier(
Identifier::new("U").with_position((36, 37))
Some(vec![TypeConstructor::Invokation(
TypeInvokationConstructor {
identifier: Identifier::new("U")
.with_position((36, 37)),
type_arguments: None,
}
)])
),
],
@ -894,7 +967,7 @@ mod tests {
Statement::TypeAssignment(
TypeAssignment::new(
Identifier::new("MyType").with_position((5, 11)),
TypeConstructor::Type(Type::String.with_position((14, 17)))
TypeConstructor::Raw(Type::String.with_position((14, 17)))
)
.with_position((0, 17))
)
@ -908,7 +981,7 @@ mod tests {
Statement::Expression(Expression::As(
Box::new(As::new(
Expression::Value(ValueNode::Integer(1).with_position((0, 1))),
TypeConstructor::Type(Type::String.with_position((5, 8)))
TypeConstructor::Raw(Type::String.with_position((5, 8)))
))
.with_position((0, 8))
))
@ -1053,7 +1126,7 @@ mod tests {
Statement::Assignment(
Assignment::new(
Identifier::new("foobar").with_position((0, 6)),
Some(TypeConstructor::Type(Type::Boolean.with_position((9, 13)))),
Some(TypeConstructor::Raw(Type::Boolean.with_position((9, 13)))),
AssignmentOperator::Assign,
Statement::Expression(Expression::Value(
ValueNode::Boolean(true).with_position((16, 20))
@ -1074,7 +1147,7 @@ mod tests {
Some(TypeConstructor::List(
ListTypeConstructor {
length: 2,
item_type: Box::new(TypeConstructor::Type(
item_type: Box::new(TypeConstructor::Raw(
Type::Integer.with_position((9, 12))
))
}
@ -1098,7 +1171,7 @@ mod tests {
Assignment::new(
Identifier::new("foobar").with_position((0, 6)),
Some(TypeConstructor::ListOf(
Box::new(TypeConstructor::Type(Type::Boolean.with_position((10, 14))))
Box::new(TypeConstructor::Raw(Type::Boolean.with_position((10, 14))))
.with_position((9, 15))
)),
AssignmentOperator::Assign,
@ -1126,11 +1199,14 @@ mod tests {
type_parameters: Some(vec![
Identifier::new("T").with_position((15, 16))
]),
value_parameters: vec![TypeConstructor::Type(
value_parameters: vec![TypeConstructor::Raw(
Type::Integer.with_position((19, 22))
)],
return_type: Box::new(TypeConstructor::Identifier(
Identifier::new("T").with_position((27, 28))
return_type: Box::new(TypeConstructor::Invokation(
TypeInvokationConstructor {
identifier: Identifier::new("T").with_position((27, 28)),
type_arguments: None,
}
)),
}
.with_position((11, 28))
@ -1163,7 +1239,7 @@ mod tests {
Statement::Expression(Expression::FunctionCall(
FunctionCall::new(
Expression::Identifier(Identifier::new("foobar").with_position((0, 6))),
Some(vec![TypeConstructor::Type(
Some(vec![TypeConstructor::Raw(
Type::String.with_position((9, 12))
)]),
vec![Expression::Value(
@ -1193,7 +1269,7 @@ mod tests {
ValueNode::Function {
type_parameters: None,
value_parameters: vec![],
return_type: TypeConstructor::Type(Type::Integer.with_position((9, 12))),
return_type: TypeConstructor::Raw(Type::Integer.with_position((9, 12))),
body: Block::new(vec![Statement::Expression(Expression::Value(
ValueNode::Integer(0).with_position((15, 16))
))])
@ -1210,9 +1286,9 @@ mod tests {
type_parameters: None,
value_parameters: vec![(
Identifier::new("x"),
TypeConstructor::Type(Type::Integer.with_position((7, 10)))
TypeConstructor::Raw(Type::Integer.with_position((7, 10)))
)],
return_type: TypeConstructor::Type(Type::Integer.with_position((15, 18))),
return_type: TypeConstructor::Raw(Type::Integer.with_position((15, 18))),
body: Block::new(vec![Statement::Expression(Expression::Identifier(
Identifier::new("x").with_position((21, 22))
))])
@ -1233,20 +1309,23 @@ mod tests {
value_parameters: vec![
(
Identifier::new("x"),
TypeConstructor::Identifier(
Identifier::new("T").with_position((14, 15))
)
TypeConstructor::Invokation(TypeInvokationConstructor {
identifier: Identifier::new("T").with_position((14, 15)),
type_arguments: None,
})
),
(
Identifier::new("y"),
TypeConstructor::Identifier(
Identifier::new("U").with_position((20, 21))
)
TypeConstructor::Invokation(TypeInvokationConstructor {
identifier: Identifier::new("U").with_position((20, 21)),
type_arguments: None,
})
)
],
return_type: TypeConstructor::Identifier(
Identifier::new("T").with_position((26, 27))
),
return_type: TypeConstructor::Invokation(TypeInvokationConstructor {
identifier: Identifier::new("T").with_position((26, 27)),
type_arguments: None,
}),
body: Block::new(vec![Statement::Expression(Expression::Identifier(
Identifier::new("x").with_position((30, 31))
))])
@ -1531,7 +1610,7 @@ mod tests {
Statement::Assignment(
Assignment::new(
Identifier::new("foobar").with_position((0, 6)),
Some(TypeConstructor::Type(Type::Integer.with_position((8, 11)))),
Some(TypeConstructor::Raw(Type::Integer.with_position((8, 11)))),
AssignmentOperator::Assign,
Statement::Expression(Expression::Value(
ValueNode::Integer(1).with_position((14, 15))

View File

@ -564,7 +564,10 @@ impl ValueInner {
if let Some(r#type) = context.get_type(type_name)? {
r#type
} else {
return Err(ValidationError::EnumDefinitionNotFound(type_name.clone()));
return Err(ValidationError::EnumDefinitionNotFound {
identifier: type_name.clone(),
position: None,
});
}
}
ValueInner::Float(_) => Type::Float,
@ -720,11 +723,14 @@ impl Function {
pub fn call(
self,
arguments: Vec<Value>,
value_arguments: Vec<Value>,
context: &mut Context,
clear_variables: bool,
) -> Result<Evaluation, RuntimeError> {
for ((identifier, _), value) in self.value_parameters.into_iter().zip(arguments.into_iter())
for ((identifier, _), value) in self
.value_parameters
.into_iter()
.zip(value_arguments.into_iter())
{
context.set_value(identifier.clone(), value)?;
}