diff --git a/Cargo.lock b/Cargo.lock index 3f56f5b6965..796ac50ca9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -274,7 +274,7 @@ dependencies = [ "ark-std", "derivative", "hashbrown 0.13.2", - "itertools 0.10.5", + "itertools", "num-traits", "zeroize", ] @@ -291,7 +291,7 @@ dependencies = [ "ark-std", "derivative", "digest", - "itertools 0.10.5", + "itertools", "num-bigint", "num-traits", "paste", @@ -380,15 +380,6 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" -[[package]] -name = "ascii-canvas" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" -dependencies = [ - "term", -] - [[package]] name = "assert_cmd" version = "2.0.12" @@ -1069,7 +1060,7 @@ dependencies = [ "clap", "criterion-plot", "is-terminal", - "itertools 0.10.5", + "itertools", "num-traits", "once_cell", "oorandom", @@ -1090,7 +1081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", - "itertools 0.10.5", + "itertools", ] [[package]] @@ -1410,15 +1401,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ena" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" -dependencies = [ - "log", -] - [[package]] name = "encode_unicode" version = "0.3.6" @@ -2207,15 +2189,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.9" @@ -2400,37 +2373,6 @@ dependencies = [ "libc", ] -[[package]] -name = "lalrpop" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" -dependencies = [ - "ascii-canvas", - "bit-set", - "ena", - "itertools 0.11.0", - "lalrpop-util", - "petgraph", - "pico-args", - "regex", - "regex-syntax 0.8.2", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", - "walkdir", -] - -[[package]] -name = "lalrpop-util" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" -dependencies = [ - "regex-automata 0.4.7", -] - [[package]] name = "lazy_static" version = "1.4.0" @@ -2731,12 +2673,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - [[package]] name = "nibble_vec" version = "0.1.0" @@ -3034,8 +2970,6 @@ dependencies = [ "fm", "im", "iter-extended", - "lalrpop", - "lalrpop-util", "noirc_arena", "noirc_errors", "noirc_printable_type", @@ -3377,12 +3311,6 @@ dependencies = [ "siphasher", ] -[[package]] -name = "pico-args" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" - [[package]] name = "pin-project-lite" version = "0.2.13" @@ -3489,12 +3417,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - [[package]] name = "predicates" version = "2.1.5" @@ -3503,7 +3425,7 @@ checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" dependencies = [ "difflib", "float-cmp", - "itertools 0.10.5", + "itertools", "normalize-line-endings", "predicates-core", "regex", @@ -3517,7 +3439,7 @@ checksum = "09963355b9f467184c04017ced4a2ba2d75cbcb4e7462690d388233253d4b1a9" dependencies = [ "anstyle", "difflib", - "itertools 0.10.5", + "itertools", "predicates-core", ] @@ -4396,19 +4318,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb" -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot 0.12.1", - "phf_shared", - "precomputed-hash", -] - [[package]] name = "strsim" version = "0.10.0" diff --git a/aztec_macros/src/lib.rs b/aztec_macros/src/lib.rs index ec1d395725d..4ba8951c2f9 100644 --- a/aztec_macros/src/lib.rs +++ b/aztec_macros/src/lib.rs @@ -66,7 +66,9 @@ fn transform( // Usage -> mut ast -> aztec_library::transform(&mut ast) // Covers all functions in the ast - for submodule in ast.submodules.iter_mut().filter(|submodule| submodule.is_contract) { + for submodule in + ast.submodules.iter_mut().map(|m| &mut m.item).filter(|submodule| submodule.is_contract) + { if transform_module( &file_id, &mut submodule.contents, @@ -111,7 +113,8 @@ fn transform_module( } let has_initializer = module.functions.iter().any(|func| { - func.def + func.item + .def .attributes .secondary .iter() @@ -121,6 +124,7 @@ fn transform_module( let mut stubs: Vec<_> = vec![]; for func in module.functions.iter_mut() { + let func = &mut func.item; let mut is_private = false; let mut is_public = false; let mut is_initializer = false; @@ -175,6 +179,7 @@ fn transform_module( let private_functions: Vec<_> = module .functions .iter() + .map(|t| &t.item) .filter(|func| { func.def .attributes @@ -187,6 +192,7 @@ fn transform_module( let public_functions: Vec<_> = module .functions .iter() + .map(|func| &func.item) .filter(|func| { func.def .attributes diff --git a/aztec_macros/src/transforms/compute_note_hash_and_optionally_a_nullifier.rs b/aztec_macros/src/transforms/compute_note_hash_and_optionally_a_nullifier.rs index 8983266dab9..4d5dcc6f1af 100644 --- a/aztec_macros/src/transforms/compute_note_hash_and_optionally_a_nullifier.rs +++ b/aztec_macros/src/transforms/compute_note_hash_and_optionally_a_nullifier.rs @@ -166,7 +166,7 @@ fn generate_compute_note_hash_and_optionally_a_nullifier( assert_eq!(errors.len(), 0, "Failed to parse Noir macro code. This is either a bug in the compiler or the Noir macro code"); let mut function_ast = function_ast.into_sorted(); - function_ast.functions.remove(0) + function_ast.functions.remove(0).item } fn generate_compute_note_hash_and_optionally_a_nullifier_source( diff --git a/aztec_macros/src/transforms/contract_interface.rs b/aztec_macros/src/transforms/contract_interface.rs index 7a8a7187857..e2de30d6d93 100644 --- a/aztec_macros/src/transforms/contract_interface.rs +++ b/aztec_macros/src/transforms/contract_interface.rs @@ -1,7 +1,7 @@ use acvm::acir::AcirField; use noirc_errors::Location; -use noirc_frontend::ast::{Ident, NoirFunction, UnresolvedTypeData}; +use noirc_frontend::ast::{Documented, Ident, NoirFunction, UnresolvedTypeData}; use noirc_frontend::{ graph::CrateId, macros_api::{FieldElement, FileId, HirContext, HirExpression, HirLiteral, HirStatement}, @@ -267,15 +267,16 @@ pub fn generate_contract_interface( .methods .iter() .enumerate() - .map(|(i, (method, orig_span))| { + .map(|(i, (documented_method, orig_span))| { + let method = &documented_method.item; if method.name() == "at" || method.name() == "interface" || method.name() == "storage" { - (method.clone(), *orig_span) + (documented_method.clone(), *orig_span) } else { let (_, new_location) = stubs[i]; let mut modified_method = method.clone(); modified_method.def.name = Ident::new(modified_method.name().to_string(), new_location.span); - (modified_method, *orig_span) + (Documented::not_documented(modified_method), *orig_span) } }) .collect(); diff --git a/aztec_macros/src/transforms/events.rs b/aztec_macros/src/transforms/events.rs index ede8a350bf2..d753bb43471 100644 --- a/aztec_macros/src/transforms/events.rs +++ b/aztec_macros/src/transforms/events.rs @@ -1,4 +1,4 @@ -use noirc_frontend::ast::{ItemVisibility, NoirFunction, NoirTraitImpl, TraitImplItem}; +use noirc_frontend::ast::{Documented, ItemVisibility, NoirFunction, NoirTraitImpl, TraitImplItem}; use noirc_frontend::macros_api::{NodeInterner, StructId}; use noirc_frontend::token::SecondaryAttribute; use noirc_frontend::{ @@ -34,10 +34,11 @@ pub fn generate_event_impls( // print!("\ngenerate_event_interface_impl COUNT: {}\n", event_struct.name.0.contents); // } - for submodule in module.submodules.iter_mut() { - let annotated_event_structs = submodule.contents.types.iter_mut().filter(|typ| { - typ.attributes.iter().any(|attr| is_custom_attribute(attr, "aztec(event)")) - }); + for submodule in module.submodules.iter_mut().map(|m| &mut m.item) { + let annotated_event_structs = + submodule.contents.types.iter_mut().map(|typ| &mut typ.item).filter(|typ| { + typ.attributes.iter().any(|attr| is_custom_attribute(attr, "aztec(event)")) + }); for event_struct in annotated_event_structs { // event_struct.attributes.push(SecondaryAttribute::Abi("events".to_string())); @@ -52,7 +53,9 @@ pub fn generate_event_impls( let mut event_fields = vec![]; - for (field_ident, field_type) in event_struct.fields.iter() { + for field in event_struct.fields.iter() { + let field_ident = &field.item.name; + let field_type = &field.item.typ; event_fields.push(( field_ident.0.contents.to_string(), field_type.typ.to_string().replace("plain::", ""), @@ -64,18 +67,30 @@ pub fn generate_event_impls( event_byte_len, empty_spans, )?; - event_interface_trait_impl.items.push(TraitImplItem::Function( - generate_fn_get_event_type_id(event_type.as_str(), event_len, empty_spans)?, + event_interface_trait_impl.items.push(Documented::not_documented( + TraitImplItem::Function(generate_fn_get_event_type_id( + event_type.as_str(), + event_len, + empty_spans, + )?), + )); + event_interface_trait_impl.items.push(Documented::not_documented( + TraitImplItem::Function(generate_fn_private_to_be_bytes( + event_type.as_str(), + event_byte_len, + empty_spans, + )?), )); - event_interface_trait_impl.items.push(TraitImplItem::Function( - generate_fn_private_to_be_bytes(event_type.as_str(), event_byte_len, empty_spans)?, + event_interface_trait_impl.items.push(Documented::not_documented( + TraitImplItem::Function(generate_fn_to_be_bytes( + event_type.as_str(), + event_byte_len, + empty_spans, + )?), )); - event_interface_trait_impl.items.push(TraitImplItem::Function( - generate_fn_to_be_bytes(event_type.as_str(), event_byte_len, empty_spans)?, + event_interface_trait_impl.items.push(Documented::not_documented( + TraitImplItem::Function(generate_fn_emit(event_type.as_str(), empty_spans)?), )); - event_interface_trait_impl - .items - .push(TraitImplItem::Function(generate_fn_emit(event_type.as_str(), empty_spans)?)); submodule.contents.trait_impls.push(event_interface_trait_impl); let serialize_trait_impl = generate_trait_impl_serialize( @@ -245,7 +260,7 @@ fn generate_fn_get_event_type_id( } let mut function_ast = function_ast.into_sorted(); - let mut noir_fn = function_ast.functions.remove(0); + let mut noir_fn = function_ast.functions.remove(0).item; noir_fn.def.visibility = ItemVisibility::Public; Ok(noir_fn) } @@ -292,7 +307,7 @@ fn generate_fn_private_to_be_bytes( } let mut function_ast = function_ast.into_sorted(); - let mut noir_fn = function_ast.functions.remove(0); + let mut noir_fn = function_ast.functions.remove(0).item; noir_fn.def.visibility = ItemVisibility::Public; Ok(noir_fn) } @@ -337,7 +352,7 @@ fn generate_fn_to_be_bytes( } let mut function_ast = function_ast.into_sorted(); - let mut noir_fn = function_ast.functions.remove(0); + let mut noir_fn = function_ast.functions.remove(0).item; noir_fn.def.visibility = ItemVisibility::Public; Ok(noir_fn) } @@ -361,7 +376,7 @@ fn generate_fn_emit(event_type: &str, empty_spans: bool) -> Result, + types: &mut Vec>, func: &NoirFunction, empty_spans: bool, ) -> Result<(), AztecMacroError> { diff --git a/aztec_macros/src/transforms/note_interface.rs b/aztec_macros/src/transforms/note_interface.rs index df237926486..6e95efa637c 100644 --- a/aztec_macros/src/transforms/note_interface.rs +++ b/aztec_macros/src/transforms/note_interface.rs @@ -1,7 +1,7 @@ use noirc_errors::Span; use noirc_frontend::ast::{ - ItemVisibility, LetStatement, NoirFunction, NoirStruct, PathKind, TraitImplItem, TypeImpl, - UnresolvedTypeData, UnresolvedTypeExpression, + Documented, ItemVisibility, LetStatement, NoirFunction, NoirStruct, PathKind, StructField, + TraitImplItem, TypeImpl, UnresolvedTypeData, UnresolvedTypeExpression, }; use noirc_frontend::{ graph::CrateId, @@ -35,10 +35,10 @@ pub fn generate_note_interface_impl( empty_spans: bool, ) -> Result<(), AztecMacroError> { // Find structs annotated with #[aztec(note)] - let annotated_note_structs = module - .types - .iter_mut() - .filter(|typ| typ.attributes.iter().any(|attr| is_custom_attribute(attr, "aztec(note)"))); + let annotated_note_structs = + module.types.iter_mut().map(|t| &mut t.item).filter(|typ| { + typ.attributes.iter().any(|attr| is_custom_attribute(attr, "aztec(note)")) + }); let mut structs_to_inject = vec![]; @@ -110,26 +110,28 @@ pub fn generate_note_interface_impl( ); // Automatically inject the header field if it's not present - let (header_field_name, _) = if let Some(existing_header) = - note_struct.fields.iter().find(|(_, field_type)| match &field_type.typ { + let header_field_name = if let Some(existing_header) = + note_struct.fields.iter().find(|field| match &field.item.typ.typ { UnresolvedTypeData::Named(path, _, _) => path.last_name() == "NoteHeader", _ => false, }) { - existing_header.clone() + existing_header.clone().item.name } else { - let generated_header = ( - ident("header"), - make_type(UnresolvedTypeData::Named( + let generated_header = StructField { + name: ident("header"), + typ: make_type(UnresolvedTypeData::Named( chained_dep!("aztec", "note", "note_header", "NoteHeader"), Default::default(), false, )), - ); - note_struct.fields.push(generated_header.clone()); - generated_header + }; + note_struct.fields.push(Documented::not_documented(generated_header.clone())); + generated_header.name }; - for (field_ident, field_type) in note_struct.fields.iter() { + for field in note_struct.fields.iter() { + let field_ident = &field.item.name; + let field_type = &field.item.typ; note_fields.push(( field_ident.0.contents.to_string(), field_type.typ.to_string().replace("plain::", ""), @@ -138,7 +140,10 @@ pub fn generate_note_interface_impl( if !check_trait_method_implemented(trait_impl, "serialize_content") && !check_trait_method_implemented(trait_impl, "deserialize_content") - && !note_impl.methods.iter().any(|(func, _)| func.def.name.0.contents == "properties") + && !note_impl + .methods + .iter() + .any(|(func, _)| func.item.def.name.0.contents == "properties") { let note_serialize_content_fn = generate_note_serialize_content( ¬e_type, @@ -148,7 +153,9 @@ pub fn generate_note_interface_impl( note_interface_impl_span, empty_spans, )?; - trait_impl.items.push(TraitImplItem::Function(note_serialize_content_fn)); + trait_impl.items.push(Documented::not_documented(TraitImplItem::Function( + note_serialize_content_fn, + ))); let note_deserialize_content_fn = generate_note_deserialize_content( ¬e_type, @@ -158,7 +165,9 @@ pub fn generate_note_interface_impl( note_interface_impl_span, empty_spans, )?; - trait_impl.items.push(TraitImplItem::Function(note_deserialize_content_fn)); + trait_impl.items.push(Documented::not_documented(TraitImplItem::Function( + note_deserialize_content_fn, + ))); let note_properties_struct = generate_note_properties_struct( ¬e_type, @@ -167,7 +176,7 @@ pub fn generate_note_interface_impl( note_interface_impl_span, empty_spans, )?; - structs_to_inject.push(note_properties_struct); + structs_to_inject.push(Documented::not_documented(note_properties_struct)); let note_properties_fn = generate_note_properties_fn( ¬e_type, ¬e_fields, @@ -175,7 +184,9 @@ pub fn generate_note_interface_impl( note_interface_impl_span, empty_spans, )?; - note_impl.methods.push((note_properties_fn, note_impl.type_span)); + note_impl + .methods + .push((Documented::not_documented(note_properties_fn), note_impl.type_span)); } if !check_trait_method_implemented(trait_impl, "get_header") { @@ -185,7 +196,9 @@ pub fn generate_note_interface_impl( note_interface_impl_span, empty_spans, )?; - trait_impl.items.push(TraitImplItem::Function(get_header_fn)); + trait_impl + .items + .push(Documented::not_documented(TraitImplItem::Function(get_header_fn))); } if !check_trait_method_implemented(trait_impl, "set_header") { let set_header_fn = generate_note_set_header( @@ -194,14 +207,18 @@ pub fn generate_note_interface_impl( note_interface_impl_span, empty_spans, )?; - trait_impl.items.push(TraitImplItem::Function(set_header_fn)); + trait_impl + .items + .push(Documented::not_documented(TraitImplItem::Function(set_header_fn))); } if !check_trait_method_implemented(trait_impl, "get_note_type_id") { let note_type_id = compute_note_type_id(¬e_type); let get_note_type_id_fn = generate_get_note_type_id(note_type_id, note_interface_impl_span, empty_spans)?; - trait_impl.items.push(TraitImplItem::Function(get_note_type_id_fn)); + trait_impl + .items + .push(Documented::not_documented(TraitImplItem::Function(get_note_type_id_fn))); } if !check_trait_method_implemented(trait_impl, "compute_note_hiding_point") { @@ -210,7 +227,9 @@ pub fn generate_note_interface_impl( note_interface_impl_span, empty_spans, )?; - trait_impl.items.push(TraitImplItem::Function(compute_note_hiding_point_fn)); + trait_impl.items.push(Documented::not_documented(TraitImplItem::Function( + compute_note_hiding_point_fn, + ))); } if !check_trait_method_implemented(trait_impl, "to_be_bytes") { @@ -221,7 +240,9 @@ pub fn generate_note_interface_impl( note_interface_impl_span, empty_spans, )?; - trait_impl.items.push(TraitImplItem::Function(to_be_bytes_fn)); + trait_impl + .items + .push(Documented::not_documented(TraitImplItem::Function(to_be_bytes_fn))); } } @@ -275,7 +296,7 @@ fn generate_note_to_be_bytes( } let mut function_ast = function_ast.into_sorted(); - let mut noir_fn = function_ast.functions.remove(0); + let mut noir_fn = function_ast.functions.remove(0).item; noir_fn.def.span = impl_span; noir_fn.def.visibility = ItemVisibility::Public; Ok(noir_fn) @@ -307,7 +328,7 @@ fn generate_note_get_header( } let mut function_ast = function_ast.into_sorted(); - let mut noir_fn = function_ast.functions.remove(0); + let mut noir_fn = function_ast.functions.remove(0).item; noir_fn.def.span = impl_span; noir_fn.def.visibility = ItemVisibility::Public; Ok(noir_fn) @@ -338,7 +359,7 @@ fn generate_note_set_header( } let mut function_ast = function_ast.into_sorted(); - let mut noir_fn = function_ast.functions.remove(0); + let mut noir_fn = function_ast.functions.remove(0).item; noir_fn.def.span = impl_span; noir_fn.def.visibility = ItemVisibility::Public; Ok(noir_fn) @@ -372,7 +393,7 @@ fn generate_get_note_type_id( } let mut function_ast = function_ast.into_sorted(); - let mut noir_fn = function_ast.functions.remove(0); + let mut noir_fn = function_ast.functions.remove(0).item; noir_fn.def.span = impl_span; noir_fn.def.visibility = ItemVisibility::Public; Ok(noir_fn) @@ -407,7 +428,7 @@ fn generate_note_properties_struct( } let mut struct_ast = struct_ast.into_sorted(); - Ok(struct_ast.types.remove(0)) + Ok(struct_ast.types.remove(0).item) } // Generate the deserialize_content method as @@ -445,7 +466,7 @@ fn generate_note_deserialize_content( } let mut function_ast = function_ast.into_sorted(); - let mut noir_fn = function_ast.functions.remove(0); + let mut noir_fn = function_ast.functions.remove(0).item; noir_fn.def.span = impl_span; noir_fn.def.visibility = ItemVisibility::Public; Ok(noir_fn) @@ -483,7 +504,7 @@ fn generate_note_serialize_content( } let mut function_ast = function_ast.into_sorted(); - let mut noir_fn = function_ast.functions.remove(0); + let mut noir_fn = function_ast.functions.remove(0).item; noir_fn.def.span = impl_span; noir_fn.def.visibility = ItemVisibility::Public; Ok(noir_fn) @@ -508,7 +529,7 @@ fn generate_note_properties_fn( }); } let mut function_ast = function_ast.into_sorted(); - let mut noir_fn = function_ast.functions.remove(0); + let mut noir_fn = function_ast.functions.remove(0).item; noir_fn.def.span = impl_span; noir_fn.def.visibility = ItemVisibility::Public; Ok(noir_fn) @@ -547,7 +568,7 @@ fn generate_compute_note_hiding_point( }); } let mut function_ast = function_ast.into_sorted(); - let mut noir_fn = function_ast.functions.remove(0); + let mut noir_fn = function_ast.functions.remove(0).item; noir_fn.def.span = impl_span; noir_fn.def.visibility = ItemVisibility::Public; Ok(noir_fn) @@ -579,7 +600,7 @@ fn generate_note_exports_global( } let mut global_ast = global_ast.into_sorted(); - Ok(global_ast.globals.pop().unwrap()) + Ok(global_ast.globals.pop().unwrap().item) } // Source code generator functions. These utility methods produce Noir code as strings, that are then parsed and added to the AST. diff --git a/aztec_macros/src/transforms/storage.rs b/aztec_macros/src/transforms/storage.rs index 7dd21f1a8ac..a6bf2e14fb3 100644 --- a/aztec_macros/src/transforms/storage.rs +++ b/aztec_macros/src/transforms/storage.rs @@ -1,8 +1,8 @@ use acvm::acir::AcirField; use noirc_errors::Span; use noirc_frontend::ast::{ - BlockExpression, Expression, ExpressionKind, FunctionDefinition, GenericTypeArgs, Ident, - Literal, NoirFunction, NoirStruct, Pattern, StatementKind, TypeImpl, UnresolvedType, + BlockExpression, Documented, Expression, ExpressionKind, FunctionDefinition, GenericTypeArgs, + Ident, Literal, NoirFunction, NoirStruct, Pattern, StatementKind, TypeImpl, UnresolvedType, UnresolvedTypeData, }; use noirc_frontend::{ @@ -38,6 +38,7 @@ pub fn check_for_storage_definition( let result: Vec<&NoirStruct> = module .types .iter() + .map(|t| &t.item) .filter(|r#struct| { r#struct.attributes.iter().any(|attr| is_custom_attribute(attr, "aztec(storage)")) }) @@ -88,6 +89,7 @@ pub fn inject_context_in_storage(module: &mut SortedModule) -> Result<(), AztecM let storage_struct = module .types .iter_mut() + .map(|t| &mut t.item) .find(|r#struct| { r#struct.attributes.iter().any(|attr| is_custom_attribute(attr, "aztec(storage)")) }) @@ -96,7 +98,7 @@ pub fn inject_context_in_storage(module: &mut SortedModule) -> Result<(), AztecM storage_struct .fields .iter_mut() - .map(|(_, field)| inject_context_in_storage_field(field)) + .map(|field| inject_context_in_storage_field(&mut field.item.typ)) .collect::, _>>()?; Ok(()) } @@ -200,6 +202,7 @@ pub fn generate_storage_implementation( let definition = module .types .iter() + .map(|t| &t.item) .find(|r#struct| r#struct.name.0.contents == *storage_struct_name) .unwrap(); @@ -212,8 +215,10 @@ pub fn generate_storage_implementation( .fields .iter() .flat_map(|field| { - generate_storage_field_constructor(field, slot_zero.clone()) - .map(|expression| (field.0.clone(), expression)) + let ident = &field.item.name; + let typ = &field.item.typ; + generate_storage_field_constructor(&(ident.clone(), typ.clone()), slot_zero.clone()) + .map(|expression| (field.item.name.clone(), expression)) }) .collect(); @@ -249,7 +254,7 @@ pub fn generate_storage_implementation( type_span: Span::default(), generics: vec![generic_context_ident.into()], - methods: vec![(init, Span::default())], + methods: vec![(Documented::not_documented(init), Span::default())], where_clause: vec![], }; @@ -509,13 +514,15 @@ pub fn generate_storage_layout( let definition = module .types .iter() + .map(|t| &t.item) .find(|r#struct| r#struct.name.0.contents == *storage_struct_name) .unwrap(); let mut storable_fields = vec![]; let mut storable_fields_impl = vec![]; - definition.fields.iter().for_each(|(field_ident, _)| { + definition.fields.iter().for_each(|field| { + let field_ident = &field.item.name; storable_fields.push(format!("{}: dep::aztec::prelude::Storable", field_ident)); storable_fields_impl .push(format!("{}: dep::aztec::prelude::Storable {{ slot: 0 }}", field_ident,)); diff --git a/aztec_macros/src/utils/ast_utils.rs b/aztec_macros/src/utils/ast_utils.rs index 316aa60da62..b68946ec020 100644 --- a/aztec_macros/src/utils/ast_utils.rs +++ b/aztec_macros/src/utils/ast_utils.rs @@ -179,7 +179,7 @@ pub fn index_array(array: Ident, index: &str) -> Expression { } pub fn check_trait_method_implemented(trait_impl: &NoirTraitImpl, method_name: &str) -> bool { - trait_impl.items.iter().any(|item| match item { + trait_impl.items.iter().any(|item| match &item.item { TraitImplItem::Function(func) => func.def.name.0.contents == method_name, _ => false, }) diff --git a/aztec_macros/src/utils/parse_utils.rs b/aztec_macros/src/utils/parse_utils.rs index e7b3e347a96..018307bfb86 100644 --- a/aztec_macros/src/utils/parse_utils.rs +++ b/aztec_macros/src/utils/parse_utils.rs @@ -64,7 +64,7 @@ fn empty_noir_trait(noir_trait: &mut NoirTrait) { empty_unresolved_generics(&mut noir_trait.generics); empty_unresolved_trait_constraints(&mut noir_trait.where_clause); for item in noir_trait.items.iter_mut() { - empty_trait_item(item); + empty_trait_item(&mut item.item); } } @@ -74,7 +74,7 @@ fn empty_noir_trait_impl(noir_trait_impl: &mut NoirTraitImpl) { empty_unresolved_type(&mut noir_trait_impl.object_type); empty_unresolved_trait_constraints(&mut noir_trait_impl.where_clause); for item in noir_trait_impl.items.iter_mut() { - empty_trait_impl_item(item); + empty_trait_impl_item(&mut item.item); } } @@ -84,7 +84,7 @@ fn empty_type_impl(type_impl: &mut TypeImpl) { empty_unresolved_generics(&mut type_impl.generics); empty_unresolved_trait_constraints(&mut type_impl.where_clause); for (noir_function, _) in type_impl.methods.iter_mut() { - empty_noir_function(noir_function); + empty_noir_function(&mut noir_function.item); } } @@ -187,9 +187,9 @@ fn empty_use_tree(use_tree: &mut UseTree) { fn empty_noir_struct(noir_struct: &mut NoirStruct) { noir_struct.span = Default::default(); empty_ident(&mut noir_struct.name); - for (name, typ) in noir_struct.fields.iter_mut() { - empty_ident(name); - empty_unresolved_type(typ); + for field in noir_struct.fields.iter_mut() { + empty_ident(&mut field.item.name); + empty_unresolved_type(&mut field.item.typ); } empty_unresolved_generics(&mut noir_struct.generics); } diff --git a/compiler/noirc_frontend/Cargo.toml b/compiler/noirc_frontend/Cargo.toml index c0f6c8965fb..510cff08dec 100644 --- a/compiler/noirc_frontend/Cargo.toml +++ b/compiler/noirc_frontend/Cargo.toml @@ -31,7 +31,6 @@ cfg-if.workspace = true tracing.workspace = true petgraph = "0.6" rangemap = "1.4.0" -lalrpop-util = { version = "0.20.2", features = ["lexer"] } strum = "0.24" strum_macros = "0.24" @@ -39,9 +38,6 @@ strum_macros = "0.24" [dev-dependencies] base64.workspace = true -[build-dependencies] -lalrpop = "0.20.2" - [features] experimental_parser = [] bn254 = [] diff --git a/compiler/noirc_frontend/build.rs b/compiler/noirc_frontend/build.rs deleted file mode 100644 index eb896a377ae..00000000000 --- a/compiler/noirc_frontend/build.rs +++ /dev/null @@ -1,28 +0,0 @@ -use std::fs::{read_to_string, File}; -use std::io::Write; - -fn main() { - lalrpop::Configuration::new() - .emit_rerun_directives(true) - .use_cargo_dir_conventions() - .process() - .unwrap(); - - // here, we get a lint error from "extern crate core" so patching that until lalrpop does - // (adding cfg directives appears to be unsupported by lalrpop) - let out_dir = std::env::var("OUT_DIR").unwrap(); - let parser_path = std::path::Path::new(&out_dir).join("noir_parser.rs"); - let content_str = read_to_string(parser_path.clone()).unwrap(); - let mut parser_file = File::create(parser_path).unwrap(); - for line in content_str.lines() { - if line.contains("extern crate core") { - parser_file - .write_all( - format!("{}\n", line.replace("extern crate core", "use core")).as_bytes(), - ) - .unwrap(); - } else { - parser_file.write_all(format!("{}\n", line).as_bytes()).unwrap(); - } - } -} diff --git a/compiler/noirc_frontend/src/ast/docs.rs b/compiler/noirc_frontend/src/ast/docs.rs new file mode 100644 index 00000000000..f00f15c215d --- /dev/null +++ b/compiler/noirc_frontend/src/ast/docs.rs @@ -0,0 +1,23 @@ +use std::fmt::Display; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Documented { + pub item: T, + pub doc_comments: Vec, +} + +impl Documented { + pub fn new(item: T, doc_comments: Vec) -> Self { + Self { item, doc_comments } + } + + pub fn not_documented(item: T) -> Self { + Self { item, doc_comments: Vec::new() } + } +} + +impl Display for Documented { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.item) + } +} diff --git a/compiler/noirc_frontend/src/ast/mod.rs b/compiler/noirc_frontend/src/ast/mod.rs index 1ed88115fa0..12a8aec05eb 100644 --- a/compiler/noirc_frontend/src/ast/mod.rs +++ b/compiler/noirc_frontend/src/ast/mod.rs @@ -4,6 +4,7 @@ //! //! Noir's Ast is produced by the parser and taken as input to name resolution, //! where it is converted into the Hir (defined in the hir_def module). +mod docs; mod expression; mod function; mod statement; @@ -18,6 +19,7 @@ pub use visitor::Visitor; pub use expression::*; pub use function::*; +pub use docs::*; use noirc_errors::Span; use serde::{Deserialize, Serialize}; pub use statement::*; diff --git a/compiler/noirc_frontend/src/ast/structure.rs b/compiler/noirc_frontend/src/ast/structure.rs index 732cbee9232..cd42abb29c7 100644 --- a/compiler/noirc_frontend/src/ast/structure.rs +++ b/compiler/noirc_frontend/src/ast/structure.rs @@ -6,16 +6,24 @@ use crate::token::SecondaryAttribute; use iter_extended::vecmap; use noirc_errors::Span; +use super::Documented; + /// Ast node for a struct #[derive(Clone, Debug, PartialEq, Eq)] pub struct NoirStruct { pub name: Ident, pub attributes: Vec, pub generics: UnresolvedGenerics, - pub fields: Vec<(Ident, UnresolvedType)>, + pub fields: Vec>, pub span: Span, } +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct StructField { + pub name: Ident, + pub typ: UnresolvedType, +} + impl Display for NoirStruct { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let generics = vecmap(&self.generics, |generic| generic.to_string()); @@ -23,8 +31,8 @@ impl Display for NoirStruct { writeln!(f, "struct {}{} {{", self.name, generics)?; - for (name, typ) in self.fields.iter() { - writeln!(f, " {name}: {typ},")?; + for field in self.fields.iter() { + writeln!(f, " {}: {},", field.item.name, field.item.typ)?; } write!(f, "}}") diff --git a/compiler/noirc_frontend/src/ast/traits.rs b/compiler/noirc_frontend/src/ast/traits.rs index e3221f287d3..0463a5b8392 100644 --- a/compiler/noirc_frontend/src/ast/traits.rs +++ b/compiler/noirc_frontend/src/ast/traits.rs @@ -10,7 +10,7 @@ use crate::ast::{ use crate::macros_api::SecondaryAttribute; use crate::node_interner::TraitId; -use super::GenericTypeArgs; +use super::{Documented, GenericTypeArgs}; /// AST node for trait definitions: /// `trait name { ... items ... }` @@ -20,7 +20,7 @@ pub struct NoirTrait { pub generics: UnresolvedGenerics, pub where_clause: Vec, pub span: Span, - pub items: Vec, + pub items: Vec>, pub attributes: Vec, } @@ -54,7 +54,7 @@ pub struct TypeImpl { pub type_span: Span, pub generics: UnresolvedGenerics, pub where_clause: Vec, - pub methods: Vec<(NoirFunction, Span)>, + pub methods: Vec<(Documented, Span)>, } /// Ast node for an implementation of a trait for a particular type @@ -71,7 +71,7 @@ pub struct NoirTraitImpl { pub where_clause: Vec, - pub items: Vec, + pub items: Vec>, } /// Represents a simple trait constraint such as `where Foo: TraitY` diff --git a/compiler/noirc_frontend/src/ast/visitor.rs b/compiler/noirc_frontend/src/ast/visitor.rs index 64b479b5fd6..6f54ad2e3b9 100644 --- a/compiler/noirc_frontend/src/ast/visitor.rs +++ b/compiler/noirc_frontend/src/ast/visitor.rs @@ -553,7 +553,7 @@ impl NoirTraitImpl { self.object_type.accept(visitor); for item in &self.items { - item.accept(visitor); + item.item.accept(visitor); } } } @@ -602,7 +602,7 @@ impl TypeImpl { self.object_type.accept(visitor); for (method, span) in &self.methods { - method.accept(*span, visitor); + method.item.accept(*span, visitor); } } } @@ -616,7 +616,7 @@ impl NoirTrait { pub fn accept_children(&self, visitor: &mut impl Visitor) { for item in &self.items { - item.accept(visitor); + item.item.accept(visitor); } } } @@ -701,8 +701,8 @@ impl NoirStruct { attribute.accept(AttributeTarget::Struct, visitor); } - for (_name, unresolved_type) in &self.fields { - unresolved_type.accept(visitor); + for field in &self.fields { + field.item.typ.accept(visitor); } } } diff --git a/compiler/noirc_frontend/src/elaborator/comptime.rs b/compiler/noirc_frontend/src/elaborator/comptime.rs index 0cd0824b6d9..240c48fd260 100644 --- a/compiler/noirc_frontend/src/elaborator/comptime.rs +++ b/compiler/noirc_frontend/src/elaborator/comptime.rs @@ -6,6 +6,7 @@ use iter_extended::vecmap; use noirc_errors::{Location, Span}; use crate::{ + ast::Documented, hir::{ comptime::{Interpreter, InterpreterError, Value}, def_collector::{ @@ -24,7 +25,7 @@ use crate::{ Expression, ExpressionKind, HirExpression, NodeInterner, SecondaryAttribute, StructId, }, node_interner::{DefinitionKind, DependencyId, FuncId, TraitId}, - parser::{self, TopLevelStatement}, + parser::{self, TopLevelStatement, TopLevelStatementKind}, Type, TypeBindings, UnificationError, }; @@ -381,8 +382,8 @@ impl<'context> Elaborator<'context> { generated_items: &mut CollectedItems, location: Location, ) { - match item { - TopLevelStatement::Function(function) => { + match item.kind { + TopLevelStatementKind::Function(function) => { let module_id = self.module_id(); if let Some(id) = dc_mod::collect_function( @@ -391,6 +392,7 @@ impl<'context> Elaborator<'context> { &function, module_id, self.file, + item.doc_comments, &mut self.errors, ) { let functions = vec![(self.local_module, id, function)]; @@ -402,7 +404,7 @@ impl<'context> Elaborator<'context> { }); } } - TopLevelStatement::TraitImpl(mut trait_impl) => { + TopLevelStatementKind::TraitImpl(mut trait_impl) => { let (methods, associated_types, associated_constants) = dc_mod::collect_trait_impl_items( self.interner, @@ -432,11 +434,11 @@ impl<'context> Elaborator<'context> { resolved_trait_generics: Vec::new(), }); } - TopLevelStatement::Global(global) => { + TopLevelStatementKind::Global(global) => { let (global, error) = dc_mod::collect_global( self.interner, self.def_maps.get_mut(&self.crate_id).unwrap(), - global, + Documented::new(global, item.doc_comments), self.file, self.local_module, self.crate_id, @@ -447,11 +449,11 @@ impl<'context> Elaborator<'context> { self.errors.push(error); } } - TopLevelStatement::Struct(struct_def) => { + TopLevelStatementKind::Struct(struct_def) => { if let Some((type_id, the_struct)) = dc_mod::collect_struct( self.interner, self.def_maps.get_mut(&self.crate_id).unwrap(), - struct_def, + Documented::new(struct_def, item.doc_comments), self.file, self.local_module, self.crate_id, @@ -460,21 +462,21 @@ impl<'context> Elaborator<'context> { generated_items.types.insert(type_id, the_struct); } } - TopLevelStatement::Impl(r#impl) => { + TopLevelStatementKind::Impl(r#impl) => { let module = self.module_id(); dc_mod::collect_impl(self.interner, generated_items, r#impl, self.file, module); } // Assume that an error has already been issued - TopLevelStatement::Error => (), - - TopLevelStatement::Module(_) - | TopLevelStatement::Import(..) - | TopLevelStatement::Trait(_) - | TopLevelStatement::TypeAlias(_) - | TopLevelStatement::SubModule(_) - | TopLevelStatement::InnerAttribute(_) => { - let item = item.to_string(); + TopLevelStatementKind::Error => (), + + TopLevelStatementKind::Module(_) + | TopLevelStatementKind::Import(..) + | TopLevelStatementKind::Trait(_) + | TopLevelStatementKind::TypeAlias(_) + | TopLevelStatementKind::SubModule(_) + | TopLevelStatementKind::InnerAttribute(_) => { + let item = item.kind.to_string(); let error = InterpreterError::UnsupportedTopLevelItemUnquote { item, location }; self.errors.push(error.into_compilation_error_pair()); } diff --git a/compiler/noirc_frontend/src/elaborator/mod.rs b/compiler/noirc_frontend/src/elaborator/mod.rs index d321d04bef9..dd8e985d3a2 100644 --- a/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/compiler/noirc_frontend/src/elaborator/mod.rs @@ -1248,7 +1248,9 @@ impl<'context> Elaborator<'context> { let struct_def = this.interner.get_struct(struct_id); this.add_existing_generics(&unresolved.generics, &struct_def.borrow().generics); - let fields = vecmap(&unresolved.fields, |(ident, typ)| { + let fields = vecmap(&unresolved.fields, |field| { + let ident = &field.item.name; + let typ = &field.item.typ; (ident.clone(), this.resolve_type(typ.clone())) }); diff --git a/compiler/noirc_frontend/src/elaborator/traits.rs b/compiler/noirc_frontend/src/elaborator/traits.rs index f651630baa2..d6bfd3aa647 100644 --- a/compiler/noirc_frontend/src/elaborator/traits.rs +++ b/compiler/noirc_frontend/src/elaborator/traits.rs @@ -13,7 +13,7 @@ use crate::{ BlockExpression, FunctionDefinition, FunctionReturnType, Ident, ItemVisibility, NodeInterner, NoirFunction, Param, Pattern, UnresolvedType, Visibility, }, - node_interner::{FuncId, TraitId}, + node_interner::{FuncId, ReferenceId, TraitId}, token::Attributes, Kind, ResolvedGeneric, Type, TypeBindings, TypeVariableKind, }; @@ -74,7 +74,7 @@ impl<'context> Elaborator<'context> { return_type, where_clause, body: _, - } = item + } = &item.item { self.recover_generics(|this| { let the_trait = this.interner.get_trait(trait_id); @@ -107,6 +107,11 @@ impl<'context> Elaborator<'context> { func_id, ); + if !item.doc_comments.is_empty() { + let id = ReferenceId::Function(func_id); + this.interner.set_doc_comments(id, item.doc_comments.clone()); + } + let func_meta = this.interner.function_meta(&func_id); let arguments = vecmap(&func_meta.parameters.0, |(_, typ, _)| typ.clone()); diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 7ee1840690a..6265d0e65f2 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -313,6 +313,11 @@ impl DefCollector { let crate_root = def_map.root; let mut def_collector = DefCollector::new(def_map); + let module_id = ModuleId { krate: crate_id, local_id: crate_root }; + context + .def_interner + .set_doc_comments(ReferenceId::Module(module_id), ast.inner_doc_comments.clone()); + // Collecting module declarations with ModCollector // and lowering the functions // i.e. Use a mod collector to collect the nodes at the root module diff --git a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index 6c1b7632a2e..d93b708c91d 100644 --- a/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -1,3 +1,4 @@ +use core::str; use std::path::Path; use std::rc::Rc; use std::vec; @@ -10,13 +11,13 @@ use num_traits::Num; use rustc_hash::FxHashMap as HashMap; use crate::ast::{ - FunctionDefinition, Ident, ItemVisibility, LetStatement, ModuleDeclaration, NoirFunction, - NoirStruct, NoirTrait, NoirTraitImpl, NoirTypeAlias, Pattern, TraitImplItem, TraitItem, - TypeImpl, + Documented, FunctionDefinition, Ident, ItemVisibility, LetStatement, ModuleDeclaration, + NoirFunction, NoirStruct, NoirTrait, NoirTraitImpl, NoirTypeAlias, Pattern, TraitImplItem, + TraitItem, TypeImpl, }; use crate::hir::resolution::errors::ResolverError; use crate::macros_api::{Expression, NodeInterner, StructId, UnresolvedType, UnresolvedTypeData}; -use crate::node_interner::ModuleAttributes; +use crate::node_interner::{ModuleAttributes, ReferenceId}; use crate::token::SecondaryAttribute; use crate::usage_tracker::UnusedItem; use crate::{ @@ -146,7 +147,7 @@ impl<'a> ModCollector<'a> { fn collect_globals( &mut self, context: &mut Context, - globals: Vec, + globals: Vec>, crate_id: CrateId, ) -> Vec<(CompilationError, fm::FileId)> { let mut errors = vec![]; @@ -235,7 +236,7 @@ impl<'a> ModCollector<'a> { fn collect_functions( &mut self, context: &mut Context, - functions: Vec, + functions: Vec>, krate: CrateId, ) -> Vec<(CompilationError, FileId)> { let mut unresolved_functions = UnresolvedFunctions { @@ -252,9 +253,10 @@ impl<'a> ModCollector<'a> { let Some(func_id) = collect_function( &mut context.def_interner, &mut self.def_collector.def_map, - &function, + &function.item, module, self.file_id, + function.doc_comments, &mut errors, ) else { continue; @@ -266,7 +268,7 @@ impl<'a> ModCollector<'a> { // and replace it // With this method we iterate each function in the Crate and not each module // This may not be great because we have to pull the module_data for each function - unresolved_functions.push_fn(self.module_id, func_id, function); + unresolved_functions.push_fn(self.module_id, func_id, function.item); } self.def_collector.items.functions.push(unresolved_functions); @@ -279,7 +281,7 @@ impl<'a> ModCollector<'a> { fn collect_structs( &mut self, context: &mut Context, - types: Vec, + types: Vec>, krate: CrateId, ) -> Vec<(CompilationError, FileId)> { let mut definition_errors = vec![]; @@ -304,11 +306,13 @@ impl<'a> ModCollector<'a> { fn collect_type_aliases( &mut self, context: &mut Context, - type_aliases: Vec, + type_aliases: Vec>, krate: CrateId, ) -> Vec<(CompilationError, FileId)> { let mut errors: Vec<(CompilationError, FileId)> = vec![]; for type_alias in type_aliases { + let doc_comments = type_alias.doc_comments; + let type_alias = type_alias.item; let name = type_alias.name.clone(); // And store the TypeId -> TypeAlias mapping somewhere it is reachable @@ -328,6 +332,8 @@ impl<'a> ModCollector<'a> { let type_alias_id = context.def_interner.push_type_alias(&unresolved, resolved_generics); + context.def_interner.set_doc_comments(ReferenceId::Alias(type_alias_id), doc_comments); + // Add the type alias to scope so its path can be looked up later let result = self.def_collector.def_map.modules[self.module_id.0] .declare_type_alias(name.clone(), type_alias_id); @@ -357,11 +363,13 @@ impl<'a> ModCollector<'a> { fn collect_traits( &mut self, context: &mut Context, - traits: Vec, + traits: Vec>, krate: CrateId, ) -> Vec<(CompilationError, FileId)> { let mut errors: Vec<(CompilationError, FileId)> = vec![]; for trait_definition in traits { + let doc_comments = trait_definition.doc_comments; + let trait_definition = trait_definition.item; let name = trait_definition.name.clone(); // Create the corresponding module for the trait namespace @@ -381,6 +389,8 @@ impl<'a> ModCollector<'a> { } }; + context.def_interner.set_doc_comments(ReferenceId::Trait(trait_id), doc_comments); + // Add the trait to scope so its path can be looked up later let result = self.def_collector.def_map.modules[self.module_id.0] .declare_trait(name.clone(), trait_id); @@ -406,7 +416,7 @@ impl<'a> ModCollector<'a> { let mut associated_types = Generics::new(); for trait_item in &trait_definition.items { - match trait_item { + match &trait_item.item { TraitItem::Function { name, generics, @@ -434,6 +444,13 @@ impl<'a> ModCollector<'a> { .def_interner .push_function_definition(func_id, modifiers, trait_id.0, location); + if !trait_item.doc_comments.is_empty() { + context.def_interner.set_doc_comments( + ReferenceId::Function(func_id), + trait_item.doc_comments.clone(), + ); + } + match self.def_collector.def_map.modules[trait_id.0.local_id.0] .declare_function(name.clone(), ItemVisibility::Public, func_id) { @@ -559,12 +576,15 @@ impl<'a> ModCollector<'a> { context: &mut Context, crate_id: CrateId, parent_module_id: LocalModuleId, - submodules: Vec, + submodules: Vec>, file_id: FileId, macro_processors: &[&dyn MacroProcessor], ) -> Vec<(CompilationError, FileId)> { let mut errors: Vec<(CompilationError, FileId)> = vec![]; for submodule in submodules { + let mut doc_comments = submodule.doc_comments; + let submodule = submodule.item; + match self.push_child_module( context, &submodule.name, @@ -584,6 +604,16 @@ impl<'a> ModCollector<'a> { false, ); + if !(doc_comments.is_empty() + && submodule.contents.inner_doc_comments.is_empty()) + { + doc_comments.extend(submodule.contents.inner_doc_comments.clone()); + + context + .def_interner + .set_doc_comments(ReferenceId::Module(child), doc_comments); + } + errors.extend(collect_defs( self.def_collector, submodule.contents, @@ -605,15 +635,19 @@ impl<'a> ModCollector<'a> { /// Search for a module named `mod_name` /// Parse it, add it as a child to the parent module in which it was declared /// and then collect all definitions of the child module + #[allow(clippy::too_many_arguments)] fn parse_module_declaration( &mut self, context: &mut Context, - mod_decl: ModuleDeclaration, + mod_decl: Documented, crate_id: CrateId, parent_file_id: FileId, parent_module_id: LocalModuleId, macro_processors: &[&dyn MacroProcessor], ) -> Vec<(CompilationError, FileId)> { + let mut doc_comments = mod_decl.doc_comments; + let mod_decl = mod_decl.item; + let mut errors: Vec<(CompilationError, FileId)> = vec![]; let child_file_id = match find_module(&context.file_manager, self.file_id, &mod_decl.ident) { @@ -691,6 +725,14 @@ impl<'a> ModCollector<'a> { // Track that the "foo" in `mod foo;` points to the module "foo" context.def_interner.add_module_reference(child_mod_id, location); + if !(doc_comments.is_empty() && ast.inner_doc_comments.is_empty()) { + doc_comments.extend(ast.inner_doc_comments.clone()); + + context + .def_interner + .set_doc_comments(ReferenceId::Module(child_mod_id), doc_comments); + } + errors.extend(collect_defs( self.def_collector, ast, @@ -827,6 +869,7 @@ pub fn collect_function( function: &NoirFunction, module: ModuleId, file: FileId, + doc_comments: Vec, errors: &mut Vec<(CompilationError, FileId)>, ) -> Option { if let Some(field) = function.attributes().get_field_attribute() { @@ -858,6 +901,8 @@ pub fn collect_function( interner.usage_tracker.add_unused_item(module, name.clone(), item, visibility); } + interner.set_doc_comments(ReferenceId::Function(func_id), doc_comments); + // Add function to scope/ns of the module let result = def_map.modules[module.local_id.0].declare_function(name, visibility, func_id); if let Err((first_def, second_def)) = result { @@ -874,12 +919,15 @@ pub fn collect_function( pub fn collect_struct( interner: &mut NodeInterner, def_map: &mut CrateDefMap, - struct_definition: NoirStruct, + struct_definition: Documented, file_id: FileId, module_id: LocalModuleId, krate: CrateId, definition_errors: &mut Vec<(CompilationError, FileId)>, ) -> Option<(StructId, UnresolvedStruct)> { + let doc_comments = struct_definition.doc_comments; + let struct_definition = struct_definition.item; + check_duplicate_field_names(&struct_definition, file_id, definition_errors); let name = struct_definition.name.clone(); @@ -915,6 +963,15 @@ pub fn collect_struct( } }; + interner.set_doc_comments(ReferenceId::Struct(id), doc_comments); + + for (index, field) in unresolved.struct_def.fields.iter().enumerate() { + if !field.doc_comments.is_empty() { + interner + .set_doc_comments(ReferenceId::StructMember(id, index), field.doc_comments.clone()); + } + } + // Add the struct to scope so its path can be looked up later let result = def_map.modules[module_id.0].declare_struct(name.clone(), id); @@ -945,12 +1002,15 @@ pub fn collect_impl( let mut unresolved_functions = UnresolvedFunctions { file_id, functions: Vec::new(), trait_id: None, self_type: None }; - for (mut method, _) in r#impl.methods { + for (method, _) in r#impl.methods { + let doc_comments = method.doc_comments; + let mut method = method.item; let func_id = interner.push_empty_fn(); method.def.where_clause.extend(r#impl.where_clause.clone()); let location = Location::new(method.span(), file_id); interner.push_function(func_id, &method.def, module_id, location); unresolved_functions.push_fn(module_id.local_id, func_id, method); + interner.set_doc_comments(ReferenceId::Function(func_id), doc_comments); } let key = (r#impl.object_type, module_id.local_id); @@ -1064,11 +1124,12 @@ pub(crate) fn collect_trait_impl_items( let module = ModuleId { krate, local_id }; for item in std::mem::take(&mut trait_impl.items) { - match item { + match item.item { TraitImplItem::Function(impl_method) => { let func_id = interner.push_empty_fn(); let location = Location::new(impl_method.span(), file_id); interner.push_function(func_id, &impl_method.def, module, location); + interner.set_doc_comments(ReferenceId::Function(func_id), item.doc_comments); unresolved_functions.push_fn(local_id, func_id, impl_method); } TraitImplItem::Constant(name, typ, expr) => { @@ -1086,11 +1147,14 @@ pub(crate) fn collect_trait_impl_items( pub(crate) fn collect_global( interner: &mut NodeInterner, def_map: &mut CrateDefMap, - global: LetStatement, + global: Documented, file_id: FileId, module_id: LocalModuleId, crate_id: CrateId, ) -> (UnresolvedGlobal, Option<(CompilationError, FileId)>) { + let doc_comments = global.doc_comments; + let global = global.item; + let name = global.pattern.name_ident().clone(); let global_id = interner.push_empty_global( @@ -1112,6 +1176,8 @@ pub(crate) fn collect_global( (err.into(), file_id) }); + interner.set_doc_comments(ReferenceId::Global(global_id), doc_comments); + let global = UnresolvedGlobal { file_id, module_id, global_id, stmt_def: global }; (global, error) } @@ -1122,7 +1188,9 @@ fn check_duplicate_field_names( definition_errors: &mut Vec<(CompilationError, FileId)>, ) { let mut seen_field_names = std::collections::HashSet::new(); - for (field_name, _) in &struct_definition.fields { + for field in &struct_definition.fields { + let field_name = &field.item.name; + if seen_field_names.insert(field_name) { continue; } diff --git a/compiler/noirc_frontend/src/lexer/lexer.rs b/compiler/noirc_frontend/src/lexer/lexer.rs index b7492396c90..7fbbb4fccef 100644 --- a/compiler/noirc_frontend/src/lexer/lexer.rs +++ b/compiler/noirc_frontend/src/lexer/lexer.rs @@ -2,9 +2,7 @@ use crate::token::{Attribute, DocStyle}; use super::{ errors::LexerErrorKind, - token::{ - token_to_borrowed_token, BorrowedToken, IntType, Keyword, SpannedToken, Token, Tokens, - }, + token::{IntType, Keyword, SpannedToken, Token, Tokens}, }; use acvm::{AcirField, FieldElement}; use noirc_errors::{Position, Span}; @@ -26,21 +24,6 @@ pub struct Lexer<'a> { pub type SpannedTokenResult = Result; -pub(crate) fn from_spanned_token_result( - token_result: &SpannedTokenResult, -) -> Result<(usize, BorrowedToken<'_>, usize), LexerErrorKind> { - token_result - .as_ref() - .map(|spanned_token| { - ( - spanned_token.to_span().start() as usize, - token_to_borrowed_token(spanned_token.into()), - spanned_token.to_span().end() as usize, - ) - }) - .map_err(Clone::clone) -} - impl<'a> Lexer<'a> { /// Given a source file of noir code, return all the tokens in the file /// in order, along with any lexing errors that occurred. @@ -623,7 +606,7 @@ impl<'a> Lexer<'a> { }; let comment = self.eat_while(None, |ch| ch != '\n'); - if self.skip_comments { + if doc_style.is_none() && self.skip_comments { return self.next_token(); } @@ -668,7 +651,7 @@ impl<'a> Lexer<'a> { } if depth == 0 { - if self.skip_comments { + if doc_style.is_none() && self.skip_comments { return self.next_token(); } Ok(Token::BlockComment(content, doc_style).into_span(start, self.position)) diff --git a/compiler/noirc_frontend/src/lexer/token.rs b/compiler/noirc_frontend/src/lexer/token.rs index 7b805b5fd8d..5a932de83f4 100644 --- a/compiler/noirc_frontend/src/lexer/token.rs +++ b/compiler/noirc_frontend/src/lexer/token.rs @@ -440,6 +440,8 @@ pub enum TokenKind { InternedLValue, InternedUnresolvedTypeData, UnquoteMarker, + OuterDocComment, + InnerDocComment, } impl fmt::Display for TokenKind { @@ -458,6 +460,8 @@ impl fmt::Display for TokenKind { TokenKind::InternedLValue => write!(f, "interned lvalue"), TokenKind::InternedUnresolvedTypeData => write!(f, "interned unresolved type"), TokenKind::UnquoteMarker => write!(f, "macro result"), + TokenKind::OuterDocComment => write!(f, "outer doc comment"), + TokenKind::InnerDocComment => write!(f, "inner doc comment"), } } } @@ -481,6 +485,10 @@ impl Token { Token::InternedStatement(_) => TokenKind::InternedStatement, Token::InternedLValue(_) => TokenKind::InternedLValue, Token::InternedUnresolvedTypeData(_) => TokenKind::InternedUnresolvedTypeData, + Token::LineComment(_, Some(DocStyle::Outer)) + | Token::BlockComment(_, Some(DocStyle::Outer)) => TokenKind::OuterDocComment, + Token::LineComment(_, Some(DocStyle::Inner)) + | Token::BlockComment(_, Some(DocStyle::Inner)) => TokenKind::InnerDocComment, tok => TokenKind::Token(tok.clone()), } } diff --git a/compiler/noirc_frontend/src/lib.rs b/compiler/noirc_frontend/src/lib.rs index ec09f680bc2..9f7a0564789 100644 --- a/compiler/noirc_frontend/src/lib.rs +++ b/compiler/noirc_frontend/src/lib.rs @@ -53,7 +53,7 @@ pub mod macros_api { pub use crate::token::SecondaryAttribute; pub use crate::ast::{ - BlockExpression, CallExpression, CastExpression, Expression, ExpressionKind, + BlockExpression, CallExpression, CastExpression, Documented, Expression, ExpressionKind, FunctionReturnType, Ident, IndexExpression, ItemVisibility, LetStatement, Literal, MemberAccessExpression, MethodCallExpression, NoirFunction, Path, PathKind, Pattern, Statement, UnresolvedType, UnresolvedTypeData, Visibility, diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index aa51779d24b..881c5e6251a 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -269,6 +269,9 @@ pub struct NodeInterner { pub(crate) comptime_scopes: Vec>, pub(crate) usage_tracker: UsageTracker, + + /// Captures the documentation comments for each module, struct, trait, function, etc. + pub(crate) doc_comments: HashMap>, } /// A dependency in the dependency graph may be a type or a definition. @@ -656,6 +659,7 @@ impl Default for NodeInterner { comptime_scopes: vec![HashMap::default()], trait_impl_associated_types: HashMap::default(), usage_tracker: UsageTracker::new(), + doc_comments: HashMap::default(), } } } @@ -2196,6 +2200,16 @@ impl NodeInterner { bindings } + + pub fn set_doc_comments(&mut self, id: ReferenceId, doc_comments: Vec) { + if !doc_comments.is_empty() { + self.doc_comments.insert(id, doc_comments); + } + } + + pub fn doc_comments(&self, id: ReferenceId) -> Option<&Vec> { + self.doc_comments.get(&id) + } } impl Methods { diff --git a/compiler/noirc_frontend/src/noir_parser.lalrpop b/compiler/noirc_frontend/src/noir_parser.lalrpop deleted file mode 100644 index 01b8be8f721..00000000000 --- a/compiler/noirc_frontend/src/noir_parser.lalrpop +++ /dev/null @@ -1,170 +0,0 @@ -use noirc_errors::Span; - -use crate::lexer::token::BorrowedToken; -use crate::lexer::token as noir_token; -use crate::lexer::errors::LexerErrorKind; -use crate::parser::TopLevelStatement; -use crate::ast::{Ident, Path, PathKind, PathSegment, UseTree, UseTreeKind}; - -use lalrpop_util::ErrorRecovery; - -grammar<'input, 'err>(input: &'input str, errors: &'err mut [ErrorRecovery, &'static str>]); - -extern { - type Location = usize; - - type Error = LexerErrorKind; - - // NOTE: each token needs a terminal defined - enum BorrowedToken<'input> { - string => BorrowedToken::Str(<&'input str>), - ident => BorrowedToken::Ident(<&'input str>), - - // symbols - "<" => BorrowedToken::Less, - "<=" => BorrowedToken::LessEqual, - ">" => BorrowedToken::Greater, - ">=" => BorrowedToken::GreaterEqual, - "==" => BorrowedToken::Equal, - "!=" => BorrowedToken::NotEqual, - "+" => BorrowedToken::Plus, - "-" => BorrowedToken::Minus, - "*" => BorrowedToken::Star, - "/" => BorrowedToken::Slash, - "%" => BorrowedToken::Percent, - "&" => BorrowedToken::Ampersand, - "^" => BorrowedToken::Caret, - "<<" => BorrowedToken::ShiftLeft, - ">>" => BorrowedToken::ShiftRight, - "." => BorrowedToken::Dot, - ".." => BorrowedToken::DoubleDot, - "(" => BorrowedToken::LeftParen, - ")" => BorrowedToken::RightParen, - "{" => BorrowedToken::LeftBrace, - "}" => BorrowedToken::RightBrace, - "[" => BorrowedToken::LeftBracket, - "]" => BorrowedToken::RightBracket, - "->" => BorrowedToken::Arrow, - "|" => BorrowedToken::Pipe, - "#" => BorrowedToken::Pound, - "," => BorrowedToken::Comma, - ":" => BorrowedToken::Colon, - "::" => BorrowedToken::DoubleColon, - ";" => BorrowedToken::Semicolon, - "!" => BorrowedToken::Bang, - "=" => BorrowedToken::Assign, - // keywords - "as" => BorrowedToken::Keyword(noir_token::Keyword::As), - "assert" => BorrowedToken::Keyword(noir_token::Keyword::Assert), - "assert_eq" => BorrowedToken::Keyword(noir_token::Keyword::AssertEq), - "bool" => BorrowedToken::Keyword(noir_token::Keyword::Bool), - "break" => BorrowedToken::Keyword(noir_token::Keyword::Break), - "call_data" => BorrowedToken::Keyword(noir_token::Keyword::CallData), - "char" => BorrowedToken::Keyword(noir_token::Keyword::Char), - "comptime" => BorrowedToken::Keyword(noir_token::Keyword::Comptime), - "constrain" => BorrowedToken::Keyword(noir_token::Keyword::Constrain), - "continue" => BorrowedToken::Keyword(noir_token::Keyword::Continue), - "contract" => BorrowedToken::Keyword(noir_token::Keyword::Contract), - "crate" => BorrowedToken::Keyword(noir_token::Keyword::Crate), - "dep" => BorrowedToken::Keyword(noir_token::Keyword::Dep), - "else" => BorrowedToken::Keyword(noir_token::Keyword::Else), - "Field" => BorrowedToken::Keyword(noir_token::Keyword::Field), - "fn" => BorrowedToken::Keyword(noir_token::Keyword::Fn), - "for" => BorrowedToken::Keyword(noir_token::Keyword::For), - "fmtstr" => BorrowedToken::Keyword(noir_token::Keyword::FormatString), - "global" => BorrowedToken::Keyword(noir_token::Keyword::Global), - "if" => BorrowedToken::Keyword(noir_token::Keyword::If), - "impl" => BorrowedToken::Keyword(noir_token::Keyword::Impl), - "in" => BorrowedToken::Keyword(noir_token::Keyword::In), - "let" => BorrowedToken::Keyword(noir_token::Keyword::Let), - "mod" => BorrowedToken::Keyword(noir_token::Keyword::Mod), - "mut" => BorrowedToken::Keyword(noir_token::Keyword::Mut), - "pub" => BorrowedToken::Keyword(noir_token::Keyword::Pub), - "return" => BorrowedToken::Keyword(noir_token::Keyword::Return), - "return_data" => BorrowedToken::Keyword(noir_token::Keyword::ReturnData), - "str" => BorrowedToken::Keyword(noir_token::Keyword::String), - "struct" => BorrowedToken::Keyword(noir_token::Keyword::Struct), - "trait" => BorrowedToken::Keyword(noir_token::Keyword::Trait), - "type" => BorrowedToken::Keyword(noir_token::Keyword::Type), - "unchecked" => BorrowedToken::Keyword(noir_token::Keyword::Unchecked), - "unconstrained" => BorrowedToken::Keyword(noir_token::Keyword::Unconstrained), - "use" => BorrowedToken::Keyword(noir_token::Keyword::Use), - "where" => BorrowedToken::Keyword(noir_token::Keyword::Where), - "while" => BorrowedToken::Keyword(noir_token::Keyword::While), - // bool - "true" => BorrowedToken::Bool(true), - "false" => BorrowedToken::Bool(false), - - r"[\t\r\n ]+" => BorrowedToken::Whitespace(_), - - EOF => BorrowedToken::EOF, - } -} - -pub(crate) TopLevelStatement: TopLevelStatement = { - "use" r"[\t\r\n ]+" ";" EOF => { - TopLevelStatement::Import(use_tree, crate::ast::ItemVisibility::Private) - } -} - -UseTree: UseTree = { - // path::to::ident as SomeAlias - => { - let ident = prefix.pop().ident; - let kind = UseTreeKind::Path(ident, alias); - UseTree { prefix, kind } - }, -} - -pub(crate) Path: Path = { - "crate" "::" => { - let kind = PathKind::Crate; - let span = Span::from(lo as u32..hi as u32); - Path { segments, kind, span } - }, - - "dep" "::" => { - let kind = PathKind::Plain; - let span = Span::from(lo as u32..hi as u32); - Path { segments, kind, span } - }, - - => { - segments.insert(0, id); - let kind = PathKind::Plain; - let span = Span::from(lo as u32..hi as u32); - Path { segments, kind, span } - }, -} - -PathSegments: Vec = { - )*> => { - segments - } -} - -PathSegment: PathSegment = { - => { - let token = noir_token::Token::Ident(i.to_string()); - let span = Span::from(lo as u32..hi as u32); - PathSegment::from(Ident::from_token(token, span)) - }, -} - -Alias: Ident = { - r"[\t\r\n ]+" "as" r"[\t\r\n ]+" => <>, -} - -Ident: Ident = { - => { - let token = noir_token::Token::Ident(i.to_string()); - let span = Span::from(lo as u32..hi as u32); - Ident::from_token(token, span) - }, -} - -Bool: BorrowedToken<'input> = { - "true" => BorrowedToken::Bool(true), - "false" => BorrowedToken::Bool(false), -}; - diff --git a/compiler/noirc_frontend/src/parser/mod.rs b/compiler/noirc_frontend/src/parser/mod.rs index 66be0fdced5..968af82a8b3 100644 --- a/compiler/noirc_frontend/src/parser/mod.rs +++ b/compiler/noirc_frontend/src/parser/mod.rs @@ -12,9 +12,9 @@ mod labels; mod parser; use crate::ast::{ - Expression, Ident, ImportStatement, ItemVisibility, LetStatement, ModuleDeclaration, - NoirFunction, NoirStruct, NoirTrait, NoirTraitImpl, NoirTypeAlias, Recoverable, StatementKind, - TypeImpl, UseTree, + Documented, Expression, Ident, ImportStatement, ItemVisibility, LetStatement, + ModuleDeclaration, NoirFunction, NoirStruct, NoirTrait, NoirTraitImpl, NoirTypeAlias, + Recoverable, StatementKind, TypeImpl, UseTree, }; use crate::token::{Keyword, SecondaryAttribute, Token}; @@ -31,7 +31,13 @@ pub use parser::{ }; #[derive(Debug, Clone)] -pub enum TopLevelStatement { +pub struct TopLevelStatement { + pub kind: TopLevelStatementKind, + pub doc_comments: Vec, +} + +#[derive(Debug, Clone)] +pub enum TopLevelStatementKind { Function(NoirFunction), Module(ModuleDeclaration), Import(UseTree, ItemVisibility), @@ -46,21 +52,21 @@ pub enum TopLevelStatement { Error, } -impl TopLevelStatement { +impl TopLevelStatementKind { pub fn into_item_kind(self) -> Option { match self { - TopLevelStatement::Function(f) => Some(ItemKind::Function(f)), - TopLevelStatement::Module(m) => Some(ItemKind::ModuleDecl(m)), - TopLevelStatement::Import(i, visibility) => Some(ItemKind::Import(i, visibility)), - TopLevelStatement::Struct(s) => Some(ItemKind::Struct(s)), - TopLevelStatement::Trait(t) => Some(ItemKind::Trait(t)), - TopLevelStatement::TraitImpl(t) => Some(ItemKind::TraitImpl(t)), - TopLevelStatement::Impl(i) => Some(ItemKind::Impl(i)), - TopLevelStatement::TypeAlias(t) => Some(ItemKind::TypeAlias(t)), - TopLevelStatement::SubModule(s) => Some(ItemKind::Submodules(s)), - TopLevelStatement::Global(c) => Some(ItemKind::Global(c)), - TopLevelStatement::InnerAttribute(a) => Some(ItemKind::InnerAttribute(a)), - TopLevelStatement::Error => None, + TopLevelStatementKind::Function(f) => Some(ItemKind::Function(f)), + TopLevelStatementKind::Module(m) => Some(ItemKind::ModuleDecl(m)), + TopLevelStatementKind::Import(i, visibility) => Some(ItemKind::Import(i, visibility)), + TopLevelStatementKind::Struct(s) => Some(ItemKind::Struct(s)), + TopLevelStatementKind::Trait(t) => Some(ItemKind::Trait(t)), + TopLevelStatementKind::TraitImpl(t) => Some(ItemKind::TraitImpl(t)), + TopLevelStatementKind::Impl(i) => Some(ItemKind::Impl(i)), + TopLevelStatementKind::TypeAlias(t) => Some(ItemKind::TypeAlias(t)), + TopLevelStatementKind::SubModule(s) => Some(ItemKind::Submodules(s)), + TopLevelStatementKind::Global(c) => Some(ItemKind::Global(c)), + TopLevelStatementKind::InnerAttribute(a) => Some(ItemKind::InnerAttribute(a)), + TopLevelStatementKind::Error => None, } } } @@ -222,11 +228,11 @@ fn parameter_name_recovery() -> impl NoirParser { try_skip_until([Colon, RightParen, Comma], [RightParen, Comma]) } -fn top_level_statement_recovery() -> impl NoirParser { +fn top_level_statement_recovery() -> impl NoirParser { none_of([Token::RightBrace, Token::EOF]) .repeated() .ignore_then(one_of([Token::Semicolon])) - .map(|_| TopLevelStatement::Error) + .map(|_| TopLevelStatementKind::Error) } /// Force the given parser to succeed, logging any errors it had @@ -237,21 +243,22 @@ fn force<'a, T: 'a>(parser: impl NoirParser + 'a) -> impl NoirParser, - pub functions: Vec, - pub types: Vec, - pub traits: Vec, + pub functions: Vec>, + pub types: Vec>, + pub traits: Vec>, pub trait_impls: Vec, pub impls: Vec, - pub type_aliases: Vec, - pub globals: Vec, + pub type_aliases: Vec>, + pub globals: Vec>, /// Module declarations like `mod foo;` - pub module_decls: Vec, + pub module_decls: Vec>, /// Full submodules as in `mod foo { ... definitions ... }` - pub submodules: Vec, + pub submodules: Vec>, pub inner_attributes: Vec, + pub inner_doc_comments: Vec, } impl std::fmt::Display for SortedModule { @@ -296,6 +303,7 @@ impl std::fmt::Display for SortedModule { #[derive(Clone, Debug, Default)] pub struct ParsedModule { pub items: Vec, + pub inner_doc_comments: Vec, } impl ParsedModule { @@ -305,19 +313,27 @@ impl ParsedModule { for item in self.items { match item.kind { ItemKind::Import(import, visibility) => module.push_import(import, visibility), - ItemKind::Function(func) => module.push_function(func), - ItemKind::Struct(typ) => module.push_type(typ), - ItemKind::Trait(noir_trait) => module.push_trait(noir_trait), + ItemKind::Function(func) => module.push_function(func, item.doc_comments), + ItemKind::Struct(typ) => module.push_type(typ, item.doc_comments), + ItemKind::Trait(noir_trait) => module.push_trait(noir_trait, item.doc_comments), ItemKind::TraitImpl(trait_impl) => module.push_trait_impl(trait_impl), ItemKind::Impl(r#impl) => module.push_impl(r#impl), - ItemKind::TypeAlias(type_alias) => module.push_type_alias(type_alias), - ItemKind::Global(global) => module.push_global(global), - ItemKind::ModuleDecl(mod_name) => module.push_module_decl(mod_name), - ItemKind::Submodules(submodule) => module.push_submodule(submodule.into_sorted()), + ItemKind::TypeAlias(type_alias) => { + module.push_type_alias(type_alias, item.doc_comments); + } + ItemKind::Global(global) => module.push_global(global, item.doc_comments), + ItemKind::ModuleDecl(mod_name) => { + module.push_module_decl(mod_name, item.doc_comments); + } + ItemKind::Submodules(submodule) => { + module.push_submodule(submodule.into_sorted(), item.doc_comments); + } ItemKind::InnerAttribute(attribute) => module.inner_attributes.push(attribute), } } + module.inner_doc_comments = self.inner_doc_comments; + module } } @@ -326,6 +342,7 @@ impl ParsedModule { pub struct Item { pub kind: ItemKind, pub span: Span, + pub doc_comments: Vec, } #[derive(Clone, Debug)] @@ -385,16 +402,16 @@ pub struct SortedSubModule { } impl SortedModule { - fn push_function(&mut self, func: NoirFunction) { - self.functions.push(func); + fn push_function(&mut self, func: NoirFunction, doc_comments: Vec) { + self.functions.push(Documented::new(func, doc_comments)); } - fn push_type(&mut self, typ: NoirStruct) { - self.types.push(typ); + fn push_type(&mut self, typ: NoirStruct, doc_comments: Vec) { + self.types.push(Documented::new(typ, doc_comments)); } - fn push_trait(&mut self, noir_trait: NoirTrait) { - self.traits.push(noir_trait); + fn push_trait(&mut self, noir_trait: NoirTrait, doc_comments: Vec) { + self.traits.push(Documented::new(noir_trait, doc_comments)); } fn push_trait_impl(&mut self, trait_impl: NoirTraitImpl) { @@ -405,24 +422,24 @@ impl SortedModule { self.impls.push(r#impl); } - fn push_type_alias(&mut self, type_alias: NoirTypeAlias) { - self.type_aliases.push(type_alias); + fn push_type_alias(&mut self, type_alias: NoirTypeAlias, doc_comments: Vec) { + self.type_aliases.push(Documented::new(type_alias, doc_comments)); } fn push_import(&mut self, import_stmt: UseTree, visibility: ItemVisibility) { self.imports.extend(import_stmt.desugar(None, visibility)); } - fn push_module_decl(&mut self, mod_decl: ModuleDeclaration) { - self.module_decls.push(mod_decl); + fn push_module_decl(&mut self, mod_decl: ModuleDeclaration, doc_comments: Vec) { + self.module_decls.push(Documented::new(mod_decl, doc_comments)); } - fn push_submodule(&mut self, submodule: SortedSubModule) { - self.submodules.push(submodule); + fn push_submodule(&mut self, submodule: SortedSubModule, doc_comments: Vec) { + self.submodules.push(Documented::new(submodule, doc_comments)); } - fn push_global(&mut self, global: LetStatement) { - self.globals.push(global); + fn push_global(&mut self, global: LetStatement, doc_comments: Vec) { + self.globals.push(Documented::new(global, doc_comments)); } } @@ -503,27 +520,27 @@ impl Precedence { } } -impl std::fmt::Display for TopLevelStatement { +impl std::fmt::Display for TopLevelStatementKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - TopLevelStatement::Function(fun) => fun.fmt(f), - TopLevelStatement::Module(m) => m.fmt(f), - TopLevelStatement::Import(tree, visibility) => { + TopLevelStatementKind::Function(fun) => fun.fmt(f), + TopLevelStatementKind::Module(m) => m.fmt(f), + TopLevelStatementKind::Import(tree, visibility) => { if visibility == &ItemVisibility::Private { write!(f, "use {tree}") } else { write!(f, "{visibility} use {tree}") } } - TopLevelStatement::Trait(t) => t.fmt(f), - TopLevelStatement::TraitImpl(i) => i.fmt(f), - TopLevelStatement::Struct(s) => s.fmt(f), - TopLevelStatement::Impl(i) => i.fmt(f), - TopLevelStatement::TypeAlias(t) => t.fmt(f), - TopLevelStatement::SubModule(s) => s.fmt(f), - TopLevelStatement::Global(c) => c.fmt(f), - TopLevelStatement::InnerAttribute(a) => write!(f, "#![{}]", a), - TopLevelStatement::Error => write!(f, "error"), + TopLevelStatementKind::Trait(t) => t.fmt(f), + TopLevelStatementKind::TraitImpl(i) => i.fmt(f), + TopLevelStatementKind::Struct(s) => s.fmt(f), + TopLevelStatementKind::Impl(i) => i.fmt(f), + TopLevelStatementKind::TypeAlias(t) => t.fmt(f), + TopLevelStatementKind::SubModule(s) => s.fmt(f), + TopLevelStatementKind::Global(c) => c.fmt(f), + TopLevelStatementKind::InnerAttribute(a) => write!(f, "#![{}]", a), + TopLevelStatementKind::Error => write!(f, "error"), } } } diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index 48d25e7a1d8..317eb01f21e 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -27,6 +27,7 @@ use self::path::as_trait_path; use self::primitives::{keyword, macro_quote_marker, mutable_reference, variable}; use self::types::{generic_type_args, maybe_comp_time}; use attributes::{attributes, inner_attribute, validate_secondary_attributes}; +use doc_comments::{inner_doc_comments, outer_doc_comments}; pub use types::parse_type; use visibility::item_visibility; pub use visibility::visibility; @@ -35,30 +36,30 @@ use super::{ foldl_with_span, labels::ParsingRuleLabel, parameter_name_recovery, parameter_recovery, parenthesized, then_commit, then_commit_ignore, top_level_statement_recovery, ExprParser, NoirParser, ParsedModule, ParsedSubModule, ParserError, ParserErrorReason, Precedence, - TopLevelStatement, + TopLevelStatementKind, }; -use super::{spanned, Item, ItemKind}; +use super::{spanned, Item, TopLevelStatement}; use crate::ast::{ - BinaryOp, BinaryOpKind, BlockExpression, ForLoopStatement, ForRange, GenericTypeArgs, Ident, - IfExpression, InfixExpression, LValue, Literal, ModuleDeclaration, NoirTypeAlias, Param, Path, - Pattern, Recoverable, Statement, TypeImpl, UnaryRhsMemberAccess, UnaryRhsMethodCall, UseTree, - UseTreeKind, Visibility, + BinaryOp, BinaryOpKind, BlockExpression, Documented, ForLoopStatement, ForRange, + GenericTypeArgs, Ident, IfExpression, InfixExpression, LValue, Literal, ModuleDeclaration, + NoirTypeAlias, Param, Path, Pattern, Recoverable, Statement, TypeImpl, UnaryRhsMemberAccess, + UnaryRhsMethodCall, UseTree, UseTreeKind, Visibility, }; use crate::ast::{ Expression, ExpressionKind, LetStatement, StatementKind, UnresolvedType, UnresolvedTypeData, }; -use crate::lexer::{lexer::from_spanned_token_result, Lexer}; +use crate::lexer::Lexer; use crate::parser::{force, ignore_then_commit, statement_recovery}; use crate::token::{Keyword, Token, TokenKind}; use acvm::AcirField; use chumsky::prelude::*; use iter_extended::vecmap; -use lalrpop_util::lalrpop_mod; use noirc_errors::{Span, Spanned}; mod assertion; mod attributes; +mod doc_comments; mod function; mod lambdas; mod literals; @@ -69,9 +70,6 @@ pub(super) mod traits; mod types; mod visibility; -// synthesized by LALRPOP -lalrpop_mod!(pub noir_parser); - #[cfg(test)] mod test_helpers; @@ -95,79 +93,9 @@ pub fn parse_program(source_program: &str) -> (ParsedModule, Vec) { parsing_errors.extend(lexing_errors.into_iter().map(Into::into)); let parsed_module = module.unwrap_or_default(); - if cfg!(feature = "experimental_parser") { - for parsed_item in &parsed_module.items { - if lalrpop_parser_supports_kind(&parsed_item.kind) { - match &parsed_item.kind { - ItemKind::Import(parsed_use_tree, _visibility) => { - prototype_parse_use_tree(Some(parsed_use_tree), source_program); - } - // other kinds prevented by lalrpop_parser_supports_kind - _ => unreachable!(), - } - } - } - } (parsed_module, parsing_errors) } -fn prototype_parse_use_tree(expected_use_tree_opt: Option<&UseTree>, input: &str) { - // TODO(https://github.com/noir-lang/noir/issues/4777): currently skipping - // recursive use trees, e.g. "use std::{foo, bar}" - if input.contains('{') { - return; - } - - let mut lexer = Lexer::new(input); - lexer = lexer.skip_whitespaces(false); - let mut errors = Vec::new(); - - // NOTE: this is a hack to get the references working - // => this likely means that we'll want to propagate the <'input> lifetime further into Token - let lexer_result = lexer.collect::>(); - let referenced_lexer_result = lexer_result.iter().map(from_spanned_token_result); - - let calculated = noir_parser::TopLevelStatementParser::new().parse( - input, - &mut errors, - referenced_lexer_result, - ); - - if let Some(expected_use_tree) = expected_use_tree_opt { - assert!( - calculated.is_ok(), - "calculated not Ok(_): {:?}\n\nlexer: {:?}\n\ninput: {:?}", - calculated, - lexer_result, - input - ); - - match calculated.unwrap() { - TopLevelStatement::Import(parsed_use_tree, _visibility) => { - assert_eq!(expected_use_tree, &parsed_use_tree); - } - unexpected_calculated => { - panic!( - "expected a TopLevelStatement::Import, but found: {:?}", - unexpected_calculated - ) - } - } - } else { - assert!( - calculated.is_err(), - "calculated not Err(_): {:?}\n\nlexer: {:?}\n\ninput: {:?}", - calculated, - lexer_result, - input - ); - } -} - -fn lalrpop_parser_supports_kind(kind: &ItemKind) -> bool { - matches!(kind, ItemKind::Import(..)) -} - /// program: module EOF fn program() -> impl NoirParser { module().then_ignore(just(Token::EOF)) @@ -177,13 +105,24 @@ fn program() -> impl NoirParser { /// | %empty pub fn module() -> impl NoirParser { recursive(|module_parser| { - empty() - .to(ParsedModule::default()) - .then(spanned(top_level_statement(module_parser)).repeated()) - .foldl(|mut program, (statement, span)| { - if let Some(kind) = statement.into_item_kind() { - program.items.push(Item { kind, span }); - } + inner_doc_comments() + .then( + empty() + .to(ParsedModule::default()) + .then(spanned(top_level_statement(module_parser)).repeated()) + .foldl(|mut program, (statement, span)| { + if let Some(kind) = statement.kind.into_item_kind() { + program.items.push(Item { + kind, + span, + doc_comments: statement.doc_comments, + }); + } + program + }), + ) + .map(|(doc_comments, mut program)| { + program.inner_doc_comments = doc_comments; program }) }) @@ -194,6 +133,14 @@ pub fn top_level_items() -> impl NoirParser> { top_level_statement(module()).repeated() } +pub fn top_level_statement<'a>( + module_parser: impl NoirParser + 'a, +) -> impl NoirParser + 'a { + outer_doc_comments() + .then(top_level_statement_kind(module_parser)) + .map(|(doc_comments, kind)| TopLevelStatement { kind, doc_comments }) +} + /// top_level_statement: function_definition /// | struct_definition /// | trait_definition @@ -202,11 +149,11 @@ pub fn top_level_items() -> impl NoirParser> { /// | module_declaration /// | use_statement /// | global_declaration -pub fn top_level_statement<'a>( +fn top_level_statement_kind<'a>( module_parser: impl NoirParser + 'a, -) -> impl NoirParser + 'a { +) -> impl NoirParser + 'a { choice(( - function::function_definition(false).map(TopLevelStatement::Function), + function::function_definition(false).map(TopLevelStatementKind::Function), structs::struct_definition(), traits::trait_definition(), traits::trait_implementation(), @@ -217,7 +164,7 @@ pub fn top_level_statement<'a>( module_declaration().then_ignore(force(just(Token::Semicolon))), use_statement().then_ignore(force(just(Token::Semicolon))), global_declaration().then_ignore(force(just(Token::Semicolon))), - inner_attribute().map(TopLevelStatement::InnerAttribute), + inner_attribute().map(TopLevelStatementKind::InnerAttribute), )) .recover_via(top_level_statement_recovery()) } @@ -225,9 +172,15 @@ pub fn top_level_statement<'a>( /// Parses a non-trait implementation, adding a set of methods to a type. /// /// implementation: 'impl' generics type '{' function_definition ... '}' -fn implementation() -> impl NoirParser { +fn implementation() -> impl NoirParser { + let method = spanned(function::function_definition(true)); + let methods = outer_doc_comments() + .then(method) + .map(|(doc_comments, (method, span))| (Documented::new(method, doc_comments), span)) + .repeated(); + let methods_or_error = just(Token::LeftBrace) - .ignore_then(spanned(function::function_definition(true)).repeated()) + .ignore_then(methods) .then_ignore(just(Token::RightBrace)) .or_not() .validate(|methods, span, emit| { @@ -250,7 +203,7 @@ fn implementation() -> impl NoirParser { .map(|args| { let ((other_args, where_clause), methods) = args; let (generics, (object_type, type_span)) = other_args; - TopLevelStatement::Impl(TypeImpl { + TopLevelStatementKind::Impl(TypeImpl { generics, object_type, type_span, @@ -261,7 +214,7 @@ fn implementation() -> impl NoirParser { } /// global_declaration: 'global' ident global_type_annotation '=' literal -fn global_declaration() -> impl NoirParser { +fn global_declaration() -> impl NoirParser { let p = attributes::attributes() .then(maybe_comp_time()) .then(spanned(keyword(Keyword::Mut)).or_not()) @@ -285,11 +238,13 @@ fn global_declaration() -> impl NoirParser { LetStatement { pattern, r#type, comptime, expression, attributes: global_attributes } }, ) - .map(TopLevelStatement::Global) + .map(TopLevelStatementKind::Global) } /// submodule: 'mod' ident '{' module '}' -fn submodule(module_parser: impl NoirParser) -> impl NoirParser { +fn submodule( + module_parser: impl NoirParser, +) -> impl NoirParser { attributes() .then_ignore(keyword(Keyword::Mod)) .then(ident()) @@ -298,7 +253,7 @@ fn submodule(module_parser: impl NoirParser) -> impl NoirParser) -> impl NoirParser) -> impl NoirParser { +fn contract( + module_parser: impl NoirParser, +) -> impl NoirParser { attributes() .then_ignore(keyword(Keyword::Contract)) .then(ident()) @@ -317,7 +274,7 @@ fn contract(module_parser: impl NoirParser) -> impl NoirParser) -> impl NoirParser impl NoirParser { +fn type_alias_definition() -> impl NoirParser { use self::Keyword::Type; let p = ignore_then_commit(keyword(Type), ident()); @@ -335,7 +292,7 @@ fn type_alias_definition() -> impl NoirParser { let p = then_commit(p, parse_type()); p.map_with_span(|((name, generics), typ), span| { - TopLevelStatement::TypeAlias(NoirTypeAlias { name, generics, typ, span }) + TopLevelStatementKind::TypeAlias(NoirTypeAlias { name, generics, typ, span }) }) } @@ -450,20 +407,20 @@ fn optional_type_annotation<'a>() -> impl NoirParser + 'a { }) } -fn module_declaration() -> impl NoirParser { +fn module_declaration() -> impl NoirParser { attributes().then_ignore(keyword(Keyword::Mod)).then(ident()).validate( |(attributes, ident), span, emit| { let attributes = validate_secondary_attributes(attributes, span, emit); - TopLevelStatement::Module(ModuleDeclaration { ident, outer_attributes: attributes }) + TopLevelStatementKind::Module(ModuleDeclaration { ident, outer_attributes: attributes }) }, ) } -fn use_statement() -> impl NoirParser { +fn use_statement() -> impl NoirParser { item_visibility() .then_ignore(keyword(Keyword::Use)) .then(use_tree()) - .map(|(visibility, use_tree)| TopLevelStatement::Import(use_tree, visibility)) + .map(|(visibility, use_tree)| TopLevelStatementKind::Import(use_tree, visibility)) } fn rename() -> impl NoirParser> { @@ -1580,12 +1537,12 @@ mod test { for (use_statement_str, expect_valid) in use_statements { let mut use_statement_str = use_statement_str.to_string(); - let expected_use_statement = if expect_valid { + if expect_valid { let (result_opt, _diagnostics) = parse_recover(&use_statement(), &use_statement_str); use_statement_str.push(';'); match result_opt.unwrap() { - TopLevelStatement::Import(expected_use_statement, _visibility) => { + TopLevelStatementKind::Import(expected_use_statement, _visibility) => { Some(expected_use_statement) } _ => unreachable!(), @@ -1595,8 +1552,6 @@ mod test { assert!(result.is_err()); None }; - - prototype_parse_use_tree(expected_use_statement.as_ref(), &use_statement_str); } } @@ -1842,7 +1797,7 @@ mod test { 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 { + let TopLevelStatementKind::Impl(impl_) = top_level_statement else { panic!("Expected to parse an impl"); }; diff --git a/compiler/noirc_frontend/src/parser/parser/doc_comments.rs b/compiler/noirc_frontend/src/parser/parser/doc_comments.rs new file mode 100644 index 00000000000..151ff21017f --- /dev/null +++ b/compiler/noirc_frontend/src/parser/parser/doc_comments.rs @@ -0,0 +1,36 @@ +use chumsky::Parser; + +use crate::{ + parser::NoirParser, + token::{DocStyle, Token, TokenKind}, +}; + +use super::primitives::token_kind; + +fn outer_doc_comment() -> impl NoirParser { + token_kind(TokenKind::OuterDocComment).map(|token| match token { + Token::LineComment(comment, Some(DocStyle::Outer)) => comment, + Token::BlockComment(comment, Some(DocStyle::Outer)) => comment, + _ => unreachable!( + "Parser should have already errored due to token not being an outer doc comment" + ), + }) +} + +pub(super) fn outer_doc_comments() -> impl NoirParser> { + outer_doc_comment().repeated() +} + +fn inner_doc_comment() -> impl NoirParser { + token_kind(TokenKind::InnerDocComment).map(|token| match token { + Token::LineComment(comment, Some(DocStyle::Inner)) => comment, + Token::BlockComment(comment, Some(DocStyle::Inner)) => comment, + _ => unreachable!( + "Parser should have already errored due to token not being an inner doc comment" + ), + }) +} + +pub(super) fn inner_doc_comments() -> impl NoirParser> { + inner_doc_comment().repeated() +} diff --git a/compiler/noirc_frontend/src/parser/parser/structs.rs b/compiler/noirc_frontend/src/parser/parser/structs.rs index 58bf1693eee..66d30a6f407 100644 --- a/compiler/noirc_frontend/src/parser/parser/structs.rs +++ b/compiler/noirc_frontend/src/parser/parser/structs.rs @@ -1,6 +1,6 @@ use chumsky::prelude::*; -use crate::ast::{Ident, NoirStruct, UnresolvedType}; +use crate::ast::{Documented, NoirStruct, StructField}; use crate::{ parser::{ parser::{ @@ -8,12 +8,14 @@ use crate::{ function, parse_type, primitives::{ident, keyword}, }, - NoirParser, TopLevelStatement, + NoirParser, TopLevelStatementKind, }, token::{Keyword, Token}, }; -pub(super) fn struct_definition() -> impl NoirParser { +use super::doc_comments::outer_doc_comments; + +pub(super) fn struct_definition() -> impl NoirParser { use self::Keyword::Struct; use Token::*; @@ -34,16 +36,16 @@ pub(super) fn struct_definition() -> impl NoirParser { .then(fields) .validate(|(((attributes, name), generics), fields), span, emit| { let attributes = validate_secondary_attributes(attributes, span, emit); - TopLevelStatement::Struct(NoirStruct { name, attributes, generics, fields, span }) + TopLevelStatementKind::Struct(NoirStruct { name, attributes, generics, fields, span }) }) } -fn struct_fields() -> impl NoirParser> { - ident() - .then_ignore(just(Token::Colon)) - .then(parse_type()) - .separated_by(just(Token::Comma)) - .allow_trailing() +fn struct_fields() -> impl NoirParser>> { + let field = ident().then_ignore(just(Token::Colon)).then(parse_type()); + let field = outer_doc_comments().then(field).map(|(doc_comments, (name, typ))| { + Documented::new(StructField { name, typ }, doc_comments) + }); + field.separated_by(just(Token::Comma)).allow_trailing() } #[cfg(test)] diff --git a/compiler/noirc_frontend/src/parser/parser/traits.rs b/compiler/noirc_frontend/src/parser/parser/traits.rs index bf5a4b4d0b4..cb17bf2caf7 100644 --- a/compiler/noirc_frontend/src/parser/parser/traits.rs +++ b/compiler/noirc_frontend/src/parser/parser/traits.rs @@ -1,6 +1,7 @@ use chumsky::prelude::*; use super::attributes::{attributes, validate_secondary_attributes}; +use super::doc_comments::outer_doc_comments; use super::function::function_return_type; use super::path::path_no_turbofish; use super::{ @@ -8,21 +9,21 @@ use super::{ }; use crate::ast::{ - Expression, ItemVisibility, NoirTrait, NoirTraitImpl, TraitBound, TraitImplItem, TraitItem, - UnresolvedTraitConstraint, UnresolvedType, + Documented, Expression, ItemVisibility, NoirTrait, NoirTraitImpl, TraitBound, TraitImplItem, + TraitItem, UnresolvedTraitConstraint, UnresolvedType, }; use crate::macros_api::Pattern; use crate::{ parser::{ ignore_then_commit, parenthesized, parser::primitives::keyword, NoirParser, ParserError, - ParserErrorReason, TopLevelStatement, + ParserErrorReason, TopLevelStatementKind, }, token::{Keyword, Token}, }; use super::{generic_type_args, parse_type, primitives::ident}; -pub(super) fn trait_definition() -> impl NoirParser { +pub(super) fn trait_definition() -> impl NoirParser { let trait_body_or_error = just(Token::LeftBrace) .ignore_then(trait_body()) .then_ignore(just(Token::RightBrace)) @@ -47,7 +48,7 @@ pub(super) fn trait_definition() -> 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 { + TopLevelStatementKind::Trait(NoirTrait { name, generics, where_clause, @@ -58,10 +59,12 @@ pub(super) fn trait_definition() -> impl NoirParser { }) } -fn trait_body() -> impl NoirParser> { - trait_function_declaration() - .or(trait_type_declaration()) - .or(trait_constant_declaration()) +fn trait_body() -> impl NoirParser>> { + let item = + trait_function_declaration().or(trait_type_declaration()).or(trait_constant_declaration()); + outer_doc_comments() + .then(item) + .map(|(doc_comments, item)| Documented::new(item, doc_comments)) .repeated() } @@ -122,7 +125,7 @@ fn trait_type_declaration() -> impl NoirParser { /// and an optional `where` clause is also useable. /// /// trait_implementation: 'impl' generics ident generic_args for type '{' trait_implementation_body '}' -pub(super) fn trait_implementation() -> impl NoirParser { +pub(super) fn trait_implementation() -> impl NoirParser { let body_or_error = just(Token::LeftBrace) .ignore_then(trait_implementation_body()) @@ -152,7 +155,7 @@ 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 { + TopLevelStatementKind::TraitImpl(NoirTraitImpl { impl_generics, trait_name, trait_generics, @@ -163,7 +166,7 @@ pub(super) fn trait_implementation() -> impl NoirParser { }) } -fn trait_implementation_body() -> impl NoirParser> { +fn trait_implementation_body() -> impl NoirParser>> { let function = function::function_definition(true).validate(|mut f, span, emit| { if f.def().is_unconstrained || f.def().visibility != ItemVisibility::Private { emit(ParserError::with_reason(ParserErrorReason::TraitImplFunctionModifiers, span)); @@ -190,7 +193,11 @@ fn trait_implementation_body() -> impl NoirParser> { }, ); - choice((function, alias, let_statement)).repeated() + let item = choice((function, alias, let_statement)); + outer_doc_comments() + .then(item) + .map(|(doc_comments, item)| Documented::new(item, doc_comments)) + .repeated() } pub(super) fn where_clause() -> impl NoirParser> { @@ -291,7 +298,7 @@ mod test { 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 { + let TopLevelStatementKind::Trait(trait_) = top_level_statement else { panic!("Expected to parse a trait"); }; @@ -308,7 +315,7 @@ mod test { 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 { + let TopLevelStatementKind::TraitImpl(trait_impl) = top_level_statement else { panic!("Expected to parse a trait impl"); }; diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index 3e01c370154..1a0f086b484 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -857,7 +857,7 @@ fn get_program_captures(src: &str) -> Vec> { let interner = context.def_interner; let mut all_captures: Vec> = Vec::new(); for func in program.into_sorted().functions { - let func_id = interner.find_function(func.name()).unwrap(); + let func_id = interner.find_function(func.item.name()).unwrap(); let hir_func = interner.function(&func_id); // Iterate over function statements and apply filtering function find_lambda_captures(hir_func.block(&interner).statements(), &interner, &mut all_captures); diff --git a/tooling/lsp/src/requests/completion.rs b/tooling/lsp/src/requests/completion.rs index dad0d37aba7..f861c8113df 100644 --- a/tooling/lsp/src/requests/completion.rs +++ b/tooling/lsp/src/requests/completion.rs @@ -4,10 +4,7 @@ use std::{ }; use async_lsp::ResponseError; -use completion_items::{ - crate_completion_item, field_completion_item, simple_completion_item, snippet_completion_item, - struct_field_completion_item, -}; +use completion_items::{field_completion_item, simple_completion_item, snippet_completion_item}; use convert_case::{Case, Casing}; use fm::{FileId, FileMap, PathString}; use kinds::{FunctionCompletionKind, FunctionKind, RequestedItems}; @@ -183,20 +180,23 @@ impl<'a> NodeFinder<'a> { let struct_type = struct_type.borrow(); // First get all of the struct's fields - let mut fields = HashMap::new(); - let fields_as_written = struct_type.get_fields_as_written(); - for (field, typ) in &fields_as_written { - fields.insert(field, typ); - } + let mut fields: Vec<_> = + struct_type.get_fields_as_written().into_iter().enumerate().collect(); // Remove the ones that already exists in the constructor - for (field, _) in &constructor_expression.fields { - fields.remove(&field.0.contents); + for (used_name, _) in &constructor_expression.fields { + fields.retain(|(_, (name, _))| name != &used_name.0.contents); } let self_prefix = false; - for (field, typ) in fields { - self.completion_items.push(struct_field_completion_item(field, typ, self_prefix)); + for (field_index, (field, typ)) in &fields { + self.completion_items.push(self.struct_field_completion_item( + field, + typ, + struct_type.id, + *field_index, + self_prefix, + )); } } @@ -652,9 +652,15 @@ impl<'a> NodeFinder<'a> { prefix: &str, self_prefix: bool, ) { - for (name, typ) in &struct_type.get_fields(generics) { + for (field_index, (name, typ)) in struct_type.get_fields(generics).iter().enumerate() { if name_matches(name, prefix) { - self.completion_items.push(struct_field_completion_item(name, typ, self_prefix)); + self.completion_items.push(self.struct_field_completion_item( + name, + typ, + struct_type.id, + field_index, + self_prefix, + )); } } } @@ -746,7 +752,10 @@ impl<'a> NodeFinder<'a> { for dependency in self.dependencies { let dependency_name = dependency.as_name(); if name_matches(&dependency_name, prefix) { - self.completion_items.push(crate_completion_item(dependency_name)); + let root_id = self.def_maps[&dependency.crate_id].root(); + let module_id = ModuleId { krate: dependency.crate_id, local_id: root_id }; + self.completion_items + .push(self.crate_completion_item(dependency_name, module_id)); } } @@ -937,7 +946,7 @@ impl<'a> Visitor for NodeFinder<'a> { self.collect_type_parameters_in_generics(&noir_trait_impl.impl_generics); for item in &noir_trait_impl.items { - item.accept(self); + item.item.accept(self); } self.type_parameters.clear(); @@ -952,7 +961,7 @@ impl<'a> Visitor for NodeFinder<'a> { self.collect_type_parameters_in_generics(&type_impl.generics); for (method, span) in &type_impl.methods { - method.accept(*span, self); + method.item.accept(*span, self); // Optimization: stop looking in functions past the completion cursor if span.end() as usize > self.byte_index { @@ -973,8 +982,8 @@ impl<'a> Visitor for NodeFinder<'a> { self.type_parameters.clear(); self.collect_type_parameters_in_generics(&noir_struct.generics); - for (_name, unresolved_type) in &noir_struct.fields { - unresolved_type.accept(self); + for field in &noir_struct.fields { + field.item.typ.accept(self); } self.type_parameters.clear(); diff --git a/tooling/lsp/src/requests/completion/completion_items.rs b/tooling/lsp/src/requests/completion/completion_items.rs index c3afc225f52..aa959b226b0 100644 --- a/tooling/lsp/src/requests/completion/completion_items.rs +++ b/tooling/lsp/src/requests/completion/completion_items.rs @@ -1,11 +1,13 @@ use lsp_types::{ - Command, CompletionItem, CompletionItemKind, CompletionItemLabelDetails, InsertTextFormat, + Command, CompletionItem, CompletionItemKind, CompletionItemLabelDetails, Documentation, + InsertTextFormat, MarkupContent, MarkupKind, }; use noirc_frontend::{ ast::AttributeTarget, + hir::def_map::ModuleId, hir_def::{function::FuncMeta, stmt::HirPattern}, - macros_api::ModuleDefId, - node_interner::{FuncId, GlobalId}, + macros_api::{ModuleDefId, StructId}, + node_interner::{FuncId, GlobalId, ReferenceId, TraitId, TypeAliasId}, QuotedType, Type, }; @@ -54,7 +56,7 @@ impl<'a> NodeFinder<'a> { }; match module_def_id { - ModuleDefId::ModuleId(_) => Some(module_completion_item(name)), + ModuleDefId::ModuleId(id) => Some(self.module_completion_item(name, id)), ModuleDefId::FunctionId(func_id) => self.function_completion_item( &name, func_id, @@ -63,23 +65,61 @@ impl<'a> NodeFinder<'a> { attribute_first_type.as_ref(), false, // self_prefix ), - ModuleDefId::TypeId(..) => Some(self.struct_completion_item(name)), - ModuleDefId::TypeAliasId(..) => Some(self.type_alias_completion_item(name)), - ModuleDefId::TraitId(..) => Some(self.trait_completion_item(name)), + ModuleDefId::TypeId(struct_id) => Some(self.struct_completion_item(name, struct_id)), + ModuleDefId::TypeAliasId(id) => Some(self.type_alias_completion_item(name, id)), + ModuleDefId::TraitId(trait_id) => Some(self.trait_completion_item(name, trait_id)), ModuleDefId::GlobalId(global_id) => Some(self.global_completion_item(name, global_id)), } } - fn struct_completion_item(&self, name: String) -> CompletionItem { - simple_completion_item(name.clone(), CompletionItemKind::STRUCT, Some(name)) + pub(super) fn crate_completion_item( + &self, + name: impl Into, + id: ModuleId, + ) -> CompletionItem { + self.module_completion_item(name, id) + } + + pub(super) fn module_completion_item( + &self, + name: impl Into, + id: ModuleId, + ) -> CompletionItem { + let completion_item = module_completion_item(name); + self.completion_item_with_doc_comments(ReferenceId::Module(id), completion_item) + } + + fn struct_completion_item(&self, name: String, struct_id: StructId) -> CompletionItem { + let completion_item = + simple_completion_item(name.clone(), CompletionItemKind::STRUCT, Some(name)); + self.completion_item_with_doc_comments(ReferenceId::Struct(struct_id), completion_item) } - fn type_alias_completion_item(&self, name: String) -> CompletionItem { - simple_completion_item(name.clone(), CompletionItemKind::STRUCT, Some(name)) + pub(super) fn struct_field_completion_item( + &self, + field: &str, + typ: &Type, + struct_id: StructId, + field_index: usize, + self_type: bool, + ) -> CompletionItem { + let completion_item = struct_field_completion_item(field, typ, self_type); + self.completion_item_with_doc_comments( + ReferenceId::StructMember(struct_id, field_index), + completion_item, + ) + } + + fn type_alias_completion_item(&self, name: String, id: TypeAliasId) -> CompletionItem { + let completion_item = + simple_completion_item(name.clone(), CompletionItemKind::STRUCT, Some(name)); + self.completion_item_with_doc_comments(ReferenceId::Alias(id), completion_item) } - fn trait_completion_item(&self, name: String) -> CompletionItem { - simple_completion_item(name.clone(), CompletionItemKind::INTERFACE, Some(name)) + fn trait_completion_item(&self, name: String, trait_id: TraitId) -> CompletionItem { + let completion_item = + simple_completion_item(name.clone(), CompletionItemKind::INTERFACE, Some(name)); + self.completion_item_with_doc_comments(ReferenceId::Trait(trait_id), completion_item) } fn global_completion_item(&self, name: String, global_id: GlobalId) -> CompletionItem { @@ -87,7 +127,9 @@ impl<'a> NodeFinder<'a> { let typ = self.interner.definition_type(global.definition_id); let description = typ.to_string(); - simple_completion_item(name, CompletionItemKind::CONSTANT, Some(description)) + let completion_item = + simple_completion_item(name, CompletionItemKind::CONSTANT, Some(description)); + self.completion_item_with_doc_comments(ReferenceId::Global(global_id), completion_item) } pub(super) fn function_completion_item( @@ -210,7 +252,8 @@ impl<'a> NodeFinder<'a> { completion_item_with_trigger_parameter_hints_command(completion_item) } }; - + let completion_item = + self.completion_item_with_doc_comments(ReferenceId::Function(func_id), completion_item); Some(completion_item) } @@ -259,6 +302,25 @@ impl<'a> NodeFinder<'a> { text } + fn completion_item_with_doc_comments( + &self, + id: ReferenceId, + completion_item: CompletionItem, + ) -> CompletionItem { + if let Some(doc_comments) = self.interner.doc_comments(id) { + let docs = doc_comments.join("\n"); + CompletionItem { + documentation: Some(Documentation::MarkupContent(MarkupContent { + kind: MarkupKind::Markdown, + value: docs, + })), + ..completion_item + } + } else { + completion_item + } + } + fn hir_pattern_to_argument(&self, pattern: &HirPattern, text: &mut String) { match pattern { HirPattern::Identifier(hir_ident) => { @@ -288,13 +350,6 @@ pub(super) fn module_completion_item(name: impl Into) -> CompletionItem ) } -pub(super) fn crate_completion_item(name: impl Into) -> CompletionItem { - completion_item_with_sort_text( - simple_completion_item(name, CompletionItemKind::MODULE, None), - crate_or_module_sort_text(), - ) -} - fn func_meta_type_to_string(func_meta: &FuncMeta, has_self_type: bool) -> String { let mut typ = &func_meta.typ; if let Type::Forall(_, typ_) = typ { diff --git a/tooling/lsp/src/requests/completion/tests.rs b/tooling/lsp/src/requests/completion/tests.rs index e6a732e9142..c449466fc5c 100644 --- a/tooling/lsp/src/requests/completion/tests.rs +++ b/tooling/lsp/src/requests/completion/tests.rs @@ -6,8 +6,8 @@ mod completion_tests { completion::{ completion_items::{ completion_item_with_sort_text, - completion_item_with_trigger_parameter_hints_command, crate_completion_item, - module_completion_item, simple_completion_item, snippet_completion_item, + completion_item_with_trigger_parameter_hints_command, module_completion_item, + simple_completion_item, snippet_completion_item, }, sort_text::{auto_import_sort_text, self_mismatch_sort_text}, }, @@ -208,7 +208,7 @@ mod completion_tests { let src = r#" use s>|< "#; - assert_completion(src, vec![crate_completion_item("std")]).await; + assert_completion(src, vec![module_completion_item("std")]).await; // "std" doesn't show up anymore because of the "crate::" prefix let src = r#" @@ -284,7 +284,7 @@ mod completion_tests { src, vec![ module_completion_item("something"), - crate_completion_item("std"), + module_completion_item("std"), simple_completion_item("super::", CompletionItemKind::KEYWORD, None), ], ) diff --git a/tooling/lsp/src/requests/document_symbol.rs b/tooling/lsp/src/requests/document_symbol.rs index 7d5efee2949..7ab0a45ad0a 100644 --- a/tooling/lsp/src/requests/document_symbol.rs +++ b/tooling/lsp/src/requests/document_symbol.rs @@ -171,7 +171,9 @@ impl<'a> Visitor for DocumentSymbolCollector<'a> { }; let mut children = Vec::new(); - for (field_name, typ) in &noir_struct.fields { + for field in &noir_struct.fields { + let field_name = &field.item.name; + let typ = &field.item.typ; let span = Span::from(field_name.span().start()..typ.span.end()); let Some(field_location) = self.to_lsp_location(span) else { @@ -223,7 +225,7 @@ impl<'a> Visitor for DocumentSymbolCollector<'a> { self.symbols = Vec::new(); for item in &noir_trait.items { - item.accept(self); + item.item.accept(self); } let children = std::mem::take(&mut self.symbols); @@ -350,7 +352,7 @@ impl<'a> Visitor for DocumentSymbolCollector<'a> { self.symbols = Vec::new(); for trait_impl_item in &noir_trait_impl.items { - trait_impl_item.accept(self); + trait_impl_item.item.accept(self); } let children = std::mem::take(&mut self.symbols); @@ -401,7 +403,7 @@ impl<'a> Visitor for DocumentSymbolCollector<'a> { self.symbols = Vec::new(); for (noir_function, noir_function_span) in &type_impl.methods { - noir_function.accept(*noir_function_span, self); + noir_function.item.accept(*noir_function_span, self); } let children = std::mem::take(&mut self.symbols); diff --git a/tooling/lsp/src/requests/hover.rs b/tooling/lsp/src/requests/hover.rs index ae1e57f5ecc..20333e8b728 100644 --- a/tooling/lsp/src/requests/hover.rs +++ b/tooling/lsp/src/requests/hover.rs @@ -60,30 +60,37 @@ fn format_reference(reference: ReferenceId, args: &ProcessRequestCallbackArgs) - fn format_module(id: ModuleId, args: &ProcessRequestCallbackArgs) -> Option { let crate_root = args.def_maps[&id.krate].root(); + let mut string = String::new(); + if id.local_id == crate_root { - let dep = args.dependencies.iter().find(|dep| dep.crate_id == id.krate); - return dep.map(|dep| format!(" crate {}", dep.name)); + let Some(dep) = args.dependencies.iter().find(|dep| dep.crate_id == id.krate) else { + return None; + }; + string.push_str(" crate "); + string.push_str(&dep.name.to_string()); + } else { + // Note: it's not clear why `try_module_attributes` might return None here, but it happens. + // This is a workaround to avoid panicking in that case (which brings the LSP server down). + // Cases where this happens are related to generated code, so once that stops happening + // this won't be an issue anymore. + let module_attributes = args.interner.try_module_attributes(&id)?; + + if let Some(parent_local_id) = module_attributes.parent { + if format_parent_module_from_module_id( + &ModuleId { krate: id.krate, local_id: parent_local_id }, + args, + &mut string, + ) { + string.push('\n'); + } + } + string.push_str(" "); + string.push_str("mod "); + string.push_str(&module_attributes.name); } - // Note: it's not clear why `try_module_attributes` might return None here, but it happens. - // This is a workaround to avoid panicking in that case (which brings the LSP server down). - // Cases where this happens are related to generated code, so once that stops happening - // this won't be an issue anymore. - let module_attributes = args.interner.try_module_attributes(&id)?; + append_doc_comments(args.interner, ReferenceId::Module(id), &mut string); - let mut string = String::new(); - if let Some(parent_local_id) = module_attributes.parent { - if format_parent_module_from_module_id( - &ModuleId { krate: id.krate, local_id: parent_local_id }, - args, - &mut string, - ) { - string.push('\n'); - } - } - string.push_str(" "); - string.push_str("mod "); - string.push_str(&module_attributes.name); Some(string) } @@ -108,6 +115,9 @@ fn format_struct(id: StructId, args: &ProcessRequestCallbackArgs) -> String { string.push_str(",\n"); } string.push_str(" }"); + + append_doc_comments(args.interner, ReferenceId::Struct(id), &mut string); + string } @@ -131,6 +141,9 @@ fn format_struct_member( string.push_str(": "); string.push_str(&format!("{}", field_type)); string.push_str(&go_to_type_links(field_type, args.interner, args.files)); + + append_doc_comments(args.interner, ReferenceId::StructMember(id, field_index), &mut string); + string } @@ -145,6 +158,9 @@ fn format_trait(id: TraitId, args: &ProcessRequestCallbackArgs) -> String { string.push_str("trait "); string.push_str(&a_trait.name.0.contents); format_generics(&a_trait.generics, &mut string); + + append_doc_comments(args.interner, ReferenceId::Trait(id), &mut string); + string } @@ -163,6 +179,9 @@ fn format_global(id: GlobalId, args: &ProcessRequestCallbackArgs) -> String { string.push_str(": "); string.push_str(&format!("{}", typ)); string.push_str(&go_to_type_links(&typ, args.interner, args.files)); + + append_doc_comments(args.interner, ReferenceId::Global(id), &mut string); + string } @@ -220,6 +239,8 @@ fn format_function(id: FuncId, args: &ProcessRequestCallbackArgs) -> String { string.push_str(&go_to_type_links(return_type, args.interner, args.files)); + append_doc_comments(args.interner, ReferenceId::Function(id), &mut string); + string } @@ -235,6 +256,9 @@ fn format_alias(id: TypeAliasId, args: &ProcessRequestCallbackArgs) -> String { string.push_str(&type_alias.name.0.contents); string.push_str(" = "); string.push_str(&format!("{}", &type_alias.typ)); + + append_doc_comments(args.interner, ReferenceId::Alias(id), &mut string); + string } @@ -270,6 +294,7 @@ fn format_local(id: DefinitionId, args: &ProcessRequestCallbackArgs) -> String { string } +/// Some doc comments fn format_generics(generics: &Generics, string: &mut String) { if generics.is_empty() { return; @@ -513,6 +538,16 @@ fn format_link(name: String, location: lsp_types::Location) -> String { ) } +fn append_doc_comments(interner: &NodeInterner, id: ReferenceId, string: &mut String) { + if let Some(doc_comments) = interner.doc_comments(id) { + string.push_str("\n\n---\n\n"); + for comment in doc_comments { + string.push_str(comment); + string.push('\n'); + } + } +} + #[cfg(test)] mod hover_tests { use crate::test_utils; diff --git a/tooling/nargo_fmt/src/visitor/item.rs b/tooling/nargo_fmt/src/visitor/item.rs index 9e556e0fcbe..ba9a8214702 100644 --- a/tooling/nargo_fmt/src/visitor/item.rs +++ b/tooling/nargo_fmt/src/visitor/item.rs @@ -151,7 +151,7 @@ impl super::FmtVisitor<'_> { } fn visit_module(&mut self, module: ParsedModule) { - for Item { kind, span } in module.items { + for Item { kind, span, doc_comments } in module.items { match kind { ItemKind::Function(func) => { self.visit_function(span, func); @@ -165,6 +165,11 @@ impl super::FmtVisitor<'_> { continue; } + for doc_comment in doc_comments { + self.push_str(&format!("///{doc_comment}\n")); + self.push_str(&self.indent.to_string()); + } + for attribute in module.outer_attributes { self.push_str(&format!("#[{}]\n", attribute.as_ref())); self.push_str(&self.indent.to_string()); @@ -214,7 +219,7 @@ impl super::FmtVisitor<'_> { self.indent.block_indent(self.config); for (method, span) in impl_.methods { - self.visit_function(span, method); + self.visit_function(span, method.item); } self.close_block((self.last_position..span.end() - 1).into());