Add C and C++ grammars

This commit is contained in:
Andrew Dupont 2023-03-28 17:03:42 -07:00
parent bd822c2599
commit e13793034a
14 changed files with 824 additions and 0 deletions

View File

@ -0,0 +1 @@
source "/Users/andrew/Code/JavaScript/emsdk/emsdk_env.sh"

View File

@ -0,0 +1 @@
nodejs 18.14.0

View File

@ -0,0 +1,13 @@
name: 'C'
scopeName: 'source.c'
type: 'tree-sitter-2'
parser: 'tree-sitter-c'
injectionRegex: '^(c|C)$'
treeSitter:
grammar: 'tree-sitter-c/tree-sitter-c.wasm'
syntaxQuery: 'tree-sitter-c/highlights.scm'
localsQuery: 'tree-sitter-c/locals.scm'
foldsQuery: 'tree-sitter-c/folds.scm'
indentsQuery: 'tree-sitter-c/indents.scm'

View File

@ -0,0 +1,13 @@
name: 'C++'
scopeName: 'source.cpp'
type: 'tree-sitter-2'
parser: 'tree-sitter-cpp'
injectionRegex: '^(cpp|CPP|cc|CC)$'
treeSitter:
grammar: 'tree-sitter-cpp/tree-sitter-cpp.wasm'
syntaxQuery: 'tree-sitter-cpp/highlights.scm'
localsQuery: 'tree-sitter-cpp/locals.scm'
foldsQuery: 'tree-sitter-cpp/folds.scm'
indentsQuery: 'tree-sitter-cpp/indents.scm'

View File

