Add parsing for tuple structs
This commit is contained in:
parent
1d75bd6594
commit
049790726a
@ -442,13 +442,32 @@ pub enum UnaryOperator {
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum StructDefinition {
|
||||
Unit { name: Node<Identifier> },
|
||||
Unit {
|
||||
name: Node<Identifier>,
|
||||
},
|
||||
Tuple {
|
||||
name: Node<Identifier>,
|
||||
fields: Vec<Node<Type>>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Display for StructDefinition {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
StructDefinition::Unit { name } => write!(f, "struct {name}"),
|
||||
StructDefinition::Tuple { name, fields } => {
|
||||
write!(f, "struct {name} {{")?;
|
||||
|
||||
for (i, field) in fields.iter().enumerate() {
|
||||
if i > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
|
||||
write!(f, "{field}")?;
|
||||
}
|
||||
|
||||
write!(f, "}}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -429,6 +429,9 @@ impl<'a> Analyzer<'a> {
|
||||
name: name.inner.clone(),
|
||||
}),
|
||||
),
|
||||
StructDefinition::Tuple { name, fields } => {
|
||||
todo!()
|
||||
}
|
||||
};
|
||||
|
||||
self.context.set_type(name, r#type, node.position);
|
||||
|
@ -13,7 +13,8 @@ use std::{
|
||||
|
||||
use crate::{
|
||||
AbstractSyntaxTree, BinaryOperator, BuiltInFunction, DustError, Identifier, LexError, Lexer,
|
||||
Node, Span, Statement, StructDefinition, Token, TokenKind, TokenOwned, UnaryOperator, Value,
|
||||
Node, Span, Statement, StructDefinition, Token, TokenKind, TokenOwned, Type, UnaryOperator,
|
||||
Value,
|
||||
};
|
||||
|
||||
/// Parses the input into an abstract syntax tree.
|
||||
@ -575,16 +576,50 @@ impl<'src> Parser<'src> {
|
||||
(Token::Struct, left_position) => {
|
||||
self.next_token()?;
|
||||
|
||||
if let Token::Identifier(_) = self.current.0 {
|
||||
let name = self.parse_identifier()?;
|
||||
let name_end = name.position.1;
|
||||
let (name, name_end) = if let Token::Identifier(_) = self.current.0 {
|
||||
let position = self.current.1 .1;
|
||||
|
||||
(self.parse_identifier()?, position)
|
||||
} else {
|
||||
return Err(ParseError::ExpectedToken {
|
||||
expected: TokenKind::Identifier,
|
||||
actual: self.current.0.to_owned(),
|
||||
position: self.current.1,
|
||||
});
|
||||
};
|
||||
|
||||
if let Token::LeftParenthesis = self.current.0 {
|
||||
self.next_token()?;
|
||||
|
||||
let mut types = Vec::new();
|
||||
|
||||
loop {
|
||||
if let (Token::RightParenthesis, right_position) = self.current {
|
||||
self.next_token()?;
|
||||
|
||||
return Ok(Node::new(
|
||||
Statement::StructDefinition(StructDefinition::Tuple {
|
||||
name,
|
||||
fields: types,
|
||||
}),
|
||||
(left_position.0, right_position.1),
|
||||
));
|
||||
}
|
||||
|
||||
if let (Token::Comma, _) = self.current {
|
||||
self.next_token()?;
|
||||
continue;
|
||||
}
|
||||
|
||||
let type_node = self.parse_type()?;
|
||||
|
||||
types.push(type_node);
|
||||
}
|
||||
} else {
|
||||
Ok(Node::new(
|
||||
Statement::StructDefinition(StructDefinition::Unit { name }),
|
||||
(left_position.0, name_end),
|
||||
))
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
(Token::While, left_position) => {
|
||||
@ -826,6 +861,26 @@ impl<'src> Parser<'src> {
|
||||
statements.push(statement);
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_type(&mut self) -> Result<Node<Type>, ParseError> {
|
||||
let r#type = match self.current.0 {
|
||||
Token::Bool => Type::Boolean,
|
||||
Token::FloatKeyword => Type::Float,
|
||||
Token::Int => Type::Integer,
|
||||
_ => {
|
||||
return Err(ParseError::ExpectedTokenMultiple {
|
||||
expected: vec![TokenKind::Bool, TokenKind::FloatKeyword, TokenKind::Int],
|
||||
actual: self.current.0.to_owned(),
|
||||
position: self.current.1,
|
||||
});
|
||||
}
|
||||
};
|
||||
let position = self.current.1;
|
||||
|
||||
self.next_token()?;
|
||||
|
||||
Ok(Node::new(r#type, position))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
@ -847,6 +902,11 @@ pub enum ParseError {
|
||||
actual: TokenOwned,
|
||||
position: Span,
|
||||
},
|
||||
ExpectedTokenMultiple {
|
||||
expected: Vec<TokenKind>,
|
||||
actual: TokenOwned,
|
||||
position: Span,
|
||||
},
|
||||
UnexpectedToken {
|
||||
actual: TokenOwned,
|
||||
position: Span,
|
||||
@ -874,6 +934,7 @@ impl ParseError {
|
||||
ParseError::ExpectedAssignment { actual } => actual.position,
|
||||
ParseError::ExpectedIdentifier { position, .. } => *position,
|
||||
ParseError::ExpectedToken { position, .. } => *position,
|
||||
ParseError::ExpectedTokenMultiple { position, .. } => *position,
|
||||
ParseError::FloatError { position, .. } => *position,
|
||||
ParseError::IntegerError { position, .. } => *position,
|
||||
ParseError::LexError(error) => error.position(),
|
||||
@ -902,6 +963,23 @@ impl Display for ParseError {
|
||||
Self::ExpectedToken {
|
||||
expected, actual, ..
|
||||
} => write!(f, "Expected token {expected}, found {actual}"),
|
||||
Self::ExpectedTokenMultiple {
|
||||
expected, actual, ..
|
||||
} => {
|
||||
write!(f, "Expected one of")?;
|
||||
|
||||
for (i, token_kind) in expected.iter().enumerate() {
|
||||
if i == 0 {
|
||||
write!(f, " {token_kind}")?;
|
||||
} else if i == expected.len() - 1 {
|
||||
write!(f, " or {token_kind}")?;
|
||||
} else {
|
||||
write!(f, ", {token_kind}")?;
|
||||
}
|
||||
}
|
||||
|
||||
write!(f, ", found {actual}")
|
||||
}
|
||||
Self::FloatError { error, .. } => write!(f, "{}", error),
|
||||
Self::IntegerError { error, .. } => write!(f, "{}", error),
|
||||
Self::LexError(error) => write!(f, "{}", error),
|
||||
@ -912,10 +990,32 @@ impl Display for ParseError {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{BinaryOperator, Identifier, StructDefinition, UnaryOperator};
|
||||
use crate::{BinaryOperator, Identifier, StructDefinition, Type, UnaryOperator};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn tuple_struct() {
|
||||
let input = "struct Foo(int, float)";
|
||||
|
||||
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)
|
||||
)]
|
||||
.into()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unit_struct() {
|
||||
let input = "struct Foo";
|
||||
|
@ -14,7 +14,7 @@ use serde::{
|
||||
Deserialize, Deserializer, Serialize,
|
||||
};
|
||||
|
||||
use crate::{identifier::Identifier, AbstractSyntaxTree, Context, StructType, Type, Vm, VmError};
|
||||
use crate::{AbstractSyntaxTree, Context, Identifier, StructType, Type, Vm, VmError};
|
||||
|
||||
/// Dust value representation
|
||||
///
|
||||
|
@ -592,6 +592,9 @@ impl Vm {
|
||||
name: name.inner.clone(),
|
||||
}),
|
||||
),
|
||||
StructDefinition::Tuple { name, fields } => {
|
||||
todo!()
|
||||
}
|
||||
};
|
||||
|
||||
self.context.set_type(type_name, r#type, node.position);
|
||||
@ -812,6 +815,22 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn assign_unit_struct_variable() {
|
||||
let input = "
|
||||
struct Foo
|
||||
x = Foo
|
||||
x
|
||||
";
|
||||
|
||||
assert_eq!(
|
||||
run(input),
|
||||
Ok(Some(Value::r#struct(Struct::Unit {
|
||||
name: Identifier::new("Foo")
|
||||
})))
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn define_and_instantiate_unit_struct() {
|
||||
let input = "struct Foo Foo";
|
||||
|
Loading…
Reference in New Issue
Block a user