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 {
|
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]";
|
||||||
|
@ -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.
|
||||||
|
@ -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, "}}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user