module.exports = grammar({
name: 'doxygen',
externals: $ => [
$.brief_description,
],
extras: _ => [
token(choice(
seq(/\n/, /[ \t]*/, repeat(seq('*', /[ \t]*/))),
/\s/,
)),
],
rules: {
document: $ => seq(
$._begin,
optional($.brief_header),
optional($.description),
repeat($.tag),
$._end,
),
brief_header: $ => prec(1, choice(
seq(alias(tagName('brief'), $.tag_name), $.brief_description),
alias(/[^\s\\*@<\[][^.<]+[.]/, $.brief_description),
)),
description: $ => repeat1(choice(
$._text,
$.emphasis,
$.link,
$.function_link,
)),
tag: $ => prec.right(choice(
seq(
alias($.tag_name_with_argument, $.tag_name),
optional($._expression),
optional($.description),
),
seq(
alias($.tag_name_with_multiple_arguments, $.tag_name),
optional($.storageclass),
commaSep1($._expression),
optional($.description),
),
seq(
$.storageclass,
optional($.description),
),
seq(
alias($.tag_name_with_types, $.tag_name),
commaSep1(seq(
$.function,
optional(alias(/[a-zA-Z_][a-zA-Z_0-9]*\s+/, $._text)),
)),
optional($.function),
),
seq(
alias($.tag_name_with_self_types, $.tag_name),
alias(/[^\s].*/, $.type),
),
seq(
alias($.tag_name_with_type, $.tag_name),
optional(alias($.identifier, $.type)),
optional($.description),
),
seq(
$.tag_name,
optional($.description),
),
)),
tag_name_with_argument: _ => token(choice(
tagName('namespace'),
tagName('exception'),
)),
tag_name_with_multiple_arguments: _ => token(choice(
tagName('param'),
)),
tag_name_with_types: _ => token(choice(
tagName('sa'),
)),
tag_name_with_self_types: _ => token(choice(
tagName('fn'),
tagName('property'),
tagName('var'),
tagName('overload'),
tagName('typedef'),
)),
tag_name_with_type: _ => token(choice(
tagName('class'),
tagName('var'),
)),
tag_name: _ => /(@|\\)([a-zA-Z_]+|\{|\})/,
_expression: $ => choice(
$.identifier,
$.qualified_identifier,
$.function,
),
identifier: _ => /[a-zA-Z_][a-zA-Z_0-9]*/,
qualified_identifier: $ => seq(
$.identifier,
repeat1(seq(token.immediate('::'), $.identifier)),
),
function: $ => seq(
optional('~'),
$.identifier,
'(',
')',
),
storageclass: _ => seq('[', choice('in', 'out', 'inout'), ']'),
emphasis: $ => seq('\\a', alias(/[a-zA-Z_][a-zA-Z_0-9]*/, $.text)),
link: $ => seq(
'<a',
/[^>]*/,
'>',
alias(/[^<]*/, $.text),
'</a>',
),
function_link: _ => token(choice(
seq(/[a-zA-Z_][a-zA-Z_0-9]*/, '(', /[^)]*/, ')'),
seq('::', /[a-zA-Z_][a-zA-Z_0-9]*/),
seq(
/[a-zA-Z_][a-zA-Z_0-9]*/,
repeat1(seq('::', /[a-zA-Z_][a-zA-Z_0-9]*/)),
'(',
/[^)]*/,
')',
),
)),
_text: _ => token(prec(-1, /[^*{}@\\\s][^*!{}\\\n]*([^*/{}\\\n][^*{}\\\n]*\*+)*/)),
_begin: _ => token(seq('/', repeat(choice('*', '/')), optional('!'), optional('<'))),
_end: _ => choice('/', '*/'),
},
});
function tagName(name) {
return choice(`@${name}`, `\\${name}`);
}
function commaSep1(rule) {
return seq(rule, repeat(seq(',', rule)));
}