Add doc-comment to function metadata.
This commit is contained in:
parent
26449a9f1c
commit
87174de051
@ -121,6 +121,10 @@ pub enum ParseErrorType {
|
|||||||
Reserved(String),
|
Reserved(String),
|
||||||
/// Missing an expression. Wrapped value is the expression type.
|
/// Missing an expression. Wrapped value is the expression type.
|
||||||
ExprExpected(String),
|
ExprExpected(String),
|
||||||
|
/// Defining a doc-comment in an appropriate place (e.g. not at global level).
|
||||||
|
///
|
||||||
|
/// Never appears under the `no_function` feature.
|
||||||
|
WrongDocComment,
|
||||||
/// Defining a function `fn` in an appropriate place (e.g. inside another function).
|
/// Defining a function `fn` in an appropriate place (e.g. inside another function).
|
||||||
///
|
///
|
||||||
/// Never appears under the `no_function` feature.
|
/// Never appears under the `no_function` feature.
|
||||||
@ -189,6 +193,7 @@ impl ParseErrorType {
|
|||||||
Self::FnMissingParams(_) => "Expecting parameters in function declaration",
|
Self::FnMissingParams(_) => "Expecting parameters in function declaration",
|
||||||
Self::FnDuplicatedParam(_,_) => "Duplicated parameters in function declaration",
|
Self::FnDuplicatedParam(_,_) => "Duplicated parameters in function declaration",
|
||||||
Self::FnMissingBody(_) => "Expecting body statement block for function declaration",
|
Self::FnMissingBody(_) => "Expecting body statement block for function declaration",
|
||||||
|
Self::WrongDocComment => "Doc-comment must be followed immediately by a function definition",
|
||||||
Self::WrongFnDefinition => "Function definitions must be at global level and cannot be inside a block or another function",
|
Self::WrongFnDefinition => "Function definitions must be at global level and cannot be inside a block or another function",
|
||||||
Self::WrongExport => "Export statement can only appear at global level",
|
Self::WrongExport => "Export statement can only appear at global level",
|
||||||
Self::AssignmentToConstant(_) => "Cannot assign to a constant value",
|
Self::AssignmentToConstant(_) => "Cannot assign to a constant value",
|
||||||
@ -243,7 +248,9 @@ impl fmt::Display for ParseErrorType {
|
|||||||
Self::LiteralTooLarge(typ, max) => {
|
Self::LiteralTooLarge(typ, max) => {
|
||||||
write!(f, "{} exceeds the maximum limit ({})", typ, max)
|
write!(f, "{} exceeds the maximum limit ({})", typ, max)
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::Reserved(s) => write!(f, "'{}' is a reserved keyword", s),
|
Self::Reserved(s) => write!(f, "'{}' is a reserved keyword", s),
|
||||||
|
|
||||||
_ => f.write_str(self.desc()),
|
_ => f.write_str(self.desc()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ use crate::stdlib::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
use crate::syntax::CustomSyntax;
|
use crate::syntax::CustomSyntax;
|
||||||
use crate::token::{is_keyword_function, is_valid_identifier, Token, TokenStream};
|
use crate::token::{is_doc_comment, is_keyword_function, is_valid_identifier, Token, TokenStream};
|
||||||
use crate::utils::{get_hasher, StraightHasherBuilder};
|
use crate::utils::{get_hasher, StraightHasherBuilder};
|
||||||
use crate::{
|
use crate::{
|
||||||
calc_script_fn_hash, Dynamic, Engine, ImmutableString, LexError, ParseError, ParseErrorType,
|
calc_script_fn_hash, Dynamic, Engine, ImmutableString, LexError, ParseError, ParseErrorType,
|
||||||
@ -54,8 +54,6 @@ struct ParseState<'e> {
|
|||||||
/// Tracks a list of external variables (variables that are not explicitly declared in the scope).
|
/// Tracks a list of external variables (variables that are not explicitly declared in the scope).
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
externals: HashMap<ImmutableString, Position>,
|
externals: HashMap<ImmutableString, Position>,
|
||||||
/// Latest global comments block.
|
|
||||||
comments: Vec<String>,
|
|
||||||
/// An indicator that disables variable capturing into externals one single time
|
/// An indicator that disables variable capturing into externals one single time
|
||||||
/// up until the nearest consumed Identifier token.
|
/// up until the nearest consumed Identifier token.
|
||||||
/// If set to false the next call to `access_var` will not capture the variable.
|
/// If set to false the next call to `access_var` will not capture the variable.
|
||||||
@ -100,7 +98,6 @@ impl<'e> ParseState<'e> {
|
|||||||
strings: HashMap::with_capacity(64),
|
strings: HashMap::with_capacity(64),
|
||||||
stack: Vec::with_capacity(16),
|
stack: Vec::with_capacity(16),
|
||||||
entry_stack_len: 0,
|
entry_stack_len: 0,
|
||||||
comments: Default::default(),
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
modules: Default::default(),
|
modules: Default::default(),
|
||||||
}
|
}
|
||||||
@ -2400,6 +2397,37 @@ fn parse_stmt(
|
|||||||
) -> Result<Option<Stmt>, ParseError> {
|
) -> Result<Option<Stmt>, ParseError> {
|
||||||
use AccessMode::{ReadOnly, ReadWrite};
|
use AccessMode::{ReadOnly, ReadWrite};
|
||||||
|
|
||||||
|
let mut fn_comments: Vec<String> = Default::default();
|
||||||
|
let mut fn_comments_pos = Position::NONE;
|
||||||
|
|
||||||
|
// Handle doc-comment.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
while let (Token::Comment(ref comment), comment_pos) = input.peek().unwrap() {
|
||||||
|
if fn_comments_pos.is_none() {
|
||||||
|
fn_comments_pos = *comment_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !is_doc_comment(comment) {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
|
||||||
|
if !settings.is_global {
|
||||||
|
return Err(PERR::WrongDocComment.into_err(fn_comments_pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Token::Comment(comment) = input.next().unwrap().0 {
|
||||||
|
fn_comments.push(comment);
|
||||||
|
|
||||||
|
match input.peek().unwrap() {
|
||||||
|
(Token::Fn, _) | (Token::Private, _) => break,
|
||||||
|
(Token::Comment(_), _) => (),
|
||||||
|
_ => return Err(PERR::WrongDocComment.into_err(fn_comments_pos)),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let (token, token_pos) = match input.peek().unwrap() {
|
let (token, token_pos) = match input.peek().unwrap() {
|
||||||
(Token::EOF, pos) => return Ok(Some(Stmt::Noop(*pos))),
|
(Token::EOF, pos) => return Ok(Some(Stmt::Noop(*pos))),
|
||||||
x => x,
|
x => x,
|
||||||
@ -2452,8 +2480,6 @@ fn parse_stmt(
|
|||||||
pos: pos,
|
pos: pos,
|
||||||
};
|
};
|
||||||
|
|
||||||
let fn_comments = state.comments.clone();
|
|
||||||
|
|
||||||
let func = parse_fn(input, &mut new_state, lib, access, settings, fn_comments)?;
|
let func = parse_fn(input, &mut new_state, lib, access, settings, fn_comments)?;
|
||||||
|
|
||||||
// Qualifiers (none) + function name + number of arguments.
|
// Qualifiers (none) + function name + number of arguments.
|
||||||
|
55
src/token.rs
55
src/token.rs
@ -355,6 +355,9 @@ impl Token {
|
|||||||
Custom(s) => s.clone().into(),
|
Custom(s) => s.clone().into(),
|
||||||
LexError(err) => err.to_string().into(),
|
LexError(err) => err.to_string().into(),
|
||||||
|
|
||||||
|
Comment(s) if is_doc_comment(s) => s[..3].to_string().into(),
|
||||||
|
Comment(s) => s[..2].to_string().into(),
|
||||||
|
|
||||||
token => match token {
|
token => match token {
|
||||||
LeftBrace => "{",
|
LeftBrace => "{",
|
||||||
RightBrace => "}",
|
RightBrace => "}",
|
||||||
@ -917,36 +920,36 @@ fn eat_next(stream: &mut impl InputStream, pos: &mut Position) -> Option<char> {
|
|||||||
/// Scan for a block comment until the end.
|
/// Scan for a block comment until the end.
|
||||||
fn scan_comment(
|
fn scan_comment(
|
||||||
stream: &mut impl InputStream,
|
stream: &mut impl InputStream,
|
||||||
state: &mut TokenizeState,
|
mut level: usize,
|
||||||
pos: &mut Position,
|
pos: &mut Position,
|
||||||
comment: &mut String,
|
comment: &mut String,
|
||||||
) {
|
) -> usize {
|
||||||
while let Some(c) = stream.get_next() {
|
while let Some(c) = stream.get_next() {
|
||||||
pos.advance();
|
pos.advance();
|
||||||
|
|
||||||
if state.include_comments {
|
if !comment.is_empty() {
|
||||||
comment.push(c);
|
comment.push(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
match c {
|
match c {
|
||||||
'/' => {
|
'/' => {
|
||||||
if let Some(c2) = stream.get_next() {
|
if let Some(c2) = stream.get_next() {
|
||||||
if state.include_comments {
|
if !comment.is_empty() {
|
||||||
comment.push(c2);
|
comment.push(c2);
|
||||||
}
|
}
|
||||||
if c2 == '*' {
|
if c2 == '*' {
|
||||||
state.comment_level += 1;
|
level += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pos.advance();
|
pos.advance();
|
||||||
}
|
}
|
||||||
'*' => {
|
'*' => {
|
||||||
if let Some(c2) = stream.get_next() {
|
if let Some(c2) = stream.get_next() {
|
||||||
if state.include_comments {
|
if !comment.is_empty() {
|
||||||
comment.push(c2);
|
comment.push(c2);
|
||||||
}
|
}
|
||||||
if c2 == '/' {
|
if c2 == '/' {
|
||||||
state.comment_level -= 1;
|
level -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pos.advance();
|
pos.advance();
|
||||||
@ -955,10 +958,12 @@ fn scan_comment(
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
if state.comment_level == 0 {
|
if level == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
level
|
||||||
}
|
}
|
||||||
|
|
||||||
/// _(INTERNALS)_ Get the next token from the `stream`.
|
/// _(INTERNALS)_ Get the next token from the `stream`.
|
||||||
@ -1012,6 +1017,12 @@ fn is_binary_char(c: char) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test if the comment block is a doc-comment.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn is_doc_comment(comment: &str) -> bool {
|
||||||
|
comment.starts_with("///") || comment.starts_with("/**")
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the next token.
|
/// Get the next token.
|
||||||
fn get_next_token_inner(
|
fn get_next_token_inner(
|
||||||
stream: &mut impl InputStream,
|
stream: &mut impl InputStream,
|
||||||
@ -1022,9 +1033,9 @@ fn get_next_token_inner(
|
|||||||
if state.comment_level > 0 {
|
if state.comment_level > 0 {
|
||||||
let start_pos = *pos;
|
let start_pos = *pos;
|
||||||
let mut comment = String::new();
|
let mut comment = String::new();
|
||||||
scan_comment(stream, state, pos, &mut comment);
|
state.comment_level = scan_comment(stream, state.comment_level, pos, &mut comment);
|
||||||
|
|
||||||
if state.include_comments {
|
if state.include_comments || is_doc_comment(&comment) {
|
||||||
return Some((Token::Comment(comment), start_pos));
|
return Some((Token::Comment(comment), start_pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1271,10 +1282,10 @@ fn get_next_token_inner(
|
|||||||
('/', '/') => {
|
('/', '/') => {
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
|
|
||||||
let mut comment = if state.include_comments {
|
let mut comment = match stream.peek_next().unwrap() {
|
||||||
"//".to_string()
|
'/' => "///".to_string(),
|
||||||
} else {
|
_ if state.include_comments => "//".to_string(),
|
||||||
String::new()
|
_ => String::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
while let Some(c) = stream.get_next() {
|
while let Some(c) = stream.get_next() {
|
||||||
@ -1283,13 +1294,13 @@ fn get_next_token_inner(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if state.include_comments {
|
if !comment.is_empty() {
|
||||||
comment.push(c);
|
comment.push(c);
|
||||||
}
|
}
|
||||||
pos.advance();
|
pos.advance();
|
||||||
}
|
}
|
||||||
|
|
||||||
if state.include_comments {
|
if state.include_comments || is_doc_comment(&comment) {
|
||||||
return Some((Token::Comment(comment), start_pos));
|
return Some((Token::Comment(comment), start_pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1298,14 +1309,14 @@ fn get_next_token_inner(
|
|||||||
|
|
||||||
eat_next(stream, pos);
|
eat_next(stream, pos);
|
||||||
|
|
||||||
let mut comment = if state.include_comments {
|
let mut comment = match stream.peek_next().unwrap() {
|
||||||
"/*".to_string()
|
'*' => "/**".to_string(),
|
||||||
} else {
|
_ if state.include_comments => "/*".to_string(),
|
||||||
String::new()
|
_ => String::new(),
|
||||||
};
|
};
|
||||||
scan_comment(stream, state, pos, &mut comment);
|
state.comment_level = scan_comment(stream, state.comment_level, pos, &mut comment);
|
||||||
|
|
||||||
if state.include_comments {
|
if state.include_comments || is_doc_comment(&comment) {
|
||||||
return Some((Token::Comment(comment), start_pos));
|
return Some((Token::Comment(comment), start_pos));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user