parse blocks
This commit is contained in:
@@ -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(())
|
||||||
}
|
}
|
||||||
|
|||||||
120
src/parser.rs
120
src/parser.rs
@@ -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 {
|
||||||
|
|||||||
@@ -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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user