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 {
|
pub enum Statement {
|
||||||
Expression(Expression),
|
Expression(Expression),
|
||||||
ExpressionNullified(Node<Expression>),
|
ExpressionNullified(Node<Expression>),
|
||||||
Let(Node<Let>),
|
Let(Node<LetStatement>),
|
||||||
StructDefinition(Node<StructDefinition>),
|
StructDefinition(Node<StructDefinition>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,14 +52,51 @@ impl Display for Statement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub struct Let {
|
pub enum LetStatement {
|
||||||
pub identifier: Node<Identifier>,
|
Let {
|
||||||
pub value: Node<Expression>,
|
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 {
|
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_even" => Token::IsEven,
|
||||||
"is_odd" => Token::IsOdd,
|
"is_odd" => Token::IsOdd,
|
||||||
"length" => Token::Length,
|
"length" => Token::Length,
|
||||||
|
"let" => Token::Let,
|
||||||
"mut" => Token::Mut,
|
"mut" => Token::Mut,
|
||||||
"read_line" => Token::ReadLine,
|
"read_line" => Token::ReadLine,
|
||||||
"struct" => Token::Struct,
|
"struct" => Token::Struct,
|
||||||
@ -507,6 +508,22 @@ impl Display for LexError {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
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]
|
#[test]
|
||||||
fn unit_struct() {
|
fn unit_struct() {
|
||||||
let input = "struct Foo";
|
let input = "struct Foo";
|
||||||
|
@ -145,6 +145,41 @@ impl<'src> Parser<'src> {
|
|||||||
pub fn parse_statement(&mut self) -> Result<Statement, ParseError> {
|
pub fn parse_statement(&mut self) -> Result<Statement, ParseError> {
|
||||||
let start_position = self.current_position;
|
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 {
|
if let Token::Struct = self.current_token {
|
||||||
self.next_token()?;
|
self.next_token()?;
|
||||||
|
|
||||||
@ -1026,10 +1061,41 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn mutable_variable() {
|
fn let_statement() {
|
||||||
let source = "mut x = false";
|
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]
|
#[test]
|
||||||
|
@ -26,6 +26,7 @@ pub enum Token<'src> {
|
|||||||
IsEven,
|
IsEven,
|
||||||
IsOdd,
|
IsOdd,
|
||||||
Length,
|
Length,
|
||||||
|
Let,
|
||||||
Mut,
|
Mut,
|
||||||
ReadLine,
|
ReadLine,
|
||||||
Str,
|
Str,
|
||||||
@ -97,6 +98,7 @@ impl<'src> Token<'src> {
|
|||||||
Token::LeftParenthesis => TokenOwned::LeftParenthesis,
|
Token::LeftParenthesis => TokenOwned::LeftParenthesis,
|
||||||
Token::LeftSquareBrace => TokenOwned::LeftSquareBrace,
|
Token::LeftSquareBrace => TokenOwned::LeftSquareBrace,
|
||||||
Token::Length => TokenOwned::Length,
|
Token::Length => TokenOwned::Length,
|
||||||
|
Token::Let => TokenOwned::Let,
|
||||||
Token::Less => TokenOwned::Less,
|
Token::Less => TokenOwned::Less,
|
||||||
Token::LessEqual => TokenOwned::LessOrEqual,
|
Token::LessEqual => TokenOwned::LessOrEqual,
|
||||||
Token::Minus => TokenOwned::Minus,
|
Token::Minus => TokenOwned::Minus,
|
||||||
@ -153,6 +155,7 @@ impl<'src> Token<'src> {
|
|||||||
Token::LeftCurlyBrace => "{",
|
Token::LeftCurlyBrace => "{",
|
||||||
Token::LeftParenthesis => "(",
|
Token::LeftParenthesis => "(",
|
||||||
Token::LeftSquareBrace => "[",
|
Token::LeftSquareBrace => "[",
|
||||||
|
Token::Let => "let",
|
||||||
Token::Length => "length",
|
Token::Length => "length",
|
||||||
Token::Less => "<",
|
Token::Less => "<",
|
||||||
Token::LessEqual => "<=",
|
Token::LessEqual => "<=",
|
||||||
@ -207,6 +210,7 @@ impl<'src> Token<'src> {
|
|||||||
Token::LeftCurlyBrace => TokenKind::LeftCurlyBrace,
|
Token::LeftCurlyBrace => TokenKind::LeftCurlyBrace,
|
||||||
Token::LeftParenthesis => TokenKind::LeftParenthesis,
|
Token::LeftParenthesis => TokenKind::LeftParenthesis,
|
||||||
Token::LeftSquareBrace => TokenKind::LeftSquareBrace,
|
Token::LeftSquareBrace => TokenKind::LeftSquareBrace,
|
||||||
|
Token::Let => TokenKind::Let,
|
||||||
Token::Length => TokenKind::Length,
|
Token::Length => TokenKind::Length,
|
||||||
Token::Less => TokenKind::Less,
|
Token::Less => TokenKind::Less,
|
||||||
Token::LessEqual => TokenKind::LessOrEqual,
|
Token::LessEqual => TokenKind::LessOrEqual,
|
||||||
@ -314,6 +318,7 @@ pub enum TokenOwned {
|
|||||||
Int,
|
Int,
|
||||||
IsEven,
|
IsEven,
|
||||||
IsOdd,
|
IsOdd,
|
||||||
|
Let,
|
||||||
Length,
|
Length,
|
||||||
Mut,
|
Mut,
|
||||||
ReadLine,
|
ReadLine,
|
||||||
@ -387,6 +392,7 @@ impl Display for TokenOwned {
|
|||||||
TokenOwned::LeftParenthesis => Token::LeftParenthesis.fmt(f),
|
TokenOwned::LeftParenthesis => Token::LeftParenthesis.fmt(f),
|
||||||
TokenOwned::LeftSquareBrace => Token::LeftSquareBrace.fmt(f),
|
TokenOwned::LeftSquareBrace => Token::LeftSquareBrace.fmt(f),
|
||||||
TokenOwned::Length => Token::Length.fmt(f),
|
TokenOwned::Length => Token::Length.fmt(f),
|
||||||
|
TokenOwned::Let => Token::Let.fmt(f),
|
||||||
TokenOwned::Less => Token::Less.fmt(f),
|
TokenOwned::Less => Token::Less.fmt(f),
|
||||||
TokenOwned::LessOrEqual => Token::LessEqual.fmt(f),
|
TokenOwned::LessOrEqual => Token::LessEqual.fmt(f),
|
||||||
TokenOwned::Minus => Token::Minus.fmt(f),
|
TokenOwned::Minus => Token::Minus.fmt(f),
|
||||||
@ -435,6 +441,7 @@ pub enum TokenKind {
|
|||||||
IsEven,
|
IsEven,
|
||||||
IsOdd,
|
IsOdd,
|
||||||
Length,
|
Length,
|
||||||
|
Let,
|
||||||
ReadLine,
|
ReadLine,
|
||||||
Str,
|
Str,
|
||||||
ToString,
|
ToString,
|
||||||
@ -506,6 +513,7 @@ impl Display for TokenKind {
|
|||||||
TokenKind::LeftParenthesis => Token::LeftParenthesis.fmt(f),
|
TokenKind::LeftParenthesis => Token::LeftParenthesis.fmt(f),
|
||||||
TokenKind::LeftSquareBrace => Token::LeftSquareBrace.fmt(f),
|
TokenKind::LeftSquareBrace => Token::LeftSquareBrace.fmt(f),
|
||||||
TokenKind::Length => Token::Length.fmt(f),
|
TokenKind::Length => Token::Length.fmt(f),
|
||||||
|
TokenKind::Let => Token::Let.fmt(f),
|
||||||
TokenKind::Less => Token::Less.fmt(f),
|
TokenKind::Less => Token::Less.fmt(f),
|
||||||
TokenKind::LessOrEqual => Token::LessEqual.fmt(f),
|
TokenKind::LessOrEqual => Token::LessEqual.fmt(f),
|
||||||
TokenKind::Minus => Token::Minus.fmt(f),
|
TokenKind::Minus => Token::Minus.fmt(f),
|
||||||
@ -535,13 +543,31 @@ impl Display for TokenKind {
|
|||||||
pub(crate) mod tests {
|
pub(crate) mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub fn all_tokens<'src>() -> [Token<'src>; 49] {
|
pub fn all_tokens<'src>() -> [Token<'src>; 51] {
|
||||||
[
|
[
|
||||||
Token::Async,
|
Token::Eof,
|
||||||
Token::Bang,
|
Token::Identifier("identifier"),
|
||||||
Token::BangEqual,
|
|
||||||
Token::Bool,
|
|
||||||
Token::Boolean("true"),
|
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::Colon,
|
||||||
Token::Comma,
|
Token::Comma,
|
||||||
Token::Dot,
|
Token::Dot,
|
||||||
@ -549,23 +575,12 @@ pub(crate) mod tests {
|
|||||||
Token::DoubleDot,
|
Token::DoubleDot,
|
||||||
Token::DoubleEqual,
|
Token::DoubleEqual,
|
||||||
Token::DoublePipe,
|
Token::DoublePipe,
|
||||||
Token::Else,
|
|
||||||
Token::Eof,
|
|
||||||
Token::Equal,
|
Token::Equal,
|
||||||
Token::Float("0.0"),
|
|
||||||
Token::FloatKeyword,
|
|
||||||
Token::Greater,
|
Token::Greater,
|
||||||
Token::GreaterEqual,
|
Token::GreaterEqual,
|
||||||
Token::Identifier(""),
|
|
||||||
Token::If,
|
|
||||||
Token::Int,
|
|
||||||
Token::Integer("0"),
|
|
||||||
Token::IsEven,
|
|
||||||
Token::IsOdd,
|
|
||||||
Token::LeftCurlyBrace,
|
Token::LeftCurlyBrace,
|
||||||
Token::LeftParenthesis,
|
Token::LeftParenthesis,
|
||||||
Token::LeftSquareBrace,
|
Token::LeftSquareBrace,
|
||||||
Token::Length,
|
|
||||||
Token::Less,
|
Token::Less,
|
||||||
Token::LessEqual,
|
Token::LessEqual,
|
||||||
Token::Minus,
|
Token::Minus,
|
||||||
@ -574,18 +589,13 @@ pub(crate) mod tests {
|
|||||||
Token::Percent,
|
Token::Percent,
|
||||||
Token::Plus,
|
Token::Plus,
|
||||||
Token::PlusEqual,
|
Token::PlusEqual,
|
||||||
Token::ReadLine,
|
|
||||||
Token::RightCurlyBrace,
|
Token::RightCurlyBrace,
|
||||||
Token::RightParenthesis,
|
Token::RightParenthesis,
|
||||||
Token::RightSquareBrace,
|
Token::RightSquareBrace,
|
||||||
Token::Semicolon,
|
Token::Semicolon,
|
||||||
Token::Star,
|
Token::Star,
|
||||||
Token::Str,
|
|
||||||
Token::String(""),
|
|
||||||
Token::Struct,
|
Token::Struct,
|
||||||
Token::ToString,
|
Token::Slash,
|
||||||
Token::While,
|
|
||||||
Token::WriteLine,
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user