From a1e35313b7336f901e67e75c392f08c49c76cda7 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Sun, 18 Aug 2024 12:42:06 -0300 Subject: [PATCH 01/11] Parse recover function definition without body or semicolon --- compiler/noirc_frontend/src/parser/errors.rs | 2 ++ .../src/parser/parser/function.rs | 33 +++++++++++++++-- .../src/parser/parser/traits.rs | 36 ++++++++++++++++--- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/compiler/noirc_frontend/src/parser/errors.rs b/compiler/noirc_frontend/src/parser/errors.rs index 72719adb4f8..ada3afdbe35 100644 --- a/compiler/noirc_frontend/src/parser/errors.rs +++ b/compiler/noirc_frontend/src/parser/errors.rs @@ -20,6 +20,8 @@ pub enum ParserErrorReason { ExpectedIdentifierAfterDot, #[error("expected an identifier after ::")] ExpectedIdentifierAfterColons, + #[error("expected {{ or -> after function parameters")] + ExpectedLeftBraceOrArrowAfterFunctionParameters, #[error("expected {{ after if condition")] ExpectedLeftBraceAfterIfCondition, #[error("Expected a ; separating these two statements")] diff --git a/compiler/noirc_frontend/src/parser/parser/function.rs b/compiler/noirc_frontend/src/parser/parser/function.rs index 3de48d2e02a..5ec92877295 100644 --- a/compiler/noirc_frontend/src/parser/parser/function.rs +++ b/compiler/noirc_frontend/src/parser/parser/function.rs @@ -6,7 +6,10 @@ use super::{ self_parameter, where_clause, NoirParser, }; use crate::token::{Keyword, Token, TokenKind}; -use crate::{ast::IntegerBitSize, parser::spanned}; +use crate::{ + ast::{BlockExpression, IntegerBitSize}, + parser::spanned, +}; use crate::{ ast::{ FunctionDefinition, FunctionReturnType, ItemVisibility, NoirFunction, Param, Visibility, @@ -20,6 +23,7 @@ use crate::{ }; use chumsky::prelude::*; +use noirc_errors::Span; /// function_definition: attribute function_modifiers 'fn' ident generics '(' function_parameters ')' function_return_type block /// function_modifiers 'fn' ident generics '(' function_parameters ')' function_return_type block @@ -32,12 +36,23 @@ pub(super) fn function_definition(allow_self: bool) -> impl NoirParser after function parameters"); + + let noir_function = noir_function.unwrap(); + assert_eq!(noir_function.name(), "foo"); + assert_eq!(noir_function.parameters().len(), 1); + assert!(noir_function.def.body.statements.is_empty()); + } } diff --git a/compiler/noirc_frontend/src/parser/parser/traits.rs b/compiler/noirc_frontend/src/parser/parser/traits.rs index 0874cadd34e..f17d2bce1a2 100644 --- a/compiler/noirc_frontend/src/parser/parser/traits.rs +++ b/compiler/noirc_frontend/src/parser/parser/traits.rs @@ -76,10 +76,21 @@ fn trait_function_declaration() -> impl NoirParser { .then(parenthesized(function_declaration_parameters())) .then(function_return_type().map(|(_, typ)| typ)) .then(where_clause()) - .then(trait_function_body_or_semicolon) - .map(|(((((name, generics), parameters), return_type), where_clause), body)| { - TraitItem::Function { name, generics, parameters, return_type, where_clause, body } - }) + .then(trait_function_body_or_semicolon.or_not()) + .validate( + |(((((name, generics), parameters), return_type), where_clause), body), span, emit| { + let body = if let Some(body) = body { + body + } else { + emit(ParserError::with_reason( + ParserErrorReason::ExpectedLeftBraceOrArrowAfterFunctionParameters, + span, + )); + None + }; + TraitItem::Function { name, generics, parameters, return_type, where_clause, body } + }, + ) } /// trait_type_declaration: 'type' ident generics @@ -227,4 +238,21 @@ mod test { vec!["trait MissingBody", "trait WrongDelimiter { fn foo() -> u8, fn bar() -> u8 }"], ); } + + #[test] + fn parse_recover_function_without_left_brace_or_semicolon() { + let src = "fn foo(x: i32)"; + + let (trait_item, errors) = parse_recover(trait_function_declaration(), src); + assert_eq!(errors.len(), 1); + assert_eq!(errors[0].message, "expected { or -> after function parameters"); + + let Some(TraitItem::Function { name, parameters, body, .. }) = trait_item else { + panic!("Expected to parser trait item as function"); + }; + + assert_eq!(name.to_string(), "foo"); + assert_eq!(parameters.len(), 1); + assert!(body.is_none()); + } } From 6d5ed808153e94df4975fae0d88fb7984aa95488 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Sun, 18 Aug 2024 16:39:25 -0300 Subject: [PATCH 02/11] Parse recover trait without body --- compiler/noirc_frontend/src/parser/errors.rs | 2 + .../src/parser/parser/traits.rs | 37 +++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/compiler/noirc_frontend/src/parser/errors.rs b/compiler/noirc_frontend/src/parser/errors.rs index ada3afdbe35..c9b25d84f28 100644 --- a/compiler/noirc_frontend/src/parser/errors.rs +++ b/compiler/noirc_frontend/src/parser/errors.rs @@ -24,6 +24,8 @@ pub enum ParserErrorReason { ExpectedLeftBraceOrArrowAfterFunctionParameters, #[error("expected {{ after if condition")] ExpectedLeftBraceAfterIfCondition, + #[error("expected <, where or {{ after trait name")] + ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterTraitName, #[error("Expected a ; separating these two statements")] MissingSeparatingSemi, #[error("constrain keyword is deprecated")] diff --git a/compiler/noirc_frontend/src/parser/parser/traits.rs b/compiler/noirc_frontend/src/parser/parser/traits.rs index f17d2bce1a2..10d8d5b5ebc 100644 --- a/compiler/noirc_frontend/src/parser/parser/traits.rs +++ b/compiler/noirc_frontend/src/parser/parser/traits.rs @@ -28,11 +28,25 @@ pub(super) fn trait_definition() -> impl NoirParser { .then(ident()) .then(function::generics()) .then(where_clause()) - .then_ignore(just(Token::LeftBrace)) - .then(trait_body()) - .then_ignore(just(Token::RightBrace)) + .then( + just(Token::LeftBrace) + .ignore_then(trait_body()) + .then_ignore(just(Token::RightBrace)) + .or_not(), + ) .validate(|((((attributes, name), generics), where_clause), items), span, emit| { let attributes = validate_secondary_attributes(attributes, span, emit); + + let items = if let Some(items) = items { + items + } else { + emit(ParserError::with_reason( + ParserErrorReason::ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterTraitName, + span, + )); + vec![] + }; + TopLevelStatement::Trait(NoirTrait { name, generics, @@ -255,4 +269,21 @@ mod test { assert_eq!(parameters.len(), 1); assert!(body.is_none()); } + + #[test] + fn parse_recover_trait_without_body() { + let src = "trait Foo"; + + let (top_level_statement, errors) = parse_recover(trait_definition(), src); + assert_eq!(errors.len(), 1); + assert_eq!(errors[0].message, "expected <, where or { after trait name"); + + let top_level_statement = top_level_statement.unwrap(); + let TopLevelStatement::Trait(trait_) = top_level_statement else { + panic!("Expected to parse a trait"); + }; + + assert_eq!(trait_.name.to_string(), "Foo"); + assert!(trait_.items.is_empty()); + } } From 069b2bc29754bcc86936b8a4c558cf68d828aee5 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Sun, 18 Aug 2024 16:46:32 -0300 Subject: [PATCH 03/11] Parse recover impl without body --- compiler/noirc_frontend/src/parser/errors.rs | 2 + compiler/noirc_frontend/src/parser/parser.rs | 39 ++++++++++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/compiler/noirc_frontend/src/parser/errors.rs b/compiler/noirc_frontend/src/parser/errors.rs index c9b25d84f28..3aaa86e0bb4 100644 --- a/compiler/noirc_frontend/src/parser/errors.rs +++ b/compiler/noirc_frontend/src/parser/errors.rs @@ -26,6 +26,8 @@ pub enum ParserErrorReason { ExpectedLeftBraceAfterIfCondition, #[error("expected <, where or {{ after trait name")] ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterTraitName, + #[error("expected <, where or {{ after impl name")] + ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterImplName, #[error("Expected a ; separating these two statements")] MissingSeparatingSemi, #[error("constrain keyword is deprecated")] diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index ed92143756c..d5366bc9b7b 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -223,12 +223,26 @@ fn implementation() -> impl NoirParser { .ignore_then(function::generics()) .then(parse_type().map_with_span(|typ, span| (typ, span))) .then(where_clause()) - .then_ignore(just(Token::LeftBrace)) - .then(spanned(function::function_definition(true)).repeated()) - .then_ignore(just(Token::RightBrace)) - .map(|args| { + .then( + just(Token::LeftBrace) + .ignore_then(spanned(function::function_definition(true)).repeated()) + .then_ignore(just(Token::RightBrace)) + .or_not(), + ) + .validate(|args, span, emit| { let ((other_args, where_clause), methods) = args; let (generics, (object_type, type_span)) = other_args; + + let methods = if let Some(methods) = methods { + methods + } else { + emit(ParserError::with_reason( + ParserErrorReason::ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterImplName, + span, + )); + vec![] + }; + TopLevelStatement::Impl(TypeImpl { generics, object_type, @@ -1760,4 +1774,21 @@ mod test { assert_eq!(var.to_string(), "foo"); } + + #[test] + fn parse_recover_impl_without_body() { + let src = "impl Foo"; + + let (top_level_statement, errors) = parse_recover(implementation(), src); + assert_eq!(errors.len(), 1); + assert_eq!(errors[0].message, "expected <, where or { after impl name"); + + let top_level_statement = top_level_statement.unwrap(); + let TopLevelStatement::Impl(impl_) = top_level_statement else { + panic!("Expected to parse an impl"); + }; + + assert_eq!(impl_.object_type.to_string(), "Foo"); + assert!(impl_.methods.is_empty()); + } } From 9a1884311513d0868a312587bc74a4aa23276413 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Sun, 18 Aug 2024 16:52:58 -0300 Subject: [PATCH 04/11] Parse recover trait impl with for --- compiler/noirc_frontend/src/parser/errors.rs | 2 + .../src/parser/parser/traits.rs | 38 +++++++++++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/compiler/noirc_frontend/src/parser/errors.rs b/compiler/noirc_frontend/src/parser/errors.rs index 3aaa86e0bb4..4cc63074871 100644 --- a/compiler/noirc_frontend/src/parser/errors.rs +++ b/compiler/noirc_frontend/src/parser/errors.rs @@ -28,6 +28,8 @@ pub enum ParserErrorReason { ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterTraitName, #[error("expected <, where or {{ after impl name")] ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterImplName, + #[error("expected <, where or {{ after trait impl for type")] + ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterTraitImplForType, #[error("Expected a ; separating these two statements")] MissingSeparatingSemi, #[error("constrain keyword is deprecated")] diff --git a/compiler/noirc_frontend/src/parser/parser/traits.rs b/compiler/noirc_frontend/src/parser/parser/traits.rs index 10d8d5b5ebc..4f95870dab7 100644 --- a/compiler/noirc_frontend/src/parser/parser/traits.rs +++ b/compiler/noirc_frontend/src/parser/parser/traits.rs @@ -133,13 +133,27 @@ pub(super) fn trait_implementation() -> impl NoirParser { .then_ignore(keyword(Keyword::For)) .then(parse_type()) .then(where_clause()) - .then_ignore(just(Token::LeftBrace)) - .then(trait_implementation_body()) - .then_ignore(just(Token::RightBrace)) - .map(|args| { + .then( + just(Token::LeftBrace) + .ignore_then(trait_implementation_body()) + .then_ignore(just(Token::RightBrace)) + .or_not(), + ) + .validate(|args, span, emit| { let (((other_args, object_type), where_clause), items) = args; let ((impl_generics, trait_name), trait_generics) = other_args; + let items = if let Some(items) = items { + items + } else { + emit(ParserError::with_reason( + ParserErrorReason::ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterTraitImplForType, + span, + )); + + vec![] + }; + TopLevelStatement::TraitImpl(NoirTraitImpl { impl_generics, trait_name, @@ -286,4 +300,20 @@ mod test { assert_eq!(trait_.name.to_string(), "Foo"); assert!(trait_.items.is_empty()); } + + #[test] + fn parse_recover_trait_impl_without_body() { + let src = "impl Foo for Bar"; + + let (top_level_statement, errors) = parse_recover(trait_implementation(), src); + assert_eq!(errors.len(), 1); + assert_eq!(errors[0].message, "expected <, where or { after trait impl for type"); + + let top_level_statement = top_level_statement.unwrap(); + let TopLevelStatement::TraitImpl(trait_impl) = top_level_statement else { + panic!("Expected to parse a trait impl"); + }; + + assert!(trait_impl.items.is_empty()); + } } From 4bdb55b20350628f0939f09f0efcfcc50e9fb86d Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Sun, 18 Aug 2024 17:04:28 -0300 Subject: [PATCH 05/11] name -> type --- compiler/noirc_frontend/src/parser/errors.rs | 4 ++-- compiler/noirc_frontend/src/parser/parser.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/noirc_frontend/src/parser/errors.rs b/compiler/noirc_frontend/src/parser/errors.rs index 4cc63074871..e22f4972f4b 100644 --- a/compiler/noirc_frontend/src/parser/errors.rs +++ b/compiler/noirc_frontend/src/parser/errors.rs @@ -26,8 +26,8 @@ pub enum ParserErrorReason { ExpectedLeftBraceAfterIfCondition, #[error("expected <, where or {{ after trait name")] ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterTraitName, - #[error("expected <, where or {{ after impl name")] - ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterImplName, + #[error("expected <, where or {{ after impl typw")] + ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterImplType, #[error("expected <, where or {{ after trait impl for type")] ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterTraitImplForType, #[error("Expected a ; separating these two statements")] diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index d5366bc9b7b..c14337ae6b0 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -237,7 +237,7 @@ fn implementation() -> impl NoirParser { methods } else { emit(ParserError::with_reason( - ParserErrorReason::ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterImplName, + ParserErrorReason::ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterImplType, span, )); vec![] @@ -1781,7 +1781,7 @@ mod test { let (top_level_statement, errors) = parse_recover(implementation(), src); assert_eq!(errors.len(), 1); - assert_eq!(errors[0].message, "expected <, where or { after impl name"); + assert_eq!(errors[0].message, "expected <, where or { after impl type"); let top_level_statement = top_level_statement.unwrap(); let TopLevelStatement::Impl(impl_) = top_level_statement else { From da36ebc1e8eed840c8142a7bcd46810429629224 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Sun, 18 Aug 2024 17:05:40 -0300 Subject: [PATCH 06/11] Autocomplete impl type and for type --- tooling/lsp/src/requests/completion.rs | 5 +++ tooling/lsp/src/requests/completion/tests.rs | 40 ++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/tooling/lsp/src/requests/completion.rs b/tooling/lsp/src/requests/completion.rs index ad0cf0c5b9b..a8eccb43528 100644 --- a/tooling/lsp/src/requests/completion.rs +++ b/tooling/lsp/src/requests/completion.rs @@ -251,6 +251,9 @@ impl<'a> NodeFinder<'a> { } fn find_in_noir_trait_impl(&mut self, noir_trait_impl: &NoirTraitImpl) { + self.find_in_path(&noir_trait_impl.trait_name, RequestedItems::OnlyTypes); + self.find_in_unresolved_type(&noir_trait_impl.object_type); + self.type_parameters.clear(); self.collect_type_parameters_in_generics(&noir_trait_impl.impl_generics); @@ -262,6 +265,8 @@ impl<'a> NodeFinder<'a> { } fn find_in_type_impl(&mut self, type_impl: &TypeImpl) { + self.find_in_unresolved_type(&type_impl.object_type); + self.type_parameters.clear(); self.collect_type_parameters_in_generics(&type_impl.generics); diff --git a/tooling/lsp/src/requests/completion/tests.rs b/tooling/lsp/src/requests/completion/tests.rs index 825a7dd0081..7b2dd3ee00f 100644 --- a/tooling/lsp/src/requests/completion/tests.rs +++ b/tooling/lsp/src/requests/completion/tests.rs @@ -1556,4 +1556,44 @@ mod completion_tests { }) ); } + + #[test] + async fn test_completes_in_impl_type() { + let src = r#" + struct FooBar { + } + + impl FooB>|< + "#; + + assert_completion( + src, + vec![simple_completion_item( + "FooBar", + CompletionItemKind::STRUCT, + Some("FooBar".to_string()), + )], + ) + .await; + } + + #[test] + async fn test_completes_in_impl_for_type() { + let src = r#" + struct FooBar { + } + + impl Default for FooB>|< + "#; + + assert_completion( + src, + vec![simple_completion_item( + "FooBar", + CompletionItemKind::STRUCT, + Some("FooBar".to_string()), + )], + ) + .await; + } } From 0141be530e42cfee96b6faa50c994cef45efa483 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Mon, 19 Aug 2024 07:19:48 -0300 Subject: [PATCH 07/11] typo --- compiler/noirc_frontend/src/parser/errors.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/parser/errors.rs b/compiler/noirc_frontend/src/parser/errors.rs index e22f4972f4b..ebb58ddc224 100644 --- a/compiler/noirc_frontend/src/parser/errors.rs +++ b/compiler/noirc_frontend/src/parser/errors.rs @@ -26,7 +26,7 @@ pub enum ParserErrorReason { ExpectedLeftBraceAfterIfCondition, #[error("expected <, where or {{ after trait name")] ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterTraitName, - #[error("expected <, where or {{ after impl typw")] + #[error("expected <, where or {{ after impl type")] ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterImplType, #[error("expected <, where or {{ after trait impl for type")] ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterTraitImplForType, From 7ee8a12d60aedb3a53502eb6ac34bca45a03e380 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Mon, 19 Aug 2024 08:38:02 -0300 Subject: [PATCH 08/11] Extract sub-parsers --- .../src/parser/parser/function.rs | 25 +++-- .../src/parser/parser/traits.rs | 103 +++++++++--------- 2 files changed, 68 insertions(+), 60 deletions(-) diff --git a/compiler/noirc_frontend/src/parser/parser/function.rs b/compiler/noirc_frontend/src/parser/parser/function.rs index 5ec92877295..fca2283dddf 100644 --- a/compiler/noirc_frontend/src/parser/parser/function.rs +++ b/compiler/noirc_frontend/src/parser/parser/function.rs @@ -28,6 +28,19 @@ use noirc_errors::Span; /// function_definition: attribute function_modifiers 'fn' ident generics '(' function_parameters ')' function_return_type block /// function_modifiers 'fn' ident generics '(' function_parameters ')' function_return_type block pub(super) fn function_definition(allow_self: bool) -> impl NoirParser { + let body_or_error = + spanned(block(fresh_statement()).or_not()).validate(|(body, body_span), span, emit| { + if let Some(body) = body { + (body, body_span) + } else { + emit(ParserError::with_reason( + ParserErrorReason::ExpectedLeftBraceOrArrowAfterFunctionParameters, + span, + )); + (BlockExpression { statements: vec![] }, Span::from(span.end()..span.end())) + } + }); + attributes() .then(function_modifiers()) .then_ignore(keyword(Keyword::Fn)) @@ -36,23 +49,13 @@ pub(super) fn function_definition(allow_self: bool) -> impl NoirParser impl NoirParser { - attributes() - .then_ignore(keyword(Keyword::Trait)) - .then(ident()) - .then(function::generics()) - .then(where_clause()) - .then( - just(Token::LeftBrace) - .ignore_then(trait_body()) - .then_ignore(just(Token::RightBrace)) - .or_not(), - ) - .validate(|((((attributes, name), generics), where_clause), items), span, emit| { - let attributes = validate_secondary_attributes(attributes, span, emit); - - let items = if let Some(items) = items { + let trait_body_or_error = just(Token::LeftBrace) + .ignore_then(trait_body()) + .then_ignore(just(Token::RightBrace)) + .or_not() + .validate(|items, span, emit| { + if let Some(items) = items { items } else { emit(ParserError::with_reason( @@ -45,7 +36,17 @@ pub(super) fn trait_definition() -> impl NoirParser { span, )); vec![] - }; + } + }); + + attributes() + .then_ignore(keyword(Keyword::Trait)) + .then(ident()) + .then(function::generics()) + .then(where_clause()) + .then(trait_body_or_error) + .validate(|((((attributes, name), generics), where_clause), items), span, emit| { + let attributes = validate_secondary_attributes(attributes, span, emit); TopLevelStatement::Trait(NoirTrait { name, @@ -84,27 +85,29 @@ fn trait_function_declaration() -> impl NoirParser { let trait_function_body_or_semicolon = block(fresh_statement()).map(Option::from).or(just(Token::Semicolon).to(Option::None)); + let trait_function_body_or_semicolon_or_error = + trait_function_body_or_semicolon.or_not().validate(|body, span, emit| { + if let Some(body) = body { + body + } else { + emit(ParserError::with_reason( + ParserErrorReason::ExpectedLeftBraceOrArrowAfterFunctionParameters, + span, + )); + None + } + }); + keyword(Keyword::Fn) .ignore_then(ident()) .then(function::generics()) .then(parenthesized(function_declaration_parameters())) .then(function_return_type().map(|(_, typ)| typ)) .then(where_clause()) - .then(trait_function_body_or_semicolon.or_not()) - .validate( - |(((((name, generics), parameters), return_type), where_clause), body), span, emit| { - let body = if let Some(body) = body { - body - } else { - emit(ParserError::with_reason( - ParserErrorReason::ExpectedLeftBraceOrArrowAfterFunctionParameters, - span, - )); - None - }; - TraitItem::Function { name, generics, parameters, return_type, where_clause, body } - }, - ) + .then(trait_function_body_or_semicolon_or_error) + .map(|(((((name, generics), parameters), return_type), where_clause), body)| { + TraitItem::Function { name, generics, parameters, return_type, where_clause, body } + }) } /// trait_type_declaration: 'type' ident generics @@ -126,6 +129,24 @@ fn trait_type_declaration() -> impl NoirParser { /// /// trait_implementation: 'impl' generics ident generic_args for type '{' trait_implementation_body '}' pub(super) fn trait_implementation() -> impl NoirParser { + let body_or_error = + just(Token::LeftBrace) + .ignore_then(trait_implementation_body()) + .then_ignore(just(Token::RightBrace)) + .or_not() + .validate(|items, span, emit| { + if let Some(items) = items { + items + } else { + emit(ParserError::with_reason( + ParserErrorReason::ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterTraitImplForType, + span, + )); + + vec![] + } + }); + keyword(Keyword::Impl) .ignore_then(function::generics()) .then(path_no_turbofish()) @@ -133,27 +154,11 @@ pub(super) fn trait_implementation() -> impl NoirParser { .then_ignore(keyword(Keyword::For)) .then(parse_type()) .then(where_clause()) - .then( - just(Token::LeftBrace) - .ignore_then(trait_implementation_body()) - .then_ignore(just(Token::RightBrace)) - .or_not(), - ) - .validate(|args, span, emit| { + .then(body_or_error) + .map(|args| { let (((other_args, object_type), where_clause), items) = args; let ((impl_generics, trait_name), trait_generics) = other_args; - let items = if let Some(items) = items { - items - } else { - emit(ParserError::with_reason( - ParserErrorReason::ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterTraitImplForType, - span, - )); - - vec![] - }; - TopLevelStatement::TraitImpl(NoirTraitImpl { impl_generics, trait_name, From 6df4ab13c66f0b65b45b23392dde73d4ed651cd5 Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Mon, 19 Aug 2024 08:40:15 -0300 Subject: [PATCH 09/11] Extract one more sub-parser --- compiler/noirc_frontend/src/parser/parser.rs | 33 ++++++++++---------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index c14337ae6b0..f3f37068ba2 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -219,21 +219,12 @@ fn top_level_statement<'a>( /// /// implementation: 'impl' generics type '{' function_definition ... '}' fn implementation() -> impl NoirParser { - keyword(Keyword::Impl) - .ignore_then(function::generics()) - .then(parse_type().map_with_span(|typ, span| (typ, span))) - .then(where_clause()) - .then( - just(Token::LeftBrace) - .ignore_then(spanned(function::function_definition(true)).repeated()) - .then_ignore(just(Token::RightBrace)) - .or_not(), - ) - .validate(|args, span, emit| { - let ((other_args, where_clause), methods) = args; - let (generics, (object_type, type_span)) = other_args; - - let methods = if let Some(methods) = methods { + let methods_or_error = just(Token::LeftBrace) + .ignore_then(spanned(function::function_definition(true)).repeated()) + .then_ignore(just(Token::RightBrace)) + .or_not() + .validate(|methods, span, emit| { + if let Some(methods) = methods { methods } else { emit(ParserError::with_reason( @@ -241,7 +232,17 @@ fn implementation() -> impl NoirParser { span, )); vec![] - }; + } + }); + + keyword(Keyword::Impl) + .ignore_then(function::generics()) + .then(parse_type().map_with_span(|typ, span| (typ, span))) + .then(where_clause()) + .then(methods_or_error) + .map(|args| { + let ((other_args, where_clause), methods) = args; + let (generics, (object_type, type_span)) = other_args; TopLevelStatement::Impl(TypeImpl { generics, From e79e94ccac9068a407ca80701fb3895fe5d0c4fd Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Mon, 19 Aug 2024 08:42:01 -0300 Subject: [PATCH 10/11] Remove extra newlines --- compiler/noirc_frontend/src/parser/parser.rs | 1 - compiler/noirc_frontend/src/parser/parser/function.rs | 1 - compiler/noirc_frontend/src/parser/parser/traits.rs | 2 -- 3 files changed, 4 deletions(-) diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index f3f37068ba2..eddf85becfe 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -243,7 +243,6 @@ fn implementation() -> impl NoirParser { .map(|args| { let ((other_args, where_clause), methods) = args; let (generics, (object_type, type_span)) = other_args; - TopLevelStatement::Impl(TypeImpl { generics, object_type, diff --git a/compiler/noirc_frontend/src/parser/parser/function.rs b/compiler/noirc_frontend/src/parser/parser/function.rs index fca2283dddf..56760898374 100644 --- a/compiler/noirc_frontend/src/parser/parser/function.rs +++ b/compiler/noirc_frontend/src/parser/parser/function.rs @@ -55,7 +55,6 @@ pub(super) fn function_definition(allow_self: bool) -> impl NoirParser impl NoirParser { .then(trait_body_or_error) .validate(|((((attributes, name), generics), where_clause), items), span, emit| { let attributes = validate_secondary_attributes(attributes, span, emit); - TopLevelStatement::Trait(NoirTrait { name, generics, @@ -158,7 +157,6 @@ pub(super) fn trait_implementation() -> impl NoirParser { .map(|args| { let (((other_args, object_type), where_clause), items) = args; let ((impl_generics, trait_name), trait_generics) = other_args; - TopLevelStatement::TraitImpl(NoirTraitImpl { impl_generics, trait_name, From 60cc8ddecdd6845d58b8659e75452569a90ae77b Mon Sep 17 00:00:00 2001 From: Ary Borenszweig Date: Mon, 19 Aug 2024 11:42:30 -0300 Subject: [PATCH 11/11] cargo fmt --- .../src/parser/parser/traits.rs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/noirc_frontend/src/parser/parser/traits.rs b/compiler/noirc_frontend/src/parser/parser/traits.rs index 28180c3ab77..0cf5e63f5f3 100644 --- a/compiler/noirc_frontend/src/parser/parser/traits.rs +++ b/compiler/noirc_frontend/src/parser/parser/traits.rs @@ -128,23 +128,23 @@ fn trait_type_declaration() -> impl NoirParser { /// /// trait_implementation: 'impl' generics ident generic_args for type '{' trait_implementation_body '}' pub(super) fn trait_implementation() -> impl NoirParser { - let body_or_error = - just(Token::LeftBrace) - .ignore_then(trait_implementation_body()) - .then_ignore(just(Token::RightBrace)) - .or_not() - .validate(|items, span, emit| { - if let Some(items) = items { - items - } else { - emit(ParserError::with_reason( - ParserErrorReason::ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterTraitImplForType, - span, - )); - - vec![] - } - }); + let body_or_error = + just(Token::LeftBrace) + .ignore_then(trait_implementation_body()) + .then_ignore(just(Token::RightBrace)) + .or_not() + .validate(|items, span, emit| { + if let Some(items) = items { + items + } else { + emit(ParserError::with_reason( + ParserErrorReason::ExpectedLeftBracketOrWhereOrLeftBraceOrArrowAfterTraitImplForType, + span, + )); + + vec![] + } + }); keyword(Keyword::Impl) .ignore_then(function::generics())