parse booleans and heavy refactoring

This commit is contained in:
Victor Timofei 2023-09-10 02:03:38 +03:00
parent 9717bb3837
commit d84878c323
Signed by: vtimofei
GPG Key ID: B790DCEBE281403A
5 changed files with 369 additions and 161 deletions

View File

@ -2,7 +2,3 @@
name = "monkeyrs" name = "monkeyrs"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -3,19 +3,122 @@ use std::{
rc::Rc, rc::Rc,
}; };
use crate::token::{Token, TokenType}; use crate::token::TokenType;
pub trait Node: Debug {} #[derive(Debug, PartialEq, Eq)]
pub enum NodeType {
Program,
LetStatement,
ReturnStatement,
ExpressionStatement,
IdentifierExpression,
IntegerLiteralExpression,
PrefixExpression,
InfixExpression,
BooleanExpression,
DummyExpression,
}
#[macro_export]
macro_rules! node_type_eq {
( $x:expr, $y:expr ) => {{
if $x.node_type() != $y.node_type() {
false
} else {
match $x.node_type() {
NodeType::Program => unreachable!(),
NodeType::DummyExpression => true,
NodeType::BooleanExpression => {
let __x = unsafe { $x.downcast::<Boolean>() };
let __y = unsafe { $y.downcast::<Boolean>() };
__x == __y
}
NodeType::ExpressionStatement => {
let __x = unsafe { $x.downcast::<ExpressionStatement>() };
let __y = unsafe { $y.downcast::<ExpressionStatement>() };
__x == __y
}
NodeType::LetStatement => {
let __x = unsafe { $x.downcast::<Let>() };
let __y = unsafe { $y.downcast::<Let>() };
__x == __y
}
NodeType::ReturnStatement => {
let __x = unsafe { $x.downcast::<Return>() };
let __y = unsafe { $y.downcast::<Return>() };
__x == __y
}
NodeType::InfixExpression => {
let __x = unsafe { $x.downcast::<Infix>() };
let __y = unsafe { $y.downcast::<Infix>() };
__x == __y
}
NodeType::PrefixExpression => {
let __x = unsafe { $x.downcast::<Prefix>() };
let __y = unsafe { $y.downcast::<Prefix>() };
__x == __y
}
NodeType::IdentifierExpression => {
let __x = unsafe { $x.downcast::<Identifier>() };
let __y = unsafe { $y.downcast::<Identifier>() };
__x == __y
}
NodeType::IntegerLiteralExpression => {
let __x = unsafe { $x.downcast::<IntegerLiteral>() };
let __y = unsafe { $y.downcast::<IntegerLiteral>() };
__x == __y
}
}
}
}};
}
pub trait Node: Debug {
fn node_type(&self) -> NodeType;
}
pub trait Statement: Node {} pub trait Statement: Node {}
impl dyn Statement {
unsafe fn downcast<T>(&self) -> &T {
&*(self as *const dyn Statement as *const T)
}
}
pub trait Expression: Node {} pub trait Expression: Node {}
impl dyn Expression {
unsafe fn downcast<T>(&self) -> &T {
&*(self as *const dyn Expression as *const T)
}
}
pub struct Program { pub struct Program {
pub statements: Vec<Rc<dyn Statement>>, pub statements: Vec<Rc<dyn Statement>>,
} }
impl Node for Program {} impl PartialEq for Program {
fn eq(&self, other: &Self) -> bool {
if self.statements.len() != other.statements.len() {
return false;
}
let mut other_iter = other.statements.iter();
for stmt in self.statements.iter() {
let other = other_iter.next().unwrap();
if !node_type_eq!(stmt, other) {
return false;
}
}
true
}
}
impl Node for Program {
fn node_type(&self) -> NodeType {
NodeType::Program
}
}
impl Debug for Program { impl Debug for Program {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
@ -33,56 +136,97 @@ impl Debug for Program {
#[derive(Debug)] #[derive(Debug)]
pub struct Let { pub struct Let {
pub token: Token,
pub name: Identifier, pub name: Identifier,
pub value: Rc<dyn Expression>, pub value: Rc<dyn Expression>,
} }
impl Node for Let {} impl PartialEq for Let {
fn eq(&self, other: &Self) -> bool {
if self.name != other.name {
return false;
}
node_type_eq!(self.value, other.value)
}
}
impl Node for Let {
fn node_type(&self) -> NodeType {
NodeType::LetStatement
}
}
impl Statement for Let {} impl Statement for Let {}
#[derive(Debug)] #[derive(Debug)]
pub struct Return { pub struct Return {
pub token: Token,
pub value: Rc<dyn Expression>, pub value: Rc<dyn Expression>,
} }
impl PartialEq for Return {
fn eq(&self, other: &Self) -> bool {
node_type_eq!(self.value, other.value)
}
}
impl Node for Return {
fn node_type(&self) -> NodeType {
NodeType::ReturnStatement
}
}
impl Statement for Return {} impl Statement for Return {}
impl Node for Return {}
#[derive(Debug)] #[derive(Debug)]
pub struct ExpressionStatement { pub struct ExpressionStatement {
// TODO: probably not needed
pub token: Token,
pub expression: Rc<dyn Expression>, pub expression: Rc<dyn Expression>,
} }
impl PartialEq for ExpressionStatement {
fn eq(&self, other: &Self) -> bool {
let expr = &self.expression;
let other = &other.expression;
node_type_eq!(expr, other)
}
}
impl Node for ExpressionStatement {
fn node_type(&self) -> NodeType {
NodeType::ExpressionStatement
}
}
impl Statement for ExpressionStatement {} impl Statement for ExpressionStatement {}
impl Node for ExpressionStatement {} #[derive(Debug, PartialEq, Eq)]
#[derive(Debug)]
pub struct Identifier { pub struct Identifier {
pub token_type: TokenType, pub token_type: TokenType,
pub value: String, pub value: String,
} }
impl Node for Identifier {} impl Node for Identifier {
fn node_type(&self) -> NodeType {
NodeType::IdentifierExpression
}
}
impl Expression for Identifier {} impl Expression for Identifier {}
#[derive(Debug)] #[derive(Debug, PartialEq, Eq)]
pub struct IntegerLiteral { pub struct IntegerLiteral {
pub value: i64, pub value: i64,
} }
impl Node for IntegerLiteral {} impl Node for IntegerLiteral {
fn node_type(&self) -> NodeType {
NodeType::IntegerLiteralExpression
}
}
impl Expression for IntegerLiteral {} impl Expression for IntegerLiteral {}
#[derive(Debug)] #[derive(Debug, PartialEq, Eq)]
pub enum PrefixOperator { pub enum PrefixOperator {
Minus, Minus,
Bang, Bang,
@ -105,11 +249,25 @@ pub struct Prefix {
pub right: Rc<dyn Expression>, pub right: Rc<dyn Expression>,
} }
impl Node for Prefix {} impl PartialEq for Prefix {
fn eq(&self, other: &Self) -> bool {
if self.operator != other.operator {
return false;
}
println!("Prefix PartialEq");
node_type_eq!(self.right, other.right)
}
}
impl Node for Prefix {
fn node_type(&self) -> NodeType {
NodeType::PrefixExpression
}
}
impl Expression for Prefix {} impl Expression for Prefix {}
#[derive(Debug)] #[derive(Debug, PartialEq, Eq)]
pub enum InfixOperator { pub enum InfixOperator {
Plus, Plus,
Minus, Minus,
@ -168,13 +326,42 @@ pub struct Infix {
pub right: Rc<dyn Expression>, pub right: Rc<dyn Expression>,
} }
impl Node for Infix {} impl PartialEq for Infix {
fn eq(&self, other: &Self) -> bool {
self.operator == other.operator
&& node_type_eq!(self.left, other.left)
&& node_type_eq!(self.right, other.right)
}
}
impl Node for Infix {
fn node_type(&self) -> NodeType {
NodeType::InfixExpression
}
}
impl Expression for Infix {} impl Expression for Infix {}
#[derive(Debug, PartialEq, Eq)]
pub struct Boolean {
pub value: bool,
}
impl Node for Boolean {
fn node_type(&self) -> NodeType {
NodeType::BooleanExpression
}
}
impl Expression for Boolean {}
#[derive(Debug)] #[derive(Debug)]
pub struct DummyExpression {} pub struct DummyExpression {}
impl Node for DummyExpression {} impl Node for DummyExpression {
fn node_type(&self) -> NodeType {
NodeType::DummyExpression
}
}
impl Expression for DummyExpression {} impl Expression for DummyExpression {}

View File

@ -158,45 +158,45 @@ mod tests {
10 == 10; 10 == 10;
10 != 9; 10 != 9;
" "
.to_string(); .into();
use Token::*; use Token::*;
let tests = vec![ let tests = vec![
Let, Let,
Ident("five".to_string()), Ident("five".into()),
Assign, Assign,
Int(5), Int(5),
Semicolon, Semicolon,
Let, Let,
Ident("ten".to_string()), Ident("ten".into()),
Assign, Assign,
Int(10), Int(10),
Semicolon, Semicolon,
Let, Let,
Ident("add".to_string()), Ident("add".into()),
Assign, Assign,
Function, Function,
Lparen, Lparen,
Ident("x".to_string()), Ident("x".into()),
Comma, Comma,
Ident("y".to_string()), Ident("y".into()),
Rparen, Rparen,
Lbrace, Lbrace,
Ident("x".to_string()), Ident("x".into()),
Plus, Plus,
Ident("y".to_string()), Ident("y".into()),
Semicolon, Semicolon,
Rbrace, Rbrace,
Semicolon, Semicolon,
Let, Let,
Ident("result".to_string()), Ident("result".into()),
Assign, Assign,
Ident("add".to_string()), Ident("add".into()),
Lparen, Lparen,
Ident("five".to_string()), Ident("five".into()),
Comma, Comma,
Ident("ten".to_string()), Ident("ten".into()),
Rparen, Rparen,
Semicolon, Semicolon,
Bang, Bang,

View File

@ -2,8 +2,8 @@ use std::{fmt, rc::Rc};
use crate::{ use crate::{
ast::{ ast::{
DummyExpression, Expression, ExpressionStatement, Identifier, Infix, InfixOperator, Boolean, DummyExpression, Expression, ExpressionStatement, Identifier, Infix,
IntegerLiteral, Let, Prefix, PrefixOperator, Program, Return, Statement, InfixOperator, IntegerLiteral, Let, Prefix, PrefixOperator, Program, Return, Statement,
}, },
lexer::Lexer, lexer::Lexer,
token::{self, Token, TokenType}, token::{self, Token, TokenType},
@ -64,7 +64,7 @@ impl fmt::Display for Error {
"expected token `{expected}`, actual token: `{}`", "expected token `{expected}`, actual token: `{}`",
match actual { match actual {
Some(token) => format!("{token}"), Some(token) => format!("{token}"),
None => "None".to_string(), None => "None".into(),
}, },
), ),
NoPrefixParseFnFound(t) => write!(f, "no prefix parse function found for `{t}`"), NoPrefixParseFnFound(t) => write!(f, "no prefix parse function found for `{t}`"),
@ -131,12 +131,6 @@ impl Parser {
} }
fn parse_let_statement(&mut self) -> Option<Rc<dyn Statement>> { fn parse_let_statement(&mut self) -> Option<Rc<dyn Statement>> {
let token = if let Some(token) = &self.cur_token {
token.clone()
} else {
return None;
};
let value = self.expect_peek_ident()?; let value = self.expect_peek_ident()?;
let name = Identifier { let name = Identifier {
@ -148,35 +142,33 @@ impl Parser {
return None; return None;
} }
while !self.cur_token_is(TokenType::Semicolon) {
self.next(); self.next();
}
let value = Rc::new(DummyExpression {});
Some(Rc::new(Let { token, name, value })) // TODO: maybe not unwrap
let value = self.parse_expression(Precedence::Lowest).unwrap();
self.next();
Some(Rc::new(Let { name, value }))
} }
fn parse_return_statement(&mut self) -> Option<Rc<dyn Statement>> { fn parse_return_statement(&mut self) -> Option<Rc<dyn Statement>> {
let token = self.cur_token.clone().unwrap();
while !self.cur_token_is(TokenType::Semicolon) {
self.next(); self.next();
}
let value = Rc::new(DummyExpression {});
Some(Rc::new(Return { token, value })) // TODO: maybe not unwrap
let value = self.parse_expression(Precedence::Lowest).unwrap();
self.next();
Some(Rc::new(Return { value }))
} }
fn parse_expression_statement(&mut self) -> Option<Rc<dyn Statement>> { fn parse_expression_statement(&mut self) -> Option<Rc<dyn Statement>> {
let token = self.cur_token.clone()?;
let expression = self.parse_expression(Precedence::Lowest)?; let expression = self.parse_expression(Precedence::Lowest)?;
if self.peek_token_is(TokenType::Semicolon) { if self.peek_token_is(TokenType::Semicolon) {
self.next(); self.next();
} }
Some(Rc::new(ExpressionStatement { token, expression })) Some(Rc::new(ExpressionStatement { expression }))
} }
fn parse_expression(&mut self, precedence: Precedence) -> Option<Rc<dyn Expression>> { fn parse_expression(&mut self, precedence: Precedence) -> Option<Rc<dyn Expression>> {
@ -237,6 +229,12 @@ impl Parser {
Rc::new(Prefix { operator, right }) Rc::new(Prefix { operator, right })
} }
fn parse_boolean(&mut self) -> Rc<dyn Expression> {
Rc::new(Boolean {
value: self.cur_token_is(TokenType::True),
})
}
fn parse_infix_expression(&mut self, left: Rc<dyn Expression>) -> Rc<dyn Expression> { fn parse_infix_expression(&mut self, left: Rc<dyn Expression>) -> Rc<dyn Expression> {
let token = if let Some(token) = &self.cur_token { let token = if let Some(token) = &self.cur_token {
token token
@ -375,6 +373,8 @@ impl Parser {
Bang => Some(Box::new(|parser| { Bang => Some(Box::new(|parser| {
Self::parse_prefix_expression(parser, PrefixOperator::Bang) Self::parse_prefix_expression(parser, PrefixOperator::Bang)
})), })),
True => Some(Box::new(Self::parse_boolean)),
False => Some(Box::new(Self::parse_boolean)),
_ => None, _ => None,
} }
} }
@ -417,9 +417,12 @@ mod tests {
use std::rc::Rc; use std::rc::Rc;
use crate::{ use crate::{
ast::{InfixOperator, PrefixOperator, Statement}, ast::{
Boolean, ExpressionStatement, Identifier, Infix, InfixOperator, IntegerLiteral, Let,
Prefix, PrefixOperator, Program, Return, Statement,
},
lexer::Lexer, lexer::Lexer,
token::Token, token::{Token, TokenType},
}; };
use super::Parser; use super::Parser;
@ -430,7 +433,7 @@ mod tests {
let y = 10;\ let y = 10;\
let foobar = 838383;\ let foobar = 838383;\
" "
.to_string(); .into();
let lexer = Lexer::new(source); let lexer = Lexer::new(source);
@ -439,14 +442,34 @@ mod tests {
let program = parser.parse().unwrap(); let program = parser.parse().unwrap();
check_parser_errors(parser); check_parser_errors(parser);
assert_eq!(program.statements.len(), 3); assert_eq!(
program,
let expected_identifiers = vec!["x", "y", "foobar"]; Program {
let mut statements_iter = program.statements.iter(); statements: vec![
for tt in expected_identifiers { Rc::new(Let {
let statement = statements_iter.next().unwrap(); name: Identifier {
test_let_statement(statement.clone(), tt); token_type: TokenType::Let,
value: "x".into()
},
value: Rc::new(IntegerLiteral { value: 5 })
}),
Rc::new(Let {
name: Identifier {
token_type: TokenType::Let,
value: "y".into()
},
value: Rc::new(IntegerLiteral { value: 10 })
}),
Rc::new(Let {
name: Identifier {
token_type: TokenType::Let,
value: "foobar".into()
},
value: Rc::new(IntegerLiteral { value: 838383 })
})
]
} }
);
} }
#[test] #[test]
@ -455,7 +478,7 @@ mod tests {
return 10;\ return 10;\
return 838383;\ return 838383;\
" "
.to_string(); .into();
let lexer = Lexer::new(source); let lexer = Lexer::new(source);
@ -464,19 +487,27 @@ mod tests {
let program = parser.parse().unwrap(); let program = parser.parse().unwrap();
check_parser_errors(parser); check_parser_errors(parser);
assert_eq!(program.statements.len(), 3);
for stmt in program.statements {
assert_eq!( assert_eq!(
format!("{stmt:?}"), program,
"Return { token: Return, value: DummyExpression }" Program {
) statements: vec![
Rc::new(Return {
value: Rc::new(IntegerLiteral { value: 5 })
}),
Rc::new(Return {
value: Rc::new(IntegerLiteral { value: 10 })
}),
Rc::new(Return {
value: Rc::new(IntegerLiteral { value: 838383 })
})
]
} }
);
} }
#[test] #[test]
fn identifier_expression() { fn identifier_expression() {
let source = "foobar;".to_owned(); let source = "foobar;".into();
let lexer = Lexer::new(source); let lexer = Lexer::new(source);
@ -485,17 +516,42 @@ mod tests {
let program = parser.parse().unwrap(); let program = parser.parse().unwrap();
check_parser_errors(parser); check_parser_errors(parser);
let expected_identifiers = vec!["foobar"]; assert_eq!(
let mut statements_iter = program.statements.iter(); program,
for tt in expected_identifiers { Program {
let statement = statements_iter.next().unwrap(); statements: vec![Rc::new(ExpressionStatement {
test_identifier_expression(statement.clone(), tt); expression: Rc::new(Identifier {
token_type: TokenType::Ident,
value: "foobar".into()
})
})]
} }
);
} }
#[test] #[test]
fn integer_literal_expression() { fn integer_literal_expression() {
let source = "6;".to_owned(); let source = "6;".into();
let lexer = Lexer::new(source);
let mut parser = Parser::new(lexer);
let program = parser.parse().unwrap();
check_parser_errors(parser);
assert_eq!(
program,
Program {
statements: vec![Rc::new(ExpressionStatement {
expression: Rc::new(IntegerLiteral { value: 6 })
})]
}
);
}
#[test]
fn bool_expression() {
let source = "true; false".into();
let lexer = Lexer::new(source); let lexer = Lexer::new(source);
@ -504,12 +560,19 @@ mod tests {
let program = parser.parse().unwrap(); let program = parser.parse().unwrap();
check_parser_errors(parser); check_parser_errors(parser);
let expected_integers = vec![6]; assert_eq!(
let mut statements_iter = program.statements.iter(); program,
for tt in expected_integers { Program {
let statement = statements_iter.next().unwrap(); statements: vec![
test_integer_literal_expression(statement.clone(), tt); Rc::new(ExpressionStatement {
expression: Rc::new(Boolean { value: true })
}),
Rc::new(ExpressionStatement {
expression: Rc::new(Boolean { value: false })
})
]
} }
);
} }
#[test] #[test]
@ -523,13 +586,13 @@ mod tests {
let tests = vec![ let tests = vec![
Test { Test {
input: "!15".to_owned(), input: "!15".into(),
token: Token::Bang, token: Token::Bang,
operator: PrefixOperator::Bang, operator: PrefixOperator::Bang,
value: 15, value: 15,
}, },
Test { Test {
input: "-15".to_owned(), input: "-15".into(),
token: Token::Minus, token: Token::Minus,
operator: PrefixOperator::Minus, operator: PrefixOperator::Minus,
value: 15, value: 15,
@ -544,13 +607,16 @@ mod tests {
let program = parser.parse().unwrap(); let program = parser.parse().unwrap();
check_parser_errors(parser); check_parser_errors(parser);
assert_eq!(program.statements.len(), 1); assert_eq!(
program,
test_prefix_expression( Program {
program.statements.first().unwrap().clone(), statements: vec![Rc::new(ExpressionStatement {
test.token, expression: Rc::new(Prefix {
test.operator, operator: test.operator,
test.value, right: Rc::new(IntegerLiteral { value: test.value })
})
})]
}
); );
} }
} }
@ -623,23 +689,24 @@ mod tests {
let program = parser.parse().unwrap(); let program = parser.parse().unwrap();
check_parser_errors(parser); check_parser_errors(parser);
assert_eq!(program.statements.len(), 1);
test_infix_expression(
program.statements.first().unwrap().clone(),
test.left_value,
test.operator,
test.right_value,
);
}
}
fn test_let_statement(stmt: Rc<dyn Statement>, name: &str) {
assert_eq!( assert_eq!(
format!("{stmt:?}"), program,
format!("Let {{ token: Let, name: Identifier {{ token_type: Let, value: \"{name}\" }}, value: DummyExpression }}"), Program {
statements: vec![Rc::new(ExpressionStatement {
expression: Rc::new(Infix {
operator: test.operator,
left: Rc::new(IntegerLiteral {
value: test.left_value
}),
right: Rc::new(IntegerLiteral {
value: test.right_value
})
})
})]
}
); );
} }
}
fn check_parser_errors(parser: Parser) { fn check_parser_errors(parser: Parser) {
if parser.errors().len() == 0 { if parser.errors().len() == 0 {
@ -654,46 +721,4 @@ mod tests {
panic!("{err}"); panic!("{err}");
} }
fn test_identifier_expression(stmt: Rc<dyn Statement>, name: &str) {
assert_eq!(
format!("{stmt:?}"),
format!(
"ExpressionStatement {{ token: Ident(\"{name}\"), expression: Identifier {{ token_type: Ident, value: \"{name}\" }} }}"
),
);
}
fn test_integer_literal_expression(stmt: Rc<dyn Statement>, num: i64) {
assert_eq!(
format!("{stmt:?}"),
format!(
"ExpressionStatement {{ token: Int({num}), expression: IntegerLiteral {{ value: {num} }} }}"
),
);
}
fn test_prefix_expression(
stmt: Rc<dyn Statement>,
token: Token,
operator: PrefixOperator,
num: i64,
) {
assert_eq!(
format!("{stmt:?}"),
format!("ExpressionStatement {{ token: {token:?}, expression: Prefix {{ operator: {operator:?}, right: IntegerLiteral {{ value: {num} }} }} }}"),
);
}
fn test_infix_expression(
stmt: Rc<dyn Statement>,
left: i64,
operator: InfixOperator,
right: i64,
) {
assert_eq!(
format!("{stmt:?}"),
format!("ExpressionStatement {{ token: Int({left}), expression: Infix {{ operator: {operator:?}, left: IntegerLiteral {{ value: {left} }}, right: IntegerLiteral {{ value: {right} }} }} }}"),
);
}
} }

View File

@ -1,6 +1,6 @@
use std::fmt::Display; use std::fmt::Display;
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub enum Token { pub enum Token {
Illegal, Illegal,
EOF, EOF,
@ -154,7 +154,7 @@ impl Token {
"if" => If, "if" => If,
"else" => Else, "else" => Else,
"return" => Return, "return" => Return,
ident => Ident(ident.to_string()), ident => Ident(ident.into()),
} }
} }
} }