From 977cd4725a8dc9a3736cc3b57891d807c27f62be Mon Sep 17 00:00:00 2001 From: Tom Anderson Date: Mon, 2 Sep 2024 23:47:14 +1000 Subject: [PATCH] fetch to new parser --- src/hir/expression/assign.rs | 2 +- src/hir/expression/block.rs | 41 +- src/hir/expression/cast.rs | 2 +- src/hir/expression/mod.rs | 9 +- src/hir/statement/mod.rs | 13 +- src/hir/statement/s_break.rs | 38 +- src/hir/statement/s_continue.rs | 38 +- src/hir/statement/s_expression.rs | 49 +- src/hir/statement/s_let.rs | 23 +- src/hir/statement/s_return.rs | 52 +- src/stage/parse/block.rs | 36 - src/stage/parse/expression/e_array.rs | 47 -- src/stage/parse/expression/e_assign.rs | 83 --- src/stage/parse/expression/e_boolean.rs | 49 -- src/stage/parse/expression/e_ident.rs | 52 -- src/stage/parse/expression/e_if.rs | 87 --- src/stage/parse/expression/e_integer.rs | 49 -- src/stage/parse/expression/e_loop.rs | 27 - src/stage/parse/expression/mod.rs | 875 ------------------------ src/stage/parse/function.rs | 25 +- src/stage/parse/mod.rs | 84 ++- src/stage/parse/statement.rs | 96 --- 22 files changed, 286 insertions(+), 1491 deletions(-) delete mode 100644 src/stage/parse/block.rs delete mode 100644 src/stage/parse/expression/e_array.rs delete mode 100644 src/stage/parse/expression/e_assign.rs delete mode 100644 src/stage/parse/expression/e_boolean.rs delete mode 100644 src/stage/parse/expression/e_ident.rs delete mode 100644 src/stage/parse/expression/e_if.rs delete mode 100644 src/stage/parse/expression/e_integer.rs delete mode 100644 src/stage/parse/expression/e_loop.rs delete mode 100644 src/stage/parse/expression/mod.rs delete mode 100644 src/stage/parse/statement.rs diff --git a/src/hir/expression/assign.rs b/src/hir/expression/assign.rs index 4b76590..c4e8d62 100644 --- a/src/hir/expression/assign.rs +++ b/src/hir/expression/assign.rs @@ -121,7 +121,7 @@ mod test { ) .unwrap(); - let Expression::Assign(assign) = dbg!(assign) else { + let Expression::Assign(assign) = assign else { panic!("expected to parse assignment") }; diff --git a/src/hir/expression/block.rs b/src/hir/expression/block.rs index 8a97ebe..dc5eaa4 100644 --- a/src/hir/expression/block.rs +++ b/src/hir/expression/block.rs @@ -5,7 +5,6 @@ use super::*; ast_node! { Block { statements: Vec>, - terminated: bool, span, ty_info, } @@ -29,14 +28,14 @@ impl Parsable for Block { }; // Parse statements - let (statements, terminated) = parser - .parse_delimited::, Precedence>( - compiler, - lexer, - Token::SemiColon, - ); - - dbg!(&statements, terminated); + let mut statements = Vec::new(); + while lexer + .peek_token() + .map(|t| !matches!(t, Token::RightBrace)) + .unwrap_or(false) + { + statements.push(parser.parse(compiler, lexer, Precedence::Lowest)?); + } // Parse ending bracket let end_span = match lexer.next_spanned().ok_or(ParseError::UnexpectedEOF)? { @@ -52,7 +51,6 @@ impl Parsable for Block { Ok(Expression::Block(Block { statements, - terminated, span: start_span.start..end_span.end, ty_info: None, })) @@ -108,7 +106,6 @@ impl SolveType for Block { Ok(Block { span: self.span, - terminated: self.terminated, statements, ty_info, }) @@ -139,19 +136,14 @@ mod test { } #[rstest] - #[case::empty("{ }", false, 0)] - #[case::single_terminated("{ true; }", true, 1)] - #[case::single_unterminated("{ true }", false, 1)] - #[case::double_terminated("{ true; true; }", true, 2)] - #[case::double_unterminated("{ true; true }", false, 2)] - #[case::triple_terminated("{ true; true; true; }", true, 3)] - #[case::triple_unterminated("{ true; true; true }", false, 3)] - fn success( - parser: Parser, - #[case] source: &str, - #[case] terminated: bool, - #[case] count: usize, - ) { + #[case::empty("{ }", 0)] + #[case::single_terminated("{ true; }", 1)] + #[case::single_unterminated("{ true }", 1)] + #[case::double_terminated("{ true; true; }", 2)] + #[case::double_unterminated("{ true; true }", 2)] + #[case::triple_terminated("{ true; true; true; }", 3)] + #[case::triple_unterminated("{ true; true; true }", 3)] + fn success(parser: Parser, #[case] source: &str, #[case] count: usize) { let b: Expression = parser .parse( &mut Compiler::default(), @@ -164,7 +156,6 @@ mod test { panic!("expected to parse block"); }; - assert_eq!(b.terminated, terminated); assert_eq!(b.statements.len(), count); } } diff --git a/src/hir/expression/cast.rs b/src/hir/expression/cast.rs index eb58d60..25497ea 100644 --- a/src/hir/expression/cast.rs +++ b/src/hir/expression/cast.rs @@ -107,7 +107,7 @@ mod test { ) .unwrap(); - let Expression::Cast(cast) = dbg!(cast) else { + let Expression::Cast(cast) = cast else { panic!("expected to parse cast"); }; diff --git a/src/hir/expression/mod.rs b/src/hir/expression/mod.rs index e0bdea0..1f19ecd 100644 --- a/src/hir/expression/mod.rs +++ b/src/hir/expression/mod.rs @@ -67,13 +67,8 @@ impl> Expression { Self::Ident(Ident::new(name, span, M::TyInfo::default())) } - pub fn block(statements: Vec>, terminated: bool, span: Span) -> Self { - Self::Block(Block::new( - statements, - terminated, - span, - M::TyInfo::default(), - )) + pub fn block(statements: Vec>, span: Span) -> Self { + Self::Block(Block::new(statements, span, M::TyInfo::default())) } pub fn _if( diff --git a/src/hir/statement/mod.rs b/src/hir/statement/mod.rs index 773e95d..4d6906f 100644 --- a/src/hir/statement/mod.rs +++ b/src/hir/statement/mod.rs @@ -41,6 +41,16 @@ impl SolveType for Statement { } } +impl Parsable for Statement { + fn register(parser: &mut Parser) { + Return::::register(parser); + Let::::register(parser); + ExpressionStatement::::register(parser); + Break::::register(parser); + Continue::::register(parser); + } +} + impl> Statement { pub fn _return(expression: Expression, span: M::Span) -> Self { Self::Return(Return::new(expression, span, M::TyInfo::default())) @@ -50,9 +60,10 @@ impl> Statement { Self::Let(Let::new(name, value, span, M::TyInfo::default())) } - pub fn expression(expression: Expression, span: M::Span) -> Self { + pub fn expression(expression: Expression, terminated: bool, span: M::Span) -> Self { Self::ExpressionStatement(ExpressionStatement::new( expression, + terminated, span, M::TyInfo::default(), )) diff --git a/src/hir/statement/s_break.rs b/src/hir/statement/s_break.rs index 0f558eb..d687306 100644 --- a/src/hir/statement/s_break.rs +++ b/src/hir/statement/s_break.rs @@ -14,7 +14,7 @@ impl Parsable for Break { assert!(parser.register_prefix::>( Token::Break, |_, _, lexer| { - let span = match lexer.next_spanned().ok_or(ParseError::UnexpectedEOF)? { + let break_span = match lexer.next_spanned().ok_or(ParseError::UnexpectedEOF)? { (Token::Break, span) => span, (token, _) => { return Err(ParseError::ExpectedToken { @@ -25,8 +25,20 @@ impl Parsable for Break { } }; + // Parse out the semicolon + let semicolon_span = match lexer.next_spanned().ok_or(ParseError::UnexpectedEOF)? { + (Token::SemiColon, span) => span, + (token, _) => { + return Err(ParseError::ExpectedToken { + expected: Box::new(Token::SemiColon), + found: Box::new(token), + reason: "expected break statement to finish with semicolon".to_string(), + }); + } + }; + Ok(Statement::Break(Break { - span, + span: break_span.start..semicolon_span.end, ty_info: None, })) } @@ -62,12 +74,16 @@ mod test { use super::*; - #[rstest] - #[case("break")] - fn success(#[case] source: &str) { + #[fixture] + fn parser() -> Parser { let mut parser = Parser::new(); Break::::register(&mut parser); + parser + } + #[rstest] + #[case("break;")] + fn success(parser: Parser, #[case] source: &str) { let b: Statement = parser .parse( &mut Compiler::default(), @@ -78,5 +94,17 @@ mod test { assert!(matches!(b, Statement::Break(_))); } + + #[rstest] + #[case::missing_semicolon("break")] + fn fail(parser: Parser, #[case] source: &str) { + assert!(parser + .parse::, _>( + &mut Compiler::default(), + &mut Lexer::from(source), + Precedence::Lowest, + ) + .is_err()); + } } } diff --git a/src/hir/statement/s_continue.rs b/src/hir/statement/s_continue.rs index 41d9b3a..cd6ac28 100644 --- a/src/hir/statement/s_continue.rs +++ b/src/hir/statement/s_continue.rs @@ -14,7 +14,7 @@ impl Parsable for Continue { assert!(parser.register_prefix::>( Token::Continue, |_, _, lexer| { - let span = match lexer.next_spanned().ok_or(ParseError::UnexpectedEOF)? { + let continue_span = match lexer.next_spanned().ok_or(ParseError::UnexpectedEOF)? { (Token::Continue, span) => span, (token, _) => { return Err(ParseError::ExpectedToken { @@ -25,8 +25,21 @@ impl Parsable for Continue { } }; + // Parse out the semicolon + let semicolon_span = match lexer.next_spanned().ok_or(ParseError::UnexpectedEOF)? { + (Token::SemiColon, span) => span, + (token, _) => { + return Err(ParseError::ExpectedToken { + expected: Box::new(Token::SemiColon), + found: Box::new(token), + reason: "expected continue statement to finish with semicolon" + .to_string(), + }); + } + }; + Ok(Statement::Continue(Continue { - span, + span: continue_span.start..semicolon_span.end, ty_info: None, })) } @@ -62,8 +75,15 @@ mod test { use super::*; + #[fixture] + fn parser() -> Parser { + let mut parser = Parser::new(); + Continue::::register(&mut parser); + parser + } + #[rstest] - #[case("continue")] + #[case("continue;")] fn success(#[case] source: &str) { let mut parser = Parser::new(); Continue::::register(&mut parser); @@ -78,5 +98,17 @@ mod test { assert!(matches!(c, Statement::Continue(_))); } + + #[rstest] + #[case::missing_semicolon("continue")] + fn fail(parser: Parser, #[case] source: &str) { + assert!(parser + .parse::, _>( + &mut Compiler::default(), + &mut Lexer::from(source), + Precedence::Lowest, + ) + .is_err()); + } } } diff --git a/src/hir/statement/s_expression.rs b/src/hir/statement/s_expression.rs index ac8c91b..70abb00 100644 --- a/src/hir/statement/s_expression.rs +++ b/src/hir/statement/s_expression.rs @@ -5,6 +5,7 @@ use super::*; ast_node! { ExpressionStatement { expression: Expression, + terminated: bool, span, ty_info, } @@ -17,8 +18,20 @@ impl Parsable for ExpressionStatement { let expression: Expression = parser.parse(compiler, lexer, Precedence::Lowest)?; + let terminating_span = lexer + .next_if(|(token, _)| matches!(token, Ok(Token::SemiColon))) + .map(|(_, span)| span); + + let expression_span = expression.span().clone(); + let span = expression_span.start + ..terminating_span + .as_ref() + .map(|span| span.end) + .unwrap_or(expression_span.end); + Ok(Statement::ExpressionStatement(ExpressionStatement { - span: expression.span().clone(), + span, + terminated: terminating_span.is_some(), expression, ty_info: None, })) @@ -41,8 +54,16 @@ impl SolveType for ExpressionStatement { let ty_info = expression.get_ty_info().clone(); Ok(ExpressionStatement { - ty_info, + ty_info: TyInfo { + ty: if self.terminated { + Ty::Unit + } else { + ty_info.ty + }, + return_ty: ty_info.return_ty, + }, expression, + terminated: self.terminated, span: self.span, }) } @@ -71,10 +92,12 @@ mod test { } #[rstest] - #[case::integer("1", |e| matches!(e, Expression::Integer(_)))] + #[case::integer_unterminated("1", false, |e| matches!(e, Expression::Integer(_)))] + #[case::integer_unterminated("1;", true, |e| matches!(e, Expression::Integer(_)))] fn success( parser: Parser, #[case] source: &str, + #[case] expect_terminated: bool, #[case] tester: fn(Expression) -> bool, ) { let s: Statement = parser @@ -85,10 +108,17 @@ mod test { ) .unwrap(); - let Statement::ExpressionStatement(ExpressionStatement { expression, .. }) = s else { + let Statement::ExpressionStatement(ExpressionStatement { + expression, + terminated, + .. + }) = s + else { panic!("expected expression statement"); }; + assert_eq!(terminated, expect_terminated); + assert!(tester(expression)); } } @@ -97,9 +127,14 @@ mod test { use super::*; #[rstest] - #[case(Ty::Int)] - fn infer(#[case] ty: Ty) { - let s = Statement::expression(Expression::integer(0, Span::default()), Span::default()); + #[case(Ty::Int, false)] + #[case(Ty::Unit, true)] + fn infer(#[case] ty: Ty, #[case] terminated: bool) { + let s = Statement::expression( + Expression::integer(0, Span::default()), + terminated, + Span::default(), + ); let ty_info = s .solve(&mut Compiler::default(), &mut Scope::new()) diff --git a/src/hir/statement/s_let.rs b/src/hir/statement/s_let.rs index 495f6ce..670465c 100644 --- a/src/hir/statement/s_let.rs +++ b/src/hir/statement/s_let.rs @@ -56,9 +56,21 @@ impl Parsable for Let { let value: Expression = parser.parse(compiler, lexer, Precedence::Lowest)?; + // Parse out the semicolon + let semicolon_span = match lexer.next_spanned().ok_or(ParseError::UnexpectedEOF)? { + (Token::SemiColon, span) => span, + (token, _) => { + return Err(ParseError::ExpectedToken { + expected: Box::new(Token::SemiColon), + found: Box::new(token), + reason: "expected let statement to finish with semicolon".to_string(), + }); + } + }; + Ok(Statement::Let(Let { binding, - span: start_span.start..value.span().end, + span: start_span.start..semicolon_span.end, value, ty_info: None, })) @@ -124,7 +136,7 @@ mod test { } #[rstest] - #[case::regular("let a = 1")] + #[case::regular("let a = 1;")] fn success(parser: Parser, #[case] source: &str) { let mut compiler = Compiler::default(); @@ -145,9 +157,10 @@ mod test { } #[rstest] - #[case::missing_binding("let = 1")] - #[case::missing_equals("let a 1")] - #[case::missing_value("let a =")] + #[case::missing_binding("let = 1;")] + #[case::missing_equals("let a 1;")] + #[case::missing_value("let a =;")] + #[case::missing_semicolon("let a = 1")] fn fail(parser: Parser, #[case] source: &str) { assert!(parser .parse::, _>( diff --git a/src/hir/statement/s_return.rs b/src/hir/statement/s_return.rs index f2aa0c8..4530fca 100644 --- a/src/hir/statement/s_return.rs +++ b/src/hir/statement/s_return.rs @@ -31,8 +31,21 @@ impl Parsable for Return { let value: Expression = parser.parse(compiler, lexer, Precedence::Lowest)?; + // Parse out the semicolon + let semicolon_span = match lexer.next_spanned().ok_or(ParseError::UnexpectedEOF)? { + (Token::SemiColon, span) => span, + (token, _) => { + return Err(ParseError::ExpectedToken { + expected: Box::new(Token::SemiColon), + found: Box::new(token), + reason: "expected return statement to finish with semicolon" + .to_string(), + }); + } + }; + Ok(Statement::Return(Return { - span: span.start..value.span().end, + span: span.start..semicolon_span.end, value, ty_info: None, })) @@ -82,35 +95,48 @@ mod test { Return::::register(&mut parser); // Helper parser for testing - Integer::::register(&mut parser); + Expression::::register(&mut parser); parser } #[rstest] - fn success(parser: Parser) { + #[case::simple("return 1;", |e| matches!(e, Expression::Integer(Integer { value: 1, .. })))] + #[case::expression("return 1 + 1;", |e| matches!(e, Expression::Infix(_)))] + #[case::expression_call("return fib(n - 1) + fib(n - 2);", |e| { + let Expression::Infix(Infix { left, right, .. }) = e else { + return false; + }; + + matches!(*left, Expression::Call(_)) && matches!(*right, Expression::Call(_)) + })] + fn success( + parser: Parser, + #[case] source: &str, + #[case] tester: fn(Expression) -> bool, + ) { let r: Statement = parser .parse( &mut Compiler::default(), - &mut Lexer::from("return 1"), + &mut Lexer::from(source), Precedence::Lowest, ) .unwrap(); - assert!(matches!( - r, - Statement::Return(Return { - value: Expression::Integer(Integer { value: 1, .. }), - .. - }) - )); + let Statement::Return(r) = r else { + panic!("expected to parse return statement"); + }; + + assert!(tester(r.value)); } #[rstest] - fn fail(parser: Parser) { + #[case::no_expression("return;")] + #[case::no_semicolon("return 1")] + fn fail(parser: Parser, #[case] source: &str) { let result: Result, _> = parser.parse( &mut Compiler::default(), - &mut Lexer::from("return"), + &mut Lexer::from(source), Precedence::Lowest, ); diff --git a/src/stage/parse/block.rs b/src/stage/parse/block.rs deleted file mode 100644 index a64d584..0000000 --- a/src/stage/parse/block.rs +++ /dev/null @@ -1,36 +0,0 @@ -use super::*; - -pub fn parse_block(compiler: &mut Compiler, lexer: &mut Lexer<'_>) -> Result { - let span_start = match lexer.next_spanned().unwrap() { - (Token::LeftBrace, span) => span.start, - (token, _) => { - return Err(ParseError::ExpectedToken { - expected: Box::new(Token::LeftBrace), - found: Box::new(token), - reason: "block must begin with an opening brace".to_string(), - }); - } - }; - - let statements = std::iter::from_fn(|| match lexer.peek_token().unwrap() { - Token::RightBrace => None, - _ => Some(parse_statement(compiler, lexer)), - }) - .collect::, _>>()?; - - // Consume the right brace that just stopped us - let span_end = match lexer.next_spanned().unwrap() { - (Token::RightBrace, span) => span.end, - (token, _) => { - return Err(ParseError::ExpectedToken { - expected: Box::new(Token::RightBrace), - found: Box::new(token), - reason: "block must end with a closing brace".to_string(), - }); - } - }; - - let span = span_start..span_end; - - Ok(Block::new(statements, true, span, Default::default())) -} diff --git a/src/stage/parse/expression/e_array.rs b/src/stage/parse/expression/e_array.rs deleted file mode 100644 index ab7e182..0000000 --- a/src/stage/parse/expression/e_array.rs +++ /dev/null @@ -1,47 +0,0 @@ -use super::*; - -pub fn parse_array(compiler: &mut Compiler, lexer: &mut Lexer) -> Result { - // Parse opening square bracket - let span_start = match lexer.next_spanned().unwrap() { - (Token::LeftSquare, span) => span.start, - (token, _) => { - return Err(ParseError::ExpectedToken { - expected: Box::new(Token::LeftSquare), - found: Box::new(token), - reason: "array literal must start with square brace".to_string(), - }); - } - }; - - // Parse each of the items, deliminated by a comma - let mut init = Vec::new(); - let mut expect_item = true; - let span_end = loop { - match (lexer.peek_token().unwrap(), expect_item) { - (Token::Comma, false) => { - expect_item = true; - lexer.next_token(); - } - (Token::RightSquare, _) => { - break lexer.next_spanned().unwrap().1.end; - } - (_, true) => { - init.push(parse_expression(compiler, lexer, Precedence::Lowest)?); - expect_item = false; - } - (token, _) => { - return Err(ParseError::ExpectedToken { - expected: Box::new(Token::RightSquare), - found: Box::new(token.clone()), - reason: "expected a comma or closing brace".to_string(), - }); - } - } - }; - - Ok(Array { - init, - span: span_start..span_end, - ty_info: None, - }) -} diff --git a/src/stage/parse/expression/e_assign.rs b/src/stage/parse/expression/e_assign.rs deleted file mode 100644 index 328cd0f..0000000 --- a/src/stage/parse/expression/e_assign.rs +++ /dev/null @@ -1,83 +0,0 @@ -pub use super::*; - -pub fn parse_assign(compiler: &mut Compiler, lexer: &mut Lexer<'_>) -> Result { - let (binding, span_start) = match lexer.next_spanned().unwrap() { - (Token::Ident(ident), span) => (ident, span), - (token, _) => { - return Err(ParseError::ExpectedToken { - expected: Box::new(Token::Ident(String::new())), - found: Box::new(token), - reason: "assign must start with ident".to_string(), - }); - } - }; - - let binding = compiler.symbols.get_or_intern(binding); - - match lexer.next_token().unwrap() { - Token::Eq => (), - token => { - return Err(ParseError::ExpectedToken { - expected: Box::new(Token::Eq), - found: Box::new(token), - reason: "equals sign following binding for assign".to_string(), - }); - } - } - - let value = parse_expression(compiler, lexer, Precedence::Lowest)?; - - Ok(Assign { - span: span_start.start..value.span().end, - binding, - value: Box::new(value), - ty_info: None, - }) -} - -pub fn parse_op_assign( - compiler: &mut Compiler, - lexer: &mut Lexer<'_>, -) -> Result { - let (binding, binding_span) = match lexer.next_spanned().unwrap() { - (Token::Ident(ident), span) => (ident, span), - (token, _) => { - return Err(ParseError::ExpectedToken { - expected: Box::new(Token::Ident(String::new())), - found: Box::new(token), - reason: "assign must start with ident".to_string(), - }); - } - }; - - let binding = compiler.symbols.get_or_intern(binding); - - let operation = match lexer.next_token().unwrap() { - Token::AddAssign => InfixOperation::Plus, - Token::MinusAssign => InfixOperation::Minus, - Token::MulAssign => InfixOperation::Multiply, - Token::DivAssign => InfixOperation::Divide, - token => { - return Err(ParseError::UnexpectedToken(token)); - } - }; - - let right = parse_expression(compiler, lexer, Precedence::Lowest)?; - - Ok(Assign { - span: binding_span.start..right.span().end, - binding, - value: Box::new(Expression::Infix(Infix { - span: right.span().start..right.span().end, - left: Box::new(Expression::Ident(Ident { - span: binding_span, - binding, - ty_info: None, - })), - operation, - right: Box::new(right), - ty_info: None, - })), - ty_info: None, - }) -} diff --git a/src/stage/parse/expression/e_boolean.rs b/src/stage/parse/expression/e_boolean.rs deleted file mode 100644 index ecb7426..0000000 --- a/src/stage/parse/expression/e_boolean.rs +++ /dev/null @@ -1,49 +0,0 @@ -use super::*; - -pub fn parse_boolean( - _compiler: &mut Compiler, - lexer: &mut Lexer<'_>, -) -> Result { - match lexer.next_spanned().unwrap() { - (Token::True, span) => Ok(Boolean::new(true, span, Default::default())), - (Token::False, span) => Ok(Boolean::new(false, span, Default::default())), - (token, _) => { - Err(ParseError::ExpectedToken { - // WARN: Should be true or false - expected: Box::new(Token::True), - found: Box::new(token), - reason: "expected boolean token".to_string(), - }) - } - } -} - -#[cfg(test)] -mod test { - use rstest::rstest; - - use super::*; - - #[rstest] - #[case::t_true("true", true)] - #[case::t_false("false", false)] - fn success(#[case] source: &str, #[case] value: bool) { - let boolean = parse_boolean(&mut Compiler::default(), &mut source.into()).unwrap(); - assert_eq!(boolean.value, value); - } - - #[test] - fn fail() { - assert!(parse_boolean(&mut Compiler::default(), &mut "someident".into()).is_err()); - } - - #[rstest] - #[case::success("true;")] - #[case::fail("someident;")] - fn single_token(#[case] source: &str) { - let mut tokens = source.into(); - let _ = parse_boolean(&mut Compiler::default(), &mut tokens); - - assert_eq!(tokens.count(), 1); - } -} diff --git a/src/stage/parse/expression/e_ident.rs b/src/stage/parse/expression/e_ident.rs deleted file mode 100644 index 4175f95..0000000 --- a/src/stage/parse/expression/e_ident.rs +++ /dev/null @@ -1,52 +0,0 @@ -use super::*; - -pub fn parse_ident(compiler: &mut Compiler, lexer: &mut Lexer<'_>) -> Result { - match lexer.next_spanned().unwrap() { - (Token::Ident(ident), span) => Ok(Ident::new( - compiler.symbols.get_or_intern(ident), - span, - Default::default(), - )), - (token, _) => Err(ParseError::ExpectedToken { - expected: Box::new(Token::Ident(String::new())), - found: Box::new(token), - reason: "expected ident".to_string(), - }), - } -} - -#[cfg(test)] -mod test { - use super::*; - - use rstest::rstest; - - #[test] - fn success() { - let mut tokens = "someident".into(); - - let mut compiler = Compiler::default(); - - let ident = parse_ident(&mut compiler, &mut tokens).unwrap(); - - assert_eq!( - compiler.symbols.resolve(ident.binding).unwrap(), - "someident" - ); - } - - #[test] - fn fail() { - assert!(parse_ident(&mut Compiler::default(), &mut "1".into(),).is_err()); - } - - #[rstest] - #[case::success("someident;")] - #[case::fail("1;")] - fn single_token(#[case] source: &str) { - let mut tokens = source.into(); - let _ = parse_ident(&mut Compiler::default(), &mut tokens); - - assert_eq!(tokens.count(), 1); - } -} diff --git a/src/stage/parse/expression/e_if.rs b/src/stage/parse/expression/e_if.rs deleted file mode 100644 index 3e50e1d..0000000 --- a/src/stage/parse/expression/e_if.rs +++ /dev/null @@ -1,87 +0,0 @@ -use super::*; - -pub fn parse_if(compiler: &mut Compiler, lexer: &mut Lexer<'_>) -> Result { - let span_start = match lexer.next_spanned().unwrap() { - (Token::If, span) => span.start, - (token, _) => { - return Err(ParseError::ExpectedToken { - expected: Box::new(Token::If), - found: Box::new(token), - reason: "if statement expected".to_string(), - }); - } - }; - - let condition = parse_expression(compiler, lexer, Precedence::Lowest)?; - - let success = parse_block(compiler, lexer)?; - - let otherwise = if matches!(lexer.peek_token(), Some(Token::Else)) { - lexer.next_token().unwrap(); - - let otherwise = parse_block(compiler, lexer)?; - - Some(otherwise) - } else { - None - }; - - let span_end = otherwise - .as_ref() - .map(|otherwise| otherwise.span.end) - .unwrap_or(success.span.end); - - Ok(If::new( - Box::new(condition), - success, - otherwise, - span_start..span_end, - Default::default(), - )) -} - -#[cfg(test)] -mod test { - use rstest::rstest; - - use super::*; - - #[test] - fn integer_condition() { - let mut tokens = "if 123 { 1 }".into(); - - let e_if = parse_if(&mut Compiler::default(), &mut tokens).unwrap(); - - assert!(matches!( - *e_if.condition, - Expression::Integer(Integer { value: 123, .. }) - )); - } - - #[test] - fn ident_condition() { - let mut tokens = "if someident { 1 }".into(); - - let e_if = parse_if(&mut Compiler::default(), &mut tokens).unwrap(); - - assert!(matches!(*e_if.condition, Expression::Ident(_))); - } - - #[test] - fn otherwise_branch() { - let mut tokens = "if someident { 1 } else { 2 }".into(); - - let e_if = parse_if(&mut Compiler::default(), &mut tokens).unwrap(); - - assert!(e_if.otherwise.is_some()); - } - - #[rstest] - #[case::multiple_condition_tokens("if 1 2")] - #[case::malformed_otherwise_block("if 1 { 3 } else else { 3 }")] - fn fail(#[case] source: &str) { - let result = parse_if(&mut Compiler::default(), &mut source.into()); - - assert!(result.is_err()); - } -} diff --git a/src/stage/parse/expression/e_integer.rs b/src/stage/parse/expression/e_integer.rs deleted file mode 100644 index 314b3a8..0000000 --- a/src/stage/parse/expression/e_integer.rs +++ /dev/null @@ -1,49 +0,0 @@ -use super::*; - -pub fn parse_integer( - _compiler: &mut Compiler, - lexer: &mut Lexer<'_>, -) -> Result { - match lexer.next_spanned().unwrap() { - (Token::Integer(value), span) => Ok(Integer::new(value, span, Default::default())), - (token, _) => Err(ParseError::ExpectedToken { - expected: Box::new(Token::Integer(0)), - found: Box::new(token), - reason: "integer token expected".to_string(), - }), - } -} - -#[cfg(test)] -mod test { - use super::*; - - use rstest::rstest; - - fn run(source: &str) -> Result { - parse_integer(&mut Compiler::default(), &mut source.into()) - } - - #[rstest] - #[case::single_digit(1)] - #[case::multi_digit(123)] - fn success(#[case] value: i64) { - let integer = run(&value.to_string()); - assert_eq!(integer.unwrap().value, value); - } - - #[test] - fn fail() { - let integer = run("someident"); - assert!(integer.is_err()); - } - - #[rstest] - #[case::success("1;")] - #[case::fail("someident;")] - fn single_token(#[case] source: &str) { - let mut tokens = source.into(); - let _ = parse_integer(&mut Compiler::default(), &mut tokens); - assert_eq!(tokens.count(), 1); - } -} diff --git a/src/stage/parse/expression/e_loop.rs b/src/stage/parse/expression/e_loop.rs deleted file mode 100644 index 216ae60..0000000 --- a/src/stage/parse/expression/e_loop.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::{ - repr::{ast::untyped::Loop, token::Token}, - stage::parse::parse_block, -}; - -use super::{Compiler, Lexer, ParseError}; - -pub fn parse_loop(compiler: &mut Compiler, lexer: &mut Lexer<'_>) -> Result { - let span_start = match lexer.next_spanned().unwrap() { - (Token::Loop, span) => span.start, - (token, _) => { - return Err(ParseError::ExpectedToken { - expected: Box::new(Token::If), - found: Box::new(token), - reason: "loop must start with keyword".to_string(), - }); - } - }; - - let body = parse_block(compiler, lexer)?; - - Ok(Loop { - span: span_start..body.span.end, - body, - ty_info: None, - }) -} diff --git a/src/stage/parse/expression/mod.rs b/src/stage/parse/expression/mod.rs deleted file mode 100644 index 1e2597b..0000000 --- a/src/stage/parse/expression/mod.rs +++ /dev/null @@ -1,875 +0,0 @@ -use std::iter; - -use e_assign::{parse_assign, parse_op_assign}; -use e_loop::parse_loop; - -use super::*; - -use self::{ - e_array::parse_array, e_boolean::parse_boolean, e_ident::parse_ident, e_if::parse_if, - e_integer::parse_integer, -}; - -mod e_array; -mod e_assign; -mod e_boolean; -mod e_ident; -mod e_if; -mod e_integer; -mod e_loop; - -#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum Precedence { - #[default] - Lowest, - Assign, - Binary, - Equality, - Sum, - Multiply, - Cast, - Call, -} - -impl Precedence { - pub fn of(token: &Token) -> Self { - match token { - Token::Minus | Token::Plus => Precedence::Sum, - Token::Asterix | Token::ForwardSlash => Precedence::Multiply, - Token::And | Token::Or => Precedence::Binary, - Token::DoubleEq - | Token::NotEq - | Token::LeftAngle - | Token::RightAngle - | Token::LeftAngleEq - | Token::RightAngleEq => Precedence::Equality, - Token::LeftParen | Token::LeftSquare => Precedence::Call, - Token::Eq - | Token::AddAssign - | Token::MinusAssign - | Token::DivAssign - | Token::MulAssign => Precedence::Assign, - Token::As => Precedence::Cast, - _ => Precedence::Lowest, - } - } -} - -impl From for Precedence { - fn from(op: InfixOperation) -> Self { - use InfixOperation::*; - - match op { - Minus | Plus => Precedence::Sum, - Multiply | Divide => Precedence::Multiply, - And | Or => Precedence::Binary, - Eq | NotEq | Greater | Less | GreaterEq | LessEq => Precedence::Equality, - } - } -} - -impl From for Precedence { - fn from(token: Token) -> Self { - Self::of(&token) - } -} - -fn parse_prefix(compiler: &mut Compiler, lexer: &mut Lexer<'_>) -> Result { - match lexer.peek_token().unwrap().clone() { - Token::Integer(_) => Ok(Expression::Integer(parse_integer(compiler, lexer)?)), - Token::Ident(_) => match lexer.double_peek_token() { - Some(Token::Eq) => Ok(Expression::Assign(parse_assign(compiler, lexer)?)), - Some(Token::AddAssign | Token::MinusAssign) => { - Ok(Expression::Assign(parse_op_assign(compiler, lexer)?)) - } - _ => Ok(Expression::Ident(parse_ident(compiler, lexer)?)), - }, - Token::True => Ok(Expression::Boolean(parse_boolean(compiler, lexer)?)), - Token::False => Ok(Expression::Boolean(parse_boolean(compiler, lexer)?)), - Token::LeftBrace => Ok(Expression::Block(parse_block(compiler, lexer)?)), - Token::LeftParen => parse_grouped(compiler, lexer), - Token::LeftSquare => Ok(Expression::Array(parse_array(compiler, lexer)?)), - Token::If => Ok(Expression::If(parse_if(compiler, lexer)?)), - Token::Loop => Ok(Expression::Loop(parse_loop(compiler, lexer)?)), - token => Err(ParseError::UnexpectedToken(token.clone())), - } -} - -pub fn parse_expression( - compiler: &mut Compiler, - lexer: &mut Lexer<'_>, - precedence: Precedence, -) -> Result { - let mut left = parse_prefix(compiler, lexer)?; - - while lexer.peek_token().is_some() && precedence < Precedence::of(lexer.peek_token().unwrap()) { - left = match (left, lexer.peek_token().unwrap()) { - // Function call - (Expression::Ident(ident), Token::LeftParen) => { - parse_function_call(compiler, lexer, ident)? - } - - // Index operation - (Expression::Ident(ident), Token::LeftSquare) => parse_index(compiler, lexer, ident)?, - - // Regular infix operation - (left, _) => parse_infix(compiler, lexer, left)?, - }; - } - - Ok(left) -} - -fn parse_index( - compiler: &mut Compiler, - lexer: &mut Lexer, - ident: Ident, -) -> Result { - // Parse out the left square bracket - match lexer.next_token().unwrap() { - Token::LeftSquare => (), - token => { - return Err(ParseError::ExpectedToken { - expected: Box::new(Token::LeftSquare), - found: Box::new(token), - reason: "index must be performed with square bracket".to_string(), - }); - } - } - - // Pull out the index - let index = parse_expression(compiler, lexer, Precedence::Lowest)?; - - // Pull out closing bracket - let end_span = match lexer.next_spanned().unwrap() { - (Token::RightSquare, span) => span.end, - (token, _) => { - return Err(ParseError::ExpectedToken { - expected: Box::new(Token::RightSquare), - found: Box::new(token), - reason: "index must be performed with square bracket".to_string(), - }); - } - }; - - Ok(Expression::Index(Index { - span: ident.span.start..end_span, - value: ident.binding, - index: Box::new(index), - ty_info: None, - })) -} - -fn parse_function_call( - compiler: &mut Compiler, - lexer: &mut Lexer, - ident: Ident, -) -> Result { - // Consume the args - let args = iter::from_fn(|| { - match lexer.peek_token().unwrap() { - Token::RightParen => None, - Token::LeftParen | Token::Comma => { - // Consume the opening paren or comma - lexer.next_token(); - - // If the closing parenthesis is encountered, stop parsing arguments - if matches!(lexer.peek_token().unwrap(), Token::RightParen) { - return None; - } - - // Parse the next argument - Some(parse_expression(compiler, lexer, Precedence::Lowest)) - } - token => Some(Err(ParseError::ExpectedToken { - expected: Box::new(Token::Comma), - found: Box::new(token.clone()), - reason: "function arguments must be separated by a comma".to_string(), - })), - } - }) - .collect::, _>>()?; - - // Consume the closing paren - let end_span = match lexer.next_spanned().unwrap() { - (Token::RightParen, span) => span, - (token, _) => { - return Err(ParseError::ExpectedToken { - expected: Box::new(Token::RightParen), - found: Box::new(token), - reason: "argument list must end with right paren".to_string(), - }) - } - }; - - let span = ident.span.start..end_span.end; - Ok(Expression::Call(Call::new( - ident.binding, - args, - span, - Default::default(), - ))) -} - -fn parse_infix( - compiler: &mut Compiler, - lexer: &mut Lexer, - left: Expression, -) -> Result { - let token = lexer.next_token().unwrap(); - - Ok( - if let Ok(operation) = InfixOperation::try_from(token.clone()) { - let precedence = Precedence::of(&token); - - let right = parse_expression(compiler, lexer, precedence)?; - - let span = left.span().start..right.span().end; - - Expression::Infix(Infix::new( - Box::new(left), - operation, - Box::new(right), - span, - Default::default(), - )) - } else { - left - }, - ) -} - -fn parse_grouped(compiler: &mut Compiler, lexer: &mut Lexer) -> Result { - let span_start = match lexer.next_spanned().unwrap() { - (Token::LeftParen, span) => span.start, - (token, _) => { - return Err(ParseError::ExpectedToken { - expected: Box::new(Token::LeftBrace), - found: Box::new(token), - reason: "open paren for grouped expression".to_string(), - }); - } - }; - - let e = parse_expression(compiler, lexer, Precedence::Lowest)?; - - let span_end = match lexer.next_spanned().unwrap() { - (Token::RightParen, span) => span.end, - (token, _) => { - return Err(ParseError::ExpectedToken { - expected: Box::new(Token::RightBrace), - found: Box::new(token), - reason: "close paren must end grouped expression".to_string(), - }); - } - }; - - // TODO: Need to somehow attach this span to the expression - #[allow(unused_variables)] - let e_span = span_start..span_end; - - Ok(e) -} - -#[cfg(test)] -mod test { - use super::*; - - use rstest::*; - - #[fixture] - fn mock_compiler(#[default("func")] ident: &'static str) -> Compiler { - let mut compiler = Compiler::default(); - - compiler.symbols.get_or_intern(ident); - - compiler - } - - #[rstest] - fn simple_addition() { - let expression = parse_expression( - &mut Compiler::default(), - &mut "3 + 4".into(), - Precedence::Lowest, - ) - .unwrap(); - - insta::assert_debug_snapshot!(expression, @r###" - Infix( - Infix { - left: Integer( - Integer { - value: 3, - span: 0..1, - ty_info: None, - }, - ), - operation: Plus, - right: Integer( - Integer { - value: 4, - span: 4..5, - ty_info: None, - }, - ), - span: 0..5, - ty_info: None, - }, - ) - "###); - } - - #[rstest] - fn multi_addition() { - let expression = parse_expression( - &mut Compiler::default(), - &mut "3 + 4 + 10".into(), - Precedence::Lowest, - ) - .unwrap(); - - insta::assert_debug_snapshot!(expression, @r###" - Infix( - Infix { - left: Infix( - Infix { - left: Integer( - Integer { - value: 3, - span: 0..1, - ty_info: None, - }, - ), - operation: Plus, - right: Integer( - Integer { - value: 4, - span: 4..5, - ty_info: None, - }, - ), - span: 0..5, - ty_info: None, - }, - ), - operation: Plus, - right: Integer( - Integer { - value: 10, - span: 8..10, - ty_info: None, - }, - ), - span: 0..10, - ty_info: None, - }, - ) - "###); - } - - #[rstest] - fn if_statement() { - let mut compiler = Compiler::default(); - - let expression = parse_expression( - &mut compiler, - &mut "if 1 { someident }".into(), - Precedence::Lowest, - ) - .unwrap(); - - assert!(compiler.symbols.get("someident").is_some()); - - insta::assert_debug_snapshot!(expression, @r###" - If( - If { - condition: Integer( - Integer { - value: 1, - span: 3..4, - ty_info: None, - }, - ), - success: Block { - statements: [ - ExpressionStatement( - ExpressionStatement { - expression: Ident( - Ident { - binding: SymbolU32 { - value: 1, - }, - span: 7..16, - ty_info: None, - }, - ), - implicit_return: true, - span: 7..16, - ty_info: None, - }, - ), - ], - span: 5..18, - ty_info: None, - }, - otherwise: None, - span: 0..18, - ty_info: None, - }, - ) - "###); - } - - #[rstest] - fn integer() { - let expression = parse_expression( - &mut Compiler::default(), - &mut "1".into(), - Precedence::Lowest, - ) - .unwrap(); - insta::assert_debug_snapshot!(expression, @r###" - Integer( - Integer { - value: 1, - span: 0..1, - ty_info: None, - }, - ) - "###); - } - - #[rstest] - fn ident(#[with("someident")] mut mock_compiler: Compiler) { - let expression = parse_expression( - &mut mock_compiler, - &mut "someident".into(), - Precedence::Lowest, - ) - .unwrap(); - insta::assert_debug_snapshot!(expression, @r###" - Ident( - Ident { - binding: SymbolU32 { - value: 1, - }, - span: 0..9, - ty_info: None, - }, - ) - "###); - } - - #[rstest] - fn equality() { - let expression = parse_expression( - &mut Compiler::default(), - &mut "1 == 1".into(), - Precedence::Lowest, - ) - .unwrap(); - - insta::assert_debug_snapshot!(expression, @r###" - Infix( - Infix { - left: Integer( - Integer { - value: 1, - span: 0..1, - ty_info: None, - }, - ), - operation: Eq, - right: Integer( - Integer { - value: 1, - span: 5..6, - ty_info: None, - }, - ), - span: 0..6, - ty_info: None, - }, - ) - "###); - } - - #[rstest] - fn complex_equality() { - let expression = parse_expression( - &mut Compiler::default(), - &mut "1 == 1 + 2".into(), - Precedence::Lowest, - ) - .unwrap(); - - insta::assert_debug_snapshot!(expression, @r###" - Infix( - Infix { - left: Integer( - Integer { - value: 1, - span: 0..1, - ty_info: None, - }, - ), - operation: Eq, - right: Infix( - Infix { - left: Integer( - Integer { - value: 1, - span: 5..6, - ty_info: None, - }, - ), - operation: Plus, - right: Integer( - Integer { - value: 2, - span: 9..10, - ty_info: None, - }, - ), - span: 5..10, - ty_info: None, - }, - ), - span: 0..10, - ty_info: None, - }, - ) - "###); - } - - #[rstest] - fn function_call_no_param(mut mock_compiler: Compiler) { - let expression = - parse_expression(&mut mock_compiler, &mut "func()".into(), Precedence::Lowest).unwrap(); - - insta::assert_debug_snapshot!(expression, @r###" - Call( - Call { - name: SymbolU32 { - value: 1, - }, - args: [], - span: 0..6, - ty_info: None, - }, - ) - "###); - } - - #[rstest] - fn function_call_one_param_no_comma(mut mock_compiler: Compiler) { - let expression = parse_expression( - &mut mock_compiler, - &mut "func(1)".into(), - Precedence::Lowest, - ) - .unwrap(); - - insta::assert_debug_snapshot!(expression, @r###" - Call( - Call { - name: SymbolU32 { - value: 1, - }, - args: [ - Integer( - Integer { - value: 1, - span: 5..6, - ty_info: None, - }, - ), - ], - span: 0..7, - ty_info: None, - }, - ) - "###); - } - - #[rstest] - fn function_call_one_param_trailing_comma(mut mock_compiler: Compiler) { - let expression = parse_expression( - &mut mock_compiler, - &mut "func(1,)".into(), - Precedence::Lowest, - ) - .unwrap(); - - insta::assert_debug_snapshot!(expression, @r###" - Call( - Call { - name: SymbolU32 { - value: 1, - }, - args: [ - Integer( - Integer { - value: 1, - span: 5..6, - ty_info: None, - }, - ), - ], - span: 0..8, - ty_info: None, - }, - ) - "###); - } - - #[rstest] - fn function_call_multi_param_no_comma(mut mock_compiler: Compiler) { - let expression = parse_expression( - &mut mock_compiler, - &mut "func(1, 2, 3)".into(), - Precedence::Lowest, - ) - .unwrap(); - - insta::assert_debug_snapshot!(expression, @r###" - Call( - Call { - name: SymbolU32 { - value: 1, - }, - args: [ - Integer( - Integer { - value: 1, - span: 5..6, - ty_info: None, - }, - ), - Integer( - Integer { - value: 2, - span: 8..9, - ty_info: None, - }, - ), - Integer( - Integer { - value: 3, - span: 11..12, - ty_info: None, - }, - ), - ], - span: 0..13, - ty_info: None, - }, - ) - "###); - } - - #[rstest] - fn function_call_multi_param_trailing_comma(mut mock_compiler: Compiler) { - let expression = parse_expression( - &mut mock_compiler, - &mut "func(1, 2, 3,)".into(), - Precedence::Lowest, - ) - .unwrap(); - - insta::assert_debug_snapshot!(expression, @r###" - Call( - Call { - name: SymbolU32 { - value: 1, - }, - args: [ - Integer( - Integer { - value: 1, - span: 5..6, - ty_info: None, - }, - ), - Integer( - Integer { - value: 2, - span: 8..9, - ty_info: None, - }, - ), - Integer( - Integer { - value: 3, - span: 11..12, - ty_info: None, - }, - ), - ], - span: 0..14, - ty_info: None, - }, - ) - "###); - } - - #[rstest] - fn function_call_with_expression_param(mut mock_compiler: Compiler) { - let expression = parse_expression( - &mut mock_compiler, - &mut "func(1 + 2, 3,)".into(), - Precedence::Lowest, - ) - .unwrap(); - - insta::assert_debug_snapshot!(expression, @r###" - Call( - Call { - name: SymbolU32 { - value: 1, - }, - args: [ - Infix( - Infix { - left: Integer( - Integer { - value: 1, - span: 5..6, - ty_info: None, - }, - ), - operation: Plus, - right: Integer( - Integer { - value: 2, - span: 9..10, - ty_info: None, - }, - ), - span: 5..10, - ty_info: None, - }, - ), - Integer( - Integer { - value: 3, - span: 12..13, - ty_info: None, - }, - ), - ], - span: 0..15, - ty_info: None, - }, - ) - "###); - } - - #[rstest] - fn function_call_in_expression(mut mock_compiler: Compiler) { - let expression = parse_expression( - &mut mock_compiler, - &mut "func(1) + 2".into(), - Precedence::Lowest, - ) - .unwrap(); - - insta::assert_debug_snapshot!(expression, @r###" - Infix( - Infix { - left: Call( - Call { - name: SymbolU32 { - value: 1, - }, - args: [ - Integer( - Integer { - value: 1, - span: 5..6, - ty_info: None, - }, - ), - ], - span: 0..7, - ty_info: None, - }, - ), - operation: Plus, - right: Integer( - Integer { - value: 2, - span: 10..11, - ty_info: None, - }, - ), - span: 0..11, - ty_info: None, - }, - ) - "###); - } - - #[rstest] - fn grouped_expression(mut mock_compiler: Compiler) { - let expression = parse_expression( - &mut mock_compiler, - &mut "1 * (2 + 3) * 4".into(), - Precedence::Lowest, - ) - .unwrap(); - - insta::assert_debug_snapshot!(expression, @r###" - Infix( - Infix { - left: Infix( - Infix { - left: Integer( - Integer { - value: 1, - span: 0..1, - ty_info: None, - }, - ), - operation: Multiply, - right: Infix( - Infix { - left: Integer( - Integer { - value: 2, - span: 5..6, - ty_info: None, - }, - ), - operation: Plus, - right: Integer( - Integer { - value: 3, - span: 9..10, - ty_info: None, - }, - ), - span: 5..10, - ty_info: None, - }, - ), - span: 0..10, - ty_info: None, - }, - ), - operation: Multiply, - right: Integer( - Integer { - value: 4, - span: 14..15, - ty_info: None, - }, - ), - span: 0..15, - ty_info: None, - }, - ) - "###); - } -} diff --git a/src/stage/parse/function.rs b/src/stage/parse/function.rs index d12d444..a4cdc3d 100644 --- a/src/stage/parse/function.rs +++ b/src/stage/parse/function.rs @@ -5,11 +5,12 @@ use ty::parse_ty; use super::*; pub fn parse_function( + parser: &Parser, compiler: &mut Compiler, - tokens: &mut Lexer<'_>, + lexer: &mut Lexer<'_>, ) -> Result { // `fn` keyword - let span_start = match tokens.next_spanned().unwrap() { + let span_start = match lexer.next_spanned().unwrap() { // `fn` keyword (Token::Fn, span) => span.start, // Some other token @@ -23,7 +24,7 @@ pub fn parse_function( }; // function name - let fn_name = match tokens.next_token().unwrap() { + let fn_name = match lexer.next_token().unwrap() { Token::Ident(fn_name) => fn_name, token => { return Err(ParseError::ExpectedToken { @@ -35,7 +36,7 @@ pub fn parse_function( }; // opening paren for argument list - match tokens.next_token().unwrap() { + match lexer.next_token().unwrap() { Token::LeftParen => (), token => { return Err(ParseError::ExpectedToken { @@ -56,7 +57,7 @@ pub fn parse_function( let parameters = iter::from_fn(|| { loop { - match (&parse_state, tokens.next_token().unwrap()) { + match (&parse_state, lexer.next_token().unwrap()) { // Parameter list finished (_, Token::RightParen) => { return None; @@ -78,7 +79,7 @@ pub fn parse_function( let ident = compiler.symbols.get_or_intern(ident); // Ensure a colon follows it - match tokens.next_token().unwrap() { + match lexer.next_token().unwrap() { Token::Colon => (), token => { return Some(Err(ParseError::ExpectedToken { @@ -91,7 +92,7 @@ pub fn parse_function( } // Extract the type - let (ty, _) = match parse_ty(tokens) { + let (ty, _) = match parse_ty(lexer) { Ok(ty) => ty, Err(e) => { return Some(Err(e)); @@ -115,7 +116,7 @@ pub fn parse_function( .collect::, _>>()?; // arrow for return type - match tokens.next_token().unwrap() { + match lexer.next_token().unwrap() { Token::ThinArrow => (), token => { return Err(ParseError::ExpectedToken { @@ -127,10 +128,14 @@ pub fn parse_function( } // return type - let (return_ty, _) = parse_ty(tokens)?; + let (return_ty, _) = parse_ty(lexer)?; // Parse out the body - let body = parse_block(compiler, tokens)?; + let Expression::::Block(body) = + parser.parse(compiler, lexer, Precedence::Lowest)? + else { + return Err(ParseError::ExpectedBlock); + }; // Construct the function span to the end of the body let span = span_start..body.span.end; diff --git a/src/stage/parse/mod.rs b/src/stage/parse/mod.rs index 3e62e79..bfeea6c 100644 --- a/src/stage/parse/mod.rs +++ b/src/stage/parse/mod.rs @@ -1,8 +1,5 @@ -mod block; -mod expression; mod function; pub mod parser; -mod statement; mod ty; use std::collections::HashMap; @@ -11,15 +8,14 @@ use std::ops::Deref; use std::ops::DerefMut; use logos::Logos; +use parser::Parser; use crate::compiler::Compiler; +use crate::hir::{Expression, Parsable, Statement}; use crate::repr::token::*; use crate::util::span::*; -use self::block::*; -pub use self::expression::*; use self::function::*; -use self::statement::*; pub use self::ty::parse_ty; use crate::repr::ast::untyped::*; @@ -38,7 +34,7 @@ pub enum ParseError { #[error("invalid infix left hand side: {reason} ({found:?})")] InvalidInfixLhs { - found: Box, + found: Box>, reason: String, }, @@ -61,18 +57,82 @@ pub enum ParseError { NoRegisteredParsers(String), } +#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum Precedence { + #[default] + Lowest, + Assign, + Binary, + Equality, + Sum, + Multiply, + Cast, + Call, +} + +impl Precedence { + pub fn of(token: &Token) -> Self { + match token { + Token::Minus | Token::Plus => Precedence::Sum, + Token::Asterix | Token::ForwardSlash => Precedence::Multiply, + Token::And | Token::Or => Precedence::Binary, + Token::DoubleEq + | Token::NotEq + | Token::LeftAngle + | Token::RightAngle + | Token::LeftAngleEq + | Token::RightAngleEq => Precedence::Equality, + Token::LeftParen | Token::LeftSquare => Precedence::Call, + Token::Eq + | Token::AddAssign + | Token::MinusAssign + | Token::DivAssign + | Token::MulAssign => Precedence::Assign, + Token::As => Precedence::Cast, + _ => Precedence::Lowest, + } + } +} + +impl From for Precedence { + fn from(op: InfixOperation) -> Self { + use InfixOperation::*; + + match op { + Minus | Plus => Precedence::Sum, + Multiply | Divide => Precedence::Multiply, + And | Or => Precedence::Binary, + Eq | NotEq | Greater | Less | GreaterEq | LessEq => Precedence::Equality, + } + } +} + +impl From for Precedence { + fn from(token: Token) -> Self { + Self::of(&token) + } +} + pub fn parse(compiler: &mut Compiler, source: &str) -> Result { - let mut tokens: Lexer = source.into(); + let mut lexer: Lexer = source.into(); + + let parser = { + let mut parser = Parser::new(); + + Statement::::register(&mut parser); + Expression::::register(&mut parser); + + parser + }; // WARN: wacky af let main = compiler.symbols.get_or_intern("main"); // Parse each expression which should be followed by a semicolon let mut functions = std::iter::from_fn(|| { - Some(match tokens.peek_token()? { - Token::Fn => { - parse_function(compiler, &mut tokens).map(|function| (function.name, function)) - } + Some(match lexer.peek_token()? { + Token::Fn => parse_function(&parser, compiler, &mut lexer) + .map(|function| (function.name, function)), token => Err(ParseError::ExpectedToken { expected: Box::new(Token::Fn), found: Box::new(token.clone()), diff --git a/src/stage/parse/statement.rs b/src/stage/parse/statement.rs deleted file mode 100644 index 5b8c3c3..0000000 --- a/src/stage/parse/statement.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::hir::{Break, Continue}; - -use super::*; - -pub fn parse_statement( - compiler: &mut Compiler, - tokens: &mut Lexer<'_>, -) -> Result { - let statement = match tokens.peek_token().unwrap() { - Token::Return => { - // Parse as return statement - let (_, return_span) = tokens.next_spanned().unwrap(); - - // Parse out the value - let value = parse_expression(compiler, tokens, Precedence::Lowest)?; - - // Build the span - let span = return_span.start..value.span().end; - - Statement::Return(ReturnStatement::new(value, span, Default::default())) - } - Token::Let => { - // let token - let (_, let_span) = tokens.next_spanned().unwrap(); - - // variable binding - let name = match tokens.next_token().unwrap() { - Token::Ident(name) => name, - token => { - return Err(ParseError::ExpectedToken { - found: Box::new(token), - expected: Box::new(Token::Ident(Default::default())), - reason: "ident must follow let binding".to_string(), - }); - } - }; - - // equals sign - match tokens.next_token().unwrap() { - Token::Eq => (), - token => { - return Err(ParseError::ExpectedToken { - found: Box::new(token), - expected: Box::new(Token::Eq), - reason: "equals sign must follow ident".to_string(), - }); - } - }; - - // value - let value = parse_expression(compiler, tokens, Precedence::Lowest)?; - let span = let_span.start..value.span().end; - - Statement::Let(LetStatement::new( - compiler.symbols.get_or_intern(name), - value, - span, - Default::default(), - )) - } - Token::Break => { - let (_, break_span) = tokens.next_spanned().unwrap(); - - Statement::Break(Break::new(break_span, Default::default())) - } - Token::Continue => { - let (_, continue_span) = tokens.next_spanned().unwrap(); - - Statement::Continue(Continue::new(continue_span, Default::default())) - } - _ => { - // Parse expression - let expression = parse_expression(compiler, tokens, Precedence::Lowest)?; - let span = expression.span().clone(); - - Statement::ExpressionStatement(ExpressionStatement::new( - expression, - span, - Default::default(), - )) - } - }; - - match tokens.next_token().unwrap() { - Token::SemiColon => (), - token => { - return Err(ParseError::ExpectedToken { - found: Box::new(token), - expected: Box::new(Token::SemiColon), - reason: "semicolon must follow statement".to_string(), - }); - } - }; - - Ok(statement) -}