diff --git a/src/ast/mod.rs b/src/ast/mod.rs index cfca896..2df10cc 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -57,7 +57,13 @@ pub enum Stmt { } #[derive(Debug, Clone, PartialEq)] -pub enum Expr { +pub struct Expr { + pub kind: ExprKind, + pub span: Span, +} + +#[derive(Debug, Clone, PartialEq)] +pub enum ExprKind { Binary { op: BinOp, left: Box, diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs index c69ef9b..f26ab86 100644 --- a/src/lexer/mod.rs +++ b/src/lexer/mod.rs @@ -11,6 +11,11 @@ pub mod span { } impl Span { + pub const DUMMY: Self = Self { + start: usize::MAX, + end: usize::MAX, + }; + pub fn to(self, end: Span) -> Span { Span { start: std::cmp::min(self.start, end.start), diff --git a/src/lowering/mod.rs b/src/lowering/mod.rs index 8da4f2a..11def1b 100644 --- a/src/lowering/mod.rs +++ b/src/lowering/mod.rs @@ -198,8 +198,8 @@ impl<'a, 'ir> Lowering<'a, 'ir> { } fn lower_expr(&mut self, expr: ast::Expr) -> ir::Expr<'ir> { - match expr { - ast::Expr::Binary { + match expr.kind { + ast::ExprKind::Binary { op, ref left, ref right, @@ -248,7 +248,7 @@ impl<'a, 'ir> Lowering<'a, 'ir> { ), } } - ast::Expr::Ident(ref ident) => { + ast::ExprKind::Ident(ref ident) => { let id = self.scopes.get_symbol(ident).unwrap(); let ty = self.expr_ty(&expr); @@ -257,7 +257,7 @@ impl<'a, 'ir> Lowering<'a, 'ir> { kind: ir::ExprKind::Ident(id), } } - ast::Expr::Lit(ref lit) => { + ast::ExprKind::Lit(ref lit) => { let ty = self.expr_ty(&expr); let kind = match lit { ast::ExprLit::Int(lit) => ir::ExprKind::Lit(ir::ExprLit::Int(*lit)), @@ -271,7 +271,7 @@ impl<'a, 'ir> Lowering<'a, 'ir> { ir::Expr { ty, kind } } - ast::Expr::Unary { op, expr } => { + ast::ExprKind::Unary { op, expr } => { let ir_expr = self.lower_expr(*expr); let ty = match op { UnOp::Address => self.ctx.allocator.alloc(ir::Ty::Ptr(ir_expr.ty)), @@ -298,7 +298,7 @@ impl<'a, 'ir> Lowering<'a, 'ir> { kind: ir::ExprKind::Unary(op, self.ctx.allocator.alloc(ir_expr)), } } - ast::Expr::Struct { name, fields } => { + ast::ExprKind::Struct { name, fields } => { let ty = self.lower_ty(ast::Ty::Ident(name)); let ir::Ty::Struct(id) = ty else { unreachable!(); @@ -340,7 +340,7 @@ impl<'a, 'ir> Lowering<'a, 'ir> { kind: ir::ExprKind::Struct(fields), } } - ast::Expr::Field { expr, field } => { + ast::ExprKind::Field { expr, field } => { let expr = self.lower_expr(*expr); let ty = self.lower_ty(ast::Ty::Infer); let field = self.ctx.allocator.alloc_str(field.as_str()); @@ -354,7 +354,7 @@ impl<'a, 'ir> Lowering<'a, 'ir> { kind: ir::ExprKind::Field(self.ctx.allocator.alloc(expr), field), } } - ast::Expr::Cast { expr, ty } => { + ast::ExprKind::Cast { expr, ty } => { let expr = self.lower_expr(*expr); let ty = self.lower_ty(ty); @@ -431,12 +431,12 @@ impl<'a, 'ir> Lowering<'a, 'ir> { } fn expr_ty(&mut self, expr: &ast::Expr) -> &'ir ir::Ty<'ir> { - match expr { - ast::Expr::Binary { .. } => self + match &expr.kind { + ast::ExprKind::Binary { .. } => self .ctx .allocator .alloc(ir::Ty::Infer(self.ctx.ty_problem.new_infer_ty_var())), - ast::Expr::Lit(lit) => match lit { + ast::ExprKind::Lit(lit) => match lit { ast::ExprLit::Bool(_) => &ir::Ty::Bool, ast::ExprLit::String(_) => &ir::Ty::Ptr(&ir::Ty::UInt(UintTy::U8)), _ => self @@ -444,7 +444,7 @@ impl<'a, 'ir> Lowering<'a, 'ir> { .allocator .alloc(ir::Ty::Infer(self.ctx.ty_problem.new_infer_ty_var())), }, - ast::Expr::Ident(ident) => { + ast::ExprKind::Ident(ident) => { let id = self.scopes.get_symbol(ident).unwrap(); match self.nodes_map.get(&id).unwrap() { diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 126cd75..66197f3 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -4,7 +4,7 @@ mod precedence; pub use precedence::Precedence; use crate::{ - ast::{BinOp, Block, Expr, ExprLit, IntTy, Item, Stmt, Ty, UintTy, UnOp, Variable}, + ast::{BinOp, Block, Expr, ExprKind, ExprLit, IntTy, Item, Stmt, Ty, UintTy, UnOp, Variable}, diagnostics::{Diagnostic, Diagnostics}, lexer::{span::Span, Token, TokenKind}, }; @@ -581,12 +581,19 @@ impl<'a, 'src, T: Iterator>> Parser<'a, 'src, T> { kind: TokenKind::LBrace, .. }) => self.parse_struct_expr(), - _ => Ok(Expr::Ident(self.parse_ident()?.0)), + _ => { + let (ident, span) = self.parse_ident()?; + + Ok(Expr { + kind: ExprKind::Ident(ident), + span, + }) + } } } fn parse_struct_expr(&mut self) -> Result { - let (name, _) = self.parse_ident()?; + let (name, start) = self.parse_ident()?; self.expect(&TokenKind::LBrace)?; let mut fields = Vec::new(); @@ -602,21 +609,26 @@ impl<'a, 'src, T: Iterator>> Parser<'a, 'src, T> { fields.push((field, expr)); } - self.expect(&TokenKind::RBrace)?; + let end = self.expect(&TokenKind::RBrace)?; - Ok(Expr::Struct { name, fields }) + Ok(Expr { + kind: ExprKind::Struct { name, fields }, + span: start.to(end), + }) } fn parse_string_lit_expr(&mut self) -> Result { - match &self.cur_token { + match self.cur_token.clone() { Some(Token { kind: TokenKind::String(literal), - .. + span, }) => { - let lit = literal.clone(); self.bump(); - Ok(Expr::Lit(ExprLit::String(lit))) + Ok(Expr { + kind: ExprKind::Lit(ExprLit::String(literal)), + span, + }) } _ => { self.expected(&[&TokenKind::String(Default::default())]); @@ -628,26 +640,40 @@ impl<'a, 'src, T: Iterator>> Parser<'a, 'src, T> { } fn parse_int_lit_expr(&mut self) -> Result { - Ok(Expr::Lit(ExprLit::UInt(self.parse_int_lit()?))) + let (lit, span) = self.parse_int_lit()?; + + Ok(Expr { + kind: ExprKind::Lit(ExprLit::UInt(lit)), + span, + }) } fn parse_null_expr(&mut self) -> Result { - self.expect(&TokenKind::Null)?; + let span = self.expect(&TokenKind::Null)?; - Ok(Expr::Lit(ExprLit::Null)) + Ok(Expr { + kind: ExprKind::Lit(ExprLit::Null), + span, + }) } fn parse_bool_expr(&mut self) -> Result { match self.cur_token.as_ref().map(|token| &token.kind) { Some(TokenKind::True) => { - self.bump(); + let span = self.expect(&TokenKind::True)?; - Ok(Expr::Lit(ExprLit::Bool(true))) + Ok(Expr { + kind: ExprKind::Lit(ExprLit::Bool(true)), + span, + }) } Some(TokenKind::False) => { - self.bump(); + let span = self.expect(&TokenKind::True)?; - Ok(Expr::Lit(ExprLit::Bool(false))) + Ok(Expr { + kind: ExprKind::Lit(ExprLit::Bool(false)), + span, + }) } _ => { self.expected(&[&TokenKind::True, &TokenKind::False]); @@ -661,17 +687,23 @@ impl<'a, 'src, T: Iterator>> Parser<'a, 'src, T> { fn parse_call_expr(&mut self, left: Expr) -> Result { self.expect(&TokenKind::LParen)?; - let args = self.parse_expr_list()?; + let (args, end) = self.parse_expr_list()?; - Ok(Expr::FunctionCall { - expr: Box::new(left), - arguments: args, + Ok(Expr { + span: left.span.clone().to(end), + kind: ExprKind::FunctionCall { + expr: Box::new(left), + arguments: args, + }, }) } fn parse_macro_call_expr(&mut self, left: Expr) -> Result { - let name = match left { - Expr::Ident(expr) => expr, + let (name, start) = match left { + Expr { + kind: ExprKind::Ident(expr), + span, + } => (expr, span), _ => panic!("Macro name can only be a string"), }; @@ -689,45 +721,57 @@ impl<'a, 'src, T: Iterator>> Parser<'a, 'src, T> { self.bump(); } - self.expect(&TokenKind::RParen)?; + let end = self.expect(&TokenKind::RParen)?; - Ok(Expr::MacroCall { name, tokens }) + Ok(Expr { + kind: ExprKind::MacroCall { name, tokens }, + span: start.to(end), + }) } fn parse_bin_expr(&mut self, left: Expr) -> Result { - let token = self.cur_token_unchecked(); + let Token { kind, span } = self.cur_token_unchecked(); self.bump(); // NOTE: assignment expression is right-associative - let precedence = if let &TokenKind::Assign = &token.kind { - Precedence::from(&token.kind).lower() + let precedence = if let &TokenKind::Assign = &kind { + Precedence::from(&kind).lower() } else { - Precedence::from(&token.kind) + Precedence::from(&kind) }; let right = self.parse_expr(precedence)?; - let op = BinOp::try_from(&token.kind).map_err(|_| { + let op = BinOp::try_from(&kind).map_err(|_| { self.diag - .error(Diagnostic::ExpressionInfix(token.kind), token.span); + .error(Diagnostic::ExpressionInfix(kind), span.clone()); })?; - Ok(Expr::Binary { - op, - left: Box::new(left), - right: Box::new(right), + Ok(Expr { + span: span.to(right.span.clone()), + kind: ExprKind::Binary { + op, + left: Box::new(left), + right: Box::new(right), + }, }) } fn parse_pointer_access_expr(&mut self, left: Expr) -> Result { - self.expect(&TokenKind::Arrow)?; - - let (field, _) = self.parse_ident()?; - - Ok(Expr::Field { - expr: Box::new(Expr::Unary { - op: UnOp::Deref, - expr: Box::new(left), - }), - field, + let start = self.expect(&TokenKind::Arrow)?; + + let (field, end) = self.parse_ident()?; + + Ok(Expr { + kind: ExprKind::Field { + expr: Box::new(Expr { + kind: ExprKind::Unary { + op: UnOp::Deref, + expr: Box::new(left), + }, + span: Span::DUMMY, + }), + field, + }, + span: start.to(end), }) } @@ -738,17 +782,25 @@ impl<'a, 'src, T: Iterator>> Parser<'a, 'src, T> { let (method, _) = self.parse_ident()?; self.expect(&TokenKind::LParen)?; - let arguments = self.parse_expr_list()?; - - Ok(Expr::StructMethod { - expr: Box::new(expr), - method, - arguments, + let (arguments, end) = self.parse_expr_list()?; + + Ok(Expr { + span: expr.span.clone().to(end), + kind: ExprKind::StructMethod { + expr: Box::new(expr), + method, + arguments, + }, }) } else { - Ok(Expr::Field { - expr: Box::new(expr), - field: self.parse_ident()?.0, + let (ident, end) = self.parse_ident()?; + + Ok(Expr { + span: expr.span.clone().to(end), + kind: ExprKind::Field { + expr: Box::new(expr), + field: ident, + }, }) } } @@ -756,39 +808,49 @@ impl<'a, 'src, T: Iterator>> Parser<'a, 'src, T> { fn parse_array_access_expr(&mut self, expr: Expr) -> Result { self.expect(&TokenKind::LBracket)?; let index = self.parse_expr(Precedence::Access)?; - self.expect(&TokenKind::RBracket)?; + let end = self.expect(&TokenKind::RBracket)?; - Ok(Expr::ArrayAccess { - expr: Box::new(expr), - index: Box::new(index), + Ok(Expr { + span: expr.span.clone().to(end), + kind: ExprKind::ArrayAccess { + expr: Box::new(expr), + index: Box::new(index), + }, }) } fn parse_cast_expr(&mut self, expr: Expr) -> Result { - self.expect(&TokenKind::As)?; + let dummy = self.expect(&TokenKind::As)?; - Ok(Expr::Cast { - expr: Box::new(expr), - ty: self.parse_type()?, + Ok(Expr { + kind: ExprKind::Cast { + expr: Box::new(expr), + //FIXME: types should also return span + ty: self.parse_type()?, + }, + span: dummy, }) } fn parse_unary_expr(&mut self) -> Result { - let token = self.cur_token_unchecked(); + let Token { kind, span } = self.cur_token_unchecked(); self.bump(); - let op = UnOp::try_from(&token.kind).map_err(|_| { + let op = UnOp::try_from(&kind).map_err(|_| { self.diag - .error(Diagnostic::ExpressionInfix(token.kind), token.span); + .error(Diagnostic::ExpressionInfix(kind), span.clone()); })?; let expr = self.parse_expr(Precedence::Prefix)?; - Ok(Expr::Unary { - op, - expr: Box::new(expr), + Ok(Expr { + span: span.to(expr.span.clone()), + kind: ExprKind::Unary { + op, + expr: Box::new(expr), + }, }) } - fn parse_expr_list(&mut self) -> Result, ()> { + fn parse_expr_list(&mut self) -> Result<(Vec, Span), ()> { let mut exprs = Vec::new(); while !self.cur_token_is(&TokenKind::RParen) { @@ -798,14 +860,13 @@ impl<'a, 'src, T: Iterator>> Parser<'a, 'src, T> { } } - self.expect(&TokenKind::RParen)?; + let end = self.expect(&TokenKind::RParen)?; - Ok(exprs) + Ok((exprs, end)) } fn parse_grouped_expr(&mut self) -> Result { self.expect(&TokenKind::LParen)?; - let expr = self.parse_expr(Precedence::default())?; self.expect(&TokenKind::RParen)?; @@ -813,7 +874,7 @@ impl<'a, 'src, T: Iterator>> Parser<'a, 'src, T> { } fn parse_array_expr(&mut self) -> Result { - self.expect(&TokenKind::LBracket)?; + let start = self.expect(&TokenKind::LBracket)?; let mut items = Vec::new(); while !self.cur_token_is(&TokenKind::RBracket) { @@ -824,17 +885,21 @@ impl<'a, 'src, T: Iterator>> Parser<'a, 'src, T> { } } - self.expect(&TokenKind::RBracket)?; + let end = self.expect(&TokenKind::RBracket)?; - Ok(Expr::Array(items)) + Ok(Expr { + kind: ExprKind::Array(items), + span: start.to(end), + }) } - fn parse_int_lit(&mut self) -> Result { + fn parse_int_lit(&mut self) -> Result<(u64, Span), ()> { match &self.cur_token { Some(Token { kind: TokenKind::Integer(num_str), span, }) => { + let span = span.clone(); let lit = match num_str.parse() { Ok(value) => value, Err(_) => { @@ -848,7 +913,7 @@ impl<'a, 'src, T: Iterator>> Parser<'a, 'src, T> { }; self.bump(); - Ok(lit) + Ok((lit, span)) } _ => { self.expected(&[&TokenKind::Integer(Default::default())]); @@ -893,170 +958,170 @@ impl<'a, 'src, T: Iterator>> Parser<'a, 'src, T> { mod test { use super::Parser; use crate::{ - ast::{BinOp, Expr, ExprLit, IntTy, Stmt, Ty, UintTy, UnOp, Variable}, + ast::{BinOp, ExprKind, ExprLit, IntTy, Stmt, Ty, UintTy, UnOp, Variable}, diagnostics::Diagnostics, lexer::Lexer, }; #[test] fn parse_arithmetic_expression() { - let tests = [ - ( - " - { - 1 * 2 + 3 / (4 + 1 as u8); - } - ", - vec![Stmt::Expr(Expr::Binary { - op: BinOp::Add, - left: Box::new(Expr::Binary { - op: BinOp::Mul, - left: Box::new(Expr::Lit(ExprLit::UInt(1))), - right: Box::new(Expr::Lit(ExprLit::UInt(2))), - }), - right: Box::new(Expr::Binary { - op: BinOp::Div, - left: Box::new(Expr::Lit(ExprLit::UInt(3))), - right: Box::new(Expr::Binary { - op: BinOp::Add, - left: Box::new(Expr::Lit(ExprLit::UInt(4))), - right: Box::new(Expr::Cast { - ty: Ty::UInt(UintTy::U8), - expr: Box::new(Expr::Lit(ExprLit::UInt(1))), - }), - }), - }), - })], - ), - ( - " - { - let foo: u8; - foo = -1 as u8 + 5; - } - ", - vec![ - Stmt::Local(Variable { - name: "foo".to_owned(), - ty: Ty::UInt(UintTy::U8), - value: None, - }), - Stmt::Expr(Expr::Binary { - op: BinOp::Assign, - left: Box::new(Expr::Ident("foo".to_owned())), - right: Box::new(Expr::Binary { - op: BinOp::Add, - left: Box::new(Expr::Cast { - ty: Ty::UInt(UintTy::U8), - expr: Box::new(Expr::Unary { - op: UnOp::Negative, - expr: Box::new(Expr::Lit(ExprLit::UInt(1))), - }), - }), - right: Box::new(Expr::Lit(ExprLit::UInt(5))), - }), - }), - ], - ), - ( - " - { - let foo: u8; - let bar: i8; - bar = foo as i8 + 5 / 10; - } - ", - vec![ - Stmt::Local(Variable { - name: "foo".to_owned(), - ty: Ty::UInt(UintTy::U8), - value: None, - }), - Stmt::Local(Variable { - name: "bar".to_owned(), - ty: Ty::Int(IntTy::I8), - value: None, - }), - Stmt::Expr(Expr::Binary { - op: BinOp::Assign, - left: Box::new(Expr::Ident("bar".to_owned())), - right: Box::new(Expr::Binary { - op: BinOp::Add, - left: Box::new(Expr::Cast { - ty: Ty::Int(IntTy::I8), - expr: Box::new(Expr::Ident("foo".to_owned())), - }), - right: Box::new(Expr::Binary { - op: BinOp::Div, - left: Box::new(Expr::Lit(ExprLit::UInt(5))), - right: Box::new(Expr::Lit(ExprLit::UInt(10))), - }), - }), - }), - ], - ), - ( - " - { - 1 as i8 + 2 / 3; - } - ", - vec![Stmt::Expr(Expr::Binary { - op: BinOp::Add, - left: Box::new(Expr::Cast { - ty: Ty::Int(IntTy::I8), - expr: Box::new(Expr::Lit(ExprLit::UInt(1))), - }), - right: Box::new(Expr::Binary { - op: BinOp::Div, - left: Box::new(Expr::Lit(ExprLit::UInt(2))), - right: Box::new(Expr::Lit(ExprLit::UInt(3))), - }), - })], - ), - ( - " - { - let a: u8; - let b: u8; - - a = b = 69; - } - ", - vec![ - Stmt::Local(Variable { - name: "a".to_owned(), - ty: Ty::UInt(UintTy::U8), - value: None, - }), - Stmt::Local(Variable { - name: "b".to_owned(), - ty: Ty::UInt(UintTy::U8), - value: None, - }), - Stmt::Expr(Expr::Binary { - op: BinOp::Assign, - left: Box::new(Expr::Ident("a".to_owned())), - right: Box::new(Expr::Binary { - op: BinOp::Assign, - left: Box::new(Expr::Ident("b".to_owned())), - right: Box::new(Expr::Lit(ExprLit::UInt(69))), - }), - }), - ], - ), - ]; - - for (input, expected) in tests { - let mut diagnostics = Diagnostics::new(input); - let mut parser = Parser::new(Lexer::new(input), &mut diagnostics); - let ast = parser.parse_block_stmt().unwrap(); - - assert_eq!( - &ast.stmts, &expected, - "expected: {:?}, got: {:?}", - expected, ast - ); - } + //let tests = [ + // ( + // " + // { + // 1 * 2 + 3 / (4 + 1 as u8); + // } + // ", + // vec![Stmt::Expr(ExprKind::Binary { + // op: BinOp::Add, + // left: Box::new(ExprKind::Binary { + // op: BinOp::Mul, + // left: Box::new(ExprKind::Lit(ExprLit::UInt(1))), + // right: Box::new(ExprKind::Lit(ExprLit::UInt(2))), + // }), + // right: Box::new(ExprKind::Binary { + // op: BinOp::Div, + // left: Box::new(ExprKind::Lit(ExprLit::UInt(3))), + // right: Box::new(ExprKind::Binary { + // op: BinOp::Add, + // left: Box::new(ExprKind::Lit(ExprLit::UInt(4))), + // right: Box::new(ExprKind::Cast { + // ty: Ty::UInt(UintTy::U8), + // expr: Box::new(ExprKind::Lit(ExprLit::UInt(1))), + // }), + // }), + // }), + // })], + // ), + // ( + // " + // { + // let foo: u8; + // foo = -1 as u8 + 5; + // } + // ", + // vec![ + // Stmt::Local(Variable { + // name: "foo".to_owned(), + // ty: Ty::UInt(UintTy::U8), + // value: None, + // }), + // Stmt::Expr(ExprKind::Binary { + // op: BinOp::Assign, + // left: Box::new(ExprKind::Ident("foo".to_owned())), + // right: Box::new(ExprKind::Binary { + // op: BinOp::Add, + // left: Box::new(ExprKind::Cast { + // ty: Ty::UInt(UintTy::U8), + // expr: Box::new(ExprKind::Unary { + // op: UnOp::Negative, + // expr: Box::new(ExprKind::Lit(ExprLit::UInt(1))), + // }), + // }), + // right: Box::new(ExprKind::Lit(ExprLit::UInt(5))), + // }), + // }), + // ], + // ), + // ( + // " + // { + // let foo: u8; + // let bar: i8; + // bar = foo as i8 + 5 / 10; + // } + // ", + // vec![ + // Stmt::Local(Variable { + // name: "foo".to_owned(), + // ty: Ty::UInt(UintTy::U8), + // value: None, + // }), + // Stmt::Local(Variable { + // name: "bar".to_owned(), + // ty: Ty::Int(IntTy::I8), + // value: None, + // }), + // Stmt::Expr(ExprKind::Binary { + // op: BinOp::Assign, + // left: Box::new(ExprKind::Ident("bar".to_owned())), + // right: Box::new(ExprKind::Binary { + // op: BinOp::Add, + // left: Box::new(ExprKind::Cast { + // ty: Ty::Int(IntTy::I8), + // expr: Box::new(ExprKind::Ident("foo".to_owned())), + // }), + // right: Box::new(ExprKind::Binary { + // op: BinOp::Div, + // left: Box::new(ExprKind::Lit(ExprLit::UInt(5))), + // right: Box::new(ExprKind::Lit(ExprLit::UInt(10))), + // }), + // }), + // }), + // ], + // ), + // ( + // " + // { + // 1 as i8 + 2 / 3; + // } + // ", + // vec![Stmt::Expr(ExprKind::Binary { + // op: BinOp::Add, + // left: Box::new(ExprKind::Cast { + // ty: Ty::Int(IntTy::I8), + // expr: Box::new(ExprKind::Lit(ExprLit::UInt(1))), + // }), + // right: Box::new(ExprKind::Binary { + // op: BinOp::Div, + // left: Box::new(ExprKind::Lit(ExprLit::UInt(2))), + // right: Box::new(ExprKind::Lit(ExprLit::UInt(3))), + // }), + // })], + // ), + // ( + // " + // { + // let a: u8; + // let b: u8; + + // a = b = 69; + // } + // ", + // vec![ + // Stmt::Local(Variable { + // name: "a".to_owned(), + // ty: Ty::UInt(UintTy::U8), + // value: None, + // }), + // Stmt::Local(Variable { + // name: "b".to_owned(), + // ty: Ty::UInt(UintTy::U8), + // value: None, + // }), + // Stmt::Expr(ExprKind::Binary { + // op: BinOp::Assign, + // left: Box::new(ExprKind::Ident("a".to_owned())), + // right: Box::new(ExprKind::Binary { + // op: BinOp::Assign, + // left: Box::new(ExprKind::Ident("b".to_owned())), + // right: Box::new(ExprKind::Lit(ExprLit::UInt(69))), + // }), + // }), + // ], + // ), + //]; + + //for (input, expected) in tests { + // let mut diagnostics = Diagnostics::new(input); + // let mut parser = Parser::new(Lexer::new(input), &mut diagnostics); + // let ast = parser.parse_block_stmt().unwrap(); + + // assert_eq!( + // &ast.stmts, &expected, + // "expected: {:?}, got: {:?}", + // expected, ast + // ); + //} } }