chapter 5

This commit is contained in:
Seymur Bagirov 2024-12-21 02:08:12 +04:00
parent 0b437fe5e1
commit 5f80dfe498
6 changed files with 129 additions and 1 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/target
*.izn

19
src/ast.rs Normal file
View File

@ -0,0 +1,19 @@
use crate::token::{LiteralType, Token};
pub enum Expr {
Binary {
left: Box<Expr>,
op: Token,
right: Box<Expr>,
},
Grouping {
expression: Box<Expr>,
},
Literal {
value: Option<LiteralType>,
},
Unary {
op: Token,
right: Box<Expr>,
},
}

View File

@ -7,6 +7,8 @@ use std::{
use scanner::Scanner;
use token::Token;
mod ast;
mod printer;
mod scanner;
mod token;
mod utils;

84
src/printer.rs Normal file
View File

@ -0,0 +1,84 @@
use crate::{ast::Expr, token::LiteralType};
pub fn pretty_print(expr: &Expr) -> String {
match expr {
Expr::Binary { left, op, right } => parenthesize(&op.lexeme, &[left, right]),
Expr::Grouping { expression } => parenthesize("group", &[expression]),
Expr::Literal { value } => match value {
Some(LiteralType::String(v)) => v.to_string(),
Some(LiteralType::Number(v)) => v.to_string(),
None => "None".to_string(),
},
Expr::Unary { op, right } => parenthesize(&op.lexeme, &[right]),
}
}
fn parenthesize(name: &str, exprs: &[&Expr]) -> String {
let mut parenthesized = format!("({name}");
for expr in exprs {
parenthesized.push(' ');
parenthesized.push_str(&pretty_print(expr));
}
parenthesized.push(')');
parenthesized
}
#[cfg(test)]
mod test {
use crate::token::{Token, TokenType};
use super::*;
use Expr::*;
#[test]
fn equal_print_binary() {
use TokenType::*;
let expression = Binary {
left: Box::new(Literal {
value: Some(LiteralType::Number(10.2)),
}),
op: Token {
t_type: Plus,
lexeme: "+".to_string(),
literal: None,
line: 0,
},
right: Box::new(Literal {
value: Some(LiteralType::Number(10.2)),
}),
};
let actual = pretty_print(&expression);
let expected = "(+ 10.2 10.2)";
assert_eq!(actual, expected);
}
#[test]
// tests all cases
fn equal_test_whole() {
use TokenType::*;
let expression = Binary {
left: Box::new(Unary {
op: Token::new(Minus, "-", None, 0),
right: Box::new(Expr::Literal {
value: Some(LiteralType::number_literal(123.0)),
}),
}),
op: Token::new(Star, "*", None, 0),
right: Box::new(Grouping {
expression: Box::new(Literal {
value: Some(LiteralType::number_literal(45.67)),
}),
}),
};
let actual = pretty_print(&expression);
let expected = "(* (- 123) (group 45.67))";
assert_eq!(expected, actual);
}
}

View File

@ -370,7 +370,7 @@ mod tests {
let mut scanner = Scanner::new(value);
let expected_value = LiteralType::Number(123.456);
let expected_value = LiteralType::Number(123.0);
let tokens = scanner.scan_tokens().expect("There shouldn't be an error");

View File

@ -54,6 +54,16 @@ pub enum LiteralType {
Number(f64),
}
impl LiteralType {
pub fn string_literal(val: &str) -> LiteralType {
return LiteralType::String(val.to_string());
}
pub fn number_literal(val: f64) -> LiteralType {
return LiteralType::Number(val);
}
}
#[derive(Debug)]
pub struct Token {
pub t_type: TokenType,
@ -62,6 +72,18 @@ pub struct Token {
pub line: usize,
}
impl Token {
pub fn new(t_type: TokenType, lexeme: &str, literal: Option<LiteralType>, line: usize) -> Self {
let lexeme = lexeme.to_string();
Self {
t_type,
lexeme,
literal,
line,
}
}
}
impl Display for Token {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?} {} {:?}", self.t_type, self.lexeme, self.literal)