Add instantiation for tuple structs

This commit is contained in:
Jeff 2024-08-13 16:21:44 -04:00
parent 049790726a
commit 83aa53b998
7 changed files with 294 additions and 87 deletions

View File

@ -6,7 +6,7 @@ use std::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{BuiltInFunction, Context, Identifier, Span, Type, Value}; use crate::{BuiltInFunction, Context, Identifier, Span, StructType, Type, Value};
/// In-memory representation of a Dust program. /// In-memory representation of a Dust program.
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] #[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
@ -50,17 +50,21 @@ pub enum Statement {
operand: Box<Node<Statement>>, operand: Box<Node<Statement>>,
}, },
// Function calls // Type definitions
StructDefinition(StructDefinition),
// Function calls and type instantiation
BuiltInFunctionCall { BuiltInFunctionCall {
function: BuiltInFunction, function: BuiltInFunction,
type_arguments: Option<Vec<Node<Statement>>>, type_arguments: Option<Vec<Node<Statement>>>,
value_arguments: Option<Vec<Node<Statement>>>, value_arguments: Option<Vec<Node<Statement>>>,
}, },
FunctionCall { Invokation {
function: Box<Node<Statement>>, invokee: Box<Node<Statement>>,
type_arguments: Option<Vec<Node<Statement>>>, type_arguments: Option<Vec<Node<Statement>>>,
value_arguments: Option<Vec<Node<Statement>>>, value_arguments: Option<Vec<Node<Statement>>>,
}, },
StructInstantiation(StructInstantiation),
// Loops // Loops
While { While {
@ -103,9 +107,6 @@ pub enum Statement {
// A statement that always returns None. Created with a semicolon, it causes the preceding // A statement that always returns None. Created with a semicolon, it causes the preceding
// statement to return None. This is analagous to the semicolon or unit type in Rust. // statement to return None. This is analagous to the semicolon or unit type in Rust.
Nil(Box<Node<Statement>>), Nil(Box<Node<Statement>>),
// Type definitions
StructDefinition(StructDefinition),
} }
impl Statement { impl Statement {
@ -159,7 +160,9 @@ impl Statement {
}, },
Statement::BuiltInFunctionCall { function, .. } => function.expected_return_type(), Statement::BuiltInFunctionCall { function, .. } => function.expected_return_type(),
Statement::Constant(value) => Some(value.r#type()), Statement::Constant(value) => Some(value.r#type()),
Statement::FunctionCall { function, .. } => function.inner.expected_type(context), Statement::Invokation {
invokee: function, ..
} => function.inner.expected_type(context),
Statement::Identifier(identifier) => context.get_type(identifier), Statement::Identifier(identifier) => context.get_type(identifier),
Statement::If { .. } => None, Statement::If { .. } => None,
Statement::IfElse { if_body, .. } => if_body.inner.expected_type(context), Statement::IfElse { if_body, .. } => if_body.inner.expected_type(context),
@ -190,6 +193,17 @@ impl Statement {
UnaryOperator::Not => Some(Type::Boolean), UnaryOperator::Not => Some(Type::Boolean),
}, },
Statement::StructDefinition(_) => None, Statement::StructDefinition(_) => None,
Statement::StructInstantiation(struct_instantiation) => match struct_instantiation {
StructInstantiation::Tuple { name, fields } => {
Some(Type::Struct(StructType::Tuple {
name: name.inner.clone(),
fields: fields
.iter()
.map(|field| field.inner.expected_type(context))
.collect::<Option<Vec<Type>>>()?,
}))
}
},
Statement::While { .. } => None, Statement::While { .. } => None,
} }
} }
@ -287,8 +301,8 @@ impl Display for Statement {
write!(f, ")") write!(f, ")")
} }
Statement::Constant(value) => write!(f, "{value}"), Statement::Constant(value) => write!(f, "{value}"),
Statement::FunctionCall { Statement::Invokation {
function, invokee: function,
type_arguments: type_parameters, type_arguments: type_parameters,
value_arguments: value_parameters, value_arguments: value_parameters,
} => { } => {
@ -398,6 +412,9 @@ impl Display for Statement {
Statement::StructDefinition(struct_definition) => { Statement::StructDefinition(struct_definition) => {
write!(f, "{struct_definition}") write!(f, "{struct_definition}")
} }
Statement::StructInstantiation(struct_instantiation) => {
write!(f, "{struct_instantiation}")
}
Statement::While { condition, body } => { Statement::While { condition, body } => {
write!(f, "while {condition} {body}") write!(f, "while {condition} {body}")
} }
@ -471,3 +488,32 @@ impl Display for StructDefinition {
} }
} }
} }
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum StructInstantiation {
// The Unit variant is absent because unit structs are instantiated without any fields
Tuple {
name: Node<Identifier>,
fields: Vec<Node<Statement>>,
},
}
impl Display for StructInstantiation {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
StructInstantiation::Tuple { name, fields } => {
write!(f, "{name}(")?;
for (i, field) in fields.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{field}")?;
}
write!(f, ")")
}
}
}
}

