From 0c4935febb80fc04f9d13246c9b2c8616b418cb6 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Thu, 1 Dec 2022 14:35:45 +0800 Subject: [PATCH] Merge multiple doc-comment lines into one. --- CHANGELOG.md | 1 + codegen/src/attrs.rs | 18 +++++-- codegen/src/rhai_module.rs | 2 +- codegen/src/test/module.rs | 16 +++--- src/ast/script_fn.rs | 8 ++- src/module/mod.rs | 41 +++++++------- src/packages/iter_basic.rs | 106 ++++++++++++++++++------------------- src/parser.rs | 19 ++++++- 8 files changed, 120 insertions(+), 91 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d13ec52..f4fb854f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,7 @@ Enhancements * `FuncArgs` is also implemented for arrays. * `Engine::set_XXX` API can now be chained. * `EvalContext::scope_mut` now returns `&mut Scope` instead of `&mut &mut Scope`. +* Line-style doc-comments are now merged into a single string to avoid creating many strings. Block-style doc-comments continue to be independent strings. Version 1.11.0 diff --git a/codegen/src/attrs.rs b/codegen/src/attrs.rs index 044252df..8e232a76 100644 --- a/codegen/src/attrs.rs +++ b/codegen/src/attrs.rs @@ -145,6 +145,7 @@ pub fn inner_item_attributes( pub fn doc_attributes(attrs: &[syn::Attribute]) -> syn::Result> { // Find the #[doc] attribute which will turn be read for function documentation. let mut comments = Vec::new(); + let mut buf = String::new(); for attr in attrs { if let Some(i) = attr.path.get_ident() { @@ -158,19 +159,30 @@ pub fn doc_attributes(attrs: &[syn::Attribute]) -> syn::Result> { if line.contains('\n') { // Must be a block comment `/** ... */` + if !buf.is_empty() { + comments.push(buf.clone()); + buf.clear(); + } line.insert_str(0, "/**"); line.push_str("*/"); + comments.push(line); } else { // Single line - assume it is `///` - line.insert_str(0, "///"); + if !buf.is_empty() { + buf.push('\n'); + } + buf.push_str("///"); + buf.push_str(&line); } - - comments.push(line); } } } } + if !buf.is_empty() { + comments.push(buf); + } + Ok(comments) } diff --git a/codegen/src/rhai_module.rs b/codegen/src/rhai_module.rs index 4e52d83d..bedccdd5 100644 --- a/codegen/src/rhai_module.rs +++ b/codegen/src/rhai_module.rs @@ -230,7 +230,7 @@ pub fn generate_body( syn::parse2::(quote! { #(#cfg_attrs)* m.set_fn_with_comments(#fn_literal, FnNamespace::#ns_str, FnAccess::Public, - #param_names, &[#(#fn_input_types),*], &[#(#comments),*], #fn_token_name().into()); + #param_names, [#(#fn_input_types),*], [#(#comments),*], #fn_token_name().into()); }) .unwrap() }); diff --git a/codegen/src/test/module.rs b/codegen/src/test/module.rs index 0a279452..abbdd3ab 100644 --- a/codegen/src/test/module.rs +++ b/codegen/src/test/module.rs @@ -92,10 +92,11 @@ mod module_tests { .cloned() .collect::>(), vec![ - "/// This is a doc-comment.", - "/// Another line.", - "/// block doc-comment ", - "/// Final line.", + "\ + /// This is a doc-comment.\n\ + /// Another line.\n\ + /// block doc-comment \n\ + /// Final line.", "/** doc-comment\n in multiple lines\n */" ] ); @@ -444,11 +445,8 @@ mod generate_tests { #[doc(hidden)] pub fn rhai_generate_into_module(m: &mut Module, flatten: bool) { m.set_fn_with_comments("get_mystic_number", FnNamespace::Internal, FnAccess::Public, - Some(get_mystic_number_token::PARAM_NAMES), &[], &[ - "/// This is a doc-comment.", - "/// Another line.", - "/// block doc-comment ", - "/// Final line.", + Some(get_mystic_number_token::PARAM_NAMES), [], [ + "/// This is a doc-comment.\n/// Another line.\n/// block doc-comment \n/// Final line.", "/** doc-comment\n in multiple lines\n */" ], get_mystic_number_token().into()); if flatten {} else {} diff --git a/src/ast/script_fn.rs b/src/ast/script_fn.rs index e523d7d7..7292563a 100644 --- a/src/ast/script_fn.rs +++ b/src/ast/script_fn.rs @@ -49,10 +49,12 @@ pub struct ScriptFnDef { /// /// Block doc-comments are kept in a single string slice with line-breaks within. /// - /// Line doc-comments are kept in one string slice per line without the termination line-break. + /// Line doc-comments are merged, with line-breaks, into a single string slice without a termination line-break. /// /// Leading white-spaces are stripped, and each string slice always starts with the /// corresponding doc-comment leader: `///` or `/**`. + /// + /// Each line in non-block doc-comments starts with `///`. #[cfg(feature = "metadata")] pub comments: Box<[Box]>, } @@ -98,10 +100,12 @@ pub struct ScriptFnMetadata<'a> { /// /// Block doc-comments are kept in a single string slice with line-breaks within. /// - /// Line doc-comments are kept in one string slice per line without the termination line-break. + /// Line doc-comments are merged, with line-breaks, into a single string slice without a termination line-break. /// /// Leading white-spaces are stripped, and each string slice always starts with the /// corresponding doc-comment leader: `///` or `/**`. + /// + /// Each line in non-block doc-comments starts with `///`. #[cfg(feature = "metadata")] pub comments: Vec<&'a str>, } diff --git a/src/module/mod.rs b/src/module/mod.rs index d540947d..2e69fa44 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -882,13 +882,10 @@ impl Module { pub fn update_fn_metadata>( &mut self, hash_fn: u64, - arg_names: impl AsRef<[S]>, + arg_names: impl IntoIterator, ) -> &mut Self { - let mut param_names: StaticVec<_> = arg_names - .as_ref() - .iter() - .map(|s| s.as_ref().into()) - .collect(); + let mut param_names: StaticVec<_> = + arg_names.into_iter().map(|s| s.as_ref().into()).collect(); if let Some(f) = self.functions.as_mut().and_then(|m| m.get_mut(&hash_fn)) { let (param_names, return_type_name) = if param_names.len() > f.metadata.num_params { @@ -920,32 +917,30 @@ impl Module { /// /// ## Comments /// - /// Block doc-comments should be kept in a single line. + /// Block doc-comments should be kept in a separate string slice. /// - /// Line doc-comments should be kept in one string slice per line without the termination line-break. + /// Line doc-comments should be merged, with line-breaks, into a single string slice without a final termination line-break. /// /// Leading white-spaces should be stripped, and each string slice always starts with the corresponding /// doc-comment leader: `///` or `/**`. + /// + /// Each line in non-block doc-comments should start with `///`. #[cfg(feature = "metadata")] #[inline] pub fn update_fn_metadata_with_comments, C: AsRef>( &mut self, hash_fn: u64, - arg_names: impl AsRef<[A]>, - comments: impl AsRef<[C]>, + arg_names: impl IntoIterator, + comments: impl IntoIterator, ) -> &mut Self { self.update_fn_metadata(hash_fn, arg_names); - let comments = comments.as_ref(); - - if !comments.is_empty() { - let f = self - .functions - .as_mut() - .and_then(|m| m.get_mut(&hash_fn)) - .unwrap(); - f.metadata.comments = comments.iter().map(|s| s.as_ref().into()).collect(); - } + self.functions + .as_mut() + .and_then(|m| m.get_mut(&hash_fn)) + .unwrap() + .metadata + .comments = comments.into_iter().map(|s| s.as_ref().into()).collect(); self } @@ -1099,12 +1094,14 @@ impl Module { /// /// ## Comments /// - /// Block doc-comments should be kept in a single line. + /// Block doc-comments should be kept in a separate string slice. /// - /// Line doc-comments should be kept in one string slice per line without the termination line-break. + /// Line doc-comments should be merged, with line-breaks, into a single string slice without a final termination line-break. /// /// Leading white-spaces should be stripped, and each string slice always starts with the corresponding /// doc-comment leader: `///` or `/**`. + /// + /// Each line in non-block doc-comments should start with `///`. #[cfg(feature = "metadata")] #[inline] pub fn set_fn_with_comments>( diff --git a/src/packages/iter_basic.rs b/src/packages/iter_basic.rs index 41dc2409..9e4588c6 100644 --- a/src/packages/iter_basic.rs +++ b/src/packages/iter_basic.rs @@ -235,18 +235,18 @@ macro_rules! reg_range { concat!("from: ", stringify!($y)), concat!("to: ", stringify!($y)), concat!("Iterator<", stringify!($y), ">"), - ], [ - "/// Return an iterator over the exclusive range of `from..to`.", - "/// The value `to` is never included.", - "///", - "/// # Example", - "///", - "/// ```rhai", - "/// // prints all values from 8 to 17", - "/// for n in range(8, 18) {", - "/// print(n);", - "/// }", - "/// ```" + ], ["\ + /// Return an iterator over the exclusive range of `from..to`.\n\ + /// The value `to` is never included.\n\ + ///\n\ + /// # Example\n\ + ///\n\ + /// ```rhai\n\ + /// // prints all values from 8 to 17\n\ + /// for n in range(8, 18) {\n\ + /// print(n);\n\ + /// }\n\ + /// ```" ]); $lib.set_iterator::>(); @@ -269,27 +269,27 @@ macro_rules! reg_range { concat!("to: ", stringify!($y)), concat!("step: ", stringify!($y)), concat!("Iterator<", stringify!($y), ">") - ], [ - "/// Return an iterator over the exclusive range of `from..to`, each iteration increasing by `step`.", - "/// The value `to` is never included.", - "///", - "/// If `from` > `to` and `step` < 0, iteration goes backwards.", - "///", - "/// If `from` > `to` and `step` > 0 or `from` < `to` and `step` < 0, an empty iterator is returned.", - "///", - "/// # Example", - "///", - "/// ```rhai", - "/// // prints all values from 8 to 17 in steps of 3", - "/// for n in range(8, 18, 3) {", - "/// print(n);", - "/// }", - "///", - "/// // prints all values down from 18 to 9 in steps of -3", - "/// for n in range(18, 8, -3) {", - "/// print(n);", - "/// }", - "/// ```" + ], ["\ + /// Return an iterator over the exclusive range of `from..to`, each iteration increasing by `step`.\n\ + /// The value `to` is never included.\n\ + ///\n\ + /// If `from` > `to` and `step` < 0, iteration goes backwards.\n\ + ///\n\ + /// If `from` > `to` and `step` > 0 or `from` < `to` and `step` < 0, an empty iterator is returned.\n\ + ///\n\ + /// # Example\n\ + ///\n\ + /// ```rhai\n\ + /// // prints all values from 8 to 17 in steps of 3\n\ + /// for n in range(8, 18, 3) {\n\ + /// print(n);\n\ + /// }\n\ + ///\n\ + /// // prints all values down from 18 to 9 in steps of -3\n\ + /// for n in range(18, 8, -3) {\n\ + /// print(n);\n\ + /// }\n\ + /// ```" ]); let _hash = $lib.set_native_fn($x, |range: std::ops::Range<$y>, step: $y| StepRange::new(range.start, range.end, step, $add)); @@ -299,26 +299,26 @@ macro_rules! reg_range { concat!("range: Range<", stringify!($y), ">"), concat!("step: ", stringify!($y)), concat!("Iterator<", stringify!($y), ">") - ], [ - "/// Return an iterator over an exclusive range, each iteration increasing by `step`.", - "///", - "/// If `range` is reversed and `step` < 0, iteration goes backwards.", - "///", - "/// Otherwise, if `range` is empty, an empty iterator is returned.", - "///", - "/// # Example", - "///", - "/// ```rhai", - "/// // prints all values from 8 to 17 in steps of 3", - "/// for n in range(8..18, 3) {", - "/// print(n);", - "/// }", - "///", - "/// // prints all values down from 18 to 9 in steps of -3", - "/// for n in range(18..8, -3) {", - "/// print(n);", - "/// }", - "/// ```" + ], ["\ + /// Return an iterator over an exclusive range, each iteration increasing by `step`.\n\ + ///\n\ + /// If `range` is reversed and `step` < 0, iteration goes backwards.\n\ + ///\n\ + /// Otherwise, if `range` is empty, an empty iterator is returned.\n\ + ///\n\ + /// # Example\n\ + ///\n\ + /// ```rhai\n\ + /// // prints all values from 8 to 17 in steps of 3\n\ + /// for n in range(8..18, 3) {\n\ + /// print(n);\n\ + /// }\n\ + ///\n\ + /// // prints all values down from 18 to 9 in steps of -3\n\ + /// for n in range(18..8, -3) {\n\ + /// print(n);\n\ + /// }\n\ + /// ```" ]); )* }; diff --git a/src/parser.rs b/src/parser.rs index 11500fae..d2584197 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3208,6 +3208,7 @@ impl Engine { let comments = { let mut comments = StaticVec::::new(); let mut comments_pos = Position::NONE; + let mut buf = SmartString::new_const(); // Handle doc-comments. while let (Token::Comment(ref comment), pos) = input.peek().expect(NEVER_ENDS) { @@ -3225,7 +3226,19 @@ impl Engine { match input.next().expect(NEVER_ENDS).0 { Token::Comment(comment) => { - comments.push(*comment); + if comment.contains('\n') { + // Assume block comment + if !buf.is_empty() { + comments.push(buf.clone()); + buf.clear(); + } + comments.push(*comment); + } else { + if !buf.is_empty() { + buf.push('\n'); + } + buf.push_str(&comment); + } match input.peek().expect(NEVER_ENDS) { (Token::Fn | Token::Private, ..) => break, @@ -3237,6 +3250,10 @@ impl Engine { } } + if !buf.is_empty() { + comments.push(buf); + } + comments };