refactor(ast): Split parser to multiple file
This commit is contained in:
@@ -0,0 +1,296 @@
|
||||
use crate::{
|
||||
ast::types::{
|
||||
BlockStmt, BreakStmt, ContinueStmt, ForInit, ForStmt, IfElseBranch, IfStmt, ReturnStmt,
|
||||
Statement, WhileStmt,
|
||||
},
|
||||
lexer::{
|
||||
err::ParseError,
|
||||
types::TokenValue,
|
||||
},
|
||||
};
|
||||
|
||||
use super::{ParseProcessError, ParseType, Parser};
|
||||
|
||||
impl Parser {
|
||||
pub(super) fn parse_block_stmt(&mut self, parse_type: ParseType) -> Result<BlockStmt, ParseProcessError> {
|
||||
assert!(!self.is_eof());
|
||||
if self.peek().value != TokenValue::LBrace {
|
||||
if parse_type == ParseType::MustParse {
|
||||
let token = self.next().clone();
|
||||
self.diagnostics.add_from_frontend_error(
|
||||
ParseError::UnexpectedToken(token.value, "`{`"),
|
||||
token.span,
|
||||
);
|
||||
return Err(ParseProcessError::ErrorInMatch);
|
||||
}
|
||||
return Err(ParseProcessError::TryNext);
|
||||
}
|
||||
self.advance(1);
|
||||
let mut statements = vec![];
|
||||
// println!("parse block stmt");
|
||||
loop {
|
||||
if self.is_eof() {
|
||||
let span = self.last().span;
|
||||
self.diagnostics
|
||||
.add_from_frontend_error(ParseError::ExpectButEof("`}`"), span);
|
||||
return Err(ParseProcessError::ErrorInMatch);
|
||||
}
|
||||
if matches!(self.peek().value, TokenValue::Semicolon) {
|
||||
// like a();;
|
||||
self.advance(1);
|
||||
continue;
|
||||
}
|
||||
if matches!(self.peek().value, TokenValue::RBrace) {
|
||||
self.advance(1);
|
||||
break;
|
||||
}
|
||||
// parse statement here
|
||||
match self.parse_stmt() {
|
||||
Ok(stmt) => statements.push(stmt),
|
||||
Err(_) => {
|
||||
self.until_next_token(&[TokenValue::Semicolon, TokenValue::RBrace]);
|
||||
if self.last().value == TokenValue::RBrace {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// println!("finish parse block stmt");
|
||||
Ok(BlockStmt {
|
||||
statements
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_stmt(&mut self) -> Result<Statement, ParseProcessError> {
|
||||
assert!(!self.is_eof());
|
||||
match self.parse_var_decl_stmt(ParseType::TryParse) {
|
||||
Ok(var_decl) => return Ok(Statement::VarDecl(var_decl)),
|
||||
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
||||
Err(_) => {},
|
||||
};
|
||||
match self.parse_return_stmt() {
|
||||
Ok(return_stmt) => return Ok(Statement::Return(return_stmt)),
|
||||
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
||||
Err(_) => {},
|
||||
};
|
||||
match self.parse_if_stmt() {
|
||||
Ok(if_stmt) => return Ok(Statement::If(if_stmt)),
|
||||
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
||||
Err(_) => {},
|
||||
}
|
||||
match self.parse_while_stmt() {
|
||||
Ok(while_stmt) => return Ok(Statement::While(while_stmt)),
|
||||
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
||||
Err(_) => {},
|
||||
}
|
||||
match self.parse_for_stmt() {
|
||||
Ok(for_stmt) => return Ok(Statement::For(for_stmt)),
|
||||
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
||||
Err(_) => {},
|
||||
}
|
||||
match self.parse_break_stmt() {
|
||||
Ok(break_stmt) => return Ok(Statement::Break(break_stmt)),
|
||||
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
||||
Err(_) => {},
|
||||
}
|
||||
match self.parse_continue_stmt() {
|
||||
Ok(continue_stmt) => return Ok(Statement::Continue(continue_stmt)),
|
||||
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
||||
Err(_) => {},
|
||||
}
|
||||
match self.parse_block_stmt(ParseType::TryParse) {
|
||||
Ok(block_stmt) => return Ok(Statement::Block(block_stmt)),
|
||||
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
||||
Err(_) => {},
|
||||
}
|
||||
match self.parse_expr() {
|
||||
Ok(expr) => {
|
||||
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
|
||||
return Ok(Statement::Expr(expr))
|
||||
},
|
||||
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
|
||||
Err(_) => {},
|
||||
}
|
||||
self.until_next_token(&[TokenValue::Semicolon]);
|
||||
Err(ParseProcessError::ErrorInMatch)
|
||||
}
|
||||
|
||||
fn parse_return_stmt(&mut self) -> Result<ReturnStmt, ParseProcessError> {
|
||||
assert!(!self.is_eof());
|
||||
if self.peek().value != TokenValue::Return {
|
||||
return Err(ParseProcessError::TryNext);
|
||||
}
|
||||
let span = self.next().span;
|
||||
let value = if matches!(self.peek().value, TokenValue::Semicolon) {
|
||||
None
|
||||
} else {
|
||||
Some(self.parse_expr()?)
|
||||
};
|
||||
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
|
||||
Ok(ReturnStmt {
|
||||
value,
|
||||
span,
|
||||
})
|
||||
}
|
||||
fn parse_if_stmt(&mut self) -> Result<IfStmt, ParseProcessError> {
|
||||
assert!(!self.is_eof());
|
||||
if self.peek().value != TokenValue::If {
|
||||
return Err(ParseProcessError::TryNext);
|
||||
}
|
||||
self.advance(1);
|
||||
self.must_match_token(&TokenValue::LParen, "`(`")?;
|
||||
self.must_have_some("if condition expr")?;
|
||||
let condition = self.parse_expr()?;
|
||||
self.must_match_token(&TokenValue::RParen, "`)`")?;
|
||||
let then_branch;
|
||||
let mut ifelse_branch = vec![];
|
||||
let mut else_branch = None;
|
||||
self.must_have_some("if statement body")?;
|
||||
if self.peek().value != TokenValue::LBrace {
|
||||
let stmt = self.parse_stmt()?;
|
||||
then_branch = BlockStmt { statements: vec![stmt] };
|
||||
} else {
|
||||
then_branch = self.parse_block_stmt(ParseType::MustParse)?;
|
||||
}
|
||||
loop {
|
||||
if self.is_eof() {
|
||||
break;
|
||||
}
|
||||
if self.peek().value == TokenValue::Else {
|
||||
self.advance(1);
|
||||
self.must_have_some("else body")?;
|
||||
if self.peek().value != TokenValue::If {
|
||||
self.back(1);
|
||||
break;
|
||||
}
|
||||
// else if
|
||||
self.advance(1);
|
||||
self.must_match_token(&TokenValue::LParen, "`(`")?;
|
||||
self.must_have_some("else if condition expr")?;
|
||||
let condition = self.parse_expr()?;
|
||||
self.must_match_token(&TokenValue::RParen, "`)`")?;
|
||||
let then_branch;
|
||||
if self.peek().value != TokenValue::LBrace {
|
||||
let stmt = self.parse_stmt()?;
|
||||
then_branch = BlockStmt { statements: vec![stmt] };
|
||||
} else {
|
||||
then_branch = self.parse_block_stmt(ParseType::MustParse)?;
|
||||
}
|
||||
ifelse_branch.push(IfElseBranch { condition, then_branch });
|
||||
} else {
|
||||
// if end ?
|
||||
break;
|
||||
}
|
||||
}
|
||||
if self.peek().value == TokenValue::Else {
|
||||
// Parse else branch
|
||||
self.advance(1);
|
||||
self.must_have_some("else body")?;
|
||||
if self.peek().value != TokenValue::LBrace {
|
||||
let stmt = self.parse_stmt()?;
|
||||
else_branch = Some(BlockStmt { statements: vec![stmt] });
|
||||
} else {
|
||||
else_branch = Some(self.parse_block_stmt(ParseType::MustParse)?);
|
||||
}
|
||||
}
|
||||
Ok(IfStmt {
|
||||
condition,
|
||||
then_branch,
|
||||
ifelse_branch,
|
||||
else_branch,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_while_stmt(&mut self) -> Result<WhileStmt, ParseProcessError> {
|
||||
assert!(!self.is_eof());
|
||||
if self.peek().value != TokenValue::While {
|
||||
return Err(ParseProcessError::TryNext);
|
||||
}
|
||||
self.advance(1);
|
||||
self.must_match_token(&TokenValue::LParen, "`(`")?;
|
||||
self.must_have_some("while condition expr")?;
|
||||
let condition = self.parse_expr()?;
|
||||
self.must_match_token(&TokenValue::RParen, "`)`")?;
|
||||
let body;
|
||||
if self.peek().value != TokenValue::LBrace {
|
||||
let stmt = self.parse_stmt()?;
|
||||
body = BlockStmt { statements: vec![stmt] };
|
||||
} else {
|
||||
body = self.parse_block_stmt(ParseType::MustParse)?;
|
||||
}
|
||||
Ok(WhileStmt {
|
||||
condition,
|
||||
body,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_for_stmt(&mut self) -> Result<ForStmt, ParseProcessError> {
|
||||
assert!(!self.is_eof());
|
||||
if self.peek().value != TokenValue::For {
|
||||
return Err(ParseProcessError::TryNext);
|
||||
}
|
||||
self.advance(1);
|
||||
self.must_match_token(&TokenValue::LParen, "`(`")?;
|
||||
let init = if self.peek().value == TokenValue::Semicolon {
|
||||
None
|
||||
} else if matches!(self.peek().value, TokenValue::TypeIdent(_)) {
|
||||
Some(ForInit::VarDecl(self.parse_var_decl_stmt_inner(ParseType::MustParse, false)?))
|
||||
} else {
|
||||
Some(ForInit::Expr(self.parse_expr()?))
|
||||
};
|
||||
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
|
||||
let condition = if self.peek().value == TokenValue::Semicolon {
|
||||
None
|
||||
} else {
|
||||
Some(self.parse_expr()?)
|
||||
};
|
||||
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
|
||||
let update = if self.peek().value == TokenValue::RParen {
|
||||
None
|
||||
} else {
|
||||
Some(self.parse_expr()?)
|
||||
};
|
||||
self.must_match_token(&TokenValue::RParen, "`)`")?;
|
||||
let body;
|
||||
if self.peek().value != TokenValue::LBrace {
|
||||
let stmt = self.parse_stmt()?;
|
||||
body = BlockStmt { statements: vec![stmt] };
|
||||
} else {
|
||||
body = self.parse_block_stmt(ParseType::MustParse)?;
|
||||
}
|
||||
Ok(ForStmt {
|
||||
init,
|
||||
condition,
|
||||
update,
|
||||
body,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_break_stmt(&mut self) -> Result<BreakStmt, ParseProcessError> {
|
||||
assert!(!self.is_eof());
|
||||
let start_span = self.peek().span;
|
||||
if self.peek().value == TokenValue::Break {
|
||||
self.advance(1);
|
||||
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
|
||||
Ok(BreakStmt {
|
||||
span: start_span,
|
||||
})
|
||||
} else {
|
||||
Err(ParseProcessError::TryNext)
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_continue_stmt(&mut self) -> Result<ContinueStmt, ParseProcessError> {
|
||||
assert!(!self.is_eof());
|
||||
let start_span = self.peek().span;
|
||||
if self.peek().value == TokenValue::Continue {
|
||||
self.advance(1);
|
||||
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
|
||||
Ok(ContinueStmt {
|
||||
span: start_span,
|
||||
})
|
||||
} else {
|
||||
Err(ParseProcessError::TryNext)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user