From 87455ed79277188cb409ae2bfa2ddfabca891615 Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 13 Aug 2024 13:28:22 -0400 Subject: [PATCH] Continue adding struct lexing and test --- dust-lang/src/lexer.rs | 56 +++++++++++++++++++++++++++++ dust-lang/src/token.rs | 49 +------------------------- dust-lang/src/type.rs | 80 ++++++++++++++++++++++++++++-------------- dust-lang/src/value.rs | 4 +++ 4 files changed, 114 insertions(+), 75 deletions(-) diff --git a/dust-lang/src/lexer.rs b/dust-lang/src/lexer.rs index f63d3da..fae4a07 100644 --- a/dust-lang/src/lexer.rs +++ b/dust-lang/src/lexer.rs @@ -499,6 +499,62 @@ impl Display for LexError { mod tests { use super::*; + #[test] + fn unit_struct() { + let input = "struct Foo"; + + assert_eq!( + lex(input), + Ok(vec![ + (Token::Struct, (0, 6)), + (Token::Identifier("Foo"), (7, 10)), + (Token::Eof, (10, 10)), + ]) + ); + } + + #[test] + fn tuple_struct() { + let input = "struct Foo(int, float)"; + + assert_eq!( + lex(input), + Ok(vec![ + (Token::Struct, (0, 6)), + (Token::Identifier("Foo"), (7, 10)), + (Token::LeftParenthesis, (10, 11)), + (Token::Int, (11, 14)), + (Token::Comma, (14, 15)), + (Token::FloatKeyword, (16, 21)), + (Token::RightParenthesis, (21, 22)), + (Token::Eof, (22, 22)) + ]) + ); + } + + #[test] + fn fields_struct() { + let input = "struct FooBar { foo: int, bar: float }"; + + assert_eq!( + lex(input), + Ok(vec![ + (Token::Struct, (0, 6)), + (Token::Identifier("FooBar"), (7, 13)), + (Token::LeftCurlyBrace, (14, 15)), + (Token::Identifier("foo"), (16, 19)), + (Token::Colon, (19, 20)), + (Token::Int, (21, 24)), + (Token::Comma, (24, 25)), + (Token::Identifier("bar"), (26, 29)), + (Token::Colon, (29, 30)), + (Token::FloatKeyword, (31, 36)), + (Token::RightCurlyBrace, (37, 38)), + (Token::Eof, (38, 38)) + ]) + ); + } + #[test] fn list_index() { let input = "[1, 2, 3][1]"; diff --git a/dust-lang/src/token.rs b/dust-lang/src/token.rs index 0363fec..ceabe91 100644 --- a/dust-lang/src/token.rs +++ b/dust-lang/src/token.rs @@ -4,7 +4,7 @@ use std::fmt::{self, Display, Formatter}; use serde::{Deserialize, Serialize}; /// Source code token. -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, PartialEq)] pub enum Token<'src> { // End of file Eof, @@ -271,53 +271,6 @@ impl<'src> Display for Token<'src> { } } -impl<'src> PartialEq for Token<'src> { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Token::Bang, Token::Bang) => true, - (Token::Boolean(left), Token::Boolean(right)) => left == right, - (Token::Comma, Token::Comma) => true, - (Token::Dot, Token::Dot) => true, - (Token::DoubleAmpersand, Token::DoubleAmpersand) => true, - (Token::DoubleDot, Token::DoubleDot) => true, - (Token::DoubleEqual, Token::DoubleEqual) => true, - (Token::DoublePipe, Token::DoublePipe) => true, - (Token::Else, Token::Else) => true, - (Token::Eof, Token::Eof) => true, - (Token::Equal, Token::Equal) => true, - (Token::Float(left), Token::Float(right)) => left == right, - (Token::Greater, Token::Greater) => true, - (Token::GreaterEqual, Token::GreaterEqual) => true, - (Token::Identifier(left), Token::Identifier(right)) => left == right, - (Token::If, Token::If) => true, - (Token::Integer(left), Token::Integer(right)) => left == right, - (Token::IsEven, Token::IsEven) => true, - (Token::IsOdd, Token::IsOdd) => true, - (Token::LeftCurlyBrace, Token::LeftCurlyBrace) => true, - (Token::LeftParenthesis, Token::LeftParenthesis) => true, - (Token::LeftSquareBrace, Token::LeftSquareBrace) => true, - (Token::Length, Token::Length) => true, - (Token::Less, Token::Less) => true, - (Token::LessEqual, Token::LessEqual) => true, - (Token::Minus, Token::Minus) => true, - (Token::Percent, Token::Percent) => true, - (Token::Plus, Token::Plus) => true, - (Token::PlusEqual, Token::PlusEqual) => true, - (Token::ReadLine, Token::ReadLine) => true, - (Token::RightCurlyBrace, Token::RightCurlyBrace) => true, - (Token::RightParenthesis, Token::RightParenthesis) => true, - (Token::RightSquareBrace, Token::RightSquareBrace) => true, - (Token::Semicolon, Token::Semicolon) => true, - (Token::Star, Token::Star) => true, - (Token::Slash, Token::Slash) => true, - (Token::String(left), Token::String(right)) => left == right, - (Token::While, Token::While) => true, - (Token::WriteLine, Token::WriteLine) => true, - _ => false, - } - } -} - /// Owned version of `Token`, which owns all the strings. /// /// This is used for errors. diff --git a/dust-lang/src/type.rs b/dust-lang/src/type.rs index e222377..f76f60f 100644 --- a/dust-lang/src/type.rs +++ b/dust-lang/src/type.rs @@ -59,10 +59,7 @@ pub enum Type { Number, Range, String, - Structure { - name: Identifier, - fields: Vec<(Identifier, Type)>, - }, + Struct(StructType), } impl Type { @@ -115,28 +112,8 @@ impl Type { } } } - ( - Type::Structure { - name: left_name, - fields: left_fields, - }, - Type::Structure { - name: right_name, - fields: right_fields, - }, - ) => { - if left_name == right_name { - for ((left_field_name, left_type), (right_field_name, right_type)) in - left_fields.iter().zip(right_fields.iter()) - { - if left_field_name != right_field_name || left_type != right_type { - return Err(TypeConflict { - actual: other.clone(), - expected: self.clone(), - }); - } - } - + (Type::Struct(left_struct_type), Type::Struct(right_struct_type)) => { + if left_struct_type == right_struct_type { return Ok(()); } } @@ -357,7 +334,56 @@ impl Display for Type { Ok(()) } } - Type::Structure { name, .. } => write!(f, "{name}"), + Type::Struct(struct_type) => write!(f, "{struct_type}"), + } + } +} + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] +pub enum StructType { + Unit { + name: Identifier, + }, + Tuple { + name: Identifier, + types: Vec, + }, + Fields { + name: Identifier, + fields: Vec<(Identifier, Type)>, + }, +} + +impl Display for StructType { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + match self { + StructType::Unit { name } => write!(f, "struct {name}"), + StructType::Tuple { name, types } => { + write!(f, "struct {name}(")?; + + for (index, r#type) in types.iter().enumerate() { + write!(f, "{type}")?; + + if index != types.len() - 1 { + write!(f, ", ")?; + } + } + + write!(f, ")") + } + StructType::Fields { name, fields } => { + write!(f, "struct {name} {{")?; + + for (index, (identifier, r#type)) in fields.iter().enumerate() { + write!(f, "{identifier}: {type}")?; + + if index != fields.len() - 1 { + write!(f, ", ")?; + } + } + + write!(f, "}}") + } } } } diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index a6d37f8..df546dd 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -88,6 +88,10 @@ impl Value { Value(Arc::new(ValueInner::String(to_string.to_string()))) } + pub fn r#struct(r#struct: Struct) -> Self { + Value(Arc::new(ValueInner::Struct(r#struct))) + } + pub fn r#type(&self) -> Type { self.0.r#type() }