diff --git a/src/ast/parser.rs b/src/ast/parser.rs deleted file mode 100644 index 48f5c67..0000000 --- a/src/ast/parser.rs +++ /dev/null @@ -1,1284 +0,0 @@ -use crate::{ - ast::types::{ - ArrayDimension, BinaryOp, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, ForInit, ForStmt, FuncDeclStmt, GlobalDeclStmt, IfElseBranch, IfStmt, IncDecOp, Param, ReturnStmt, Statement, UnaryOp, VarDeclStmt, VarDeclStmtValue, WhileStmt - }, - diagnostic::{Diagnositics, span::Span}, - lexer::{ - err::ParseError, - types::{Token, TokenValue, TypeIdent}, - }, -}; - -pub struct Parser { - tokens: Vec, - eof_token: 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, diagnostics: Diagnositics) -> Self { - let eof_pos = tokens.last().map_or(0, |token| token.span.end); - Self { - tokens, - eof_token: Token { - value: TokenValue::Eof, - span: Span { - start: eof_pos, - end: eof_pos, - }, - }, - diagnostics, - pos: 0, - } - } - pub fn parse(&mut self) -> CompileUnit { - self.parse_compile_unit() - } - fn peek(&self) -> &Token { - self.tokens.get(self.pos).unwrap_or(&self.eof_token) - } - fn peek_n(&self, n: usize) -> &Token { - self.tokens.get(self.pos + n).unwrap_or(&self.eof_token) - } - fn next(&mut self) -> Token { - let token = self.peek().clone(); - if !matches!(token.value, TokenValue::Eof) { - 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) -> &Token { - if self.pos == 0 { - &self.eof_token - } else { - self.tokens.get(self.pos - 1).unwrap_or(&self.eof_token) - } - } - fn is_eof(&self) -> bool { - matches!(self.peek().value, TokenValue::Eof) - } - fn must_match_token(&mut self, expected: &TokenValue, diagnostic_text: &'static str) -> Result<(), ParseProcessError> { - if &self.peek().value == expected { - self.advance(1); - Ok(()) - } else if self.is_eof() { - let span = self.peek().span; - self.diagnostics - .add_from_frontend_error(ParseError::ExpectButEof(diagnostic_text), span); - Err(ParseProcessError::ErrorInMatch) - } else { - let token = self.next(); - self.diagnostics.add_from_frontend_error( - ParseError::UnexpectedToken(token.value, diagnostic_text), - token.span, - ); - Err(ParseProcessError::ErrorInMatch) - } - } - fn must_have_some(&mut self, diagnostic_text: &'static str) -> Result<(), ParseProcessError> { - if self.is_eof() { - let span = self.last().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 !self.is_eof() { - if expected.contains(&self.peek().value) { - self.advance(1); - break; - } - self.advance(1); - } - } - fn parse_compile_unit(&mut self) -> CompileUnit { - let mut global_decls = vec![]; - while !self.is_eof() { - 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.is_eof()); - 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().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.is_eof()); - let type_token = self.peek().clone(); - let type_ident = match self.peek().value.as_type_ident() { - Some(ti) => ti, - None => { - if matches!(parse_type, ParseType::MustParse) { - let token = self.next().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().value.as_ident() { - None if self.is_eof() => { - self.diagnostics.add_from_frontend_error( - ParseError::ExpectButEof("ident"), - type_span, - ); - return Err(ParseProcessError::ErrorInMatch); - }, - None => { - let next_span = self.peek().span; - self.diagnostics.add_from_frontend_error( - ParseError::CantCombineWith(type_token.value), - next_span - ); - return Err(ParseProcessError::ErrorInMatch); - } - Some(ident) => ident, - }; - let name_span = self.peek().span; - self.advance(1); - Ok((type_ident, name, type_span, name_span)) - } - fn parse_func_decl_stmt(&mut self) -> Result { - assert!(!self.is_eof()); - let (return_type, name, ret_type_span, name_span) = self.parse_type_and_name(ParseType::MustParse)?; - if matches!(self.peek().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 = if self.is_eof() { - let span = self.next().span; - self.diagnostics - .add_from_frontend_error(ParseError::ExpectButEof("function body"), span); - return Err(ParseProcessError::ErrorInMatch); - } else { - self.parse_block_stmt(ParseType::MustParse)? - }; - 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.is_eof()); - if self.peek().value != TokenValue::LParen { - let token = self.next().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.is_eof() { - if self.peek().value == 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().value == TokenValue::RParen { - break; - } - } - } - } - Ok(params) - } - fn parse_param(&mut self) -> Result { - assert!(!self.is_eof()); - let (param_type, name, type_span, name_span) = self.parse_type_and_name(ParseType::MustParse)?; - Ok(Param { - param_type: param_type.into(), - name, - dimensions: self.parse_array_dimensions(true)?, - 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().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 { - self.parse_var_decl_stmt_inner(parse_type, true) - } - - fn parse_var_decl_stmt_inner(&mut self, parse_type: ParseType, consume_semicolon: bool) -> Result { - assert!(!self.is_eof()); - 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); - } - } - }; - let dimensions = self.parse_array_dimensions(false)?; - let value = if self.peek().value == TokenValue::Equal { - self.advance(1); - Some(self.parse_expr()?) - } else { - None - }; - values.push(VarDeclStmtValue { name, name_span, dimensions, value }); - let mut last_name = true; // indicate whether the last parsed token is a variable name - while !self.is_eof() { - if matches!(self.peek().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.is_eof() { - let span = self.last().span; - self.diagnostics - .add_from_frontend_error(ParseError::ExpectButEof("`,` or `;`"), span); - break; - } - if let Some(ident) = self.peek().value.as_ident() { - let span = self.next().span; - let dimensions = self.parse_array_dimensions(false)?; - let value = if self.peek().value == TokenValue::Equal { - self.advance(1); - Some(self.parse_expr()?) - } else { - None - }; - values.push(VarDeclStmtValue { name: ident, name_span: span, dimensions, value }); - last_name = true; - } else { - let token = self.next().clone(); - self.diagnostics.add_from_frontend_error( - ParseError::CantCombineWith(TokenValue::TypeIdent(var_type)), - token.span, - ); - return Err(ParseProcessError::ErrorInMatch); - } - } - if consume_semicolon { - self.must_match_token(&TokenValue::Semicolon, "`;`")?; - } - Ok(VarDeclStmt { values, type_span, data_type: var_type.into() }) - } - - fn parse_array_dimensions(&mut self, allow_empty_first: bool) -> Result, ParseProcessError> { - let mut dimensions = vec![]; - while self.peek().value == TokenValue::LBracket { - let start_span = self.next().span; - let value = if self.peek().value == TokenValue::RBracket { - if !allow_empty_first || !dimensions.is_empty() { - let span = self.peek().span; - self.diagnostics.add_from_frontend_error( - ParseError::UnexpectedToken(TokenValue::RBracket, "array dimension expression"), - span, - ); - return Err(ParseProcessError::ErrorInMatch); - } - None - } else { - Some(self.parse_expr()?) - }; - let end_span = match &self.peek().value { - TokenValue::RBracket => { - let span = self.peek().span; - self.advance(1); - span - } - TokenValue::Eof => { - self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("`]`"), start_span); - return Err(ParseProcessError::ErrorInMatch); - } - _ => { - let token = self.next(); - self.diagnostics.add_from_frontend_error( - ParseError::UnexpectedToken(token.value, "`]`"), - token.span, - ); - return Err(ParseProcessError::ErrorInMatch); - } - }; - dimensions.push(ArrayDimension { - value, - span: Span::from_two(start_span, end_span), - }); - } - Ok(dimensions) - } - - fn parse_block_stmt(&mut self, parse_type: ParseType) -> Result { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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 { - 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) - } - } - // 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_atom(&mut self) -> Result { - assert!(!self.is_eof()); - let token = self.next().clone(); - match token.value { - TokenValue::Ident(name) => { - if matches!(self.peek().value, TokenValue::LParen) { - self.advance(1); - let mut args = vec![]; - loop { - match &self.peek().value { - TokenValue::RParen => { - let end_span = self.peek().span; - self.advance(1); - return Ok(Expr { - value: ExprValue::FuncCall(name, args), - span: Span::from_two(token.span, end_span), - }); - } - TokenValue::Eof => { - self.diagnostics.add_from_frontend_error( - ParseError::ExpectButEof("`)`"), - token.span, - ); - return Err(ParseProcessError::ErrorInMatch); - } - _ => {} - } - args.push(self.parse_expr()?); - match &self.peek().value { - TokenValue::Comma => { - self.advance(1); - } - TokenValue::RParen => { - let end_span = self.peek().span; - self.advance(1); - return Ok(Expr { - value: ExprValue::FuncCall(name, args), - span: Span::from_two(token.span, end_span), - }); - } - TokenValue::Eof => { - self.diagnostics.add_from_frontend_error( - ParseError::ExpectButEof("`)`"), - token.span, - ); - return Err(ParseProcessError::ErrorInMatch); - } - _ => { - let token = self.next(); - self.diagnostics.add_from_frontend_error( - ParseError::UnexpectedToken(token.value, "`,` or `)`"), - 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 = if self.is_eof() { - self.diagnostics.add_from_frontend_error( - ParseError::ExpectButEof("expression"), - token.span, - ); - return Err(ParseProcessError::ErrorInMatch); - } else { - self.parse_expr()? - }; - match &self.peek().value { - TokenValue::RParen => { - let end_span = self.peek().span; - self.advance(1); - Ok(Expr { - span: Span::from_two(token.span, end_span), - ..expr - }) - } - TokenValue::Eof => { - self.diagnostics - .add_from_frontend_error(ParseError::ExpectButEof("`)`"), expr.span); - Err(ParseProcessError::ErrorInMatch) - } - _ => { - let token = self.next(); - self.diagnostics.add_from_frontend_error( - ParseError::UnexpectedToken(token.value, "`)`"), - token.span, - ); - Err(ParseProcessError::ErrorInMatch) - } - } - } - _ => { - self.diagnostics.add_from_frontend_error( - ParseError::UnexpectedToken(token.value, "expression"), - token.span, - ); - Err(ParseProcessError::ErrorInMatch) - } - } - } - fn parse_primary(&mut self) -> Result { - let mut expr = self.parse_primary_atom()?; - loop { - if self.peek().value == TokenValue::LBracket { - let start_span = expr.span; - self.advance(1); - let index = if self.is_eof() { - self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("array index expression"), start_span); - return Err(ParseProcessError::ErrorInMatch); - } else { - self.parse_expr()? - }; - let end_span = match &self.peek().value { - TokenValue::RBracket => { - let span = self.peek().span; - self.advance(1); - span - } - TokenValue::Eof => { - self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("`]`"), index.span); - return Err(ParseProcessError::ErrorInMatch); - } - _ => { - let token = self.next(); - self.diagnostics.add_from_frontend_error( - ParseError::UnexpectedToken(token.value, "`]`"), - token.span, - ); - return Err(ParseProcessError::ErrorInMatch); - } - }; - expr = Expr { - value: ExprValue::ArrayAccess { - array: Box::new(expr), - index: Box::new(index), - }, - span: Span::from_two(start_span, end_span), - }; - continue; - } - let op = match (&self.peek().value, &self.peek_n(1).value) { - (TokenValue::Plus, TokenValue::Plus) => Some(IncDecOp::Inc), - (TokenValue::Minus, TokenValue::Minus) => Some(IncDecOp::Dec), - _ => None, - }; - if let Some(op) = op { - let end_span = self.peek_n(1).span; - self.advance(2); - expr = Expr { - span: Span::from_two(expr.span, end_span), - value: ExprValue::IncDec { - op, - operand: Box::new(expr), - is_prefix: false, - }, - }; - continue; - } - break; - } - Ok(expr) - } - fn parse_unary(&mut self) -> Result { - assert!(!self.is_eof()); - let token = self.peek().clone(); - match token.value { - TokenValue::Plus => { - if self.peek_n(1).value == TokenValue::Plus { - self.advance(2); - let expr = if self.is_eof() { - self.diagnostics.add_from_frontend_error( - ParseError::ExpectButEof("expression"), - token.span, - ); - return Err(ParseProcessError::ErrorInMatch); - } else { - self.parse_unary()? - }; - let span = Span::from_two(token.span, expr.span); - return Ok(Expr { - value: ExprValue::IncDec { - op: IncDecOp::Inc, - operand: Box::new(expr), - is_prefix: true, - }, - span, - }); - } - self.advance(1); - let expr = if self.is_eof() { - self.diagnostics.add_from_frontend_error( - ParseError::ExpectButEof("expression"), - token.span, - ); - return Err(ParseProcessError::ErrorInMatch); - } else { - self.parse_unary()? - }; - let span = Span::from_two(token.span, expr.span); - Ok(Expr { - value: ExprValue::UnaryOp { - op: UnaryOp::Add, - operand: Box::new(expr), - }, - span, - }) - } - TokenValue::Minus => { - if self.peek_n(1).value == TokenValue::Minus { - self.advance(2); - let rhs = if self.is_eof() { - self.diagnostics.add_from_frontend_error( - ParseError::ExpectButEof("expression"), - token.span, - ); - return Err(ParseProcessError::ErrorInMatch); - } else { - self.parse_unary()? - }; - let span = Span::from_two(token.span, rhs.span); - return Ok(Expr { - value: ExprValue::IncDec { - op: IncDecOp::Dec, - operand: Box::new(rhs), - is_prefix: true, - }, - span, - }); - } - self.advance(1); - let rhs = if self.is_eof() { - self.diagnostics.add_from_frontend_error( - ParseError::ExpectButEof("expression"), - token.span, - ); - return Err(ParseProcessError::ErrorInMatch); - } else { - self.parse_unary()? - }; - 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 = if self.is_eof() { - self.diagnostics.add_from_frontend_error( - ParseError::ExpectButEof("expression"), - token.span, - ); - return Err(ParseProcessError::ErrorInMatch); - } else { - self.parse_unary()? - }; - 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.is_eof()); - let mut left = self.parse_unary()?; - while !self.is_eof() { - let op = match self.peek().value { - TokenValue::Star => BinaryOp::Mul, - TokenValue::Slash => BinaryOp::Div, - TokenValue::Percent => BinaryOp::Mod, - _ => break, - }; - self.advance(1); - let right = if self.is_eof() { - self.diagnostics - .add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span); - return Err(ParseProcessError::ErrorInMatch); - } else { - self.parse_unary()? - }; - 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.is_eof()); - let mut left = self.parse_multiplicative()?; - while !self.is_eof() { - let op = match self.peek().value { - TokenValue::Plus => BinaryOp::Add, - TokenValue::Minus => BinaryOp::Sub, - _ => break, - }; - self.advance(1); - let right = if self.is_eof() { - self.diagnostics - .add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span); - return Err(ParseProcessError::ErrorInMatch); - } else { - self.parse_multiplicative()? - }; - 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.is_eof()); - let mut left = self.parse_additive()?; - while !self.is_eof() { - let op = match self.peek().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 = if self.is_eof() { - self.diagnostics - .add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span); - return Err(ParseProcessError::ErrorInMatch); - } else { - self.parse_additive()? - }; - 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.is_eof()); - let mut left = self.parse_relational()?; - while !self.is_eof() { - let op = match self.peek().value { - TokenValue::And => BinaryOp::And, - _ => break, - }; - self.advance(1); - let right = if self.is_eof() { - self.diagnostics - .add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span); - return Err(ParseProcessError::ErrorInMatch); - } else { - self.parse_relational()? - }; - 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.is_eof()); - let mut left = self.parse_logical_and()?; - while !self.is_eof() { - let op = match self.peek().value { - TokenValue::Or => BinaryOp::Or, - _ => break, - }; - self.advance(1); - let right = if self.is_eof() { - self.diagnostics - .add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span); - return Err(ParseProcessError::ErrorInMatch); - } else { - self.parse_logical_and()? - }; - 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.is_eof()); - let lvalue = self.parse_logical_or()?; - if self.peek().value != TokenValue::Equal { - return Ok(lvalue); - } - self.advance(1); - let rvalue = if self.is_eof() { - self.diagnostics.add_from_frontend_error( - ParseError::ExpectButEof("expression"), - lvalue.span, - ); - return Err(ParseProcessError::ErrorInMatch); - } else { - self.parse_assign()? - }; - 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.is_eof()); - 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::lexer::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"); - } - #[test] - fn test_func() { - test_case("12-13,58-60"); - } - #[test] - fn test_array() { - test_case("4-7,11,42,71,74-78,82,84,86,90,95,96,100,101,103"); - } -} diff --git a/src/ast/parser/decl.rs b/src/ast/parser/decl.rs new file mode 100644 index 0000000..71c5f7c --- /dev/null +++ b/src/ast/parser/decl.rs @@ -0,0 +1,310 @@ +use crate::{ + ast::types::{ + ArrayDimension, CompileUnit, FuncDeclStmt, GlobalDeclStmt, Param, VarDeclStmt, VarDeclStmtValue, + }, + diagnostic::span::Span, + lexer::{ + err::ParseError, + types::{TokenValue, TypeIdent}, + }, +}; + +use super::{ParseProcessError, ParseType, Parser}; + +impl Parser { + pub(super) fn parse_compile_unit(&mut self) -> CompileUnit { + let mut global_decls = vec![]; + while !self.is_eof() { + 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.is_eof()); + 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().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.is_eof()); + let type_token = self.peek().clone(); + let type_ident = match self.peek().value.as_type_ident() { + Some(ti) => ti, + None => { + if matches!(parse_type, ParseType::MustParse) { + let token = self.next().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().value.as_ident() { + None if self.is_eof() => { + self.diagnostics.add_from_frontend_error( + ParseError::ExpectButEof("ident"), + type_span, + ); + return Err(ParseProcessError::ErrorInMatch); + }, + None => { + let next_span = self.peek().span; + self.diagnostics.add_from_frontend_error( + ParseError::CantCombineWith(type_token.value), + next_span + ); + return Err(ParseProcessError::ErrorInMatch); + } + Some(ident) => ident, + }; + let name_span = self.peek().span; + self.advance(1); + Ok((type_ident, name, type_span, name_span)) + } + fn parse_func_decl_stmt(&mut self) -> Result { + assert!(!self.is_eof()); + let (return_type, name, ret_type_span, name_span) = self.parse_type_and_name(ParseType::MustParse)?; + if matches!(self.peek().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 = if self.is_eof() { + let span = self.next().span; + self.diagnostics + .add_from_frontend_error(ParseError::ExpectButEof("function body"), span); + return Err(ParseProcessError::ErrorInMatch); + } else { + self.parse_block_stmt(ParseType::MustParse)? + }; + 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.is_eof()); + if self.peek().value != TokenValue::LParen { + let token = self.next().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.is_eof() { + if self.peek().value == 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().value == TokenValue::RParen { + break; + } + } + } + } + Ok(params) + } + fn parse_param(&mut self) -> Result { + assert!(!self.is_eof()); + let (param_type, name, type_span, name_span) = self.parse_type_and_name(ParseType::MustParse)?; + Ok(Param { + param_type: param_type.into(), + name, + dimensions: self.parse_array_dimensions(true)?, + 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().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 + // } + // } + pub(super) fn parse_var_decl_stmt(&mut self, parse_type: ParseType) -> Result { + self.parse_var_decl_stmt_inner(parse_type, true) + } + + pub(super) fn parse_var_decl_stmt_inner(&mut self, parse_type: ParseType, consume_semicolon: bool) -> Result { + assert!(!self.is_eof()); + 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); + } + } + }; + let dimensions = self.parse_array_dimensions(false)?; + let value = if self.peek().value == TokenValue::Equal { + self.advance(1); + Some(self.parse_expr()?) + } else { + None + }; + values.push(VarDeclStmtValue { name, name_span, dimensions, value }); + let mut last_name = true; // indicate whether the last parsed token is a variable name + while !self.is_eof() { + if matches!(self.peek().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.is_eof() { + let span = self.last().span; + self.diagnostics + .add_from_frontend_error(ParseError::ExpectButEof("`,` or `;`"), span); + break; + } + if let Some(ident) = self.peek().value.as_ident() { + let span = self.next().span; + let dimensions = self.parse_array_dimensions(false)?; + let value = if self.peek().value == TokenValue::Equal { + self.advance(1); + Some(self.parse_expr()?) + } else { + None + }; + values.push(VarDeclStmtValue { name: ident, name_span: span, dimensions, value }); + last_name = true; + } else { + let token = self.next().clone(); + self.diagnostics.add_from_frontend_error( + ParseError::CantCombineWith(TokenValue::TypeIdent(var_type)), + token.span, + ); + return Err(ParseProcessError::ErrorInMatch); + } + } + if consume_semicolon { + self.must_match_token(&TokenValue::Semicolon, "`;`")?; + } + Ok(VarDeclStmt { values, type_span, data_type: var_type.into() }) + } + + fn parse_array_dimensions(&mut self, allow_empty_first: bool) -> Result, ParseProcessError> { + let mut dimensions = vec![]; + while self.peek().value == TokenValue::LBracket { + let start_span = self.next().span; + let value = if self.peek().value == TokenValue::RBracket { + if !allow_empty_first || !dimensions.is_empty() { + let span = self.peek().span; + self.diagnostics.add_from_frontend_error( + ParseError::UnexpectedToken(TokenValue::RBracket, "array dimension expression"), + span, + ); + return Err(ParseProcessError::ErrorInMatch); + } + None + } else { + Some(self.parse_expr()?) + }; + let end_span = match &self.peek().value { + TokenValue::RBracket => { + let span = self.peek().span; + self.advance(1); + span + } + TokenValue::Eof => { + self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("`]`"), start_span); + return Err(ParseProcessError::ErrorInMatch); + } + _ => { + let token = self.next(); + self.diagnostics.add_from_frontend_error( + ParseError::UnexpectedToken(token.value, "`]`"), + token.span, + ); + return Err(ParseProcessError::ErrorInMatch); + } + }; + dimensions.push(ArrayDimension { + value, + span: Span::from_two(start_span, end_span), + }); + } + Ok(dimensions) + } +} diff --git a/src/ast/parser/expr.rs b/src/ast/parser/expr.rs new file mode 100644 index 0000000..2adda7a --- /dev/null +++ b/src/ast/parser/expr.rs @@ -0,0 +1,486 @@ +use crate::{ + ast::types::{BinaryOp, Expr, ExprValue, IncDecOp, UnaryOp}, + diagnostic::span::Span, + lexer::{ + err::ParseError, + types::TokenValue, + }, +}; + +use super::{ParseProcessError, Parser}; + +impl Parser { + // 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_atom(&mut self) -> Result { + assert!(!self.is_eof()); + let token = self.next().clone(); + match token.value { + TokenValue::Ident(name) => { + if matches!(self.peek().value, TokenValue::LParen) { + self.advance(1); + let mut args = vec![]; + loop { + match &self.peek().value { + TokenValue::RParen => { + let end_span = self.peek().span; + self.advance(1); + return Ok(Expr { + value: ExprValue::FuncCall(name, args), + span: Span::from_two(token.span, end_span), + }); + } + TokenValue::Eof => { + self.diagnostics.add_from_frontend_error( + ParseError::ExpectButEof("`)`"), + token.span, + ); + return Err(ParseProcessError::ErrorInMatch); + } + _ => {} + } + args.push(self.parse_expr()?); + match &self.peek().value { + TokenValue::Comma => { + self.advance(1); + } + TokenValue::RParen => { + let end_span = self.peek().span; + self.advance(1); + return Ok(Expr { + value: ExprValue::FuncCall(name, args), + span: Span::from_two(token.span, end_span), + }); + } + TokenValue::Eof => { + self.diagnostics.add_from_frontend_error( + ParseError::ExpectButEof("`)`"), + token.span, + ); + return Err(ParseProcessError::ErrorInMatch); + } + _ => { + let token = self.next(); + self.diagnostics.add_from_frontend_error( + ParseError::UnexpectedToken(token.value, "`,` or `)`"), + 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 = if self.is_eof() { + self.diagnostics.add_from_frontend_error( + ParseError::ExpectButEof("expression"), + token.span, + ); + return Err(ParseProcessError::ErrorInMatch); + } else { + self.parse_expr()? + }; + match &self.peek().value { + TokenValue::RParen => { + let end_span = self.peek().span; + self.advance(1); + Ok(Expr { + span: Span::from_two(token.span, end_span), + ..expr + }) + } + TokenValue::Eof => { + self.diagnostics + .add_from_frontend_error(ParseError::ExpectButEof("`)`"), expr.span); + Err(ParseProcessError::ErrorInMatch) + } + _ => { + let token = self.next(); + self.diagnostics.add_from_frontend_error( + ParseError::UnexpectedToken(token.value, "`)`"), + token.span, + ); + Err(ParseProcessError::ErrorInMatch) + } + } + } + _ => { + self.diagnostics.add_from_frontend_error( + ParseError::UnexpectedToken(token.value, "expression"), + token.span, + ); + Err(ParseProcessError::ErrorInMatch) + } + } + } + fn parse_primary(&mut self) -> Result { + let mut expr = self.parse_primary_atom()?; + loop { + if self.peek().value == TokenValue::LBracket { + let start_span = expr.span; + self.advance(1); + let index = if self.is_eof() { + self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("array index expression"), start_span); + return Err(ParseProcessError::ErrorInMatch); + } else { + self.parse_expr()? + }; + let end_span = match &self.peek().value { + TokenValue::RBracket => { + let span = self.peek().span; + self.advance(1); + span + } + TokenValue::Eof => { + self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("`]`"), index.span); + return Err(ParseProcessError::ErrorInMatch); + } + _ => { + let token = self.next(); + self.diagnostics.add_from_frontend_error( + ParseError::UnexpectedToken(token.value, "`]`"), + token.span, + ); + return Err(ParseProcessError::ErrorInMatch); + } + }; + expr = Expr { + value: ExprValue::ArrayAccess { + array: Box::new(expr), + index: Box::new(index), + }, + span: Span::from_two(start_span, end_span), + }; + continue; + } + let op = match (&self.peek().value, &self.peek_n(1).value) { + (TokenValue::Plus, TokenValue::Plus) => Some(IncDecOp::Inc), + (TokenValue::Minus, TokenValue::Minus) => Some(IncDecOp::Dec), + _ => None, + }; + if let Some(op) = op { + let end_span = self.peek_n(1).span; + self.advance(2); + expr = Expr { + span: Span::from_two(expr.span, end_span), + value: ExprValue::IncDec { + op, + operand: Box::new(expr), + is_prefix: false, + }, + }; + continue; + } + break; + } + Ok(expr) + } + fn parse_unary(&mut self) -> Result { + assert!(!self.is_eof()); + let token = self.peek().clone(); + match token.value { + TokenValue::Plus => { + if self.peek_n(1).value == TokenValue::Plus { + self.advance(2); + let expr = if self.is_eof() { + self.diagnostics.add_from_frontend_error( + ParseError::ExpectButEof("expression"), + token.span, + ); + return Err(ParseProcessError::ErrorInMatch); + } else { + self.parse_unary()? + }; + let span = Span::from_two(token.span, expr.span); + return Ok(Expr { + value: ExprValue::IncDec { + op: IncDecOp::Inc, + operand: Box::new(expr), + is_prefix: true, + }, + span, + }); + } + self.advance(1); + let expr = if self.is_eof() { + self.diagnostics.add_from_frontend_error( + ParseError::ExpectButEof("expression"), + token.span, + ); + return Err(ParseProcessError::ErrorInMatch); + } else { + self.parse_unary()? + }; + let span = Span::from_two(token.span, expr.span); + Ok(Expr { + value: ExprValue::UnaryOp { + op: UnaryOp::Add, + operand: Box::new(expr), + }, + span, + }) + } + TokenValue::Minus => { + if self.peek_n(1).value == TokenValue::Minus { + self.advance(2); + let rhs = if self.is_eof() { + self.diagnostics.add_from_frontend_error( + ParseError::ExpectButEof("expression"), + token.span, + ); + return Err(ParseProcessError::ErrorInMatch); + } else { + self.parse_unary()? + }; + let span = Span::from_two(token.span, rhs.span); + return Ok(Expr { + value: ExprValue::IncDec { + op: IncDecOp::Dec, + operand: Box::new(rhs), + is_prefix: true, + }, + span, + }); + } + self.advance(1); + let rhs = if self.is_eof() { + self.diagnostics.add_from_frontend_error( + ParseError::ExpectButEof("expression"), + token.span, + ); + return Err(ParseProcessError::ErrorInMatch); + } else { + self.parse_unary()? + }; + 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 = if self.is_eof() { + self.diagnostics.add_from_frontend_error( + ParseError::ExpectButEof("expression"), + token.span, + ); + return Err(ParseProcessError::ErrorInMatch); + } else { + self.parse_unary()? + }; + 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.is_eof()); + let mut left = self.parse_unary()?; + while !self.is_eof() { + let op = match self.peek().value { + TokenValue::Star => BinaryOp::Mul, + TokenValue::Slash => BinaryOp::Div, + TokenValue::Percent => BinaryOp::Mod, + _ => break, + }; + self.advance(1); + let right = if self.is_eof() { + self.diagnostics + .add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span); + return Err(ParseProcessError::ErrorInMatch); + } else { + self.parse_unary()? + }; + 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.is_eof()); + let mut left = self.parse_multiplicative()?; + while !self.is_eof() { + let op = match self.peek().value { + TokenValue::Plus => BinaryOp::Add, + TokenValue::Minus => BinaryOp::Sub, + _ => break, + }; + self.advance(1); + let right = if self.is_eof() { + self.diagnostics + .add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span); + return Err(ParseProcessError::ErrorInMatch); + } else { + self.parse_multiplicative()? + }; + 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.is_eof()); + let mut left = self.parse_additive()?; + while !self.is_eof() { + let op = match self.peek().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 = if self.is_eof() { + self.diagnostics + .add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span); + return Err(ParseProcessError::ErrorInMatch); + } else { + self.parse_additive()? + }; + 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.is_eof()); + let mut left = self.parse_relational()?; + while !self.is_eof() { + let op = match self.peek().value { + TokenValue::And => BinaryOp::And, + _ => break, + }; + self.advance(1); + let right = if self.is_eof() { + self.diagnostics + .add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span); + return Err(ParseProcessError::ErrorInMatch); + } else { + self.parse_relational()? + }; + 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.is_eof()); + let mut left = self.parse_logical_and()?; + while !self.is_eof() { + let op = match self.peek().value { + TokenValue::Or => BinaryOp::Or, + _ => break, + }; + self.advance(1); + let right = if self.is_eof() { + self.diagnostics + .add_from_frontend_error(ParseError::ExpectButEof("expression"), left.span); + return Err(ParseProcessError::ErrorInMatch); + } else { + self.parse_logical_and()? + }; + 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.is_eof()); + let lvalue = self.parse_logical_or()?; + if self.peek().value != TokenValue::Equal { + return Ok(lvalue); + } + self.advance(1); + let rvalue = if self.is_eof() { + self.diagnostics.add_from_frontend_error( + ParseError::ExpectButEof("expression"), + lvalue.span, + ); + return Err(ParseProcessError::ErrorInMatch); + } else { + self.parse_assign()? + }; + let span = Span::from_two(lvalue.span, rvalue.span); + Ok(Expr { + value: ExprValue::Assign { + lvalue: Box::new(lvalue), + rvalue: Box::new(rvalue), + }, + span, + }) + } + pub(super) fn parse_expr(&mut self) -> Result { + assert!(!self.is_eof()); + self.parse_assign() + } +} diff --git a/src/ast/parser/mod.rs b/src/ast/parser/mod.rs new file mode 100644 index 0000000..d09678d --- /dev/null +++ b/src/ast/parser/mod.rs @@ -0,0 +1,119 @@ +use crate::{ + ast::types::CompileUnit, + diagnostic::{Diagnositics, span::Span}, + lexer::{ + err::ParseError, + types::{Token, TokenValue}, + }, +}; + +mod decl; +mod expr; +mod stmt; + +#[cfg(test)] +mod tests; + +pub struct Parser { + tokens: Vec, + eof_token: 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, diagnostics: Diagnositics) -> Self { + let eof_pos = tokens.last().map_or(0, |token| token.span.end); + Self { + tokens, + eof_token: Token { + value: TokenValue::Eof, + span: Span { + start: eof_pos, + end: eof_pos, + }, + }, + diagnostics, + pos: 0, + } + } + pub fn parse(&mut self) -> CompileUnit { + self.parse_compile_unit() + } + fn peek(&self) -> &Token { + self.tokens.get(self.pos).unwrap_or(&self.eof_token) + } + fn peek_n(&self, n: usize) -> &Token { + self.tokens.get(self.pos + n).unwrap_or(&self.eof_token) + } + fn next(&mut self) -> Token { + let token = self.peek().clone(); + if !matches!(token.value, TokenValue::Eof) { + 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) -> &Token { + if self.pos == 0 { + &self.eof_token + } else { + self.tokens.get(self.pos - 1).unwrap_or(&self.eof_token) + } + } + fn is_eof(&self) -> bool { + matches!(self.peek().value, TokenValue::Eof) + } + fn must_match_token(&mut self, expected: &TokenValue, diagnostic_text: &'static str) -> Result<(), ParseProcessError> { + if &self.peek().value == expected { + self.advance(1); + Ok(()) + } else if self.is_eof() { + let span = self.peek().span; + self.diagnostics + .add_from_frontend_error(ParseError::ExpectButEof(diagnostic_text), span); + Err(ParseProcessError::ErrorInMatch) + } else { + let token = self.next(); + self.diagnostics.add_from_frontend_error( + ParseError::UnexpectedToken(token.value, diagnostic_text), + token.span, + ); + Err(ParseProcessError::ErrorInMatch) + } + } + fn must_have_some(&mut self, diagnostic_text: &'static str) -> Result<(), ParseProcessError> { + if self.is_eof() { + let span = self.last().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 !self.is_eof() { + if expected.contains(&self.peek().value) { + self.advance(1); + break; + } + self.advance(1); + } + } +} diff --git a/src/ast/parser/stmt.rs b/src/ast/parser/stmt.rs new file mode 100644 index 0000000..a0ab55d --- /dev/null +++ b/src/ast/parser/stmt.rs @@ -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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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 { + 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) + } + } +} diff --git a/src/ast/parser/tests.rs b/src/ast/parser/tests.rs new file mode 100644 index 0000000..59aad3c --- /dev/null +++ b/src/ast/parser/tests.rs @@ -0,0 +1,76 @@ + use std::io::BufRead; + use std::path::Path; + use std::fs::File; + use crate::ast::graph::AstGraphExt; + use crate::lexer::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"); + } + #[test] + fn test_func() { + test_case("12-13,58-60"); + } + #[test] + fn test_array() { + test_case("4-7,11,42,71,74-78,82,84,86,90,95,96,100,101,103"); + }