@ -0,0 +1,24 @@
; When we've got
;
; if (foo) {
; // something
; } else {
; // something else
; }
;
; we want the folds to work a little differently so that collapsing the `if`
; fold doesn't interfere with our ability to collapse the `else` fold.
(if_statement
consequence: (compound_statement) @fold
(#set! adjustToEndOfPreviousRow true))
[
(field_declaration_list)
(enumerator_list)
(compound_statement)
] @fold
; Divided folds for preprocessor statements because they can't reliably be
; expressed with simple folds.
["#ifndef" "#ifdef" "#elif" "#else" "#if"] @fold.start
["#elif" "#else" "#endif"] @fold.end

View File

@ -0,0 +1,310 @@
; PREPROCESSOR
; ============
[
"#if"
"#ifdef"
"#ifndef"
"#endif"
"#elif"
"#else"
] @keyword.control.directive.conditional.c
"#define" @keyword.control.directive.define.c
"#include" @keyword.control.directive.include.c
; This will match if the more specific rules above haven't matched. The
; anonymous nodes will match under ideal conditions, but might not be present
; if the parser is flummoxed.
((preproc_directive) @keyword.control.directive.c
(#set! shy true))
((preproc_ifdef
(identifier) @entity.name.function.preprocessor.c
(#match? @entity.name.function.preprocessor.c "[a-zA-Z_$][\\w$]*")))
(preproc_function_def
(identifier) @entity.name.function.preprocessor.c
(#set! final true))
(system_lib_string) @string.quoted.other.lt-gt.include.c
((system_lib_string) @punctuation.definition.string.begin.c
(#set! endAfterFirstMatchOf "^<"))
((system_lib_string) @punctuation.definition.string.end.c
(#set! startBeforeFirstMatchOf ">$"))
; TYPES
; =====
; WORKAROUND: If we're in an error state, don't trust the parser's designation
; of `type_identifier`. Someone's probably just typing on a new line.
(ERROR
(type_identifier) @_IGNORE_
(#set! final true))
(primitive_type) @storage.type.builtin.c
(type_identifier) @storage.type.other.c
[
"enum"
"long"
"short"
"signed"
"struct"
"typedef"
"union"
"unsigned"
] @storage.type.c
[
"const"
"extern"
"inline"
"register"
"restrict"
"static"
"volatile"
] @storage.modifier.c
((primitive_type) @support.type.stdint.c
(#match? @support.type.stdint.c "^(int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|int_least8_t|int_least16_t|int_least32_t|int_least64_t|uint_least8_t|uint_least16_t|uint_least32_t|uint_least64_t|int_fast8_t|int_fast16_t|int_fast32_t|int_fast64_t|uint_fast8_t|uint_fast16_t|uint_fast32_t|uint_fast64_t|intptr_t|uintptr_t|intmax_t|intmax_t|uintmax_t|uintmax_t)$"))
; CAVEAT: tree-sitter-c doesn't identify placeholders like `%c` in strings.
; Candidate for an injection grammar.
(string_literal "\"") @string.quoted.double.c
(string_literal
"\"" @punctuation.definition.string.begin.c
(#set! onlyIfFirst true))
(string_literal
"\"" @punctuation.definition.string.end.c
(#set! onlyIfLast true))
(char_literal "'") @string.quoted.single.c
(char_literal
"'" @punctuation.definition.string.begin.c
(#set! onlyIfFirst true))
(char_literal
"'" @punctuation.definition.string.end.c
(#set! onlyIfLast true))
(string_literal (escape_sequence) @constant.character.escape.c)
(char_literal (escape_sequence) @constant.character.escape.c)
; VARIABLES
; =========
; Declarations and assignments
; ----------------------------
(declaration
(identifier) @variable.declaration.c)
(field_declaration
(field_identifier) @variable.declaration.c)
(field_declaration
(pointer_declarator
(field_identifier) @variable.declaration.c))
(field_declaration
(array_declarator
(field_identifier) @variable.declaration.c))
(init_declarator
(identifier) @variable.declaration.c)
(init_declarator
(pointer_declarator
(identifier) @variable.declaration.c))
(assignment_expression
left: (identifier) @variable.other.assignment.c)
; Function parameters
; -------------------
(preproc_params
(identifier) @variable.parameter.preprocessor.c)
; The "foo" in `const char foo` within a parameter list.
(parameter_declaration
declarator: (identifier) @variable.parameter.c)
; The "foo" in `const char *foo` within a parameter list.
(parameter_declaration
declarator: (pointer_declarator
declarator: (identifier) @variable.parameter.c))
; The "foo" in `const char foo[]` within a parameter list.
(parameter_declaration
declarator: (array_declarator
declarator: (identifier) @variable.parameter.c))
; The "argv" in `char* argv[]` within a parameter list.
(parameter_declaration
declarator: (pointer_declarator
declarator: (array_declarator
declarator: (identifier) @variable.parameter.c)))
; The "size" in `finfo->size`.
(field_expression
"->"
field: (field_identifier) @variable.other.member.c)
; FUNCTIONS
; =========
(function_declarator
(identifier) @entity.name.function.c)
(call_expression
(identifier) @support.function.c99.c
; Regex copied from the TM grammar.
(#match? @support.function.c99.c "^(_Exit|(?:nearbyint|nextafter|nexttoward|netoward|nan)[fl]?|a(?:cos|sin)h?[fl]?|abort|abs|asctime|assert|atan(?:[h2]?[fl]?)?|atexit|ato[ifl]|atoll|bsearch|btowc|cabs[fl]?|cacos|cacos[fl]|cacosh[fl]?|calloc|carg[fl]?|casinh?[fl]?|catanh?[fl]?|cbrt[fl]?|ccosh?[fl]?|ceil[fl]?|cexp[fl]?|cimag[fl]?|clearerr|clock|clog[fl]?|conj[fl]?|copysign[fl]?|cosh?[fl]?|cpow[fl]?|cproj[fl]?|creal[fl]?|csinh?[fl]?|csqrt[fl]?|ctanh?[fl]?|ctime|difftime|div|erfc?[fl]?|exit|fabs[fl]?|exp(?:2[fl]?|[fl]|m1[fl]?)?|fclose|fdim[fl]?|fe[gs]et(?:env|exceptflag|round)|feclearexcept|feholdexcept|feof|feraiseexcept|ferror|fetestexcept|feupdateenv|fflush|fgetpos|fgetw?[sc]|floor[fl]?|fmax?[fl]?|fmin[fl]?|fmod[fl]?|fopen|fpclassify|fprintf|fputw?[sc]|fread|free|freopen|frexp[fl]?|fscanf|fseek|fsetpos|ftell|fwide|fwprintf|fwrite|fwscanf|genv|get[sc]|getchar|gmtime|gwc|gwchar|hypot[fl]?|ilogb[fl]?|imaxabs|imaxdiv|isalnum|isalpha|isblank|iscntrl|isdigit|isfinite|isgraph|isgreater|isgreaterequal|isinf|isless(?:equal|greater)?|isw?lower|isnan|isnormal|isw?print|isw?punct|isw?space|isunordered|isw?upper|iswalnum|iswalpha|iswblank|iswcntrl|iswctype|iswdigit|iswgraph|isw?xdigit|labs|ldexp[fl]?|ldiv|lgamma[fl]?|llabs|lldiv|llrint[fl]?|llround[fl]?|localeconv|localtime|log[2b]?[fl]?|log1[p0][fl]?|longjmp|lrint[fl]?|lround[fl]?|malloc|mbr?len|mbr?towc|mbsinit|mbsrtowcs|mbstowcs|memchr|memcmp|memcpy|memmove|memset|mktime|modf[fl]?|perror|pow[fl]?|printf|puts|putw?c(?:har)?|qsort|raise|rand|remainder[fl]?|realloc|remove|remquo[fl]?|rename|rewind|rint[fl]?|round[fl]?|scalbl?n[fl]?|scanf|setbuf|setjmp|setlocale|setvbuf|signal|signbit|sinh?[fl]?|snprintf|sprintf|sqrt[fl]?|srand|sscanf|strcat|strchr|strcmp|strcoll|strcpy|strcspn|strerror|strftime|strlen|strncat|strncmp|strncpy|strpbrk|strrchr|strspn|strstr|strto[kdf]|strtoimax|strtol[dl]?|strtoull?|strtoumax|strxfrm|swprintf|swscanf|system|tan|tan[fl]|tanh[fl]?|tgamma[fl]?|time|tmpfile|tmpnam|tolower|toupper|trunc[fl]?|ungetw?c|va_arg|va_copy|va_end|va_start|vfw?printf|vfw?scanf|vprintf|vscanf|vsnprintf|vsprintf|vsscanf|vswprintf|vswscanf|vwprintf|vwscanf|wcrtomb|wcscat|wcschr|wcscmp|wcscoll|wcscpy|wcscspn|wcsftime|wcslen|wcsncat|wcsncmp|wcsncpy|wcspbrk|wcsrchr|wcsrtombs|wcsspn|wcsstr|wcsto[dkf]|wcstoimax|wcstol[dl]?|wcstombs|wcstoull?|wcstoumax|wcsxfrm|wctom?b|wmem(?:set|chr|cpy|cmp|move)|wprintf|wscanf)$")
(#set! final true))
; The "foo" in `thing->troz->foo(...)`.
(call_expression
(field_expression
field: (field_identifier) @support.function.other.c)
(#set! final true))
(call_expression
(identifier) @support.function.other.c
(#set! final true))
; NUMBERS
; =======
(number_literal) @constant.numeric.c
; CONSTANTS
; =========
[
(null)
(true)
(false)
] @constant.language._TYPE_.c
((identifier) @constant.c
(#match? @constant.c "[_A-Z][_A-Z0-9]*$"))
; COMMENTS
; ========
; Match // comments.
((comment) @comment.line.double-slash.c
(#match? @comment.line.double-slash.c "^\\s*//"))
((comment) @punctuation.definition.comment.c
(#match? @comment.line.double-slash.c "^\\s*//")
(#set! startAndEndAroundFirstMatchOf "//"))
; Match /* */ comments.
((comment) @comment.block.c
(#match? @comment.block.c "^/\\*"))
((comment) @punctuation.definition.comment.begin.c
(#match? @punctuation.definition.comment.begin.c "^/\\*")
(#set! startAndEndAroundFirstMatchOf "^/\\*"))
((comment) @punctuation.definition.comment.end.c
(#match? @punctuation.definition.comment.end.c "\\*/$")
(#set! startAndEndAroundFirstMatchOf "\\*/$"))
[
"break"
"case"
"continue"
"default"
"do"
"else"
"for"
"goto"
"if"
"return"
"switch"
"while"
] @keyword.control._TYPE_.c
; OPERATORS
; =========
(pointer_declarator "*" @keyword.operator.pointer.c)
(abstract_pointer_declarator "*" @keyword.operator.pointer.c)
(pointer_expression "*" @keyword.operator.pointer.c)
"sizeof" @keyword.operator.sizeof.c
(pointer_expression "&" @keyword.operator.pointer.c)
"=" @keyword.operator.assignment.c
[
"%="
"+="
"-="
"*="
"/="
"&="
"^="
"<<="
">>="
"|="
] @keyword.operator.assignment.compound.c
(binary_expression
["==" "!=" ">" "<" ">=" "<="] @keyword.operator.comparison.c)
(binary_expression
["&" "|" "^" "~" "<<" ">>"]
@keyword.operator.bitwise.c)
"++" @keyword.operator.increment.c
"--" @keyword.operator.decrement.c
(binary_expression ["+" "-" "*" "/" "%"] @keyword.operator.arithmetic.c)
(unary_expression ["+" "-" "!"] @keyword.operator.unary.c)
(conditional_expression
["?" ":"] @keyword.operator.ternary.c)
["||" "&&"] @keyword.operator.logical.c
(field_expression "." @keyword.operator.accessor.dot.c)
(preproc_params "..." @keyword.operator.ellipsis.c)
; PUNCTUATION
; ===========
";" @punctuation.terminator.statement.c
"," @punctuation.separator.comma.c
"->" @punctuation.separator.pointer-access.c
"{" @punctuation.definition.begin.brace.curly.c
"}" @punctuation.definition.end.brace.curly.c
"(" @punctuation.definition.begin.brace.round.c
")" @punctuation.definition.end.brace.round.c
"[" @punctuation.definition.begin.brace.square.c
"]" @punctuation.definition.end.brace.square.c
; TODO:
;
; * TM-style grammar has a lot of `mac-classic` scopes. I doubt they'd be
; present if this wasn't converted from a TextMate grammar, so I'm leaving
; them out for now.
;

View File

@ -0,0 +1,20 @@
["{" "(" "["] @indent
["}" ")" "]"] @dedent
; `switch` statements have a couple schools of thought, indentation-wise, and
; we might have to make this configurable somehow.
(switch_statement
body: (compound_statement "}" @match
(#set! onlyIfLast true))
(#set! matchIndentOf parent.startPosition))
; 'case' and 'default' need to be indented one level more than their containing
; `switch`.
(["case" "default"] @match
(#set! matchIndentOf parent.parent.startPosition)
(#set! offsetIndent 1))
["case" "default"] @indent

View File

@ -0,0 +1 @@
;

View File

@ -0,0 +1,24 @@
; When we've got
;
; if (foo) {
; // something
; } else {
; // something else
; }
;
; we want the folds to work a little differently so that collapsing the `if`
; fold doesn't interfere with our ability to collapse the `else` fold.
(if_statement
consequence: (compound_statement) @fold
(#set! adjustToEndOfPreviousRow true))
[
(field_declaration_list)
(enumerator_list)
(compound_statement)
] @fold
; Divided folds for preprocessor statements because they can't reliably be
; expressed with simple folds.
["#ifndef" "#ifdef" "#elif" "#else" "#if"] @fold.start
["#elif" "#else" "#endif"] @fold.end

View File

@ -0,0 +1,384 @@
; PREPROCESSOR
; ============
[
"#if"
"#ifdef"
"#ifndef"
"#endif"
"#elif"
"#else"
] @keyword.control.directive.conditional.cpp
"#define" @keyword.control.directive.define.cpp
"#include" @keyword.control.directive.include.cpp
; This will match if the more specific rules above haven't matched. The
; anonymous nodes will match under ideal conditions, but might not be present
; if the parser is flummoxed.
((preproc_directive) @keyword.control.directive.c
(#set! shy true))
((preproc_ifdef
(identifier) @entity.name.function.preprocessor.c
(#match? @entity.name.function.preprocessor.c "[a-zA-Z_$][\\w$]*")))
(preproc_function_def
(identifier) @entity.name.function.preprocessor.c
(#set! final true))
(preproc_function_def
(identifier) @entity.name.function.preprocessor.cpp
(#set! final true)
)
(system_lib_string) @string.quoted.other.lt-gt.include.c
((system_lib_string) @punctuation.definition.string.begin.c
(#set! endAfterFirstMatchOf "^<"))
((system_lib_string) @punctuation.definition.string.end.c
(#set! startBeforeFirstMatchOf ">$"))
; TYPES
; =====
; WORKAROUND: If we're in an error state, don't trust the parser's designation
; of `type_identifier`. Someone's probably just typing on a new line.
(ERROR
(type_identifier) @_IGNORE_
(#set! final true))
(primitive_type) @storage.type.builtin.cpp
(class_specifier
(type_identifier) @entity.name.class.cpp
(#set! final true))
(type_identifier) @storage.type.other.cpp
; (struct_specifier) @storage.type.cpp
[
"enum"
"long"
"short"
"signed"
"struct"
"typedef"
"union"
"unsigned"
"template"
] @storage.type.cpp
[
"const"
"extern"
"inline"
"register"
"restrict"
"static"
"volatile"
"private"
"protected"
"public"
"friend"
"explicit"
"virtual"
"override"
"final"
"noexcept"
] @storage.modifier.cpp
(
(primitive_type) @support.type.stdint.cpp
(#match? @support.type.stdint.cpp "^(int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|int_least8_t|int_least16_t|int_least32_t|int_least64_t|uint_least8_t|uint_least16_t|uint_least32_t|uint_least64_t|int_fast8_t|int_fast16_t|int_fast32_t|int_fast64_t|uint_fast8_t|uint_fast16_t|uint_fast32_t|uint_fast64_t|intptr_t|uintptr_t|intmax_t|intmax_t|uintmax_t|uintmax_t)$")
)
"typename" @storage.modifier.typename.cpp
; FUNCTIONS
; =========
(function_declarator
(identifier) @entity.name.function.cpp)
(function_declarator
(field_identifier) @entity.name.function.method.cpp)
(call_expression
(identifier) @support.function.c99.cpp
; Regex copied from the TM grammar.
(#match? @support.function.c99.cpp "^(_Exit|(?:nearbyint|nextafter|nexttoward|netoward|nan)[fl]?|a(?:cos|sin)h?[fl]?|abort|abs|asctime|assert|atan(?:[h2]?[fl]?)?|atexit|ato[ifl]|atoll|bsearch|btowc|cabs[fl]?|cacos|cacos[fl]|cacosh[fl]?|calloc|carg[fl]?|casinh?[fl]?|catanh?[fl]?|cbrt[fl]?|ccosh?[fl]?|ceil[fl]?|cexp[fl]?|cimag[fl]?|clearerr|clock|clog[fl]?|conj[fl]?|copysign[fl]?|cosh?[fl]?|cpow[fl]?|cproj[fl]?|creal[fl]?|csinh?[fl]?|csqrt[fl]?|ctanh?[fl]?|ctime|difftime|div|erfc?[fl]?|exit|fabs[fl]?|exp(?:2[fl]?|[fl]|m1[fl]?)?|fclose|fdim[fl]?|fe[gs]et(?:env|exceptflag|round)|feclearexcept|feholdexcept|feof|feraiseexcept|ferror|fetestexcept|feupdateenv|fflush|fgetpos|fgetw?[sc]|floor[fl]?|fmax?[fl]?|fmin[fl]?|fmod[fl]?|fopen|fpclassify|fprintf|fputw?[sc]|fread|free|freopen|frexp[fl]?|fscanf|fseek|fsetpos|ftell|fwide|fwprintf|fwrite|fwscanf|genv|get[sc]|getchar|gmtime|gwc|gwchar|hypot[fl]?|ilogb[fl]?|imaxabs|imaxdiv|isalnum|isalpha|isblank|iscntrl|isdigit|isfinite|isgraph|isgreater|isgreaterequal|isinf|isless(?:equal|greater)?|isw?lower|isnan|isnormal|isw?print|isw?punct|isw?space|isunordered|isw?upper|iswalnum|iswalpha|iswblank|iswcntrl|iswctype|iswdigit|iswgraph|isw?xdigit|labs|ldexp[fl]?|ldiv|lgamma[fl]?|llabs|lldiv|llrint[fl]?|llround[fl]?|localeconv|localtime|log[2b]?[fl]?|log1[p0][fl]?|longjmp|lrint[fl]?|lround[fl]?|malloc|mbr?len|mbr?towc|mbsinit|mbsrtowcs|mbstowcs|memchr|memcmp|memcpy|memmove|memset|mktime|modf[fl]?|perror|pow[fl]?|printf|puts|putw?c(?:har)?|qsort|raise|rand|remainder[fl]?|realloc|remove|remquo[fl]?|rename|rewind|rint[fl]?|round[fl]?|scalbl?n[fl]?|scanf|setbuf|setjmp|setlocale|setvbuf|signal|signbit|sinh?[fl]?|snprintf|sprintf|sqrt[fl]?|srand|sscanf|strcat|strchr|strcmp|strcoll|strcpy|strcspn|strerror|strftime|strlen|strncat|strncmp|strncpy|strpbrk|strrchr|strspn|strstr|strto[kdf]|strtoimax|strtol[dl]?|strtoull?|strtoumax|strxfrm|swprintf|swscanf|system|tan|tan[fl]|tanh[fl]?|tgamma[fl]?|time|tmpfile|tmpnam|tolower|toupper|trunc[fl]?|ungetw?c|va_arg|va_copy|va_end|va_start|vfw?printf|vfw?scanf|vprintf|vscanf|vsnprintf|vsprintf|vsscanf|vswprintf|vswscanf|vwprintf|vwscanf|wcrtomb|wcscat|wcschr|wcscmp|wcscoll|wcscpy|wcscspn|wcsftime|wcslen|wcsncat|wcsncmp|wcsncpy|wcspbrk|wcsrchr|wcsrtombs|wcsspn|wcsstr|wcsto[dkf]|wcstoimax|wcstol[dl]?|wcstombs|wcstoull?|wcstoumax|wcsxfrm|wctom?b|wmem(?:set|chr|cpy|cmp|move)|wprintf|wscanf)$")
(#set! final true))
; The "foo" in `thing->troz->foo(...)`.
(call_expression
(field_expression
field: (field_identifier) @support.function.other.cpp)
(#set! final true))
(call_expression
(identifier) @support.function.other.cpp
(#set! final true))
; STRINGS
; =======
; CAVEAT: tree-sitter-c doesn't identify placeholders like `%c` in strings.
; Candidate for an injection grammar.
(string_literal "\"") @string.quoted.double.cpp
(string_literal
"\"" @punctuation.definition.string.begin.cpp
(#set! onlyIfFirst true))
(string_literal
"\"" @punctuation.definition.string.end.cpp
(#set! onlyIfLast true))
(char_literal "'") @string.quoted.single.cpp
(char_literal
"'" @punctuation.definition.string.begin.cpp
(#set! onlyIfFirst true))
(char_literal
"'" @punctuation.definition.string.end.cpp
(#set! onlyIfLast true))
(string_literal (escape_sequence) @constant.character.escape.cpp)
(char_literal (escape_sequence) @constant.character.escape.cpp)
; VARIABLES
; =========
(this) @variable.language.this.cpp
; Declarations and assignments
; ----------------------------
(declaration
(identifier) @variable.declaration.cpp)
(field_declaration
(field_identifier) @variable.declaration.cpp)
(field_declaration
(pointer_declarator
(field_identifier) @variable.declaration.cpp))
(field_declaration
(array_declarator
(field_identifier) @variable.declaration.cpp))
(init_declarator
(identifier) @variable.declaration.cpp)
(init_declarator
(pointer_declarator
(identifier) @variable.declaration.cpp))
(assignment_expression
left: (identifier) @variable.other.assignment.cpp)
; Function parameters
; -------------------
(preproc_params
(identifier) @variable.parameter.preprocessor.cpp)
(parameter_declaration
declarator: (identifier) @variable.parameter.cpp)
(parameter_declaration
declarator: (pointer_declarator
declarator: (identifier) @variable.parameter.cpp))
; The "foo" in `const char foo[]` within a parameter list.
(parameter_declaration
declarator: (array_declarator
declarator: (identifier) @variable.parameter.cpp))
; The "argv" in `char* argv[]` within a parameter list.
(parameter_declaration
declarator: (pointer_declarator
declarator: (array_declarator
declarator: (identifier) @variable.parameter.cpp)))
; The "size" in `finfo->size`.
(field_expression
"->"
field: (field_identifier) @variable.other.member.cpp)
; Common naming idiom for C++ instanced vars: "fMemberName"
; ((identifier) @variable.other.readwrite.member.cpp
; (#match? @variable.other.readwrite.member.cpp "^(f|m)[A-Z]\\w*$"))
; NUMBERS
; =======
(number_literal) @constant.numeric.cpp
; CONSTANTS
; =========
[
(null)
(true)
(false)
(nullptr)
] @constant.language._TYPE_.cpp
((identifier) @constant.cpp
(#match? @constant.cpp "[_A-Z][_A-Z0-9]*$"))
; COMMENTS
; ========
; Match // comments.
((comment) @comment.line.double-slash.cpp
(#match? @comment.line.double-slash.cpp "^\\s*//"))
((comment) @punctuation.definition.comment.cpp
(#match? @comment.line.double-slash.cpp "^\\s*//")
(#set! startAndEndAroundFirstMatchOf "//"))
; Match /* */ comments.
((comment) @comment.block.cpp
(#match? @comment.block.cpp "^/\\*"))
((comment) @punctuation.definition.comment.begin.cpp
(#match? @punctuation.definition.comment.begin.cpp "^/\\*")
(#set! startAndEndAroundFirstMatchOf "^/\\*"))
((comment) @punctuation.definition.comment.end.cpp
(#match? @punctuation.definition.comment.end.cpp "\\*/$")
(#set! startAndEndAroundFirstMatchOf "\\*/$"))
; KEYWORDS
; ========
[
"break"
"case"
"continue"
"default"
"do"
"else"
"for"
"goto"
"if"
"return"
"switch"
"while"
"new"
"delete"
] @keyword.control._TYPE_.cpp
[
"catch"
"operator"
"try"
"throw"
"using"
"namespace"
] @keyword.control._TYPE_.cpp
; OPERATORS
; =========
(pointer_declarator "*" @keyword.operator.pointer.cpp)
(abstract_pointer_declarator "*" @keyword.operator.pointer.cpp)
(pointer_expression "*" @keyword.operator.pointer.cpp)
"sizeof" @keyword.operator.sizeof.cpp
(pointer_expression "&" @keyword.operator.pointer.c)
"=" @keyword.operator.assignment.cpp
[
"%="
"+="
"-="
"*="
"/="
"&="
"^="
"<<="
">>="
"|="
] @keyword.operator.assignment.compound.cpp
(binary_expression
["==" "!=" ">" "<" ">=" "<="] @keyword.operator.comparison.cpp)
["&&" "||"] @keyword.operator.logical.cpp
"++" @keyword.operator.increment.cpp
"--" @keyword.operator.decrement.cpp
(binary_expression
["&" "|" "^" "~" "<<" ">>"]
@keyword.operator.bitwise.cpp)
(binary_expression
["<" ">"] @keyword.operator.comparison.cpp)
(binary_expression
["+" "-" "*" "/" "%"] @keyword.operator.arithmetic.cpp)
(unary_expression
["+" "-" "!"] @keyword.operator.unary.cpp)
(conditional_expression
["?" ":"] @keyword.operator.ternary.cpp)
(qualified_identifier
"::" @keyword.operator.accessor.namespace.cpp)
(field_expression "." @keyword.operator.accessor.dot.cpp)
(preproc_params "..." @keyword.operator.ellipsis.cpp)
; PUNCTUATION
; ===========
";" @punctuation.terminator.statement.cpp
"," @punctuation.separator.comma.cpp
"->" @punctuation.separator.pointer-access.cpp
"{" @punctuation.definition.begin.brace.curly.cpp
"}" @punctuation.definition.end.brace.curly.cpp
"(" @punctuation.definition.begin.brace.round.cpp
")" @punctuation.definition.end.brace.round.cpp
"[" @punctuation.definition.begin.brace.square.cpp
"]" @punctuation.definition.end.brace.square.cpp
; TODO:
;
; * TM-style grammar has a lot of `mac-classic` scopes. I doubt they'd be
; present if this wasn't converted from a TextMate grammar, so I'm leaving
; them out for now.
;
; (
; (compound_statement) @invalid.illegal
; )
(compound_statement
(compound_statement) @invalid.illegal
)

View File

@ -0,0 +1,32 @@
["{" "(" "["] @indent
["}" ")" "]"] @dedent
; With access specifiers like…
;
; class Foo {
; public:
; void bar() {}
; }
;
; …prevailing style is to dedent the specifier so it matches the indentation of
; the line above.
(access_specifier) @dedent @indent
; `switch` statements have a couple schools of thought, indentation-wise, and
; we might have to make this configurable somehow.
(switch_statement
body: (compound_statement "}" @match
(#set! onlyIfLast true))
(#set! matchIndentOf parent.startPosition))
; 'case' and 'default' need to be indented one level more than their containing
; `switch`.
(["case" "default"] @match
(#set! matchIndentOf parent.parent.startPosition)
(#set! offsetIndent 1))
["case" "default"] @indent

View File

@ -0,0 +1 @@
;