Skip to content

Commit

Permalink
enh(cpp) Misc fixes and improvements for function detection
Browse files Browse the repository at this point in the history
- enh(cpp) Properly detect decltype(auto)
- enh(cpp) recognize primitive types (`int8_t`, etc.) as function types
- enh(cpp) Detect namespaced function types (`A::typeName func(...)`)
- enh(cpp) Detect namespaced functions also (`A::functionName`)
- enh(cpp) template type in function declaration (`vector<int> func(...)`)

Closes #1730.
Closes #1222.
Closes #1502.
  • Loading branch information
joshgoebel committed Jan 15, 2020
1 parent b33ef93 commit ee8cf44
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 58 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Expand Up @@ -19,6 +19,10 @@ Language Improvements:
- (ini) support TOML arrays, clean up grammar (#2335) [Josh Goebel][]
- (vbnet) add nameof operator to the keywords (#2329) [Youssef Victor][]
- (stan) updated with improved coverage of language keywords and patterns. (#1829) [Jeffrey Arnold][]
- enh(cpp) Detect namespaced function types (`A::typeName func(...)`) (#2332) [Josh Goebel][]
- enh(cpp) Detect namespaced functions also (`A::functionName`) (#2332) [Josh Goebel][]
- enh(cpp) Properly detect decltype(auto) (#2332) [Josh Goebel][]
- enh(cpp) recognize primitive types (`int8_t`, etc.) as function types (#2332) [Josh Goebel][]

Developer Tools:

Expand Down
145 changes: 87 additions & 58 deletions src/languages/cpp.js
Expand Up @@ -7,6 +7,16 @@ Website: https://isocpp.org
*/

function(hljs) {
function optional(s) {
return '(?:' + s + ')?';
}
var DECLTYPE_AUTO_RE = 'decltype\\(auto\\)'
var NAMESPACE_RE = '[a-zA-Z_]\\w*::'
var TEMPLATE_ARGUMENT_RE = '<.*?>';
var FUNCTION_TYPE_RE = '(' +
DECLTYPE_AUTO_RE + '|' +
optional(NAMESPACE_RE) +'[a-zA-Z_]\\w*' + optional(TEMPLATE_ARGUMENT_RE) +
')';
var CPP_PRIMITIVE_TYPES = {
className: 'keyword',
begin: '\\b[a-z\\d_]*_t\\b'
Expand Down Expand Up @@ -64,7 +74,13 @@ function(hljs) {
]
};

var FUNCTION_TITLE = hljs.IDENT_RE + '\\s*\\(';
var TITLE_MODE = {
className: 'title',
begin: optional(NAMESPACE_RE) + hljs.IDENT_RE,
relevance: 0
};

var FUNCTION_TITLE = optional(NAMESPACE_RE) + hljs.IDENT_RE + '\\s*\\(';

var CPP_KEYWORDS = {
keyword: 'int float while private char char8_t char16_t char32_t catch import module export virtual operator sizeof ' +
Expand Down Expand Up @@ -99,86 +115,99 @@ function(hljs) {
STRINGS
];

return {
aliases: ['c', 'cc', 'h', 'c++', 'h++', 'hpp', 'hh', 'hxx', 'cxx'],
var EXPRESSION_CONTEXT = {
// This mode covers expression context where we can't expect a function
// definition and shouldn't highlight anything that looks like one:
// `return some()`, `else if()`, `(x*sum(1, 2))`
variants: [
{begin: /=/, end: /;/},
{begin: /\(/, end: /\)/},
{beginKeywords: 'new throw return else', end: /;/}
],
keywords: CPP_KEYWORDS,
illegal: '</',
contains: EXPRESSION_CONTAINS.concat([
PREPROCESSOR,
{
begin: '\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<', end: '>',
begin: /\(/, end: /\)/,
keywords: CPP_KEYWORDS,
contains: ['self', CPP_PRIMITIVE_TYPES]
},
{
begin: hljs.IDENT_RE + '::',
keywords: CPP_KEYWORDS
contains: EXPRESSION_CONTAINS.concat(['self']),
relevance: 0
}
]),
relevance: 0
};

var FUNCTION_DECLARATION = {
className: 'function',
begin: '(' + FUNCTION_TYPE_RE + '[\\*&\\s]+)+' + FUNCTION_TITLE,
returnBegin: true, end: /[{;=]/,
excludeEnd: true,
keywords: CPP_KEYWORDS,
illegal: /[^\w\s\*&:<>]/,
contains: [

{ // to prevent it from being confused as the function title
begin: DECLTYPE_AUTO_RE,
keywords: CPP_KEYWORDS,
relevance: 0,
},
{
// This mode covers expression context where we can't expect a function
// definition and shouldn't highlight anything that looks like one:
// `return some()`, `else if()`, `(x*sum(1, 2))`
variants: [
{begin: /=/, end: /;/},
{begin: /\(/, end: /\)/},
{beginKeywords: 'new throw return else', end: /;/}
],
keywords: CPP_KEYWORDS,
contains: EXPRESSION_CONTAINS.concat([
{
begin: /\(/, end: /\)/,
keywords: CPP_KEYWORDS,
contains: EXPRESSION_CONTAINS.concat(['self']),
relevance: 0
}
]),
begin: FUNCTION_TITLE, returnBegin: true,
contains: [TITLE_MODE],
relevance: 0
},
{
className: 'function',
begin: '(' + hljs.IDENT_RE + '[\\*&\\s]+)+' + FUNCTION_TITLE,
returnBegin: true, end: /[{;=]/,
excludeEnd: true,
className: 'params',
begin: /\(/, end: /\)/,
keywords: CPP_KEYWORDS,
illegal: /[^\w\s\*&]/,
relevance: 0,
contains: [
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
STRINGS,
NUMBERS,
CPP_PRIMITIVE_TYPES,
// Count matching parentheses.
{
begin: FUNCTION_TITLE, returnBegin: true,
contains: [hljs.TITLE_MODE],
relevance: 0
},
{
className: 'params',
begin: /\(/, end: /\)/,
keywords: CPP_KEYWORDS,
relevance: 0,
contains: [
'self',
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
STRINGS,
NUMBERS,
CPP_PRIMITIVE_TYPES,
// Count matching parentheses.
{
begin: /\(/, end: /\)/,
keywords: CPP_KEYWORDS,
relevance: 0,
contains: [
'self',
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
STRINGS,
NUMBERS,
CPP_PRIMITIVE_TYPES
]
}
CPP_PRIMITIVE_TYPES
]
},
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
PREPROCESSOR
}
]
},
CPP_PRIMITIVE_TYPES,
hljs.C_LINE_COMMENT_MODE,
hljs.C_BLOCK_COMMENT_MODE,
PREPROCESSOR
]
};

return {
aliases: ['c', 'cc', 'h', 'c++', 'h++', 'hpp', 'hh', 'hxx', 'cxx'],
keywords: CPP_KEYWORDS,
illegal: '</',
contains: [].concat(
EXPRESSION_CONTEXT,
FUNCTION_DECLARATION,
EXPRESSION_CONTAINS,
[
PREPROCESSOR,
{
begin: '\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<', end: '>',
keywords: CPP_KEYWORDS,
contains: ['self', CPP_PRIMITIVE_TYPES]
},
{
begin: hljs.IDENT_RE + '::',
keywords: CPP_KEYWORDS
},
{
className: 'class',
beginKeywords: 'class struct', end: /[{;:]/,
Expand Down
16 changes: 16 additions & 0 deletions test/markup/cpp/function-declarations.expect.txt
@@ -0,0 +1,16 @@
<span class="hljs-function"><span class="hljs-keyword">decltype</span>(<span class="hljs-keyword">auto</span>) <span class="hljs-title">look_up_a_string_1</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">return</span> lookup1(); }
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">look_up_a_string_2</span><span class="hljs-params">()</span> </span>{ <span class="hljs-keyword">return</span> lookup2(); }
<span class="hljs-function"><span class="hljs-keyword">friend</span> <span class="hljs-keyword">void</span> <span class="hljs-title">A::showB</span><span class="hljs-params">(B x)</span> </span>{}
<span class="hljs-function"><span class="hljs-keyword">friend</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showB</span><span class="hljs-params">(B x)</span> </span>{}
<span class="hljs-function"><span class="hljs-keyword">friend</span> <span class="hljs-keyword">void</span> <span class="hljs-title">showB</span><span class="hljs-params">(B::SomeType x)</span> </span>{}
<span class="hljs-function"><span class="hljs-keyword">inline</span> <span class="hljs-keyword">int</span> <span class="hljs-title">add</span><span class="hljs-params">(<span class="hljs-keyword">int</span> a, <span class="hljs-keyword">int</span> b)</span> </span>{}
<span class="hljs-function">int8t <span class="hljs-title">Get_Tile_Value</span><span class="hljs-params">()</span> </span>{}

<span class="hljs-function"><span class="hljs-keyword">int8_t</span> <span class="hljs-title">Get_Tile_Value</span><span class="hljs-params">()</span> </span>{}

<span class="hljs-function">B::type <span class="hljs-title">test</span><span class="hljs-params">()</span> </span>{};

<span class="hljs-comment">// template</span>
<span class="hljs-function">boost::optional&lt;application&gt; <span class="hljs-title">handle_key</span><span class="hljs-params">(application state, key_code key, coord size)</span></span>;

test();
16 changes: 16 additions & 0 deletions test/markup/cpp/function-declarations.txt
@@ -0,0 +1,16 @@
decltype(auto) look_up_a_string_1() { return lookup1(); }
void look_up_a_string_2() { return lookup2(); }
friend void A::showB(B x) {}
friend void showB(B x) {}
friend void showB(B::SomeType x) {}
inline int add(int a, int b) {}
int8t Get_Tile_Value() {}

int8_t Get_Tile_Value() {}

B::type test() {};

// template
boost::optional<application> handle_key(application state, key_code key, coord size);

test();

0 comments on commit ee8cf44

Please sign in to comment.