diff --git a/parser/src/lib.rs b/parser/src/lib.rs index 6797219..16616fa 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -17,10 +17,11 @@ pub fn parse(_str: &str, _file_name: PathBuf) -> Result { pub fn test() { let lexer = Token::lexer( - "fn foo() { - 1 + 5; - struct test {} - }", + " +fn main() { + if 1 { 5 + 5; } +} +", ); let len = lexer.source().len(); diff --git a/parser/src/main.rs b/parser/src/main.rs new file mode 100644 index 0000000..335123c --- /dev/null +++ b/parser/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + parser::test(); +} diff --git a/parser/src/parser.rs b/parser/src/parser.rs index b4df281..7b8e78d 100644 --- a/parser/src/parser.rs +++ b/parser/src/parser.rs @@ -4,8 +4,8 @@ use chumsky::{prelude::*, Stream}; use crate::{ ast::{ - Assignment, BinOp, BinOpKind, Call, Expr, File, FnDecl, Item, Literal, NameTyPair, Stmt, - StructDecl, Ty, TyKind, VarDecl, + Assignment, BinOp, BinOpKind, Call, ElsePart, Expr, File, FnDecl, IfStmt, Item, Literal, + NameTyPair, Stmt, StructDecl, Ty, TyKind, VarDecl, }, lexer::Token, }; @@ -14,11 +14,10 @@ type Error<'src> = Simple>; type Span = Range; fn ident_parser<'src>() -> impl Parser, String, Error = Error<'src>> + Clone { - filter_map(|span, tok| match tok { - Token::Ident(ident) => Ok(ident.to_owned()), - _ => Err(Simple::expected_input_found(span, Vec::new(), Some(tok))), - }) - .labelled("identifier") + let ident = select! { + Token::Ident(ident) => ident.to_owned(), + }; + ident.labelled("identifier") } fn ty_parser<'src>() -> impl Parser, Ty, Error = Error<'src>> + Clone { @@ -131,40 +130,6 @@ fn expr_parser<'src>() -> impl Parser, Expr, Error = Error<'src>> + }) } -fn statement_parser<'src>( - item: impl Parser, Item, Error = Error<'src>> + Clone, -) -> impl Parser, Stmt, Error = Error<'src>> + Clone { - let var_decl = ty_parser() - .then(ident_parser()) - .then_ignore(just(Token::Eq)) - .then(expr_parser()) - .map(|((ty, name), rhs)| { - Stmt::VarDecl(VarDecl { - name, - ty, - rhs: Some(rhs), - span: Default::default(), - }) - }); - - let assignment = expr_parser() - .then_ignore(just(Token::Eq)) - .then(expr_parser()) - .map(|(place, rhs)| { - Stmt::Assignment(Assignment { - place, - rhs, - span: Default::default(), - }) - }); - - var_decl - .or(assignment) - .or(expr_parser().map(|expr| Stmt::Expr(expr))) - .or(item.clone().map(|item| Stmt::Item(item))) - .then_ignore(just(Token::Semi)) -} - fn name_ty_pair_parser<'src>() -> impl Parser, NameTyPair, Error = Error<'src>> + Clone { ident_parser() @@ -173,39 +138,6 @@ fn name_ty_pair_parser<'src>() -> impl Parser, NameTyPair, Error = E .map_with_span(|(name, ty), span| NameTyPair { name, ty, span }) } -fn function_parser<'src>( - item: impl Parser, Item, Error = Error<'src>> + Clone, -) -> impl Parser, FnDecl, Error = Error<'src>> + Clone { - let name = ident_parser(); - - let params = name_ty_pair_parser() - .separated_by(just(Token::Comma)) - .allow_trailing() - .delimited_by(just(Token::ParenO), just(Token::ParenC)) - .labelled("function arguments"); - - let ret_ty = just(Token::Arrow).ignore_then(ty_parser()).or_not(); - - just(Token::Fn) - .map_with_span(|_, span| span) - .then(name) - .then(params) - .then(ret_ty) - .then( - statement_parser(item) - .repeated() - .delimited_by(just(Token::BraceO), just(Token::BraceC)), - ) - .map(|((((fn_span, name), params), ret_ty), body)| FnDecl { - name, - params, - ret_ty, - span: fn_span, - body, - }) - .labelled("function") -} - fn struct_parser<'src>() -> impl Parser, StructDecl, Error = Error<'src>> + Clone { let name = just(Token::Struct).ignore_then(ident_parser()); @@ -224,7 +156,105 @@ fn struct_parser<'src>() -> impl Parser, StructDecl, Error = Error<' fn item_parser<'src>() -> impl Parser, Item, Error = Error<'src>> + Clone { recursive(|item| { - function_parser(item) + // ---- statement + + let var_decl = ty_parser() + .then(ident_parser()) + .then_ignore(just(Token::Eq)) + .then(expr_parser()) + .map(|((ty, name), rhs)| { + Stmt::VarDecl(VarDecl { + name, + ty, + rhs: Some(rhs), + span: Default::default(), + }) + }); + + let assignment = expr_parser() + .then_ignore(just(Token::Eq)) + .then(expr_parser()) + .map(|(place, rhs)| { + Stmt::Assignment(Assignment { + place, + rhs, + span: Default::default(), + }) + }); + + let mut stmt = Recursive::declare(); + let if_stmt = recursive(|if_stmt| { + just(Token::If) + .ignore_then(expr_parser()) + .then( + stmt.clone() + .repeated() + .delimited_by(just(Token::BraceO), just(Token::BraceC)), + ) + .then( + just(Token::Else).ignore_then( + if_stmt + .map(|if_stmt| ElsePart::ElseIf(Box::new(if_stmt))) + .or(stmt + .clone() + .repeated() + .delimited_by(just(Token::BraceO), just(Token::BraceC)) + .map_with_span(ElsePart::Else)) + .or_not(), + ), + ) + .map_with_span(|((cond, body), else_part), span| IfStmt { + cond, + body, + else_part, + span, + }) + }) + .map(Stmt::IfStmt); + + stmt.define( + choice(( + var_decl, + assignment, + if_stmt, + expr_parser().map(Stmt::Expr), + item.map(Stmt::Item), + )) + .then_ignore(just(Token::Semi)), + ); + + // ---- function + + let name = ident_parser(); + + let params = name_ty_pair_parser() + .separated_by(just(Token::Comma)) + .allow_trailing() + .delimited_by(just(Token::ParenO), just(Token::ParenC)) + .labelled("function arguments"); + + let ret_ty = just(Token::Arrow).ignore_then(ty_parser()).or_not(); + let function = just(Token::Fn) + .map_with_span(|_, span| span) + .then(name) + .then(params) + .then(ret_ty) + .then( + stmt.repeated() + .delimited_by(just(Token::BraceO), just(Token::BraceC)), + ) + .map(|((((fn_span, name), params), ret_ty), body)| FnDecl { + name, + params, + ret_ty, + span: fn_span, + body, + }) + .labelled("function"); + + // ---- item + + function .map(Item::FnDecl) .or(struct_parser().map(Item::StructDecl)) }) diff --git a/parser/src/snapshots/parser__parser__tests__nested_function2.snap.new b/parser/src/snapshots/parser__parser__tests__nested_function2.snap.new new file mode 100644 index 0000000..8eebe1c --- /dev/null +++ b/parser/src/snapshots/parser__parser__tests__nested_function2.snap.new @@ -0,0 +1,14 @@ +--- +source: parser/src/parser.rs +assertion_line: 330 +expression: r +--- +( + Some( + File { + name: "parser__parser__tests", + items: [], + }, + ), + [], +)