Continue adding struct lexing and test
This commit is contained in:
parent
2b8dda14e3
commit
87455ed792
@ -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]";
|
||||
|
@ -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.
|
||||
|
@ -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<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, "}}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user