diff --git a/src/api/compile.rs b/src/api/compile.rs index 9605a609..b9e95e50 100644 --- a/src/api/compile.rs +++ b/src/api/compile.rs @@ -2,7 +2,6 @@ use crate::parser::{ParseResult, ParseState}; use crate::{Engine, OptimizationLevel, Scope, AST}; -use std::mem; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -225,9 +224,7 @@ impl Engine { let mut state = ParseState::new(self, scope, tokenizer_control); let mut ast = self.parse(&mut stream.peekable(), &mut state, optimization_level)?; #[cfg(feature = "metadata")] - ast.set_doc(mem::take( - &mut state.tokenizer_control.borrow_mut().global_comments, - )); + ast.set_doc(state.tokenizer_control.borrow().global_comments.join("\n")); Ok(ast) } /// Compile a string containing an expression into an [`AST`], diff --git a/src/ast/ast.rs b/src/ast/ast.rs index a0c462ac..0c201593 100644 --- a/src/ast/ast.rs +++ b/src/ast/ast.rs @@ -23,7 +23,7 @@ pub struct AST { source: Identifier, /// [`AST`] documentation. #[cfg(feature = "metadata")] - doc: Vec, + doc: SmartString, /// Global statements. body: StmtBlock, /// Script-defined functions. @@ -47,7 +47,7 @@ impl fmt::Debug for AST { fp.field("source", &self.source); #[cfg(feature = "metadata")] - fp.field("doc", &self.doc()); + fp.field("doc", &self.doc); #[cfg(not(feature = "no_module"))] fp.field("resolver", &self.resolver); @@ -76,7 +76,7 @@ impl AST { Self { source: Identifier::new_const(), #[cfg(feature = "metadata")] - doc: Vec::new(), + doc: SmartString::new_const(), body: StmtBlock::new(statements, Position::NONE, Position::NONE), #[cfg(not(feature = "no_function"))] lib: functions.into(), @@ -96,7 +96,7 @@ impl AST { Self { source: Identifier::new_const(), #[cfg(feature = "metadata")] - doc: Vec::new(), + doc: SmartString::new_const(), body: StmtBlock::new(statements, Position::NONE, Position::NONE), #[cfg(not(feature = "no_function"))] lib: functions.into(), @@ -146,7 +146,7 @@ impl AST { Self { source: Identifier::new_const(), #[cfg(feature = "metadata")] - doc: Vec::new(), + doc: SmartString::new_const(), body: StmtBlock::NONE, #[cfg(not(feature = "no_function"))] lib: crate::Module::new().into(), @@ -187,17 +187,19 @@ impl AST { self.source.clear(); self } - /// Get the documentation. + /// Get the documentation (if any). + /// Exported under the `metadata` feature only. /// - /// Only available under `metadata`. + /// Documentation is a collection of all comment lines beginning with `//!`. + /// + /// Leading white-spaces are stripped, and each line always starts with `//!`. #[cfg(feature = "metadata")] #[inline(always)] - pub fn doc(&self) -> String { - self.doc.join("\n") + pub fn doc(&self) -> &str { + &self.doc } /// Clear the documentation. - /// - /// Only available under `metadata`. + /// Exported under the `metadata` feature only. #[cfg(feature = "metadata")] #[inline(always)] pub fn clear_doc(&mut self) -> &mut Self { @@ -209,7 +211,7 @@ impl AST { /// Only available under `metadata`. #[cfg(feature = "metadata")] #[inline(always)] - pub(crate) fn doc_mut(&mut self) -> &mut Vec { + pub(crate) fn doc_mut(&mut self) -> &mut SmartString { &mut self.doc } /// Set the documentation. @@ -217,8 +219,8 @@ impl AST { /// Only available under `metadata`. #[cfg(feature = "metadata")] #[inline(always)] - pub(crate) fn set_doc(&mut self, doc: Vec) { - self.doc = doc; + pub(crate) fn set_doc(&mut self, doc: impl Into) { + self.doc = doc.into(); } /// Get the statements. #[cfg(not(feature = "internals"))] @@ -588,7 +590,12 @@ impl AST { } #[cfg(feature = "metadata")] - _ast.doc.extend(other.doc.iter().cloned()); + if !other.doc.is_empty() { + if !_ast.doc.is_empty() { + _ast.doc.push('\n'); + } + _ast.doc.push_str(other.doc()); + } _ast } @@ -684,7 +691,12 @@ impl AST { } #[cfg(feature = "metadata")] - self.doc.extend(other.doc.into_iter()); + if !other.doc.is_empty() { + if !self.doc.is_empty() { + self.doc.push('\n'); + } + self.doc.push_str(&other.doc); + } self } diff --git a/src/ast/script_fn.rs b/src/ast/script_fn.rs index 38edeea1..e7c44a87 100644 --- a/src/ast/script_fn.rs +++ b/src/ast/script_fn.rs @@ -45,6 +45,16 @@ pub struct ScriptFnDef { pub params: StaticVec, /// _(metadata)_ Function doc-comments (if any). /// Exported under the `metadata` feature only. + /// + /// Doc-comments are comment lines beginning with `///` or comment blocks beginning with `/**`, + /// placed immediately before a function definition. + /// + /// 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. + /// + /// Leading white-spaces are stripped, and each string slice always starts with the + /// corresponding doc-comment leader: `///` or `/**`. #[cfg(feature = "metadata")] pub comments: Box<[Box]>, } @@ -85,13 +95,15 @@ pub struct ScriptFnMetadata<'a> { /// _(metadata)_ Function doc-comments (if any). /// Exported under the `metadata` feature only. /// + /// Doc-comments are comment lines beginning with `///` or comment blocks beginning with `/**`, + /// placed immediately before a function definition. + /// /// 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. /// /// Leading white-spaces are stripped, and each string slice always starts with the /// corresponding doc-comment leader: `///` or `/**`. - /// Function access mode. #[cfg(feature = "metadata")] pub comments: Vec<&'a str>, }