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, 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, 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 { 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 { 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, 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { // 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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"); } }