// Copyright (c) ZeroC, Inc.
use crate::grammar::*;
use crate::parsers::comments::tokens::*;
use crate::parsers::comments::grammar::*;
use crate::parsers::comments::parser::CommentParser;
use crate::slice_file::Span;
// Specify the signature of the parser's entry function.
grammar<'input, 'a>(comment_parser: &mut CommentParser<'a>);
extern {
// Specify the types that the parser should use for location tracking and error emission.
type Location = crate::slice_file::Location;
type Error = crate::parsers::comments::tokens::Error<'input>;
// Link the names of terminal tokens with their actual token types. Ex: `identifier => TokenKind::Identifier`
// says that wherever we use `identifier` in the grammar, it actually represents a `TokenKind::Identifier`.
// Identifiers must match the names we use in the grammar rules, and values must match enumerators in `tokens.rs`.
enum TokenKind<'input> {
identifier => TokenKind::Identifier(<&'input str>),
text => TokenKind::Text(<&'input str>),
newline => TokenKind::Newline,
// Tag keywords
param_keyword => TokenKind::ParamKeyword,
returns_keyword => TokenKind::ReturnsKeyword,
throws_keyword => TokenKind::ThrowsKeyword,
see_keyword => TokenKind::SeeKeyword,
link_keyword => TokenKind::LinkKeyword,
// Symbols
"{" => TokenKind::LeftBrace,
"}" => TokenKind::RightBrace,
":" => TokenKind::Colon,
"::" => TokenKind::DoubleColon,
}
}
// Grammar Rules
pub DocComment: DocComment = {
<l: @L> <overview: MessageLines?> => create_doc_comment(overview, l, comment_parser.file_name),
<mut comment: DocComment> <param_block: ParamBlock> => {
append_tag_to_comment!(comment, params, param_block)
},
<mut comment: DocComment> <returns_block: ReturnsBlock> => {
append_tag_to_comment!(comment, returns, returns_block)
},
<mut comment: DocComment> <throws_block: ThrowsBlock> => {
append_tag_to_comment!(comment, throws, throws_block)
},
<mut comment: DocComment> <see_block: SeeBlock> => {
append_tag_to_comment!(comment, see, see_block)
},
}
ParamBlock: ParamTag = {
<l: @L> param_keyword <identifier: Identifier> <r: @R> <message: Section> => {
let span = Span::new(l, r, comment_parser.file_name);
ParamTag { identifier, message, span }
},
}
ReturnsBlock: ReturnsTag = {
<l: @L> returns_keyword <identifier: Identifier?> <r: @R> <message: Section> => {
let span = Span::new(l, r, comment_parser.file_name);
ReturnsTag { identifier, message, span }
},
}
ThrowsBlock: ThrowsTag = {
<l: @L> throws_keyword <identifier: ScopedIdentifier> <r: @R> <message: Section> => {
let span = Span::new(l, r, comment_parser.file_name);
let thrown_type = TypeRefDefinition::Unpatched(identifier);
ThrowsTag { thrown_type, message, span }
},
}
SeeBlock: SeeTag = {
<l: @L> see_keyword <identifier: ScopedIdentifier> <r: @R> newline => {
let span = Span::new(l, r, comment_parser.file_name);
SeeTag { link: TypeRefDefinition::Unpatched(identifier), span }
},
}
InlineLink: LinkTag = {
<l: @L> link_keyword <identifier: ScopedIdentifier> <r: @R> => {
let span = Span::new(l, r, comment_parser.file_name);
LinkTag { link: TypeRefDefinition::Unpatched(identifier), span }
},
}
Section: Message = {
<l: @L> <inline_message: (":" <Message?>)?> newline <message_lines: MessageLines?> <r: @R> => {
let span = Span::new(l, r, comment_parser.file_name);
construct_section_message(inline_message.flatten(), message_lines, span)
},
}
MessageLines: Message = {
<l: @L> <m: (<Message?> newline)+> <r: @R> => {
let span = Span::new(l, r, comment_parser.file_name);
sanitize_message_lines(m, span)
}
}
Message = MessageComponent+;
MessageComponent: MessageComponent = {
<text: text> => MessageComponent::Text(text.to_owned()),
"{" <link: InlineLink> "}" => MessageComponent::Link(link),
}
Identifier: Identifier = {
<l: @L> <identifier: identifier> <r: @R> => {
let span = Span::new(l, r, comment_parser.file_name);
Identifier { value: identifier.to_owned(), span }
},
}
ScopedIdentifier: Identifier = {
<l: @L> <dc: "::"?> <i: identifier> <mut v: ("::" <identifier>)*> <r: @R> => {
let value = get_scoped_identifier_string(i, v, dc.is_some());
let span = Span::new(l, r, comment_parser.file_name);
Identifier { value, span }
},
}