mirror of
https://github.com/TheM1Stery/izanami.git
synced 2025-04-20 00:41:11 +00:00
feat: finish chapter 9
This commit is contained in:
parent
7a43d22b77
commit
54912b7087
14
src/ast.rs
14
src/ast.rs
@ -29,6 +29,11 @@ pub enum Expr {
|
|||||||
name: Token,
|
name: Token,
|
||||||
value: Box<Expr>,
|
value: Box<Expr>,
|
||||||
},
|
},
|
||||||
|
Logical {
|
||||||
|
left: Box<Expr>,
|
||||||
|
op: Token,
|
||||||
|
right: Box<Expr>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum Stmt {
|
pub enum Stmt {
|
||||||
@ -38,6 +43,11 @@ pub enum Stmt {
|
|||||||
Expression {
|
Expression {
|
||||||
expression: Expr,
|
expression: Expr,
|
||||||
},
|
},
|
||||||
|
If {
|
||||||
|
condition: Expr,
|
||||||
|
then_branch: Box<Stmt>,
|
||||||
|
else_branch: Option<Box<Stmt>>,
|
||||||
|
},
|
||||||
Print {
|
Print {
|
||||||
expression: Expr,
|
expression: Expr,
|
||||||
},
|
},
|
||||||
@ -45,4 +55,8 @@ pub enum Stmt {
|
|||||||
name: Token,
|
name: Token,
|
||||||
initializer: Option<Expr>,
|
initializer: Option<Expr>,
|
||||||
},
|
},
|
||||||
|
While {
|
||||||
|
condition: Expr,
|
||||||
|
body: Box<Stmt>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ use std::{cell::RefCell, rc::Rc};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{Expr, Stmt},
|
ast::{Expr, Stmt},
|
||||||
environment::Environment,
|
environment::{self, Environment},
|
||||||
token::{LiteralType, Token, TokenType},
|
token::{LiteralType, Token, TokenType},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -52,6 +52,22 @@ fn execute(statement: &Stmt, environment: &Rc<RefCell<Environment>>) -> Result<(
|
|||||||
Stmt::Block { statements } => {
|
Stmt::Block { statements } => {
|
||||||
execute_block(statements, environment)?;
|
execute_block(statements, environment)?;
|
||||||
}
|
}
|
||||||
|
Stmt::If {
|
||||||
|
condition,
|
||||||
|
then_branch,
|
||||||
|
else_branch,
|
||||||
|
} => {
|
||||||
|
if is_truthy(&evaluate(condition, &mut environment.borrow_mut())?) {
|
||||||
|
execute(then_branch, environment)?;
|
||||||
|
} else if let Some(else_branch) = else_branch {
|
||||||
|
execute(else_branch, environment)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Stmt::While { condition, body } => {
|
||||||
|
while is_truthy(&evaluate(condition, &mut environment.borrow_mut())?) {
|
||||||
|
execute(body, environment)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -108,6 +124,19 @@ fn evaluate(expr: &Expr, environment: &mut Environment) -> Result<LiteralType, R
|
|||||||
|
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
}
|
||||||
|
Expr::Logical { left, op, right } => {
|
||||||
|
let left = evaluate(left, environment)?;
|
||||||
|
|
||||||
|
if op.t_type == TokenType::OR {
|
||||||
|
if is_truthy(&left) {
|
||||||
|
return Ok(left);
|
||||||
|
}
|
||||||
|
} else if !is_truthy(&left) {
|
||||||
|
return Ok(left);
|
||||||
|
}
|
||||||
|
|
||||||
|
evaluate(right, environment)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
122
src/parser.rs
122
src/parser.rs
@ -71,9 +71,18 @@ impl Parser<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn statement(&mut self) -> Result<Stmt, ParseError> {
|
fn statement(&mut self) -> Result<Stmt, ParseError> {
|
||||||
|
if self.match_token(&[TokenType::For]) {
|
||||||
|
return self.for_statement();
|
||||||
|
}
|
||||||
|
if self.match_token(&[TokenType::If]) {
|
||||||
|
return self.if_statement();
|
||||||
|
}
|
||||||
if self.match_token(&[TokenType::Print]) {
|
if self.match_token(&[TokenType::Print]) {
|
||||||
return self.print_statement();
|
return self.print_statement();
|
||||||
}
|
}
|
||||||
|
if self.match_token(&[TokenType::While]) {
|
||||||
|
return self.while_statement();
|
||||||
|
}
|
||||||
|
|
||||||
if self.match_token(&[TokenType::LeftBrace]) {
|
if self.match_token(&[TokenType::LeftBrace]) {
|
||||||
return Ok(Stmt::Block {
|
return Ok(Stmt::Block {
|
||||||
@ -96,6 +105,86 @@ impl Parser<'_> {
|
|||||||
Ok(statements)
|
Ok(statements)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn if_statement(&mut self) -> Result<Stmt, ParseError> {
|
||||||
|
self.consume(TokenType::LeftParen, "Expect '(' after 'if'.")?;
|
||||||
|
let condition = self.expression()?;
|
||||||
|
self.consume(TokenType::RightParen, "Expect ')' after if condition.")?;
|
||||||
|
|
||||||
|
let then_branch = Box::new(self.statement()?);
|
||||||
|
let else_branch = if self.match_token(&[TokenType::Else]) {
|
||||||
|
Some(Box::new(self.statement()?))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Stmt::If {
|
||||||
|
condition,
|
||||||
|
then_branch,
|
||||||
|
else_branch,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn while_statement(&mut self) -> Result<Stmt, ParseError> {
|
||||||
|
self.consume(TokenType::LeftParen, "Expect '(' after 'while'.")?;
|
||||||
|
let condition = self.expression()?;
|
||||||
|
self.consume(TokenType::RightParen, "Expect ')' after while condition.")?;
|
||||||
|
let body = Box::new(self.statement()?);
|
||||||
|
|
||||||
|
Ok(Stmt::While { condition, body })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn for_statement(&mut self) -> Result<Stmt, ParseError> {
|
||||||
|
self.consume(TokenType::LeftParen, "Expect '(' after 'for'.")?;
|
||||||
|
let initializer = if self.match_token(&[TokenType::Semicolon]) {
|
||||||
|
None
|
||||||
|
} else if self.match_token(&[TokenType::Var]) {
|
||||||
|
Some(self.var_declaration()?)
|
||||||
|
} else {
|
||||||
|
Some(self.expression_statement()?)
|
||||||
|
};
|
||||||
|
|
||||||
|
let condition = if !self.match_token(&[TokenType::Semicolon]) {
|
||||||
|
Some(self.expression()?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
self.consume(TokenType::Semicolon, "Expect ';' after loop condition")?;
|
||||||
|
|
||||||
|
let increment = if !self.match_token(&[TokenType::RightParen]) {
|
||||||
|
Some(self.expression()?)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
self.consume(TokenType::RightParen, "Expect ')' after for clauses.")?;
|
||||||
|
|
||||||
|
let body = match increment {
|
||||||
|
Some(inc) => Stmt::Block {
|
||||||
|
statements: vec![self.statement()?, Stmt::Expression { expression: inc }],
|
||||||
|
},
|
||||||
|
None => self.statement()?,
|
||||||
|
};
|
||||||
|
|
||||||
|
let condition = condition.unwrap_or(Expr::Literal {
|
||||||
|
value: LiteralType::Bool(true),
|
||||||
|
});
|
||||||
|
|
||||||
|
let body = Stmt::While {
|
||||||
|
condition,
|
||||||
|
body: Box::new(body),
|
||||||
|
};
|
||||||
|
|
||||||
|
let body = match initializer {
|
||||||
|
Some(init) => Stmt::Block {
|
||||||
|
statements: vec![init, body],
|
||||||
|
},
|
||||||
|
None => body,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(body)
|
||||||
|
}
|
||||||
|
|
||||||
fn print_statement(&mut self) -> Result<Stmt, ParseError> {
|
fn print_statement(&mut self) -> Result<Stmt, ParseError> {
|
||||||
let expression = self.expression()?;
|
let expression = self.expression()?;
|
||||||
self.consume(TokenType::Semicolon, "Expect ';' after value.")?;
|
self.consume(TokenType::Semicolon, "Expect ';' after value.")?;
|
||||||
@ -146,7 +235,7 @@ impl Parser<'_> {
|
|||||||
// ternary -> equality ("?" expression : ternary)? // expression grammar
|
// ternary -> equality ("?" expression : ternary)? // expression grammar
|
||||||
fn ternary(&mut self) -> Result<Expr, ParseError> {
|
fn ternary(&mut self) -> Result<Expr, ParseError> {
|
||||||
use TokenType::*;
|
use TokenType::*;
|
||||||
let expr = self.equality()?;
|
let expr = self.or()?;
|
||||||
|
|
||||||
if self.match_token(&[Question]) {
|
if self.match_token(&[Question]) {
|
||||||
let second = self.expression()?;
|
let second = self.expression()?;
|
||||||
@ -162,6 +251,37 @@ impl Parser<'_> {
|
|||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn or(&mut self) -> Result<Expr, ParseError> {
|
||||||
|
let mut expr = self.and()?;
|
||||||
|
|
||||||
|
while self.match_token(&[TokenType::OR]) {
|
||||||
|
let op = self.previous().clone();
|
||||||
|
let right = self.and()?;
|
||||||
|
expr = Expr::Logical {
|
||||||
|
left: Box::new(expr),
|
||||||
|
op,
|
||||||
|
right: Box::new(right),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn and(&mut self) -> Result<Expr, ParseError> {
|
||||||
|
let mut expr = self.equality()?;
|
||||||
|
while self.match_token(&[TokenType::And]) {
|
||||||
|
let op = self.previous().clone();
|
||||||
|
let right = self.equality()?;
|
||||||
|
expr = Expr::Logical {
|
||||||
|
left: Box::new(expr),
|
||||||
|
op,
|
||||||
|
right: Box::new(right),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(expr)
|
||||||
|
}
|
||||||
|
|
||||||
fn equality(&mut self) -> Result<Expr, ParseError> {
|
fn equality(&mut self) -> Result<Expr, ParseError> {
|
||||||
use TokenType::*;
|
use TokenType::*;
|
||||||
self.left_association_binary(&[BangEqual, EqualEqual], Self::comparison)
|
self.left_association_binary(&[BangEqual, EqualEqual], Self::comparison)
|
||||||
|
@ -18,6 +18,7 @@ pub fn pretty_print(expr: &Expr) -> String {
|
|||||||
} => parenthesize("?:", &[first, second, third]),
|
} => parenthesize("?:", &[first, second, third]),
|
||||||
Expr::Variable { name } => name.lexeme.clone(),
|
Expr::Variable { name } => name.lexeme.clone(),
|
||||||
Expr::Assign { name, value } => parenthesize(&name.lexeme, &[value]),
|
Expr::Assign { name, value } => parenthesize(&name.lexeme, &[value]),
|
||||||
|
Expr::Logical { left, op, right } => parenthesize(&op.lexeme, &[left, right]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user