Files
rusty-minic/src/frontend/parser.rs
T

1100 lines
40 KiB
Rust

use crate::{
ast::types::{
BinaryOp, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, FuncDeclStmt, GlobalDeclStmt, IfElseBranch, IfStmt, Param, ReturnStmt, Statement, UnaryOp, VarDeclStmt, VarDeclStmtValue, WhileStmt
},
diagnostic::{Diagnositics, span::Span},
frontend::{
err::ParseError,
types::{Token, TokenValue, TypeIdent},
},
};
pub struct Parser {
tokens: Vec<Token>,
pub diagnostics: Diagnositics,
pos: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ParseType {
MustParse,
TryParse,
}
enum ParseProcessError {
TryNext,
ErrorInMatch
}
impl Parser {
pub fn new(tokens: Vec<Token>, diagnostics: Diagnositics) -> Self {
Self {
tokens,
diagnostics,
pos: 0,
}
}
pub fn parse(&mut self) -> CompileUnit {
self.parse_compile_unit()
}
fn peek(&self) -> Option<&Token> {
self.tokens.get(self.pos)
}
fn next(&mut self) -> Option<&Token> {
let token = self.tokens.get(self.pos);
if token.is_some() {
self.pos += 1;
}
token
}
fn advance(&mut self, n: usize) {
self.pos += n;
assert!(self.pos <= self.tokens.len());
}
fn back(&mut self, n: usize) {
assert!(self.pos >= n);
self.pos -= n;
}
fn last(&self) -> Option<&Token> {
if self.pos == 0 {
None
} else {
self.tokens.get(self.pos - 1)
}
}
fn must_match_token(&mut self, expected: &TokenValue, diagnostic_text: &'static str) -> Result<(), ParseProcessError> {
if let Some(t) = self.peek() {
if &t.value == expected {
self.advance(1);
Ok(())
} else {
let token = self.next().unwrap().clone();
self.diagnostics.add_from_frontend_error(
ParseError::UnexpectedToken(token.value, diagnostic_text),
token.span,
);
Err(ParseProcessError::ErrorInMatch)
}
} else {
let span = self.next().unwrap().span;
self.diagnostics
.add_from_frontend_error(ParseError::ExpectButEof(diagnostic_text), span);
Err(ParseProcessError::ErrorInMatch)
}
}
fn must_have_some(&mut self, diagnostic_text: &'static str) -> Result<(), ParseProcessError> {
if self.peek().is_none() {
let span = self.last().unwrap().span;
self.diagnostics
.add_from_frontend_error(ParseError::ExpectButEof(diagnostic_text), span);
return Err(ParseProcessError::ErrorInMatch);
}
Ok(())
}
fn until_next_token(&mut self, expected: &[TokenValue]) {
while let Some(t) = self.peek() {
if expected.contains(&t.value) {
self.advance(1);
break;
}
self.advance(1);
}
}
fn parse_compile_unit(&mut self) -> CompileUnit {
let mut global_decls = vec![];
while self.peek().is_some() {
if let Some(decl) = self.parse_global_decl_stmt() {
global_decls.push(decl);
} else {
self.until_next_token(&[TokenValue::Semicolon, TokenValue::RBrace]);
}
}
CompileUnit { global_decls }
}
fn parse_global_decl_stmt(&mut self) -> Option<GlobalDeclStmt> {
assert!(self.peek().is_some());
match self.parse_func_decl_stmt() {
Ok(func_decl) => return Some(GlobalDeclStmt::FuncDecl(func_decl)),
Err(ParseProcessError::ErrorInMatch) => {
return None
},
_ => {}
};
match self.parse_var_decl_stmt(ParseType::MustParse) {
Ok(var_decl) => return Some(GlobalDeclStmt::VarDecl(var_decl)),
Err(ParseProcessError::ErrorInMatch) => {
return None
},
_ => {}
}
let token = self.next().unwrap().clone();
self.diagnostics.add_from_frontend_error(
ParseError::UnexpectedToken(token.value, "ident"),
token.span,
);
None
}
// fn until_next_stmt(&mut self) {
// // skip tokens until we find a semicolon or a right brace, which may indicate the end of the declaration
// while let Some(t) = self.peek() {
// if matches!(t.value, TokenValue::Semicolon | TokenValue::RBrace) {
// self.advance(1);
// break;
// }
// self.advance(1);
// }
// }
fn parse_type_and_name(&mut self, parse_type: ParseType) -> Result<(TypeIdent, String, Span, Span), ParseProcessError> {
assert!(self.peek().is_some());
let type_token = self.peek().unwrap().clone();
let type_ident = match self.peek().unwrap().value.as_type_ident() {
Some(ti) => ti,
None => {
if matches!(parse_type, ParseType::MustParse) {
let token = self.next().unwrap().clone();
self.diagnostics.add_from_frontend_error(
ParseError::UnexpectedToken(token.value, "type ident"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
return Err(ParseProcessError::TryNext);
},
};
let type_span = type_token.span;
self.advance(1);
let name = match self.peek().map(|t| t.value.as_ident()) {
None => {
self.diagnostics.add_from_frontend_error(
ParseError::ExpectButEof("ident"),
type_span,
);
return Err(ParseProcessError::ErrorInMatch);
},
Some(None) => {
let next_span = self.peek().unwrap().span;
self.diagnostics.add_from_frontend_error(
ParseError::CantCombineWith(type_token.value),
next_span
);
return Err(ParseProcessError::ErrorInMatch);
}
Some(Some(ident)) => ident,
};
let name_span = self.peek().unwrap().span;
self.advance(1);
Ok((type_ident, name, type_span, name_span))
}
fn parse_func_decl_stmt(&mut self) -> Result<FuncDeclStmt, ParseProcessError> {
assert!(self.peek().is_some());
let (return_type, name, ret_type_span, name_span) = self.parse_type_and_name(ParseType::MustParse)?;
if self
.peek()
.is_some_and(|t| matches!(t.value, TokenValue::LParen))
{
} else {
self.back(2);
return Err(ParseProcessError::TryNext);
}
// from here we can be sure it's a function declaration, so we can report error if the syntax is wrong
let params = self.parse_param_list()?;
let body = match self.peek().map(|t| &t.value) {
Some(_) => self.parse_block_stmt(ParseType::MustParse)?,
None => {
let span = self.next().unwrap().span;
self.diagnostics
.add_from_frontend_error(ParseError::ExpectButEof("function body"), span);
return Err(ParseProcessError::ErrorInMatch);
}
};
Ok(FuncDeclStmt {
return_type: return_type.into(),
name,
params,
body,
ret_type_span,
name_span,
})
}
fn parse_param_list(&mut self) -> Result<Vec<Param>, ParseProcessError> {
assert!(self.peek().is_some());
if self.peek().unwrap().value != TokenValue::LParen {
let token = self.next().unwrap().clone();
self.diagnostics.add_from_frontend_error(
ParseError::UnexpectedToken(token.value, "`(`"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
self.advance(1);
let mut params = vec![];
let mut last_is_var = false;
while self.peek().is_some() {
if self.peek().map(|t| &t.value) == Some(&TokenValue::RParen) {
self.advance(1);
break;
}
if last_is_var {
self.must_match_token(&TokenValue::Comma, "`,` or `)`")
.inspect_err(|_| self.until_next_token(&[TokenValue::RBrace]))?;
}
match self.parse_param() {
Ok(param) => {
params.push(param);
last_is_var = true;
}
Err(_e) => {
self.until_next_token(&[TokenValue::RParen]);
if self.last().map(|t| &t.value) == Some(&TokenValue::RParen) {
break;
}
}
}
}
Ok(params)
}
fn parse_param(&mut self) -> Result<Param, ParseProcessError> {
assert!(self.peek().is_some());
let (param_type, name, type_span, name_span) = self.parse_type_and_name(ParseType::MustParse)?;
Ok(Param {
param_type: param_type.into(),
name,
name_span,
type_span,
})
}
// fn must_match_semicolon(&mut self) -> Option<()> {
// if self
// .peek()
// .is_some_and(|t| matches!(t.value, TokenValue::Semicolon))
// {
// self.advance(1);
// Some(())
// } else {
// let token = self.next().unwrap().clone();
// self.diagnostics
// .add_from_frontend_error(ParseError::UnexpectedToken(token.value, "`;`"), token.span);
// while let Some(t) = self.peek() {
// if matches!(t.value, TokenValue::Semicolon) {
// self.advance(1);
// break;
// }
// if matches!(t.value, TokenValue::RBrace) {
// break;
// }
// self.advance(1);
// }
// None
// }
// }
fn parse_var_decl_stmt(&mut self, parse_type: ParseType) -> Result<VarDeclStmt, ParseProcessError> {
assert!(self.peek().is_some());
let mut values = vec![];
let (var_type, name, type_span, name_span) = match self.parse_type_and_name(parse_type) {
Ok(res) => res,
Err(_e) => {
if matches!(parse_type, ParseType::TryParse) {
return Err(ParseProcessError::TryNext);
} else {
return Err(ParseProcessError::ErrorInMatch);
}
}
};
values.push(VarDeclStmtValue { name, name_span });
let mut last_name = true; // indicate whether the last parsed token is a variable name
while let Some(t) = self.peek() {
if matches!(t.value, TokenValue::Semicolon) { // statement end
break;
}
if last_name { // expect a comma after a variable name
self.must_match_token(&TokenValue::Comma, "`,` or `;`")?;
last_name = false;
}
// check eof again
if self.peek().is_none() {
let span = self.last().unwrap().span;
self.diagnostics
.add_from_frontend_error(ParseError::ExpectButEof("`,` or `;`"), span);
break;
}
if let Some(ident) = self.peek().unwrap().value.as_ident() {
let span = self.next().unwrap().span;
values.push(VarDeclStmtValue { name: ident, name_span: span });
last_name = true;
} else {
let token = self.next().unwrap().clone();
self.diagnostics.add_from_frontend_error(
ParseError::CantCombineWith(TokenValue::TypeIdent(var_type)),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
}
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
Ok(VarDeclStmt { values, type_span, data_type: var_type.into() })
}
fn parse_block_stmt(&mut self, parse_type: ParseType) -> Result<BlockStmt, ParseProcessError> {
assert!(self.peek().is_some());
if self
.peek()
.unwrap().value != TokenValue::LBrace
{
if parse_type == ParseType::MustParse {
let token = self.next().unwrap().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.peek().is_none() {
let span = self.last().unwrap().span;
self.diagnostics
.add_from_frontend_error(ParseError::ExpectButEof("`}`"), span);
return Err(ParseProcessError::ErrorInMatch);
}
if self
.peek()
.map(|t| matches!(t.value, TokenValue::Semicolon))
.unwrap()
{
// like a();;
self.advance(1);
continue;
}
if self
.peek()
.map(|t| matches!(t.value, TokenValue::RBrace))
.unwrap()
{
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().unwrap().value == TokenValue::RBrace {
break;
}
}
}
}
// println!("finish parse block stmt");
Ok(BlockStmt {
statements
})
}
fn parse_stmt(&mut self) -> Result<Statement, ParseProcessError> {
assert!(self.peek().is_some());
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_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.peek().is_some());
if self.peek().unwrap().value != TokenValue::Return {
return Err(ParseProcessError::TryNext);
}
let span = self.next().unwrap().span;
let value = if self
.peek()
.map(|t| matches!(t.value, TokenValue::Semicolon))
.unwrap_or(false)
{
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.peek().is_some());
if self.peek().unwrap().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().unwrap().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.peek().is_none() {
break;
}
if self.peek().unwrap().value == TokenValue::Else {
self.advance(1);
self.must_have_some("else body")?;
if self.peek().unwrap().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().unwrap().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().is_some_and(|t| t.value == TokenValue::Else) {
// Parse else branch
self.advance(1);
self.must_have_some("else body")?;
if self.peek().unwrap().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.peek().is_some());
if self.peek().unwrap().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().unwrap().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_break_stmt(&mut self) -> Result<BreakStmt, ParseProcessError> {
assert!(self.peek().is_some());
let start_span = self.peek().unwrap().span;
if self.peek().unwrap().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.peek().is_some());
let start_span = self.peek().unwrap().span;
if self.peek().unwrap().value == TokenValue::Continue {
self.advance(1);
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
Ok(ContinueStmt {
span: start_span,
})
} else {
Err(ParseProcessError::TryNext)
}
}
// fn parse_expr_tail(&mut self, left: Expr) -> Option<Expr> {
// match self.peek() {
// None => Some(left),
// Some(t1) => {
// // TODO: add delimiter judge to support better error recovery
// let op = BinaryOp::from_token_value(&t1.value)?;
// match op {
// BinaryOp::Add
// }
// let right = self.parse_term()?;
// let expr = Expr { value: ExprValue::BinaryOp { lhs: Box::new(left), op, rhs: Box::new(right) }, span: Span::from_two(left.span, right.span) };
// self.parse_expr_tail(expr)
// }
// }
// }
fn parse_primary(&mut self) -> Result<Expr, ParseProcessError> {
assert!(self.peek().is_some());
let token = self.next().unwrap().clone();
match token.value {
TokenValue::Ident(name) => {
if self
.peek()
.is_some_and(|t| matches!(t.value, TokenValue::LParen))
{
self.advance(1);
let mut args = vec![];
loop {
match self.peek() {
Some(t) if matches!(t.value, TokenValue::RParen) => {
let end_span = t.span;
self.advance(1);
return Ok(Expr {
value: ExprValue::FuncCall(name, args),
span: Span::from_two(token.span, end_span),
});
}
Some(_) => {}
None => {
self.diagnostics.add_from_frontend_error(
ParseError::ExpectButEof("`)`"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
}
args.push(self.parse_expr()?);
match self.peek() {
Some(t) if matches!(t.value, TokenValue::Comma) => {
self.advance(1);
}
Some(t) if matches!(t.value, TokenValue::RParen) => {
let end_span = t.span;
self.advance(1);
return Ok(Expr {
value: ExprValue::FuncCall(name, args),
span: Span::from_two(token.span, end_span),
});
}
Some(_) => {
let token = self.next().unwrap().clone();
self.diagnostics.add_from_frontend_error(
ParseError::UnexpectedToken(token.value, "`,` or `)`"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
None => {
self.diagnostics.add_from_frontend_error(
ParseError::ExpectButEof("`)`"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
}
}
}
Ok(Expr {
value: ExprValue::Var(name),
span: token.span,
})
},
TokenValue::IntLit(value) => Ok(Expr {
value: ExprValue::IntLit(value),
span: token.span,
}),
TokenValue::LParen => {
let expr = match self.peek() {
Some(_) => self.parse_expr()?,
None => {
self.diagnostics.add_from_frontend_error(
ParseError::ExpectButEof("expression"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
};
match self.peek() {
Some(t) if matches!(t.value, TokenValue::RParen) => {
let end_span = t.span;
self.advance(1);
Ok(Expr {
span: Span::from_two(token.span, end_span),
..expr
})
}
Some(_) => {
let token = self.next().unwrap().clone();
self.diagnostics.add_from_frontend_error(
ParseError::UnexpectedToken(token.value, "`)`"),
token.span,
);
Err(ParseProcessError::ErrorInMatch)
}
None => {
self.diagnostics
.add_from_frontend_error(ParseError::ExpectButEof("`)`"), expr.span);
Err(ParseProcessError::ErrorInMatch)
}
}
}
_ => {
self.diagnostics.add_from_frontend_error(
ParseError::UnexpectedToken(token.value, "expression"),
token.span,
);
Err(ParseProcessError::ErrorInMatch)
}
}
}
fn parse_unary(&mut self) -> Result<Expr, ParseProcessError> {
assert!(self.peek().is_some());
let token = self.peek().unwrap().clone();
match token.value {
TokenValue::Plus => {
self.advance(1);
let expr = match self.peek() {
Some(_) => self.parse_unary()?,
None => {
self.diagnostics.add_from_frontend_error(
ParseError::ExpectButEof("expression"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
};
let span = Span::from_two(token.span, expr.span);
Ok(Expr {
value: ExprValue::UnaryOp {
op: UnaryOp::Add,
operand: Box::new(expr),
},
span,
})
}
TokenValue::Minus => {
self.advance(1);
let rhs = match self.peek() {
Some(_) => self.parse_unary()?,
None => {
self.diagnostics.add_from_frontend_error(
ParseError::ExpectButEof("expression"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
};
let span = Span::from_two(token.span, rhs.span);
Ok(Expr {
value: ExprValue::UnaryOp {
op: UnaryOp::Sub,
operand: Box::new(rhs),
},
span,
})
}
TokenValue::Not => {
self.advance(1);
let rhs = match self.peek() {
Some(_) => self.parse_unary()?,
None => {
self.diagnostics.add_from_frontend_error(
ParseError::ExpectButEof("expression"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
};
let span = Span::from_two(token.span, rhs.span);
Ok(Expr {
value: ExprValue::UnaryOp {
op: UnaryOp::Not,
operand: Box::new(rhs),
},
span,
})
}
_ => self.parse_primary(),
}
}
fn parse_multiplicative(&mut self) -> Result<Expr, ParseProcessError> {
assert!(self.peek().is_some());
let mut left = self.parse_unary()?;
while let Some(t) = self.peek() {
let op = match t.value {
TokenValue::Star => BinaryOp::Mul,
TokenValue::Slash => BinaryOp::Div,
TokenValue::Percent => BinaryOp::Mod,
_ => break,
};
self.advance(1);
let right = match self.peek() {
Some(_) => self.parse_unary()?,
None => {
self.diagnostics
.add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span);
return Err(ParseProcessError::ErrorInMatch);
}
};
let span = Span::from_two(left.span, right.span);
left = Expr {
value: ExprValue::BinaryOp {
lhs: Box::new(left),
op,
rhs: Box::new(right),
},
span,
};
}
Ok(left)
}
fn parse_additive(&mut self) -> Result<Expr, ParseProcessError> {
assert!(self.peek().is_some());
let mut left = self.parse_multiplicative()?;
while let Some(t) = self.peek() {
let op = match t.value {
TokenValue::Plus => BinaryOp::Add,
TokenValue::Minus => BinaryOp::Sub,
_ => break,
};
self.advance(1);
let right = match self.peek() {
Some(_) => self.parse_multiplicative()?,
None => {
self.diagnostics
.add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span);
return Err(ParseProcessError::ErrorInMatch);
}
};
let span = Span::from_two(left.span, right.span);
left = Expr {
value: ExprValue::BinaryOp {
lhs: Box::new(left),
op,
rhs: Box::new(right),
},
span,
};
}
Ok(left)
}
fn parse_relational(&mut self) -> Result<Expr, ParseProcessError> {
assert!(self.peek().is_some());
let mut left = self.parse_additive()?;
while let Some(t) = self.peek() {
let op = match t.value {
TokenValue::Less => BinaryOp::Less,
TokenValue::Greater => BinaryOp::Greater,
TokenValue::LessEqual => BinaryOp::LessEqual,
TokenValue::GreaterEqual => BinaryOp::GreaterEqual,
TokenValue::DoubleEqual => BinaryOp::Equal,
TokenValue::NotEqual => BinaryOp::NotEqual,
_ => break,
};
self.advance(1);
let right = match self.peek() {
Some(_) => self.parse_additive()?,
None => {
self.diagnostics
.add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span);
return Err(ParseProcessError::ErrorInMatch);
}
};
let span = Span::from_two(left.span, right.span);
left = Expr {
value: ExprValue::BinaryOp {
lhs: Box::new(left),
op,
rhs: Box::new(right),
},
span,
};
}
Ok(left)
}
fn parse_logical_and(&mut self) -> Result<Expr, ParseProcessError> {
assert!(self.peek().is_some());
let mut left = self.parse_relational()?;
while let Some(t) = self.peek() {
let op = match t.value {
TokenValue::And => BinaryOp::And,
_ => break,
};
self.advance(1);
let right = match self.peek() {
Some(_) => self.parse_relational()?,
None => {
self.diagnostics
.add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span);
return Err(ParseProcessError::ErrorInMatch);
}
};
let span = Span::from_two(left.span, right.span);
left = Expr {
value: ExprValue::BinaryOp {
lhs: Box::new(left),
op,
rhs: Box::new(right),
},
span,
};
}
Ok(left)
}
fn parse_logical_or(&mut self) -> Result<Expr, ParseProcessError> {
assert!(self.peek().is_some());
let mut left = self.parse_logical_and()?;
while let Some(t) = self.peek() {
let op = match t.value {
TokenValue::Or => BinaryOp::Or,
_ => break,
};
self.advance(1);
let right = match self.peek() {
Some(_) => self.parse_logical_and()?,
None => {
self.diagnostics
.add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span);
return Err(ParseProcessError::ErrorInMatch);
}
};
let span = Span::from_two(left.span, right.span);
left = Expr {
value: ExprValue::BinaryOp {
lhs: Box::new(left),
op,
rhs: Box::new(right),
},
span,
};
}
Ok(left)
}
fn parse_assign(&mut self) -> Result<Expr, ParseProcessError> {
assert!(self.peek().is_some());
let is_assign = matches!(
(self.tokens.get(self.pos), self.tokens.get(self.pos + 1)),
(
Some(Token {
value: TokenValue::Ident(_),
..
}),
Some(Token {
value: TokenValue::Equal,
..
})
)
);
if !is_assign {
return self.parse_logical_or();
}
let lvalue_token = self.next().unwrap().clone();
let name = lvalue_token.value.as_ident().unwrap();
self.advance(1);
let rvalue = match self.peek() {
Some(_) => self.parse_assign()?,
None => {
self.diagnostics.add_from_frontend_error(
ParseError::ExpectButEof("expression"),
lvalue_token.span,
);
return Err(ParseProcessError::ErrorInMatch);
}
};
let lvalue = Expr {
value: ExprValue::Var(name),
span: lvalue_token.span,
};
let span = Span::from_two(lvalue.span, rvalue.span);
Ok(Expr {
value: ExprValue::Assign {
lvalue: Box::new(lvalue),
rvalue: Box::new(rvalue),
},
span,
})
}
/*
expr
:= assign
assign
:= logical
| IDENT "=" assign
logical
:= relational
| logical "||" relational
| logical "&&" relational
relational
:= additive
| relational "<" additive
| relational ">" additive
| relational "<=" additive
| relational ">=" additive
| relational "==" additive
| relational "!=" additive
additive
:= multiplicative
| additive "+" multiplicative
| additive "-" multiplicative
multiplicative
:= unary
| multiplicative "*" unary
| multiplicative "/" unary
unary
:= primary
| "+" unary
| "-" unary
primary
:= IDENT
| NUMBER
| "(" expr ")"
*/
fn parse_expr(&mut self) -> Result<Expr, ParseProcessError> {
assert!(self.peek().is_some());
self.parse_assign()
}
}
#[cfg(test)]
mod tests {
use std::io::BufRead;
use std::path::Path;
use std::fs::File;
use crate::ast::graph::AstGraphExt;
use crate::frontend::lexer::Lexer;
use crate::utils::case_list::CaseList;
use crate::utils::num_sequence::NumberSequence;
pub use super::*;
fn test_case(case_str: &str) {
let case_sequence = NumberSequence::from_str(case_str).unwrap();
let case_list = CaseList::from_dir(&Path::new("./testcases")).unwrap();
let mut error_case_cnt = 0;
for case_no in case_sequence {
let case_path = case_list.get_case_path(case_no).unwrap();
println!("{}", case_path.display());
let file = File::open(&case_path).unwrap();
let mut buf_reader = std::io::BufReader::new(file);
let mut lexer = Lexer::new();
let mut full_text = String::new();
loop {
let mut line = String::new();
let bytes_read = buf_reader.read_line(&mut line).unwrap();
if bytes_read == 0 {
break;
}
full_text.push_str(&line);
lexer.parse_next_str(&line);
}
let (tokens, diagnostics) = lexer.finish();
let mut is_error = false;
if !diagnostics.is_empty() {
diagnostics.print(&format!("{}", case_path.display()), &full_text);
is_error = true;
}
let mut parser = Parser::new(tokens, diagnostics);
let compile_unit = parser.parse_compile_unit();
let dot = compile_unit.to_dot();
let case_name = case_list.get_case_name(case_no).unwrap().strip_suffix(".c").unwrap();
std::fs::write(format!("output/{}.dot", case_name), dot).unwrap();
if !parser.diagnostics.is_empty() {
parser.diagnostics.print(&format!("{}", case_path.display()), &full_text);
is_error = true;
}
if is_error {
error_case_cnt += 1;
}
}
if error_case_cnt > 0 {
panic!("Found {} cases with errors", error_case_cnt);
}
}
#[test]
fn test_expr() {
test_case("0-3,14-25");
// test_case("0-3,14-25");
}
#[test]
fn test_if_while() {
test_case("26-32,34-41,46-51,57");
}
#[test]
fn test_error() {
test_case("999");
}
}