Add instantiation for tuple structs
This commit is contained in:
parent
049790726a
commit
83aa53b998
@ -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, ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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};
|
||||||
|
@ -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,7 +762,38 @@ 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 {
|
||||||
|
Token::LeftParenthesis => {
|
||||||
|
self.next_token()?;
|
||||||
|
|
||||||
|
let mut arguments = Vec::new();
|
||||||
|
|
||||||
|
while self.current.0 != Token::RightParenthesis {
|
||||||
|
let argument = self.parse_statement(0)?;
|
||||||
|
|
||||||
|
arguments.push(argument);
|
||||||
|
|
||||||
|
if let Token::Comma = self.current.0 {
|
||||||
|
self.next_token()?;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let right_end = self.current.1 .1;
|
||||||
|
|
||||||
|
self.next_token()?;
|
||||||
|
|
||||||
|
Node::new(
|
||||||
|
Statement::Invokation {
|
||||||
|
invokee: Box::new(left),
|
||||||
|
type_arguments: None,
|
||||||
|
value_arguments: Some(arguments),
|
||||||
|
},
|
||||||
|
(left_start, right_end),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Token::LeftSquareBrace => {
|
||||||
let operator_start = self.current.1 .0;
|
let operator_start = self.current.1 .0;
|
||||||
|
|
||||||
self.next_token()?;
|
self.next_token()?;
|
||||||
@ -788,22 +819,28 @@ impl<'src> Parser<'src> {
|
|||||||
Node::new(
|
Node::new(
|
||||||
Statement::BinaryOperation {
|
Statement::BinaryOperation {
|
||||||
left: Box::new(left),
|
left: Box::new(left),
|
||||||
operator: Node::new(BinaryOperator::ListIndex, (operator_start, operator_end)),
|
operator: Node::new(
|
||||||
|
BinaryOperator::ListIndex,
|
||||||
|
(operator_start, operator_end),
|
||||||
|
),
|
||||||
right: Box::new(index),
|
right: Box::new(index),
|
||||||
},
|
},
|
||||||
(left_start, right_end),
|
(left_start, right_end),
|
||||||
)
|
)
|
||||||
} else if let Token::Semicolon = &self.current.0 {
|
}
|
||||||
|
Token::Semicolon => {
|
||||||
let operator_end = self.current.1 .1;
|
let operator_end = self.current.1 .1;
|
||||||
|
|
||||||
self.next_token()?;
|
self.next_token()?;
|
||||||
|
|
||||||
Node::new(Statement::Nil(Box::new(left)), (left_start, operator_end))
|
Node::new(Statement::Nil(Box::new(left)), (left_start, operator_end))
|
||||||
} else {
|
}
|
||||||
|
_ => {
|
||||||
return Err(ParseError::UnexpectedToken {
|
return Err(ParseError::UnexpectedToken {
|
||||||
actual: self.current.0.to_owned(),
|
actual: self.current.0.to_owned(),
|
||||||
position: self.current.1,
|
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)";
|
||||||
|
@ -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
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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, ", ")?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 = "
|
||||||
|
Loading…
Reference in New Issue
Block a user