View File

@ -10,7 +10,7 @@ use std::{
}; };
use crate::{ use crate::{
abstract_tree::{BinaryOperator, UnaryOperator}, abstract_tree::{BinaryOperator, StructInstantiation, UnaryOperator},
parse, AbstractSyntaxTree, Context, DustError, Identifier, Node, Span, Statement, parse, AbstractSyntaxTree, Context, DustError, Identifier, Node, Span, Statement,
StructDefinition, StructType, Type, StructDefinition, StructType, Type,
}; };
@ -290,8 +290,8 @@ impl<'a> Analyzer<'a> {
} }
} }
Statement::Constant(_) => {} Statement::Constant(_) => {}
Statement::FunctionCall { Statement::Invokation {
function, invokee: function,
value_arguments, value_arguments,
.. ..
} => { } => {
@ -429,13 +429,31 @@ impl<'a> Analyzer<'a> {
name: name.inner.clone(), name: name.inner.clone(),
}), }),
), ),
StructDefinition::Tuple { name, fields } => { StructDefinition::Tuple { name, fields } => (
todo!() name.inner.clone(),
} Type::Struct(StructType::Tuple {
name: name.inner.clone(),
fields: fields
.iter()
.map(|type_node| type_node.inner.clone())
.collect(),
}),
),
}; };
self.context.set_type(name, r#type, node.position); self.context.set_type(name, r#type, node.position);
} }
Statement::StructInstantiation(struct_instantiation) => {
let name = match struct_instantiation {
StructInstantiation::Tuple { name, .. } => name,
};
if self.context.get_type(&name.inner).is_none() {
return Err(AnalyzerError::UndefinedType {
identifier: name.clone(),
});
}
}
Statement::UnaryOperation { operator, operand } => { Statement::UnaryOperation { operator, operand } => {
self.analyze_statement(operand)?; self.analyze_statement(operand)?;
@ -517,19 +535,22 @@ pub enum AnalyzerError {
actual_type: Type, actual_type: Type,
expected: Type, expected: Type,
}, },
UndefinedVariable {
identifier: Node<Statement>,
},
UndefinedField { UndefinedField {
identifier: Node<Statement>, identifier: Node<Statement>,
map: Node<Statement>, map: Node<Statement>,
}, },
UndefinedType {
identifier: Node<Identifier>,
},
UnexpectedIdentifier { UnexpectedIdentifier {
identifier: Node<Statement>, identifier: Node<Statement>,
}, },
UnexectedString { UnexectedString {
actual: Node<Statement>, actual: Node<Statement>,
}, },
UndefinedVariable {
identifier: Node<Statement>,
},
} }
impl AnalyzerError { impl AnalyzerError {
@ -550,6 +571,7 @@ impl AnalyzerError {
actual_statement, .. actual_statement, ..
} => actual_statement.position, } => actual_statement.position,
AnalyzerError::UndefinedField { identifier, .. } => identifier.position, AnalyzerError::UndefinedField { identifier, .. } => identifier.position,
AnalyzerError::UndefinedType { identifier } => identifier.position,
AnalyzerError::UndefinedVariable { identifier } => identifier.position, AnalyzerError::UndefinedVariable { identifier } => identifier.position,
AnalyzerError::UnexpectedIdentifier { identifier } => identifier.position, AnalyzerError::UnexpectedIdentifier { identifier } => identifier.position,
AnalyzerError::UnexectedString { actual } => actual.position, AnalyzerError::UnexectedString { actual } => actual.position,
@ -606,6 +628,9 @@ impl Display for AnalyzerError {
AnalyzerError::UndefinedField { identifier, map } => { AnalyzerError::UndefinedField { identifier, map } => {
write!(f, "Undefined field {} in map {}", identifier, map) write!(f, "Undefined field {} in map {}", identifier, map)
} }
AnalyzerError::UndefinedType { identifier } => {
write!(f, "Undefined type {}", identifier)
}
AnalyzerError::UndefinedVariable { identifier } => { AnalyzerError::UndefinedVariable { identifier } => {
write!(f, "Undefined variable {}", identifier) write!(f, "Undefined variable {}", identifier)
} }

View File

@ -15,7 +15,8 @@ pub mod value;
pub mod vm; pub mod vm;
pub use abstract_tree::{ pub use abstract_tree::{
AbstractSyntaxTree, BinaryOperator, Node, Statement, StructDefinition, UnaryOperator, AbstractSyntaxTree, BinaryOperator, Node, Statement, StructDefinition, StructInstantiation,
UnaryOperator,
}; };
pub use analyzer::{analyze, Analyzer, AnalyzerError}; pub use analyzer::{analyze, Analyzer, AnalyzerError};
pub use built_in_function::{BuiltInFunction, BuiltInFunctionError}; pub use built_in_function::{BuiltInFunction, BuiltInFunctionError};

View File

@ -686,8 +686,8 @@ impl<'src> Parser<'src> {
)); ));
} }
if let Statement::FunctionCall { if let Statement::Invokation {
function, invokee: function,
type_arguments, type_arguments,
value_arguments, value_arguments,
} = right.inner } = right.inner
@ -701,8 +701,8 @@ impl<'src> Parser<'src> {
}; };
return Ok(Node::new( return Ok(Node::new(
Statement::FunctionCall { Statement::Invokation {
function, invokee: function,
type_arguments, type_arguments,
value_arguments, value_arguments,
}, },
@ -762,48 +762,85 @@ impl<'src> Parser<'src> {
fn parse_postfix(&mut self, left: Node<Statement>) -> Result<Node<Statement>, ParseError> { fn parse_postfix(&mut self, left: Node<Statement>) -> Result<Node<Statement>, ParseError> {
let left_start = left.position.0; let left_start = left.position.0;
let statement = if let Token::LeftSquareBrace = &self.current.0 { let statement = match &self.current.0 {
let operator_start = self.current.1 .0; Token::LeftParenthesis => {
self.next_token()?;
self.next_token()?; let mut arguments = Vec::new();
let index = self.parse_statement(0)?; while self.current.0 != Token::RightParenthesis {
let argument = self.parse_statement(0)?;
let operator_end = if let Token::RightSquareBrace = self.current.0 { arguments.push(argument);
let end = self.current.1 .1;
if let Token::Comma = self.current.0 {
self.next_token()?;
} else {
break;
}
}
let right_end = self.current.1 .1;
self.next_token()?; self.next_token()?;
end Node::new(
} else { Statement::Invokation {
return Err(ParseError::ExpectedToken { invokee: Box::new(left),
expected: TokenKind::RightSquareBrace, type_arguments: None,
value_arguments: Some(arguments),
},
(left_start, right_end),
)
}
Token::LeftSquareBrace => {
let operator_start = self.current.1 .0;
self.next_token()?;
let index = self.parse_statement(0)?;
let operator_end = if let Token::RightSquareBrace = self.current.0 {
let end = self.current.1 .1;
self.next_token()?;
end
} else {
return Err(ParseError::ExpectedToken {
expected: TokenKind::RightSquareBrace,
actual: self.current.0.to_owned(),
position: self.current.1,
});
};
let right_end = self.current.1 .1;
Node::new(
Statement::BinaryOperation {
left: Box::new(left),
operator: Node::new(
BinaryOperator::ListIndex,
(operator_start, operator_end),
),
right: Box::new(index),
},
(left_start, right_end),
)
}
Token::Semicolon => {
let operator_end = self.current.1 .1;
self.next_token()?;
Node::new(Statement::Nil(Box::new(left)), (left_start, operator_end))
}
_ => {
return Err(ParseError::UnexpectedToken {
actual: self.current.0.to_owned(), actual: self.current.0.to_owned(),
position: self.current.1, position: self.current.1,
}); });
}; }
let right_end = self.current.1 .1;
Node::new(
Statement::BinaryOperation {
left: Box::new(left),
operator: Node::new(BinaryOperator::ListIndex, (operator_start, operator_end)),
right: Box::new(index),
},
(left_start, right_end),
)
} else if let Token::Semicolon = &self.current.0 {
let operator_end = self.current.1 .1;
self.next_token()?;
Node::new(Statement::Nil(Box::new(left)), (left_start, operator_end))
} else {
return Err(ParseError::UnexpectedToken {
actual: self.current.0.to_owned(),
position: self.current.1,
});
}; };
if self.current.0.is_postfix() { if self.current.0.is_postfix() {
@ -990,10 +1027,50 @@ impl Display for ParseError {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{BinaryOperator, Identifier, StructDefinition, Type, UnaryOperator}; use crate::{
BinaryOperator, Identifier, StructDefinition, StructInstantiation, Type, UnaryOperator,
};
use super::*; use super::*;
#[test]
fn tuple_struct_instantiation() {
let input = "struct Foo(int, float) Foo(1, 2.0)";
assert_eq!(
parse(input),
Ok(AbstractSyntaxTree {
nodes: [
Node::new(
Statement::StructDefinition(StructDefinition::Tuple {
name: Node::new(Identifier::new("Foo"), (7, 10)),
fields: vec![
Node::new(Type::Integer, (11, 14)),
Node::new(Type::Float, (16, 21))
]
}),
(0, 22)
),
Node::new(
Statement::Invokation {
invokee: Box::new(Node::new(
Statement::Identifier(Identifier::new("Foo")),
(23, 26)
)),
type_arguments: None,
value_arguments: Some(vec![
Node::new(Statement::Constant(Value::integer(1)), (27, 28)),
Node::new(Statement::Constant(Value::float(2.0)), (30, 33))
])
},
(23, 34)
)
]
.into()
})
);
}
#[test] #[test]
fn tuple_struct() { fn tuple_struct() {
let input = "struct Foo(int, float)"; let input = "struct Foo(int, float)";

View File

@ -223,7 +223,7 @@ impl<'src> Token<'src> {
pub fn precedence(&self) -> u8 { pub fn precedence(&self) -> u8 {
match self { match self {
Token::Dot => 10, Token::Dot => 10,
Token::LeftSquareBrace => 9, Token::LeftParenthesis | Token::LeftSquareBrace => 9,
Token::Star | Token::Slash | Token::Percent => 8, Token::Star | Token::Slash | Token::Percent => 8,
Token::Minus | Token::Plus => 6, Token::Minus | Token::Plus => 6,
Token::DoubleEqual Token::DoubleEqual
@ -261,7 +261,10 @@ impl<'src> Token<'src> {
} }
pub fn is_postfix(&self) -> bool { pub fn is_postfix(&self) -> bool {
matches!(self, Token::LeftSquareBrace | Token::Semicolon) matches!(
self,
Token::LeftParenthesis | Token::LeftSquareBrace | Token::Semicolon
)
} }
} }

View File

@ -16,7 +16,7 @@ use std::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{Identifier, Struct}; use crate::Identifier;
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct TypeConflict { pub struct TypeConflict {
@ -344,7 +344,7 @@ pub enum StructType {
}, },
Tuple { Tuple {
name: Identifier, name: Identifier,
types: Vec<Type>, fields: Vec<Type>,
}, },
Fields { Fields {
name: Identifier, name: Identifier,
@ -352,26 +352,17 @@ pub enum StructType {
}, },
} }
impl StructType {
pub fn instantiate(&self) -> Struct {
match self {
StructType::Unit { name } => Struct::Unit { name: name.clone() },
_ => todo!(),
}
}
}
impl Display for StructType { impl Display for StructType {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self { match self {
StructType::Unit { name } => write!(f, "struct {name}"), StructType::Unit { name } => write!(f, "struct {name}"),
StructType::Tuple { name, types } => { StructType::Tuple { name, fields } => {
write!(f, "struct {name}(")?; write!(f, "struct {name}(")?;
for (index, r#type) in types.iter().enumerate() { for (index, r#type) in fields.iter().enumerate() {
write!(f, "{type}")?; write!(f, "{type}")?;
if index != types.len() - 1 { if index != fields.len() - 1 {
write!(f, ", ")?; write!(f, ", ")?;
} }
} }

View File

@ -11,8 +11,8 @@ use std::{
use crate::{ use crate::{
parse, value::ValueInner, AbstractSyntaxTree, Analyzer, BinaryOperator, BuiltInFunctionError, parse, value::ValueInner, AbstractSyntaxTree, Analyzer, BinaryOperator, BuiltInFunctionError,
Context, DustError, Identifier, Node, ParseError, Span, Statement, StructDefinition, Context, DustError, Identifier, Node, ParseError, Span, Statement, Struct, StructDefinition,
StructType, Type, UnaryOperator, Value, ValueError, StructInstantiation, StructType, Type, UnaryOperator, Value, ValueError,
}; };
/// Run the source code and return the result. /// Run the source code and return the result.
@ -329,17 +329,43 @@ impl Vm {
Ok(function_call_return) Ok(function_call_return)
} }
Statement::Constant(value) => Ok(Some(value.clone())), Statement::Constant(value) => Ok(Some(value.clone())),
Statement::FunctionCall { Statement::Invokation {
function: function_node, invokee,
type_arguments: _, type_arguments: _,
value_arguments: value_parameter_nodes, value_arguments: value_parameter_nodes,
} => { } => {
let function_position = function_node.position; let invokee_position = invokee.position;
let function_value = if let Some(value) = self.run_statement(*function_node)? { let invokee_type = invokee.inner.expected_type(&self.context);
if let Some(Type::Struct(StructType::Tuple { name, .. })) = invokee_type {
let mut fields = Vec::new();
if let Some(value_parameter_nodes) = value_parameter_nodes {
for statement in value_parameter_nodes {
let position = statement.position;
let value = if let Some(value) = self.run_statement(statement)? {
value
} else {
return Err(VmError::ExpectedValue { position });
};
fields.push(value);
}
}
let struct_value = Value::r#struct(Struct::Tuple {
name: name.clone(),
fields,
});
return Ok(Some(struct_value));
}
let function_value = if let Some(value) = self.run_statement(*invokee)? {
value value
} else { } else {
return Err(VmError::ExpectedValue { return Err(VmError::ExpectedValue {
position: function_position, position: invokee_position,
}); });
}; };
let function = if let Some(function) = function_value.as_function() { let function = if let Some(function) = function_value.as_function() {
@ -347,7 +373,7 @@ impl Vm {
} else { } else {
return Err(VmError::ExpectedFunction { return Err(VmError::ExpectedFunction {
actual: function_value, actual: function_value,
position: function_position, position: invokee_position,
}); });
}; };
@ -385,8 +411,8 @@ impl Vm {
println!("{type_option:?}"); println!("{type_option:?}");
if let Some(Type::Struct(struct_type)) = type_option { if let Some(Type::Struct(StructType::Unit { name })) = type_option {
return Ok(Some(Value::r#struct(struct_type.instantiate()))); return Ok(Some(Value::r#struct(Struct::Unit { name })));
} }
Err(VmError::UndefinedVariable { Err(VmError::UndefinedVariable {
@ -592,15 +618,40 @@ impl Vm {
name: name.inner.clone(), name: name.inner.clone(),
}), }),
), ),
StructDefinition::Tuple { name, fields } => { StructDefinition::Tuple { name, fields } => (
todo!() name.inner.clone(),
} Type::Struct(StructType::Tuple {
name: name.inner.clone(),
fields: fields
.into_iter()
.map(|type_node| type_node.inner)
.collect(),
}),
),
}; };
self.context.set_type(type_name, r#type, node.position); self.context.set_type(type_name, r#type, node.position);
Ok(None) Ok(None)
} }
Statement::StructInstantiation(struct_instantiation) => match struct_instantiation {
StructInstantiation::Tuple { name, fields } => {
Ok(Some(Value::r#struct(Struct::Tuple {
name: name.inner,
fields: fields
.into_iter()
.map(|node| {
let position = node.position;
if let Some(value) = self.run_statement(node)? {
Ok(value)
} else {
Err(VmError::ExpectedValue { position })
}
})
.collect::<Result<Vec<Value>, VmError>>()?,
})))
}
},
Statement::UnaryOperation { operator, operand } => { Statement::UnaryOperation { operator, operand } => {
let position = operand.position; let position = operand.position;
let value = if let Some(value) = self.run_statement(*operand)? { let value = if let Some(value) = self.run_statement(*operand)? {
@ -815,6 +866,19 @@ mod tests {
use super::*; use super::*;
#[test]
fn define_and_instantiate_tuple_struct() {
let input = "struct Foo(int) Foo(42)";
assert_eq!(
run(input),
Ok(Some(Value::r#struct(Struct::Tuple {
name: Identifier::new("Foo"),
fields: vec![Value::integer(42)]
})))
);
}
#[test] #[test]
fn assign_unit_struct_variable() { fn assign_unit_struct_variable() {
let input = " let input = "