Implement "let" and "let mut" lexing/parsing
This commit is contained in:
parent
84429ef187
commit
fedefdb29f
@ -10,7 +10,7 @@ use super::{Expression, Node};
|
||||
pub enum Statement {
|
||||
Expression(Expression),
|
||||
ExpressionNullified(Node<Expression>),
|
||||
Let(Node<Let>),
|
||||
Let(Node<LetStatement>),
|
||||
StructDefinition(Node<StructDefinition>),
|
||||
}
|
||||
|
||||
@ -52,14 +52,51 @@ impl Display for Statement {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct Let {
|
||||
pub identifier: Node<Identifier>,
|
||||
pub value: Node<Expression>,
|
||||
pub enum LetStatement {
|
||||
Let {
|
||||
identifier: Node<Identifier>,
|
||||
value: Expression,
|
||||
},
|
||||
LetMut {
|
||||
identifier: Node<Identifier>,
|
||||
value: Expression,
|
||||
},
|
||||
LetType {
|
||||
identifier: Node<Identifier>,
|
||||
r#type: Node<Type>,
|
||||
value: Expression,
|
||||
},
|
||||
LetMutType {
|
||||
identifier: Node<Identifier>,
|
||||
r#type: Node<Type>,
|
||||
value: Expression,
|
||||
},
|
||||
}
|
||||
|
||||
impl Display for Let {
|
||||
impl Display for LetStatement {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "let {} = {}", self.identifier, self.value)
|
||||
match self {
|
||||
LetStatement::Let { identifier, value } => {
|
||||
write!(f, "let {identifier} = {value}")
|
||||
}
|
||||
LetStatement::LetMut { identifier, value } => {
|
||||
write!(f, "let mut {identifier} = {value}")
|
||||
}
|
||||
LetStatement::LetType {
|
||||
identifier,
|
||||
r#type,
|
||||
value,
|
||||
} => {
|
||||
write!(f, "let {identifier}: {type} = {value}")
|
||||
}
|
||||
LetStatement::LetMutType {
|
||||
identifier,
|
||||
r#type,
|
||||
value,
|
||||
} => {
|
||||
write!(f, "let mut {identifier}: {type} = {value}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -429,6 +429,7 @@ impl Lexer {
|
||||
"is_even" => Token::IsEven,
|
||||
"is_odd" => Token::IsOdd,
|
||||
"length" => Token::Length,
|
||||
"let" => Token::Let,
|
||||
"mut" => Token::Mut,
|
||||
"read_line" => Token::ReadLine,
|
||||
"struct" => Token::Struct,
|
||||
@ -507,6 +508,22 @@ impl Display for LexError {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn let_statement() {
|
||||
let input = "let x = 42";
|
||||
|
||||
assert_eq!(
|
||||
lex(input),
|
||||
Ok(vec![
|
||||
(Token::Let, (0, 3)),
|
||||
(Token::Identifier("x"), (4, 5)),
|
||||
(Token::Equal, (6, 7)),
|
||||
(Token::Integer("42"), (8, 10)),
|
||||
(Token::Eof, (10, 10)),
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unit_struct() {
|
||||
let input = "struct Foo";
|
||||
|
@ -145,6 +145,41 @@ impl<'src> Parser<'src> {
|
||||
pub fn parse_statement(&mut self) -> Result<Statement, ParseError> {
|
||||
let start_position = self.current_position;
|
||||
|
||||
if let Token::Let = self.current_token {
|
||||
self.next_token()?;
|
||||
|
||||
let is_mutable = if let Token::Mut = self.current_token {
|
||||
self.next_token()?;
|
||||
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let identifier = self.parse_identifier()?;
|
||||
|
||||
if let Token::Equal = self.current_token {
|
||||
self.next_token()?;
|
||||
} else {
|
||||
return Err(ParseError::ExpectedToken {
|
||||
expected: TokenKind::Equal,
|
||||
actual: self.current_token.to_owned(),
|
||||
position: self.current_position,
|
||||
});
|
||||
}
|
||||
|
||||
let value = self.parse_expression(0)?;
|
||||
|
||||
let r#let = if is_mutable {
|
||||
LetStatement::LetMut { identifier, value }
|
||||
} else {
|
||||
LetStatement::Let { identifier, value }
|
||||
};
|
||||
let position = (start_position.0, self.current_position.1);
|
||||
|
||||
return Ok(Statement::Let(Node::new(r#let, position)));
|
||||
}
|
||||
|
||||
if let Token::Struct = self.current_token {
|
||||
self.next_token()?;
|
||||
|
||||
@ -1026,10 +1061,41 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn mutable_variable() {
|
||||
let source = "mut x = false";
|
||||
fn let_statement() {
|
||||
let source = "let x = 42";
|
||||
|
||||
assert_eq!(parse(source), todo!());
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree {
|
||||
statements: [Statement::Let(Node::new(
|
||||
LetStatement::Let {
|
||||
identifier: Node::new(Identifier::new("x"), (4, 5)),
|
||||
value: Expression::literal(LiteralExpression::Integer(42), (8, 10)),
|
||||
},
|
||||
(0, 10),
|
||||
))]
|
||||
.into()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn let_mut_statement() {
|
||||
let source = "let mut x = false";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(AbstractSyntaxTree {
|
||||
statements: [Statement::Let(Node::new(
|
||||
LetStatement::LetMut {
|
||||
identifier: Node::new(Identifier::new("x"), (8, 9)),
|
||||
value: Expression::literal(LiteralExpression::Boolean(false), (12, 17)),
|
||||
},
|
||||
(0, 17),
|
||||
))]
|
||||
.into()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -26,6 +26,7 @@ pub enum Token<'src> {
|
||||
IsEven,
|
||||
IsOdd,
|
||||
Length,
|
||||
Let,
|
||||
Mut,
|
||||
ReadLine,
|
||||
Str,
|
||||
@ -97,6 +98,7 @@ impl<'src> Token<'src> {
|
||||
Token::LeftParenthesis => TokenOwned::LeftParenthesis,
|
||||
Token::LeftSquareBrace => TokenOwned::LeftSquareBrace,
|
||||
Token::Length => TokenOwned::Length,
|
||||
Token::Let => TokenOwned::Let,
|
||||
Token::Less => TokenOwned::Less,
|
||||
Token::LessEqual => TokenOwned::LessOrEqual,
|
||||
Token::Minus => TokenOwned::Minus,
|
||||
@ -153,6 +155,7 @@ impl<'src> Token<'src> {
|
||||
Token::LeftCurlyBrace => "{",
|
||||
Token::LeftParenthesis => "(",
|
||||
Token::LeftSquareBrace => "[",
|
||||
Token::Let => "let",
|
||||
Token::Length => "length",
|
||||
Token::Less => "<",
|
||||
Token::LessEqual => "<=",
|
||||
@ -207,6 +210,7 @@ impl<'src> Token<'src> {
|
||||
Token::LeftCurlyBrace => TokenKind::LeftCurlyBrace,
|
||||
Token::LeftParenthesis => TokenKind::LeftParenthesis,
|
||||
Token::LeftSquareBrace => TokenKind::LeftSquareBrace,
|
||||
Token::Let => TokenKind::Let,
|
||||
Token::Length => TokenKind::Length,
|
||||
Token::Less => TokenKind::Less,
|
||||
Token::LessEqual => TokenKind::LessOrEqual,
|
||||
@ -314,6 +318,7 @@ pub enum TokenOwned {
|
||||
Int,
|
||||
IsEven,
|
||||
IsOdd,
|
||||
Let,
|
||||
Length,
|
||||
Mut,
|
||||
ReadLine,
|
||||
@ -387,6 +392,7 @@ impl Display for TokenOwned {
|
||||
TokenOwned::LeftParenthesis => Token::LeftParenthesis.fmt(f),
|
||||
TokenOwned::LeftSquareBrace => Token::LeftSquareBrace.fmt(f),
|
||||
TokenOwned::Length => Token::Length.fmt(f),
|
||||
TokenOwned::Let => Token::Let.fmt(f),
|
||||
TokenOwned::Less => Token::Less.fmt(f),
|
||||
TokenOwned::LessOrEqual => Token::LessEqual.fmt(f),
|
||||
TokenOwned::Minus => Token::Minus.fmt(f),
|
||||
@ -435,6 +441,7 @@ pub enum TokenKind {
|
||||
IsEven,
|
||||
IsOdd,
|
||||
Length,
|
||||
Let,
|
||||
ReadLine,
|
||||
Str,
|
||||
ToString,
|
||||
@ -506,6 +513,7 @@ impl Display for TokenKind {
|
||||
TokenKind::LeftParenthesis => Token::LeftParenthesis.fmt(f),
|
||||
TokenKind::LeftSquareBrace => Token::LeftSquareBrace.fmt(f),
|
||||
TokenKind::Length => Token::Length.fmt(f),
|
||||
TokenKind::Let => Token::Let.fmt(f),
|
||||
TokenKind::Less => Token::Less.fmt(f),
|
||||
TokenKind::LessOrEqual => Token::LessEqual.fmt(f),
|
||||
TokenKind::Minus => Token::Minus.fmt(f),
|
||||
@ -535,13 +543,31 @@ impl Display for TokenKind {
|
||||
pub(crate) mod tests {
|
||||
use super::*;
|
||||
|
||||
pub fn all_tokens<'src>() -> [Token<'src>; 49] {
|
||||
pub fn all_tokens<'src>() -> [Token<'src>; 51] {
|
||||
[
|
||||
Token::Async,
|
||||
Token::Bang,
|
||||
Token::BangEqual,
|
||||
Token::Bool,
|
||||
Token::Eof,
|
||||
Token::Identifier("identifier"),
|
||||
Token::Boolean("true"),
|
||||
Token::Float("1.0"),
|
||||
Token::Integer("1"),
|
||||
Token::String("string"),
|
||||
Token::Async,
|
||||
Token::Bool,
|
||||
Token::Else,
|
||||
Token::FloatKeyword,
|
||||
Token::If,
|
||||
Token::Int,
|
||||
Token::IsEven,
|
||||
Token::IsOdd,
|
||||
Token::Length,
|
||||
Token::Let,
|
||||
Token::ReadLine,
|
||||
Token::Str,
|
||||
Token::ToString,
|
||||
Token::While,
|
||||
Token::WriteLine,
|
||||
Token::BangEqual,
|
||||
Token::Bang,
|
||||
Token::Colon,
|
||||
Token::Comma,
|
||||
Token::Dot,
|
||||
@ -549,23 +575,12 @@ pub(crate) mod tests {
|
||||
Token::DoubleDot,
|
||||
Token::DoubleEqual,
|
||||
Token::DoublePipe,
|
||||
Token::Else,
|
||||
Token::Eof,
|
||||
Token::Equal,
|
||||
Token::Float("0.0"),
|
||||
Token::FloatKeyword,
|
||||
Token::Greater,
|
||||
Token::GreaterEqual,
|
||||
Token::Identifier(""),
|
||||
Token::If,
|
||||
Token::Int,
|
||||
Token::Integer("0"),
|
||||
Token::IsEven,
|
||||
Token::IsOdd,
|
||||
Token::LeftCurlyBrace,
|
||||
Token::LeftParenthesis,
|
||||
Token::LeftSquareBrace,
|
||||
Token::Length,
|
||||
Token::Less,
|
||||
Token::LessEqual,
|
||||
Token::Minus,
|
||||
@ -574,18 +589,13 @@ pub(crate) mod tests {
|
||||
Token::Percent,
|
||||
Token::Plus,
|
||||
Token::PlusEqual,
|
||||
Token::ReadLine,
|
||||
Token::RightCurlyBrace,
|
||||
Token::RightParenthesis,
|
||||
Token::RightSquareBrace,
|
||||
Token::Semicolon,
|
||||
Token::Star,
|
||||
Token::Str,
|
||||
Token::String(""),
|
||||
Token::Struct,
|
||||
Token::ToString,
|
||||
Token::While,
|
||||
Token::WriteLine,
|
||||
Token::Slash,
|
||||
]
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user