parse blocks

This commit is contained in:
2025-05-29 20:32:54 +02:00
parent 01cc38f31d
commit 47fd9a36a4
4 changed files with 199 additions and 26 deletions

View File

@@ -83,6 +83,21 @@ section .note.GNU-stack
env.locals.insert(name.lexeme, offset); env.locals.insert(name.lexeme, offset);
writeln!(&mut self.output, " mov QWORD [rbp-{}], rax", offset)?; writeln!(&mut self.output, " mov QWORD [rbp-{}], rax", offset)?;
} }
Stmt::Block(statements) => {
let mut env = Env::new();
for stmt in statements {
self.compile_stmt(&mut env, stmt)?;
}
}
Stmt::If {
condition: _,
then_branch: _,
else_branch: _,
} => todo!(),
Stmt::While {
condition: _,
body: _,
} => todo!(),
} }
Ok(()) Ok(())
} }

View File

@@ -1,10 +1,25 @@
use std::error::Error;
use crate::tokenizer::{MotError, Token, TokenType, error}; use crate::tokenizer::{MotError, Token, TokenType, error};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Stmt { pub enum Stmt {
Expression(Expr), Expression(Expr),
Print(Expr), Print(Expr),
Var { name: Token, initializer: Expr }, Var {
name: Token,
initializer: Expr,
},
Block(Vec<Stmt>),
If {
condition: Expr,
then_branch: Box<Stmt>,
else_branch: Option<Box<Stmt>>,
},
While {
condition: Expr,
body: Box<Stmt>,
},
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@@ -37,7 +52,7 @@ impl Parser {
Parser { tokens, current: 0 } Parser { tokens, current: 0 }
} }
pub fn parse(mut self) -> Result<Vec<Stmt>, MotError> { pub fn parse(mut self) -> Result<Vec<Stmt>, Box<dyn Error>> {
let mut statements = vec![]; let mut statements = vec![];
while !self.eof() { while !self.eof() {
statements.push(self.declaration()?); statements.push(self.declaration()?);
@@ -45,7 +60,7 @@ impl Parser {
Ok(statements) Ok(statements)
} }
fn declaration(&mut self) -> Result<Stmt, MotError> { fn declaration(&mut self) -> Result<Stmt, Box<dyn Error>> {
// TODO: synchronization after parse error // TODO: synchronization after parse error
if self.match_token(&[TokenType::KeywordLet]) { if self.match_token(&[TokenType::KeywordLet]) {
self.let_declaration() self.let_declaration()
@@ -54,27 +69,70 @@ impl Parser {
} }
} }
fn let_declaration(&mut self) -> Result<Stmt, MotError> { fn let_declaration(&mut self) -> Result<Stmt, Box<dyn Error>> {
let name = self.consume(TokenType::Identifier, "expected variable name")?; let name = self.consume(TokenType::Identifier, "expected variable name")?;
self.consume(TokenType::Equal, "expected '=' after variable name")?; self.consume(TokenType::Equal, "expected '=' after variable name")?;
let initializer = self.expression()?; let initializer = self.expression()?;
Ok(Stmt::Var { name, initializer }) Ok(Stmt::Var { name, initializer })
} }
fn statement(&mut self) -> Result<Stmt, MotError> { fn block(&mut self) -> Result<Stmt, Box<dyn Error>> {
self.consume(TokenType::Indent, "expected an indent")?;
let mut statements = vec![];
while !self.eof() && !self.match_token(&[TokenType::Dedent]) {
statements.push(self.declaration()?);
}
Ok(Stmt::Block(statements))
}
fn statement(&mut self) -> Result<Stmt, Box<dyn Error>> {
if self.match_token(&[TokenType::KeywordPrint]) { if self.match_token(&[TokenType::KeywordPrint]) {
Ok(Stmt::Print(self.expression()?)) Ok(Stmt::Print(self.expression()?))
} else if self.match_token(&[TokenType::KeywordIf]) {
self.if_statement()
} else if self.match_token(&[TokenType::KeywordWhile]) {
self.while_statement()
} else { } else {
Ok(Stmt::Expression(self.expression()?)) Ok(Stmt::Expression(self.expression()?))
} }
} }
fn expression(&mut self) -> Result<Expr, MotError> { fn if_statement(&mut self) -> Result<Stmt, Box<dyn Error>> {
let condition = self.expression()?;
let then_branch = self.block()?;
let else_branch = if self.match_token(&[TokenType::KeywordElse]) {
if self.match_token(&[TokenType::KeywordIf]) {
Some(Box::new(self.if_statement()?))
} else {
Some(Box::new(self.block()?))
}
} else {
None
};
Ok(Stmt::If {
condition,
then_branch: Box::new(then_branch),
else_branch,
})
}
fn while_statement(&mut self) -> Result<Stmt, Box<dyn Error>> {
let condition = self.expression()?;
let body = self.block()?;
Ok(Stmt::While {
condition,
body: Box::new(body),
})
}
fn expression(&mut self) -> Result<Expr, Box<dyn Error>> {
self.assignment() self.assignment()
} }
fn assignment(&mut self) -> Result<Expr, MotError> { fn assignment(&mut self) -> Result<Expr, Box<dyn Error>> {
let expr = self.equality()?; let expr = self.logical_or()?;
if self.match_token(&[TokenType::Equal]) { if self.match_token(&[TokenType::Equal]) {
let equals = self.previous().clone(); let equals = self.previous().clone();
@@ -92,7 +150,39 @@ impl Parser {
Ok(expr) Ok(expr)
} }
fn equality(&mut self) -> Result<Expr, MotError> { fn logical_or(&mut self) -> Result<Expr, Box<dyn Error>> {
let mut expr = self.logical_and()?;
while self.match_token(&[TokenType::Or]) {
let op = self.previous().clone();
let right = self.logical_and()?;
expr = Expr::Binary {
left: Box::new(expr),
op,
right: Box::new(right),
}
}
Ok(expr)
}
fn logical_and(&mut self) -> Result<Expr, Box<dyn Error>> {
let mut expr = self.equality()?;
while self.match_token(&[TokenType::And]) {
let op = self.previous().clone();
let right = self.equality()?;
expr = Expr::Binary {
left: Box::new(expr),
op,
right: Box::new(right),
}
}
Ok(expr)
}
fn equality(&mut self) -> Result<Expr, Box<dyn Error>> {
let mut expr = self.comparison()?; let mut expr = self.comparison()?;
while self.match_token(&[TokenType::DoubleEqual, TokenType::NotEqual]) { while self.match_token(&[TokenType::DoubleEqual, TokenType::NotEqual]) {
@@ -108,7 +198,7 @@ impl Parser {
Ok(expr) Ok(expr)
} }
fn comparison(&mut self) -> Result<Expr, MotError> { fn comparison(&mut self) -> Result<Expr, Box<dyn Error>> {
let mut expr = self.term()?; let mut expr = self.term()?;
while self.match_token(&[ while self.match_token(&[
@@ -129,7 +219,7 @@ impl Parser {
Ok(expr) Ok(expr)
} }
fn term(&mut self) -> Result<Expr, MotError> { fn term(&mut self) -> Result<Expr, Box<dyn Error>> {
let mut expr = self.factor()?; let mut expr = self.factor()?;
while self.match_token(&[TokenType::Plus, TokenType::Minus, TokenType::Xor]) { while self.match_token(&[TokenType::Plus, TokenType::Minus, TokenType::Xor]) {
@@ -145,7 +235,7 @@ impl Parser {
Ok(expr) Ok(expr)
} }
fn factor(&mut self) -> Result<Expr, MotError> { fn factor(&mut self) -> Result<Expr, Box<dyn Error>> {
let mut expr = self.unary()?; let mut expr = self.unary()?;
while self.match_token(&[TokenType::Star, TokenType::Slash, TokenType::Mod]) { while self.match_token(&[TokenType::Star, TokenType::Slash, TokenType::Mod]) {
@@ -161,7 +251,7 @@ impl Parser {
Ok(expr) Ok(expr)
} }
fn unary(&mut self) -> Result<Expr, MotError> { fn unary(&mut self) -> Result<Expr, Box<dyn Error>> {
if self.match_token(&[TokenType::Bang, TokenType::Minus]) { if self.match_token(&[TokenType::Bang, TokenType::Minus]) {
let op = self.previous().clone(); let op = self.previous().clone();
let right = self.unary()?; let right = self.unary()?;
@@ -174,7 +264,7 @@ impl Parser {
self.primary() self.primary()
} }
fn primary(&mut self) -> Result<Expr, MotError> { fn primary(&mut self) -> Result<Expr, Box<dyn Error>> {
if self.match_token(&[TokenType::Number, TokenType::String]) { if self.match_token(&[TokenType::Number, TokenType::String]) {
Ok(Expr::Literal(self.previous().clone())) Ok(Expr::Literal(self.previous().clone()))
} else if self.match_token(&[TokenType::LeftParen]) { } else if self.match_token(&[TokenType::LeftParen]) {
@@ -188,7 +278,7 @@ impl Parser {
} }
} }
fn consume(&mut self, token_type: TokenType, message: &str) -> Result<Token, MotError> { fn consume(&mut self, token_type: TokenType, message: &str) -> Result<Token, Box<dyn Error>> {
if self.check(&token_type) { if self.check(&token_type) {
Ok(self.advance().clone()) Ok(self.advance().clone())
} else { } else {

View File

@@ -1,4 +1,4 @@
use std::fmt; use std::{cmp::Ordering, error::Error, fmt};
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub enum TokenType { pub enum TokenType {
@@ -32,7 +32,12 @@ pub enum TokenType {
KeywordPrint, KeywordPrint,
KeywordLet, KeywordLet,
KeywordIf,
KeywordElse,
KeywordWhile,
Indent,
Dedent,
Eof, Eof,
} }
@@ -52,10 +57,10 @@ impl std::error::Error for MotError {}
macro_rules! error { macro_rules! error {
($loc:expr, $msg:expr) => { ($loc:expr, $msg:expr) => {
Err(MotError { Err(Box::new(MotError {
loc: $loc.clone(), loc: $loc.clone(),
message: $msg.into(), message: $msg.into(),
}) }))
}; };
} }
@@ -84,6 +89,8 @@ pub struct Token {
pub struct Tokenizer { pub struct Tokenizer {
source: Vec<char>, source: Vec<char>,
tokens: Vec<Token>, tokens: Vec<Token>,
indent_stack: Vec<usize>,
current_indent: usize,
start: usize, start: usize,
current: usize, current: usize,
loc: Loc, loc: Loc,
@@ -94,6 +101,8 @@ impl Tokenizer {
Tokenizer { Tokenizer {
source: source.chars().collect(), source: source.chars().collect(),
tokens: vec![], tokens: vec![],
indent_stack: vec![0],
current_indent: 0,
start: 0, start: 0,
current: 0, current: 0,
loc: Loc { loc: Loc {
@@ -104,7 +113,7 @@ impl Tokenizer {
} }
} }
pub fn tokenize(mut self) -> Result<Vec<Token>, MotError> { pub fn tokenize(mut self) -> Result<Vec<Token>, Box<dyn Error>> {
while !self.eof() { while !self.eof() {
self.start = self.current; self.start = self.current;
self.scan_token()?; self.scan_token()?;
@@ -118,7 +127,7 @@ impl Tokenizer {
Ok(self.tokens) Ok(self.tokens)
} }
fn scan_token(&mut self) -> Result<(), MotError> { fn scan_token(&mut self) -> Result<(), Box<dyn Error>> {
match self.advance() { match self.advance() {
'(' => self.add_token(TokenType::LeftParen), '(' => self.add_token(TokenType::LeftParen),
')' => self.add_token(TokenType::RightParen), ')' => self.add_token(TokenType::RightParen),
@@ -202,6 +211,7 @@ impl Tokenizer {
'\n' => { '\n' => {
self.loc.line += 1; self.loc.line += 1;
self.loc.column = 1; self.loc.column = 1;
self.handle_indentation()?;
} }
'0'..='9' => self.scan_number(), '0'..='9' => self.scan_number(),
'A'..='Z' | 'a'..='z' | '_' => self.scan_identifier(), 'A'..='Z' | 'a'..='z' | '_' => self.scan_identifier(),
@@ -210,6 +220,59 @@ impl Tokenizer {
Ok(()) Ok(())
} }
fn handle_indentation(&mut self) -> Result<(), Box<dyn Error>> {
if self.peek() == '\n' {
return Ok(());
}
let new_indent = self.count_indentation();
match new_indent.cmp(&self.current_indent) {
Ordering::Greater => {
self.indent_stack.push(new_indent);
self.tokens.push(Token {
token_type: TokenType::Indent,
lexeme: String::new(),
loc: self.loc.clone(),
});
}
Ordering::Less => {
while !self.indent_stack.is_empty()
&& *self.indent_stack.last().unwrap() > new_indent
{
self.indent_stack.pop();
self.tokens.push(Token {
token_type: TokenType::Dedent,
lexeme: String::new(),
loc: self.loc.clone(),
});
}
if self.indent_stack.is_empty() || *self.indent_stack.last().unwrap() != new_indent
{
return error!(self.loc, "invalid indentation");
}
}
Ordering::Equal => {}
}
self.current_indent = new_indent;
Ok(())
}
fn count_indentation(&mut self) -> usize {
let mut count = 0;
while self.peek() == ' ' || self.peek() == '\t' {
if self.peek() == ' ' {
count += 1;
}
if self.peek() == '\t' {
count += 4;
}
self.advance();
}
count
}
fn scan_number(&mut self) { fn scan_number(&mut self) {
while self.peek().is_ascii_digit() { while self.peek().is_ascii_digit() {
self.advance(); self.advance();
@@ -234,6 +297,9 @@ impl Tokenizer {
self.add_token(match lexeme.as_str() { self.add_token(match lexeme.as_str() {
"print" => TokenType::KeywordPrint, "print" => TokenType::KeywordPrint,
"let" => TokenType::KeywordLet, "let" => TokenType::KeywordLet,
"if" => TokenType::KeywordIf,
"else" => TokenType::KeywordElse,
"while" => TokenType::KeywordWhile,
_ => TokenType::Identifier, _ => TokenType::Identifier,
}) })
} }

View File

@@ -1,6 +1,8 @@
let a = 5 let a = 0
let b = 7 let b = 1
print(b - a) let temp = 0
a = 4
print(b - a) while a < 10000
print(b) print a
temp = a
b = temp + b