Continue adding struct lexing and test

This commit is contained in:
Jeff 2024-08-13 13:28:22 -04:00
parent 2b8dda14e3
commit 87455ed792
4 changed files with 114 additions and 75 deletions

View File

@ -499,6 +499,62 @@ impl Display for LexError {
mod tests { mod tests {
use super::*; 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] #[test]
fn list_index() { fn list_index() {
let input = "[1, 2, 3][1]"; let input = "[1, 2, 3][1]";

View File

@ -4,7 +4,7 @@ use std::fmt::{self, Display, Formatter};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// Source code token. /// Source code token.
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize, PartialEq)]
pub enum Token<'src> { pub enum Token<'src> {
// End of file // End of file
Eof, 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. /// Owned version of `Token`, which owns all the strings.
/// ///
/// This is used for errors. /// This is used for errors.

View File

@ -59,10 +59,7 @@ pub enum Type {
Number, Number,
Range, Range,
String, String,
Structure { Struct(StructType),
name: Identifier,
fields: Vec<(Identifier, Type)>,
},
} }
impl Type { impl Type {
@ -115,28 +112,8 @@ impl Type {
} }
} }
} }
( (Type::Struct(left_struct_type), Type::Struct(right_struct_type)) => {
Type::Structure { if left_struct_type == right_struct_type {
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(),
});
}
}
return Ok(()); return Ok(());
} }
} }
@ -357,7 +334,56 @@ impl Display for Type {
Ok(()) 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<Type>,
},
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, "}}")
}
} }
} }
} }

View File

@ -88,6 +88,10 @@ impl Value {
Value(Arc::new(ValueInner::String(to_string.to_string()))) 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 { pub fn r#type(&self) -> Type {
self.0.r#type() self.0.r#type()
} }