├── .gitignore ├── CONTRIBUTING.md ├── lib └── main.js ├── README.md ├── .github ├── workflows │ └── main.yml └── no-response.yml ├── settings └── language-c.cson ├── package.json ├── coffeelint.json ├── PULL_REQUEST_TEMPLATE.md ├── LICENSE.md ├── ISSUE_TEMPLATE.md ├── snippets └── language-c.cson ├── grammars ├── tree-sitter-c.cson ├── tree-sitter-cpp.cson ├── c++.cson └── c.cson └── spec └── c-spec.coffee /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | See the [Atom contributing guide](https://github.com/atom/atom/blob/master/CONTRIBUTING.md) 2 | -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | exports.activate = function () { 2 | // Highlight macro bodies as C/C++ 3 | for (const language of ['c', 'cpp']) { 4 | for (const nodeType of ['preproc_def', 'preproc_function_def']) { 5 | atom.grammars.addInjectionPoint(`source.${language}`, { 6 | type: nodeType, 7 | language (node) { return language }, 8 | content (node) { return node.lastNamedChild } 9 | }) 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ##### Atom and all repositories under Atom will be archived on December 15, 2022. Learn more in our [official announcement](https://github.blog/2022-06-08-sunsetting-atom/) 2 | # C/C++ language support in Atom 3 | ![CI Status](https://github.com/atom/language-c/actions/workflows/main.yml/badge.svg) 4 | 5 | Adds syntax highlighting and snippets to C/C++ files in Atom. 6 | 7 | Originally [converted](http://flight-manual.atom.io/hacking-atom/sections/converting-from-textmate) 8 | from the [C TextMate bundle](https://github.com/textmate/c.tmbundle). 9 | 10 | Contributions are greatly appreciated. Please fork this repository and open a 11 | pull request to add snippets, make grammar tweaks, etc. 12 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | env: 6 | CI: true 7 | 8 | jobs: 9 | Test: 10 | strategy: 11 | matrix: 12 | os: [ubuntu-latest, macos-latest, windows-latest] 13 | channel: [stable, beta] 14 | runs-on: ${{ matrix.os }} 15 | steps: 16 | - uses: actions/checkout@v1 17 | - uses: UziTech/action-setup-atom@v2 18 | with: 19 | version: ${{ matrix.channel }} 20 | - name: Install windows-build-tools 21 | if: ${{ matrix.os == 'windows-latest' }} 22 | run: | 23 | npm i windows-build-tools@4.0.0 24 | - name: Install dependencies 25 | run: apm install 26 | - name: Run tests 27 | run: atom --test spec 28 | -------------------------------------------------------------------------------- /settings/language-c.cson: -------------------------------------------------------------------------------- 1 | '.source.c, .source.cpp, .source.objc, .source.objcpp': 2 | 'editor': 3 | 'commentStart': '// ' 4 | 'increaseIndentPattern': '(?x) 5 | ^ .* \\{ [^}"\']* $ 6 | |^ .* \\( [^\\)"\']* $ 7 | |^ \\s* (public|private|protected): \\s* $ 8 | |^ \\s* @(public|private|protected) \\s* $ 9 | |^ \\s* \\{ \\} $ 10 | ' 11 | 'decreaseIndentPattern': '(?x) 12 | ^ \\s* (\\s* /[*] .* [*]/ \\s*)* \\} 13 | |^ \\s* (\\s* /[*] .* [*]/ \\s*)* \\) 14 | |^ \\s* (public|private|protected): \\s* $ 15 | |^ \\s* @(public|private|protected) \\s* $ 16 | ' 17 | '.source.c, .source.cpp': 18 | 'editor': 19 | 'foldEndPattern': '(? 11 | This issue has been automatically closed because there has been no response 12 | to our request for more information from the original author. With only the 13 | information that is currently in the issue, we don't have enough information 14 | to take action. Please reach out if you have or find the answers we need so 15 | that we can investigate further. 16 | -------------------------------------------------------------------------------- /coffeelint.json: -------------------------------------------------------------------------------- 1 | { 2 | "max_line_length": { 3 | "level": "ignore" 4 | }, 5 | "no_empty_param_list": { 6 | "level": "error" 7 | }, 8 | "arrow_spacing": { 9 | "level": "error" 10 | }, 11 | "no_interpolation_in_single_quotes": { 12 | "level": "error" 13 | }, 14 | "no_debugger": { 15 | "level": "error" 16 | }, 17 | "prefer_english_operator": { 18 | "level": "error" 19 | }, 20 | "colon_assignment_spacing": { 21 | "spacing": { 22 | "left": 0, 23 | "right": 1 24 | }, 25 | "level": "error" 26 | }, 27 | "braces_spacing": { 28 | "spaces": 0, 29 | "level": "error" 30 | }, 31 | "spacing_after_comma": { 32 | "level": "error" 33 | }, 34 | "no_stand_alone_at": { 35 | "level": "error" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Requirements 2 | 3 | * Filling out the template is required. Any pull request that does not include enough information to be reviewed in a timely manner may be closed at the maintainers' discretion. 4 | * All new code requires tests to ensure against regressions 5 | 6 | ### Description of the Change 7 | 8 | 13 | 14 | ### Alternate Designs 15 | 16 | 17 | 18 | ### Benefits 19 | 20 | 21 | 22 | ### Possible Drawbacks 23 | 24 | 25 | 26 | ### Applicable Issues 27 | 28 | 29 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 GitHub Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------- 23 | 24 | This package was derived from a TextMate bundle located at 25 | https://github.com/textmate/c.tmbundle and distributed under the following 26 | license, located in `README.mdown`: 27 | 28 | Permission to copy, use, modify, sell and distribute this 29 | software is granted. This software is provided "as is" without 30 | express or implied warranty, and with no claim as to its 31 | suitability for any purpose. 32 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | ### Prerequisites 10 | 11 | * [ ] Put an X between the brackets on this line if you have done all of the following: 12 | * Reproduced the problem in Safe Mode: http://flight-manual.atom.io/hacking-atom/sections/debugging/#using-safe-mode 13 | * Followed all applicable steps in the debugging guide: http://flight-manual.atom.io/hacking-atom/sections/debugging/ 14 | * Checked the FAQs on the message board for common solutions: https://discuss.atom.io/c/faq 15 | * Checked that your issue isn't already filed: https://github.com/issues?utf8=✓&q=is%3Aissue+user%3Aatom 16 | * Checked that there is not already an Atom package that provides the described functionality: https://atom.io/packages 17 | 18 | ### Description 19 | 20 | [Description of the issue] 21 | 22 | ### Steps to Reproduce 23 | 24 | 1. [First Step] 25 | 2. [Second Step] 26 | 3. [and so on...] 27 | 28 | **Expected behavior:** [What you expect to happen] 29 | 30 | **Actual behavior:** [What actually happens] 31 | 32 | **Reproduces how often:** [What percentage of the time does it reproduce?] 33 | 34 | ### Versions 35 | 36 | You can get this information from copy and pasting the output of `atom --version` and `apm --version` from the command line. Also, please include the OS and what version of the OS you're running. 37 | 38 | ### Additional Information 39 | 40 | Any additional information, configuration or data that might be necessary to reproduce the issue. 41 | -------------------------------------------------------------------------------- /snippets/language-c.cson: -------------------------------------------------------------------------------- 1 | '.source.c, .source.cpp, .source.objc, .source.objcpp': 2 | '#ifndef … #define … #endif': 3 | 'prefix': 'def' 4 | 'body': '#ifndef ${1:SYMBOL}\n#define $1 ${2:value}\n#endif' 5 | '#include <>': 6 | 'prefix': 'Inc' 7 | 'body': '#include <${1:.h}>' 8 | '#include ""': 9 | 'prefix': 'inc' 10 | 'body': '#include "${1:.h}"' 11 | '#pragma mark': 12 | 'prefix': 'mark' 13 | 'body': '#if 0\n${1:#pragma mark -\n}#pragma mark $2\n#endif\n\n$0' 14 | 'main()': 15 | 'prefix': 'main' 16 | 'body': 'int main(int argc, char const *argv[]) {\n\t${1:/* code */}\n\treturn 0;\n}' 17 | 'For Loop': 18 | 'prefix': 'for' 19 | 'body': 'for (size_t ${1:i} = 0; ${1:i} < ${2:count}; ${1:i}${3:++}) {\n\t${4:/* code */}\n}' 20 | 'Header Include-Guard': 21 | 'prefix': 'once' 22 | 'body': '#ifndef ${1:SYMBOL}\n#define $1\n\n${2}\n\n#endif /* end of include guard: $1 */\n' 23 | 'Shared Pointer': 24 | 'prefix': 'sp' 25 | 'body': 'typedef std::shared_ptr<${2:${1:my_type}_t}> ${3:${4:my_type}_ptr};' 26 | 'Typedef': 27 | 'prefix': 'td' 28 | 'body': 'typedef ${1:int} ${2:MyCustomType};' 29 | 'Do While Loop': 30 | 'prefix': 'do' 31 | 'body': 'do {\n\t${0:/* code */}\n} while(${1:/* condition */});' 32 | 'While Loop': 33 | 'prefix': 'while' 34 | 'body': 'while (${1:/* condition */}) {\n\t${2:/* code */}\n}' 35 | 'fprintf': 36 | 'prefix': 'fprintf' 37 | 'body': 'fprintf(${1:stderr}, "${2:%s}\\\\n", $3);$4' 38 | 'If Condition': 39 | 'prefix': 'if' 40 | 'body': 'if (${1:/* condition */}) {\n\t${2:/* code */}\n}' 41 | 'If Else': 42 | 'prefix': 'ife' 43 | 'body': 'if (${1:/* condition */}) {\n\t${2:/* code */}\n} else {\n\t${3:/* code */}\n}' 44 | 'If ElseIf': 45 | 'prefix': 'iff' 46 | 'body': 'if (${1:/* condition */}) {\n\t${2:/* code */}\n} else if (${3:/* condition */}) {\n\t${4:/* code */}\n}' 47 | 'If ElseIf Else': 48 | 'prefix': 'iffe' 49 | 'body': 'if (${1:/* condition */}) {\n\t${2:/* code */}\n} else if (${3:/* condition */}) {\n\t${4:/* code */}\n} else {\n\t${5:/* code */}\n}' 50 | 'Switch Statement': 51 | 'prefix': 'switch' 52 | 'body': 'switch (${1:/* expression */}) {\n\tcase ${2:/* value */}:\n}' 53 | 'case': 54 | 'prefix': 'cs' 55 | 'body': 'case ${1:/* value */}:$0' 56 | 'printf': 57 | 'prefix': 'printf' 58 | 'body': 'printf("${1:%s}\\\\n", $2);$3' 59 | 'scanf': 60 | 'prefix': 'scanf' 61 | 'body': 'scanf(\"${1:%s}\\\\n\", $2);$3' 62 | 'Struct': 63 | 'prefix': 'st' 64 | 'body': 'struct ${1:name_t} {\n\t${2:/* data */}\n};' 65 | 'void': 66 | 'prefix': 'void' 67 | 'body': 'void ${1:name}(${2:/* arguments */}) {\n\t${3:/* code */}\n}' 68 | 'any function': 69 | 'prefix': 'func' 70 | 'body': '${1:int} ${2:name}(${3:/* arguments */}) {\n\t${5:/* code */}\n\treturn ${4:0};\n}' 71 | 'write file': 72 | 'prefix': 'wf' 73 | 'body': 'FILE *${1:fp};\n${1:fp} = fopen ("${2:filename.txt}","w");\nif (${1:fp}!=NULL)\n{\n\tfprintf(${1:fp},"${3:Some String\\\\n}");\n\tfclose (${1:fp});\n}' 74 | 'read file': 75 | 'prefix': 'rf' 76 | 'body': 'FILE *${1:fp};\n${1:fp} = fopen ("${2:filename.txt}","r");\nif (${1:fp}!=NULL)\n{\n\tfscanf(${1:fp},"${3:Some String\\\\n}", ${3:&var});\n\tfclose (${1:fp});\n}' 77 | '.source.cpp, .source.objcpp': 78 | 'Enumeration': 79 | 'prefix': 'enum' 80 | 'body': 'enum ${1:name} { $0 };' 81 | 'Class': 82 | 'prefix': 'cl' 83 | 'body': 'class ${1:name_t} {\nprivate:\n\t${0:/* data */}\n\npublic:\n\t${1:name_t} (${2:arguments});\n\tvirtual ~${1:name_t} ();\n};' 84 | 'Namespace': 85 | 'prefix': 'ns' 86 | 'body': 'namespace ${1:name} {\n\t$2\n} /* $1 */' 87 | 'cout': 88 | 'prefix': 'cout' 89 | 'body': 'std::cout << \"${1:/* message */}\" << \'\\\\n\';' 90 | 'cin': 91 | 'prefix': 'cin' 92 | 'body': 'std::cin >> ${1:/* variable */};' 93 | 'cerr': 94 | 'prefix': 'cerr' 95 | 'body': 'std::cerr << \"${1:/* error message */}\" << \'\\\\n\';' 96 | 'std::map': 97 | 'prefix': 'map' 98 | 'body': 'std::map<${1:key}, ${2:value}> map$3;' 99 | 'std::string': 100 | 'prefix': 'str' 101 | 'body': 'std::string' 102 | 'std::vector': 103 | 'prefix': 'vector' 104 | 'body': 'std::vector<${1:int}> v$2;' 105 | 'template ': 106 | 'prefix': 'tp' 107 | 'body': 'template ' 108 | 'output file': 109 | 'prefix': 'outf' 110 | 'body': 'std::ofstream ${1:afile}("${2:filename.txt}", std::ios::out);\nif (${1:afile}.is_open()) {\n\t${1:afile} << "${3:This is a line.}\\\\n";\n\t${1:afile}.close();\n}' 111 | 'input file': 112 | 'prefix': 'inf' 113 | 'body': 'std::ifstream ${1:afile}("${2:filename.txt}", std::ios::in);\nif (${1:afile}.is_open()) {\n\tstd::string line;\n\twhile (std::getline(${1:afile}, line)) {\n\t\tstd::cout << line << \'\\\\n\';\n\t}\n\t${1:afile}.close();\n}\nelse {\n\tstd::cerr << "Unable to open file\\\\n";\n}' 114 | -------------------------------------------------------------------------------- /grammars/tree-sitter-c.cson: -------------------------------------------------------------------------------- 1 | name: 'C' 2 | scopeName: 'source.c' 3 | type: 'tree-sitter' 4 | parser: 'tree-sitter-c' 5 | 6 | injectionRegex: 'c|C' 7 | 8 | fileTypes: [ 9 | 'h' 10 | 'c' 11 | 'h.in' 12 | ] 13 | 14 | folds: [ 15 | { 16 | type: ['comment', 'preproc_arg'] 17 | } 18 | { 19 | type: ['preproc_if', 'preproc_ifdef', 'preproc_elif'], 20 | end: {type: ['preproc_else', 'preproc_elif']} 21 | } 22 | { 23 | type: ['preproc_if', 'preproc_ifdef'], 24 | end: {index: -1} 25 | } 26 | { 27 | type: ['preproc_else', 'preproc_elif'] 28 | start: {index: 0} 29 | } 30 | { 31 | type: [ 32 | 'enumerator_list' 33 | 'compound_statement' 34 | 'declaration_list' 35 | 'field_declaration_list' 36 | 'parameter_list' 37 | 'argument_list' 38 | 'initializer_list' 39 | 'parenthesized_expression' 40 | 'template_parameter_list' 41 | 'template_argument_list' 42 | ] 43 | start: {index: 0} 44 | end: {index: -1} 45 | } 46 | { 47 | type: 'case_statement' 48 | start: {index: 0} 49 | end: {type: 'break_statement', index: -1} 50 | } 51 | { 52 | type: 'case_statement' 53 | start: {index: 0} 54 | } 55 | ] 56 | 57 | comments: 58 | start: '// ' 59 | 60 | scopes: 61 | 'translation_unit': 'source.c' 62 | 'comment': 'comment.block' 63 | 64 | 'identifier': [ 65 | {match: '^[A-Z\\d_]+$', scopes: 'constant.other'} 66 | ] 67 | 68 | '"#if"': 'keyword.control.directive' 69 | '"#ifdef"': 'keyword.control.directive' 70 | '"#ifndef"': 'keyword.control.directive' 71 | '"#elif"': 'keyword.control.directive' 72 | '"#else"': 'keyword.control.directive' 73 | '"#endif"': 'keyword.control.directive' 74 | '"#define"': 'keyword.control.directive' 75 | '"#include"': 'keyword.control.directive' 76 | 'preproc_directive': 'keyword.control.directive' 77 | 78 | '"if"': 'keyword.control' 79 | '"else"': 'keyword.control' 80 | '"do"': 'keyword.control' 81 | '"for"': 'keyword.control' 82 | '"while"': 'keyword.control' 83 | '"break"': 'keyword.control' 84 | '"continue"': 'keyword.control' 85 | '"return"': 'keyword.control' 86 | '"switch"': 'keyword.control' 87 | '"case"': 'keyword.control' 88 | '"default"': 'keyword.control' 89 | '"goto"': 'keyword.control' 90 | 91 | '"struct"': 'keyword.control' 92 | '"enum"': 'keyword.control' 93 | '"union"': 'keyword.control' 94 | '"typedef"': 'keyword.control' 95 | 96 | 'preproc_function_def > identifier:nth-child(1)': 'entity.name.function.preprocessor' 97 | 'preproc_arg': 'meta.preprocessor.macro' 98 | 99 | ''' 100 | call_expression > identifier, 101 | call_expression > field_expression > field_identifier, 102 | function_declarator > identifier 103 | ''': 'entity.name.function' 104 | 105 | 'statement_identifier': 'constant.variable' 106 | 107 | 'field_identifier': 'variable.other.member' 108 | 109 | 'type_identifier': 'support.storage.type' 110 | 'primitive_type': 'support.storage.type' 111 | '"signed"': 'support.storage.type' 112 | '"unsigned"': 'support.storage.type' 113 | '"short"': 'support.storage.type' 114 | '"long"': 'support.storage.type' 115 | 116 | 'char_literal': 'string.quoted.single' 117 | 'string_literal': 'string.quoted.double' 118 | 'system_lib_string': 'string.quoted.other' 119 | 'escape_sequence': 'constant.character.escape' 120 | 121 | 'number_literal': 'constant.numeric.decimal' 122 | 'null': 'constant.language.null' 123 | 'true': 'constant.language.boolean' 124 | 'false': 'constant.language.boolean' 125 | 126 | 'auto': 'storage.modifier' 127 | '"extern"': 'storage.modifier' 128 | '"register"': 'storage.modifier' 129 | '"static"': 'storage.modifier' 130 | '"inline"': 'storage.modifier' 131 | '"const"': 'storage.modifier' 132 | '"volatile"': 'storage.modifier' 133 | '"restrict"': 'storage.modifier' 134 | '"_Atomic"': 'storage.modifier' 135 | 'function_specifier': 'storage.modifier' 136 | 137 | '";"': 'punctuation.terminator.statement' 138 | '"["': 'punctuation.definition.begin.bracket.square' 139 | '"]"': 'punctuation.definition.end.bracket.square' 140 | '","': 'punctuation.separator.delimiter' 141 | 'char_literal > "\'"': 'punctuation.definition.string' 142 | 'string_literal > "\\""': 'punctuation.definition.string' 143 | '"{"': 'punctuation.section.block.begin.bracket.curly' 144 | '"}"': 'punctuation.section.block.end.bracket.curly' 145 | '"("': 'punctuation.section.parens.begin.bracket.round' 146 | '")"': 'punctuation.section.parens.end.bracket.round' 147 | 148 | '"sizeof"': 'keyword.operator.sizeof' 149 | '"."': 'keyword.operator.member' 150 | '"->"': 'keyword.operator.member' 151 | '"*"': 'keyword.operator' 152 | '"-"': 'keyword.operator' 153 | '"+"': 'keyword.operator' 154 | '"/"': 'keyword.operator' 155 | '"%"': 'keyword.operator' 156 | '"++"': 'keyword.operator' 157 | '"--"': 'keyword.operator' 158 | '"=="': 'keyword.operator' 159 | '"!"': 'keyword.operator' 160 | '"!="': 'keyword.operator' 161 | '"<"': 'keyword.operator' 162 | '">"': 'keyword.operator' 163 | '">="': 'keyword.operator' 164 | '"<="': 'keyword.operator' 165 | '"&&"': 'keyword.operator' 166 | '"||"': 'keyword.operator' 167 | '"&"': 'keyword.operator' 168 | '"|"': 'keyword.operator' 169 | '"^"': 'keyword.operator' 170 | '"~"': 'keyword.operator' 171 | '"<<"': 'keyword.operator' 172 | '">>"': 'keyword.operator' 173 | '"="': 'keyword.operator' 174 | '"+="': 'keyword.operator' 175 | '"-="': 'keyword.operator' 176 | '"*="': 'keyword.operator' 177 | '"/="': 'keyword.operator' 178 | '"%="': 'keyword.operator' 179 | '"<<="': 'keyword.operator' 180 | '">>="': 'keyword.operator' 181 | '"&="': 'keyword.operator' 182 | '"^="': 'keyword.operator' 183 | '"|="': 'keyword.operator' 184 | '"?"': 'keyword.operator' 185 | '":"': 'keyword.operator' 186 | -------------------------------------------------------------------------------- /grammars/tree-sitter-cpp.cson: -------------------------------------------------------------------------------- 1 | name: 'C++' 2 | scopeName: 'source.cpp' 3 | type: 'tree-sitter' 4 | parser: 'tree-sitter-cpp' 5 | 6 | injectionRegex: '(c|C)(\\+\\+|pp|PP)' 7 | 8 | fileTypes: [ 9 | 'cc' 10 | 'cpp' 11 | 'cp' 12 | 'cxx' 13 | 'c++' 14 | 'cu' 15 | 'cuh' 16 | 'h' 17 | 'hh' 18 | 'hpp' 19 | 'hxx' 20 | 'h++' 21 | 'inl' 22 | 'ino' 23 | 'ipp' 24 | 'tcc' 25 | 'tpp' 26 | ] 27 | 28 | contentRegex: '\n\\s*(namespace|class|template)\\s+' 29 | 30 | folds: [ 31 | { 32 | type: ['comment', 'preproc_arg'] 33 | } 34 | { 35 | type: ['preproc_if', 'preproc_ifdef', 'preproc_elif'], 36 | end: {type: ['preproc_else', 'preproc_elif']} 37 | } 38 | { 39 | type: ['preproc_if', 'preproc_ifdef'], 40 | end: {index: -1} 41 | } 42 | { 43 | type: ['preproc_else', 'preproc_elif'] 44 | start: {index: 0} 45 | } 46 | { 47 | type: [ 48 | 'enumerator_list' 49 | 'compound_statement' 50 | 'declaration_list' 51 | 'field_declaration_list' 52 | 'parameter_list' 53 | 'argument_list' 54 | 'initializer_list' 55 | 'parenthesized_expression' 56 | 'template_parameter_list' 57 | 'template_argument_list' 58 | ] 59 | start: {index: 0} 60 | end: {index: -1} 61 | } 62 | { 63 | type: 'case_statement' 64 | start: {index: 0} 65 | end: {type: 'break_statement', index: -1} 66 | } 67 | { 68 | type: 'case_statement' 69 | start: {index: 0} 70 | } 71 | ] 72 | 73 | comments: 74 | start: '// ' 75 | 76 | scopes: 77 | 'translation_unit': 'source.cpp' 78 | 'comment': 'comment.block' 79 | 80 | 'identifier': [ 81 | {match: '^[A-Z\\d_]+$', scopes: 'constant.other'} 82 | ] 83 | 84 | '"#if"': 'keyword.control.directive' 85 | '"#ifdef"': 'keyword.control.directive' 86 | '"#ifndef"': 'keyword.control.directive' 87 | '"#elif"': 'keyword.control.directive' 88 | '"#else"': 'keyword.control.directive' 89 | '"#endif"': 'keyword.control.directive' 90 | '"#define"': 'keyword.control.directive' 91 | '"#include"': 'keyword.control.directive' 92 | 'preproc_directive': 'keyword.control.directive' 93 | 94 | '"if"': 'keyword.control' 95 | '"else"': 'keyword.control' 96 | '"do"': 'keyword.control' 97 | '"for"': 'keyword.control' 98 | '"while"': 'keyword.control' 99 | '"break"': 'keyword.control' 100 | '"continue"': 'keyword.control' 101 | '"return"': 'keyword.control' 102 | '"switch"': 'keyword.control' 103 | '"case"': 'keyword.control' 104 | '"default"': 'keyword.control' 105 | '"goto"': 'keyword.control' 106 | 107 | '"struct"': 'keyword.control' 108 | '"enum"': 'keyword.control' 109 | '"union"': 'keyword.control' 110 | '"typedef"': 'keyword.control' 111 | '"class"': 'keyword.control' 112 | '"using"': 'keyword.control' 113 | '"namespace"': 'keyword.control' 114 | '"template"': 'keyword.control' 115 | '"typename"': 'keyword.control' 116 | '"try"': 'keyword.control' 117 | '"catch"': 'keyword.control' 118 | '"throw"': 'keyword.control' 119 | '"__attribute__"': 'keyword.attribute' 120 | 121 | 'preproc_function_def > identifier:nth-child(1)': 'entity.name.function.preprocessor' 122 | 'preproc_arg': 'meta.preprocessor.macro' 123 | 'preproc_directive': 'keyword.control.directive' 124 | 125 | 'template_function > identifier': [ 126 | { 127 | match: '^(static|const|dynamic|reinterpret)_cast$' 128 | scopes: 'keyword.operator' 129 | } 130 | ] 131 | 132 | ''' 133 | call_expression > identifier, 134 | call_expression > field_expression > field_identifier, 135 | call_expression > scoped_identifier > identifier, 136 | template_function > identifier, 137 | template_function > scoped_identifier > identifier, 138 | template_method > field_identifier, 139 | function_declarator > identifier, 140 | function_declarator > field_identifier, 141 | function_declarator > scoped_identifier > identifier, 142 | destructor_name > identifier 143 | ''': 'entity.name.function' 144 | 145 | 'statement_identifier': 'constant.variable' 146 | 147 | 'field_identifier': 'variable.other.member' 148 | 149 | 'type_identifier': 'support.storage.type' 150 | 'primitive_type': 'support.storage.type' 151 | '"unsigned"': 'support.storage.type' 152 | '"signed"': 'support.storage.type' 153 | '"short"': 'support.storage.type' 154 | '"long"': 'support.storage.type' 155 | 'auto': 'support.storage.type' 156 | 157 | 'char_literal': 'string.quoted.single' 158 | 'string_literal': 'string.quoted.double' 159 | 'system_lib_string': 'string.quoted.other' 160 | 'raw_string_literal': 'string.quoted.other' 161 | 'escape_sequence': 'constant.character.escape' 162 | 'preproc_include > string_literal > escape_sequence': 'string.quoted.double' 163 | 164 | 'number_literal': 'constant.numeric.decimal' 165 | 'null': 'constant.language.null' 166 | 'nullptr': 'constant.language.null' 167 | 'true': 'constant.language.boolean' 168 | 'false': 'constant.language.boolean' 169 | 170 | '"extern"': 'storage.modifier' 171 | '"static"': 'storage.modifier' 172 | '"register"': 'storage.modifier' 173 | '"friend"': 'storage.modifier' 174 | '"inline"': 'storage.modifier' 175 | '"explicit"': 'storage.modifier' 176 | '"const"': 'storage.modifier' 177 | '"constexpr"': 'storage.modifier' 178 | '"volatile"': 'storage.modifier' 179 | '"restrict"': 'storage.modifier' 180 | 'function_specifier': 'storage.modifier' 181 | '"public"': 'storage.modifier' 182 | '"private"': 'storage.modifier' 183 | '"protected"': 'storage.modifier' 184 | '"final"': 'storage.modifier' 185 | '"override"': 'storage.modifier' 186 | '"virtual"': 'storage.modifier' 187 | '"noexcept"': 'storage.modifier' 188 | '"mutable"': 'storage.modifier' 189 | 190 | '";"': 'punctuation.terminator.statement' 191 | '"["': 'punctuation.definition.begin.bracket.square' 192 | '"]"': 'punctuation.definition.end.bracket.square' 193 | 'access_specifier > ":"': 'punctuation.definition.visibility.colon' 194 | 'base_class_clause > ":"': 'punctuation.definition.inheritance.colon' 195 | 'base_class_clause > ","': 'punctuation.definition.separator.class.comma' 196 | 'field_declaration > ","': 'punctuation.separator.delimiter' 197 | 'parameter_list > ","': 'punctuation.separator.delimiter' 198 | 'field_initializer_list > ":"': 'punctuation.definition.initialization.colon' 199 | 'field_initializer_list > ","': 'punctuation.separator.delimiter' 200 | '"::"': 'punctuation.separator.method.double-colon' 201 | 'template_parameter_list > "<"': 'punctuation.definition.template.bracket.angle' 202 | 'template_parameter_list > ">"': 'punctuation.definition.template.bracket.angle' 203 | 'template_argument_list > ">"': 'punctuation.definition.template.bracket.angle' 204 | 'template_argument_list > "<"': 'punctuation.definition.template.bracket.angle' 205 | 'char_literal > "\'"': 'punctuation.definition.string' 206 | 'string_literal > "\\""': 'punctuation.definition.string' 207 | '"{"': 'punctuation.section.block.begin.bracket.curly' 208 | '"}"': 'punctuation.section.block.end.bracket.curly' 209 | '"("': 'punctuation.section.parens.begin.bracket.round' 210 | '")"': 'punctuation.section.parens.end.bracket.round' 211 | 212 | '"sizeof"': 'keyword.operator.sizeof' 213 | '"new"': 'keyword.operator' 214 | '"delete"': 'keyword.operator' 215 | '"."': 'keyword.operator.member' 216 | '"->"': 'keyword.operator.member' 217 | '"*"': 'keyword.operator' 218 | '"-"': 'keyword.operator' 219 | '"+"': 'keyword.operator' 220 | '"/"': 'keyword.operator' 221 | '"%"': 'keyword.operator' 222 | '"++"': 'keyword.operator' 223 | '"--"': 'keyword.operator' 224 | '"=="': 'keyword.operator' 225 | '"!"': 'keyword.operator' 226 | '"!="': 'keyword.operator' 227 | 'relational_expression > "<"': 'keyword.operator' 228 | 'relational_expression > ">"': 'keyword.operator' 229 | '">="': 'keyword.operator' 230 | '"<="': 'keyword.operator' 231 | '"&&"': 'keyword.operator' 232 | '"||"': 'keyword.operator' 233 | '"&"': 'keyword.operator' 234 | '"|"': 'keyword.operator' 235 | '"^"': 'keyword.operator' 236 | '"~"': 'keyword.operator' 237 | '"<<"': 'keyword.operator' 238 | '">>"': 'keyword.operator' 239 | '"="': 'keyword.operator' 240 | '"+="': 'keyword.operator' 241 | '"-="': 'keyword.operator' 242 | '"*="': 'keyword.operator' 243 | '"/="': 'keyword.operator' 244 | '"%="': 'keyword.operator' 245 | '"<<="': 'keyword.operator' 246 | '">>="': 'keyword.operator' 247 | '"&="': 'keyword.operator' 248 | '"^="': 'keyword.operator' 249 | '"|="': 'keyword.operator' 250 | '"?"': 'keyword.operator' 251 | 'conditional_expression > ":"': 'keyword.operator' 252 | -------------------------------------------------------------------------------- /grammars/c++.cson: -------------------------------------------------------------------------------- 1 | 'scopeName': 'source.cpp' 2 | 'fileTypes': [ 3 | 'cc' 4 | 'cpp' 5 | 'cp' 6 | 'cxx' 7 | 'c++' 8 | 'cu' 9 | 'cuh' 10 | 'h' 11 | 'hh' 12 | 'hpp' 13 | 'hxx' 14 | 'h++' 15 | 'inl' 16 | 'ino' 17 | 'ipp' 18 | 'tcc' 19 | 'tpp' 20 | ] 21 | 'firstLineMatch': '(?i)-\\*-[^*]*(Mode:\\s*)?C\\+\\+(\\s*;.*?)?\\s*-\\*-' 22 | 'name': 'C++' 23 | 'patterns': [ 24 | { 25 | 'include': '#special_block' 26 | } 27 | { 28 | 'include': '#strings' 29 | } 30 | { 31 | 'match': '\\b(friend|explicit|virtual|override|final|noexcept)\\b' 32 | 'name': 'storage.modifier.cpp' 33 | } 34 | { 35 | 'match': '\\b(private:|protected:|public:)' 36 | 'name': 'storage.modifier.cpp' 37 | } 38 | { 39 | 'match': '\\b(catch|operator|try|throw|using)\\b' 40 | 'name': 'keyword.control.cpp' 41 | } 42 | { 43 | 'match': '\\bdelete\\b(\\s*\\[\\])?|\\bnew\\b(?!])' 44 | 'name': 'keyword.control.cpp' 45 | } 46 | { 47 | # Common naming idiom for C++ instanced vars: "fMemberName" 48 | 'match': '\\b(f|m)[A-Z]\\w*\\b' 49 | 'name': 'variable.other.readwrite.member.cpp' 50 | } 51 | { 52 | 'match': '\\bthis\\b' 53 | 'name': 'variable.language.this.cpp' 54 | } 55 | { 56 | 'match': '\\bnullptr\\b' 57 | 'name': 'constant.language.cpp' 58 | } 59 | { 60 | 'match': '\\btemplate\\b\\s*' 61 | 'name': 'storage.type.template.cpp' 62 | } 63 | { 64 | 'match': '\\b(const_cast|dynamic_cast|reinterpret_cast|static_cast)\\b\\s*' 65 | 'name': 'keyword.operator.cast.cpp' 66 | } 67 | { 68 | 'match': '::' 69 | 'name': 'punctuation.separator.namespace.access.cpp' 70 | } 71 | { 72 | 'match': '\\b(and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|typeid|xor|xor_eq|alignof|alignas)\\b' 73 | 'name': 'keyword.operator.cpp' 74 | } 75 | { 76 | 'match': '\\b(class|decltype|wchar_t|char16_t|char32_t)\\b' 77 | 'name': 'storage.type.cpp' 78 | } 79 | { 80 | 'match': '\\b(constexpr|export|mutable|typename|thread_local)\\b' 81 | 'name': 'storage.modifier.cpp' 82 | } 83 | { 84 | 'begin': '''(?x) 85 | (?: 86 | ^ | # beginning of line 87 | (?:(?' 141 | 'name': 'meta.angle-brackets.cpp' 142 | 'patterns': [ 143 | { 144 | 'include': '#angle_brackets' 145 | } 146 | { 147 | 'include': '$base' 148 | } 149 | ] 150 | 'block': 151 | 'begin': '\\{' 152 | 'beginCaptures': 153 | '0': 154 | 'name': 'punctuation.section.block.begin.bracket.curly.c' 155 | 'end': '\\}' 156 | 'endCaptures': 157 | '0': 158 | 'name': 'punctuation.section.block.end.bracket.curly.c' 159 | 'name': 'meta.block.cpp' 160 | 'patterns': [ 161 | { 162 | 'captures': 163 | '1': 164 | 'name': 'support.function.any-method.c' 165 | '2': 166 | 'name': 'punctuation.definition.parameters.c' 167 | 'match': '''(?x) 168 | ( 169 | (?!while|for|do|if|else|switch|catch|enumerate|return|r?iterate) 170 | (?:\\b[A-Za-z_][A-Za-z0-9_]*+\\b|::)*+ # actual name 171 | ) 172 | \\s*(\\() # opening bracket 173 | ''' 174 | 'name': 'meta.function-call.c' 175 | } 176 | { 177 | 'include': '$base' 178 | } 179 | ] 180 | 'constructor': 181 | 'patterns': [ 182 | { 183 | 'begin': '''(?x) 184 | (?:^\\s*) # beginning of line 185 | ((?!while|for|do|if|else|switch|catch|enumerate|r?iterate)[A-Za-z_][A-Za-z0-9_:]*) # actual name 186 | \\s*(\\() # opening bracket 187 | ''' 188 | 'beginCaptures': 189 | '1': 190 | 'name': 'entity.name.function.cpp' 191 | '2': 192 | 'name': 'punctuation.definition.parameters.begin.c' 193 | 'end': '\\)' 194 | 'endCaptures': 195 | '0': 196 | 'name': 'punctuation.definition.parameters.end.c' 197 | 'name': 'meta.function.constructor.cpp' 198 | 'patterns': [ 199 | { 200 | 'include': '$base' 201 | } 202 | ] 203 | } 204 | { 205 | 'begin': '''(?x) 206 | (:) 207 | ( 208 | (?= 209 | \\s*[A-Za-z_][A-Za-z0-9_:]* # actual name 210 | \\s* (\\() # opening bracket 211 | ) 212 | ) 213 | ''' 214 | 'beginCaptures': 215 | '1': 216 | 'name': 'punctuation.definition.parameters.c' 217 | 'end': '(?=\\{)' 218 | 'name': 'meta.function.constructor.initializer-list.cpp' 219 | 'patterns': [ 220 | { 221 | 'include': '$base' 222 | } 223 | ] 224 | } 225 | ] 226 | 'special_block': 227 | 'patterns': [ 228 | { 229 | "begin": "\\b(using)\\b\\s*(namespace)\\b\\s*((?:[_A-Za-z][_A-Za-z0-9]*\\b(::)?)*)", 230 | "beginCaptures": { 231 | "1": { 232 | "name": "keyword.control.cpp" 233 | }, 234 | "2": { 235 | "name": "storage.type.cpp" 236 | }, 237 | "3": { 238 | "name": "entity.name.type.cpp" 239 | } 240 | }, 241 | "end": "(;)", 242 | "name": "meta.using-namespace-declaration.cpp" 243 | }, 244 | { 245 | 'begin': '\\b(namespace)\\b\\s*([_A-Za-z][_A-Za-z0-9]*\\b)?+' 246 | 'beginCaptures': 247 | '1': 248 | 'name': 'storage.type.cpp' 249 | '2': 250 | 'name': 'entity.name.type.cpp' 251 | 'captures': 252 | '1': 253 | 'name': 'keyword.control.namespace.$2' 254 | 'end': '(?<=\\})|(?=(;|,|\\(|\\)|>|\\[|\\]|=))' 255 | 'name': 'meta.namespace-block.cpp' 256 | 'patterns': [ 257 | { 258 | 'begin': '\\{' 259 | 'beginCaptures': 260 | '0': 261 | 'name': 'punctuation.definition.scope.cpp' 262 | 'end': '\\}' 263 | 'endCaptures': 264 | '0': 265 | 'name': 'punctuation.definition.scope.cpp' 266 | 'patterns': [ 267 | { 268 | 'include': '#special_block' 269 | } 270 | { 271 | 'include': '#constructor' 272 | } 273 | { 274 | 'include': '$base' 275 | } 276 | ] 277 | } 278 | { 279 | 'include': '$base' 280 | } 281 | ] 282 | } 283 | { 284 | 'begin': '\\b(class|struct)\\b\\s*([_A-Za-z][_A-Za-z0-9]*\\b)?+(\\s*:\\s*(public|protected|private)\\s*([_A-Za-z][_A-Za-z0-9]*\\b)((\\s*,\\s*(public|protected|private)\\s*[_A-Za-z][_A-Za-z0-9]*\\b)*))?' 285 | 'beginCaptures': 286 | '1': 287 | 'name': 'storage.type.cpp' 288 | '2': 289 | 'name': 'entity.name.type.cpp' 290 | '4': 291 | 'name': 'storage.type.modifier.cpp' 292 | '5': 293 | 'name': 'entity.name.type.inherited.cpp' 294 | '6': 295 | 'patterns': [ 296 | { 297 | 'match': '(public|protected|private)' 298 | 'name': 'storage.type.modifier.cpp' 299 | } 300 | { 301 | 'match': '[_A-Za-z][_A-Za-z0-9]*' 302 | 'name': 'entity.name.type.inherited.cpp' 303 | } 304 | ] 305 | 'end': '(?<=\\})|(?=(;|\\(|\\)|>|\\[|\\]|=))' 306 | 'name': 'meta.class-struct-block.cpp' 307 | 'patterns': [ 308 | { 309 | 'include': '#angle_brackets' 310 | } 311 | { 312 | 'begin': '\\{' 313 | 'beginCaptures': 314 | '0': 315 | 'name': 'punctuation.section.block.begin.bracket.curly.cpp' 316 | 'end': '(\\})(\\s*\\n)?' 317 | 'endCaptures': 318 | '1': 319 | 'name': 'punctuation.section.block.end.bracket.curly.cpp' 320 | '2': 321 | 'name': 'invalid.illegal.you-forgot-semicolon.cpp' 322 | 'patterns': [ 323 | { 324 | 'include': '#special_block' 325 | } 326 | { 327 | 'include': '#constructor' 328 | } 329 | { 330 | 'include': '$base' 331 | } 332 | ] 333 | } 334 | { 335 | 'include': '$base' 336 | } 337 | ] 338 | } 339 | { 340 | 'begin': '\\b(extern)(?=\\s*")' 341 | 'beginCaptures': 342 | '1': 343 | 'name': 'storage.modifier.cpp' 344 | 'end': '(?<=\\})|(?=\\w)|(?=\\s*#\\s*endif\\b)' 345 | 'name': 'meta.extern-block.cpp' 346 | 'patterns': [ 347 | { 348 | 'begin': '\\{' 349 | 'beginCaptures': 350 | '0': 351 | 'name': 'punctuation.section.block.begin.bracket.curly.c' 352 | 'end': '\\}|(?=\\s*#\\s*endif\\b)' 353 | 'endCaptures': 354 | '0': 355 | 'name': 'punctuation.section.block.end.bracket.curly.c' 356 | 'patterns': [ 357 | { 358 | 'include': '#special_block' 359 | } 360 | { 361 | 'include': '$base' 362 | } 363 | ] 364 | } 365 | { 366 | 'include': '$base' 367 | } 368 | ] 369 | } 370 | ] 371 | 'strings': 372 | 'patterns': [ 373 | { 374 | 'begin': '(u|u8|U|L)?"' 375 | 'beginCaptures': 376 | '0': 377 | 'name': 'punctuation.definition.string.begin.cpp' 378 | '1': 379 | 'name': 'meta.encoding.cpp' 380 | 'end': '"' 381 | 'endCaptures': 382 | '0': 383 | 'name': 'punctuation.definition.string.end.cpp' 384 | 'name': 'string.quoted.double.cpp' 385 | 'patterns': [ 386 | { 387 | 'match': '\\\\u\\h{4}|\\\\U\\h{8}' 388 | 'name': 'constant.character.escape.cpp' 389 | } 390 | { 391 | 'match': '\\\\[\'"?\\\\abfnrtv]' 392 | 'name': 'constant.character.escape.cpp' 393 | } 394 | { 395 | 'match': '\\\\[0-7]{1,3}' 396 | 'name': 'constant.character.escape.cpp' 397 | } 398 | { 399 | 'match': '\\\\x\\h+' 400 | 'name': 'constant.character.escape.cpp' 401 | } 402 | { 403 | 'include': 'source.c#string_placeholder' 404 | } 405 | ] 406 | } 407 | { 408 | 'begin': '(u|u8|U|L)?R"(?:([^ ()\\\\\\t]{0,16})|([^ ()\\\\\\t]*))\\(' 409 | 'beginCaptures': 410 | '0': 411 | 'name': 'punctuation.definition.string.begin.cpp' 412 | '1': 413 | 'name': 'meta.encoding.cpp' 414 | '3': 415 | 'name': 'invalid.illegal.delimiter-too-long.cpp' 416 | 'end': '\\)\\2(\\3)"' 417 | 'endCaptures': 418 | '0': 419 | 'name': 'punctuation.definition.string.end.cpp' 420 | '1': 421 | 'name': 'invalid.illegal.delimiter-too-long.cpp' 422 | 'name': 'string.quoted.double.raw.cpp' 423 | } 424 | ] 425 | -------------------------------------------------------------------------------- /grammars/c.cson: -------------------------------------------------------------------------------- 1 | 'scopeName': 'source.c' 2 | 'fileTypes': [ 3 | 'c' 4 | 'h.in' 5 | 'xpm' 6 | ] 7 | 'firstLineMatch': '(?i)-\\*-[^*]*(Mode:\\s*)?C(\\s*;.*?)?\\s*-\\*-' 8 | 'name': 'C' 9 | 'patterns': [ 10 | { 11 | 'include': '#preprocessor-rule-enabled' 12 | } 13 | { 14 | 'include': '#preprocessor-rule-disabled' 15 | } 16 | { 17 | 'include': '#preprocessor-rule-conditional' 18 | } 19 | { 20 | 'include': '#comments' 21 | } 22 | { 23 | 'match': '\\b(break|case|continue|default|do|else|for|goto|if|_Pragma|return|switch|while)\\b' 24 | 'name': 'keyword.control.c' 25 | } 26 | { 27 | 'include': '#storage_types' 28 | } 29 | { 30 | 'match': '\\b(const|extern|register|restrict|static|volatile|inline)\\b' 31 | 'name': 'storage.modifier.c' 32 | } 33 | { 34 | # Common naming idiom for C constants: "kConstantVariable" 35 | 'match': '\\bk[A-Z]\\w*\\b' 36 | 'name': 'constant.other.variable.mac-classic.c' 37 | } 38 | { 39 | 'match': '\\bg[A-Z]\\w*\\b' 40 | 'name': 'variable.other.readwrite.global.mac-classic.c' 41 | } 42 | { 43 | 'match': '\\bs[A-Z]\\w*\\b' 44 | 'name': 'variable.other.readwrite.static.mac-classic.c' 45 | } 46 | { 47 | 'match': '\\b(NULL|true|false|TRUE|FALSE)\\b' 48 | 'name': 'constant.language.c' 49 | } 50 | { 51 | 'include': '#operators' 52 | } 53 | { 54 | 'include': '#numbers' 55 | } 56 | { 57 | 'include': '#strings' 58 | } 59 | { 60 | 'begin': '''(?x) 61 | ^\\s* ((\\#)\\s*define) \\s+ # define 62 | ((?[a-zA-Z_$][\\w$]*)) # macro name 63 | (?: 64 | (\\() 65 | ( 66 | \\s* \\g \\s* # first argument 67 | ((,) \\s* \\g \\s*)* # additional arguments 68 | (?:\\.\\.\\.)? # varargs ellipsis? 69 | ) 70 | (\\)) 71 | )? 72 | ''' 73 | 'beginCaptures': 74 | '1': 75 | 'name': 'keyword.control.directive.define.c' 76 | '2': 77 | 'name': 'punctuation.definition.directive.c' 78 | '3': 79 | 'name': 'entity.name.function.preprocessor.c' 80 | '5': 81 | 'name': 'punctuation.definition.parameters.begin.c' 82 | '6': 83 | 'name': 'variable.parameter.preprocessor.c' 84 | '8': 85 | 'name': 'punctuation.separator.parameters.c' 86 | '9': 87 | 'name': 'punctuation.definition.parameters.end.c' 88 | 'end': '(?=(?://|/\\*))|(?' 147 | 'endCaptures': 148 | '0': 149 | 'name': 'punctuation.definition.string.end.c' 150 | 'name': 'string.quoted.other.lt-gt.include.c' 151 | } 152 | ] 153 | } 154 | { 155 | 'include': '#pragma-mark' 156 | } 157 | { 158 | 'begin': '^\\s*((#)\\s*line)\\b' 159 | 'beginCaptures': 160 | '1': 161 | 'name': 'keyword.control.directive.line.c' 162 | '2': 163 | 'name': 'punctuation.definition.directive.c' 164 | 'end': '(?=(?://|/\\*))|(?=+!]+|\\(\\)|\\[\\]))\\s*\\( 275 | ) 276 | ''' 277 | 'end': '(?<=\\))(?!\\w)' 278 | 'name': 'meta.function.c' 279 | 'patterns': [ 280 | { 281 | 'include': '#function-innards' 282 | } 283 | ] 284 | } 285 | { 286 | 'include': '#line_continuation_character' 287 | } 288 | { 289 | 'match': '(\\[)|(\\])' 290 | 'captures': 291 | '1': 292 | 'name': 'punctuation.definition.begin.bracket.square.c' 293 | '2': 294 | 'name': 'punctuation.definition.end.bracket.square.c' 295 | } 296 | { 297 | 'match': ';' 298 | 'name': 'punctuation.terminator.statement.c' 299 | } 300 | { 301 | 'match': ',' 302 | 'name': 'punctuation.separator.delimiter.c' 303 | } 304 | ] 305 | 'repository': 306 | 'access': 307 | 'captures': 308 | '2': 309 | 'name': 'punctuation.separator.dot-access.c' 310 | '3': 311 | 'name': 'punctuation.separator.pointer-access.c' 312 | '4': 313 | 'name': 'variable.other.member.c' 314 | 'match': '((\\.)|(->))\\s*(([a-zA-Z_][a-zA-Z_0-9]*)\\b(?!\\s*\\())?' 315 | 'block': 316 | 'patterns': [ 317 | { 318 | 'begin': '{' 319 | 'beginCaptures': 320 | '0': 321 | 'name': 'punctuation.section.block.begin.bracket.curly.c' 322 | 'end': '}|(?=\\s*#\\s*(?:elif|else|endif)\\b)' 323 | 'endCaptures': 324 | '0': 325 | 'name': 'punctuation.section.block.end.bracket.curly.c' 326 | 'name': 'meta.block.c' 327 | 'patterns': [ 328 | { 329 | 'include': '#block_innards' 330 | } 331 | ] 332 | } 333 | ] 334 | 'block_innards': 335 | 'patterns': [ 336 | { 337 | 'include': '#preprocessor-rule-enabled-block' 338 | } 339 | { 340 | 'include': '#preprocessor-rule-disabled-block' 341 | } 342 | { 343 | 'include': '#preprocessor-rule-conditional-block' 344 | } 345 | { 346 | 'include': '#access' 347 | } 348 | { 349 | 'include': '#libc' 350 | } 351 | { 352 | 'include': '#c_function_call' 353 | } 354 | { 355 | 'captures': 356 | '1': 357 | 'name': 'variable.other.c' 358 | '2': 359 | 'name': 'punctuation.definition.parameters.c' 360 | 'match': '''(?x) 361 | (?: 362 | (?: 363 | (?=\\s)(?=+!]+ | \\(\\) | \\[\\])) 371 | ) 372 | \\s*(\\() # opening bracket 373 | ''' 374 | 'name': 'meta.initialization.c' 375 | } 376 | { 377 | # Prevent unnecessary nesting of meta.block.c scope 378 | 'begin': '{' 379 | 'beginCaptures': 380 | '0': 381 | 'name': 'punctuation.section.block.begin.bracket.curly.c' 382 | 'end': '}|(?=\\s*#\\s*(?:elif|else|endif)\\b)' 383 | 'endCaptures': 384 | '0': 385 | 'name': 'punctuation.section.block.end.bracket.curly.c' 386 | 'patterns': [ 387 | { 388 | 'include': '#block_innards' 389 | } 390 | ] 391 | } 392 | { 393 | 'include': '#parens-block' 394 | } 395 | { 396 | 'include': '$base' 397 | } 398 | ] 399 | 'c_function_call': 400 | # FIRST CAPTURE meta.function-call.c scope (provides an injectable scope, balanced parentheses and prevents unnecessary scope nesting) 401 | 'begin': '''(?x) 402 | (?!(?:while|for|do|if|else|switch|catch|enumerate|return|typeid|alignof|alignas|sizeof|[cr]?iterate)\\s*\\() 403 | (?= 404 | (?:[A-Za-z_][A-Za-z0-9_]*+|::)++\\s*\\( # actual name 405 | | 406 | (?:(?<=operator)(?:[-*&<>=+!]+|\\(\\)|\\[\\]))\\s*\\( 407 | ) 408 | ''' 409 | 'end': '(?<=\\))(?!\\w)' 410 | 'name': 'meta.function-call.c' 411 | 'patterns': [ 412 | { 413 | 'include': '#function-call-innards' 414 | } 415 | ] 416 | 'comments': 417 | 'patterns': [ 418 | { 419 | 'captures': 420 | '1': 421 | 'name': 'meta.toc-list.banner.block.c' 422 | 'match': '^/\\* =(\\s*.*?)\\s*= \\*/$\\n?' 423 | 'name': 'comment.block.c' 424 | } 425 | { 426 | 'begin': '/\\*' 427 | 'beginCaptures': 428 | '0': 429 | 'name': 'punctuation.definition.comment.begin.c' 430 | 'end': '\\*/' 431 | 'endCaptures': 432 | '0': 433 | 'name': 'punctuation.definition.comment.end.c' 434 | 'name': 'comment.block.c' 435 | } 436 | { 437 | 'match': '\\*/.*\\n' 438 | 'name': 'invalid.illegal.stray-comment-end.c' 439 | } 440 | { 441 | 'captures': 442 | '1': 443 | 'name': 'meta.toc-list.banner.line.c' 444 | 'match': '^// =(\\s*.*?)\\s*=\\s*$\\n?' 445 | 'name': 'comment.line.banner.cpp' 446 | } 447 | { 448 | 'begin': '(^[ \\t]+)?(?=//)' 449 | 'beginCaptures': 450 | '1': 451 | 'name': 'punctuation.whitespace.comment.leading.cpp' 452 | 'end': '(?!\\G)' 453 | 'patterns': [ 454 | { 455 | 'begin': '//' 456 | 'beginCaptures': 457 | '0': 458 | 'name': 'punctuation.definition.comment.cpp' 459 | 'end': '(?=\\n)' 460 | 'name': 'comment.line.double-slash.cpp' 461 | 'patterns': [ 462 | { 463 | 'include': '#line_continuation_character' 464 | } 465 | ] 466 | } 467 | ] 468 | } 469 | ] 470 | 'disabled': 471 | # Consume nested preprocessor if(def)s 472 | 'begin': '^\\s*#\\s*if(n?def)?\\b.*$' 473 | 'end': '^\\s*#\\s*endif\\b' 474 | 'patterns': [ 475 | { 476 | 'include': '#disabled' 477 | } 478 | { 479 | 'include': '#pragma-mark' 480 | } 481 | ] 482 | 'libc': 483 | 'captures': 484 | '1': 485 | 'name': 'punctuation.whitespace.support.function.leading.c' 486 | '2': 487 | 'name': 'support.function.C99.c' 488 | 'match': '''(?x) (\\s*) \\b 489 | (_Exit|(?:nearbyint|nextafter|nexttoward|netoward|nan)[fl]?|a(?:cos|sin)h?[fl]?|abort|abs|asctime|assert 490 | |atan(?:[h2]?[fl]?)?|atexit|ato[ifl]|atoll|bsearch|btowc|cabs[fl]?|cacos|cacos[fl]|cacosh[fl]? 491 | |calloc|carg[fl]?|casinh?[fl]?|catanh?[fl]?|cbrt[fl]?|ccosh?[fl]?|ceil[fl]?|cexp[fl]?|cimag[fl]? 492 | |clearerr|clock|clog[fl]?|conj[fl]?|copysign[fl]?|cosh?[fl]?|cpow[fl]?|cproj[fl]?|creal[fl]? 493 | |csinh?[fl]?|csqrt[fl]?|ctanh?[fl]?|ctime|difftime|div|erfc?[fl]?|exit|fabs[fl]? 494 | |exp(?:2[fl]?|[fl]|m1[fl]?)?|fclose|fdim[fl]?|fe[gs]et(?:env|exceptflag|round)|feclearexcept 495 | |feholdexcept|feof|feraiseexcept|ferror|fetestexcept|feupdateenv|fflush|fgetpos|fgetw?[sc] 496 | |floor[fl]?|fmax?[fl]?|fmin[fl]?|fmod[fl]?|fopen|fpclassify|fprintf|fputw?[sc]|fread|free|freopen 497 | |frexp[fl]?|fscanf|fseek|fsetpos|ftell|fwide|fwprintf|fwrite|fwscanf|genv|get[sc]|getchar|gmtime 498 | |gwc|gwchar|hypot[fl]?|ilogb[fl]?|imaxabs|imaxdiv|isalnum|isalpha|isblank|iscntrl|isdigit|isfinite 499 | |isgraph|isgreater|isgreaterequal|isinf|isless(?:equal|greater)?|isw?lower|isnan|isnormal|isw?print 500 | |isw?punct|isw?space|isunordered|isw?upper|iswalnum|iswalpha|iswblank|iswcntrl|iswctype|iswdigit|iswgraph 501 | |isw?xdigit|labs|ldexp[fl]?|ldiv|lgamma[fl]?|llabs|lldiv|llrint[fl]?|llround[fl]?|localeconv|localtime 502 | |log[2b]?[fl]?|log1[p0][fl]?|longjmp|lrint[fl]?|lround[fl]?|malloc|mbr?len|mbr?towc|mbsinit|mbsrtowcs 503 | |mbstowcs|memchr|memcmp|memcpy|memmove|memset|mktime|modf[fl]?|perror|pow[fl]?|printf|puts|putw?c(?:har)? 504 | |qsort|raise|rand|remainder[fl]?|realloc|remove|remquo[fl]?|rename|rewind|rint[fl]?|round[fl]?|scalbl?n[fl]? 505 | |scanf|setbuf|setjmp|setlocale|setvbuf|signal|signbit|sinh?[fl]?|snprintf|sprintf|sqrt[fl]?|srand|sscanf 506 | |strcat|strchr|strcmp|strcoll|strcpy|strcspn|strerror|strftime|strlen|strncat|strncmp|strncpy|strpbrk 507 | |strrchr|strspn|strstr|strto[kdf]|strtoimax|strtol[dl]?|strtoull?|strtoumax|strxfrm|swprintf|swscanf 508 | |system|tan|tan[fl]|tanh[fl]?|tgamma[fl]?|time|tmpfile|tmpnam|tolower|toupper|trunc[fl]?|ungetw?c|va_arg 509 | |va_copy|va_end|va_start|vfw?printf|vfw?scanf|vprintf|vscanf|vsnprintf|vsprintf|vsscanf|vswprintf|vswscanf 510 | |vwprintf|vwscanf|wcrtomb|wcscat|wcschr|wcscmp|wcscoll|wcscpy|wcscspn|wcsftime|wcslen|wcsncat|wcsncmp|wcsncpy 511 | |wcspbrk|wcsrchr|wcsrtombs|wcsspn|wcsstr|wcsto[dkf]|wcstoimax|wcstol[dl]?|wcstombs|wcstoull?|wcstoumax|wcsxfrm 512 | |wctom?b|wmem(?:set|chr|cpy|cmp|move)|wprintf|wscanf)\\b 513 | ''' 514 | 'line_continuation_character': 515 | 'patterns': [ 516 | { 517 | 'match': '(\\\\)\\n' 518 | 'captures': 519 | '1': 520 | 'name': 'constant.character.escape.line-continuation.c' 521 | } 522 | ] 523 | 'numbers': 524 | 'patterns': [ 525 | { 526 | 'match': '\\b((0(x|X)[0-9a-fA-F]([0-9a-fA-F\']*[0-9a-fA-F])?)|(0(b|B)[01]([01\']*[01])?)|(([0-9]([0-9\']*[0-9])?\\.?[0-9]*([0-9\']*[0-9])?)|(\\.[0-9]([0-9\']*[0-9])?))((e|E)(\\+|-)?[0-9]([0-9\']*[0-9])?)?)(L|l|UL|ul|u|U|F|f|ll|LL|ull|ULL)?\\b' 527 | 'name': 'constant.numeric.c' 528 | } 529 | ] 530 | 'parens': 531 | 'begin': '\\(' 532 | 'beginCaptures': 533 | '0': 534 | 'name': 'punctuation.section.parens.begin.bracket.round.c' 535 | 'end': '\\)' 536 | 'endCaptures': 537 | '0': 538 | 'name': 'punctuation.section.parens.end.bracket.round.c' 539 | 'patterns': [ 540 | { 541 | 'include': '$base' 542 | } 543 | ] 544 | 'parens-block': 545 | 'begin': '\\(' 546 | 'beginCaptures': 547 | '0': 548 | 'name': 'punctuation.section.parens.begin.bracket.round.c' 549 | 'end': '\\)' 550 | 'endCaptures': 551 | '0': 552 | 'name': 'punctuation.section.parens.end.bracket.round.c' 553 | 'patterns': [ 554 | { 555 | 'include': '#block_innards' 556 | } 557 | ] 558 | 'pragma-mark': 559 | 'captures': 560 | '1': 561 | 'name': 'meta.preprocessor.pragma.c' 562 | '2': 563 | 'name': 'keyword.control.directive.pragma.pragma-mark.c' 564 | '3': 565 | 'name': 'punctuation.definition.directive.c' 566 | '4': 567 | 'name': 'entity.name.tag.pragma-mark.c' 568 | 'match': '^\\s*(((#)\\s*pragma\\s+mark)\\s+(.*))' 569 | 'name': 'meta.section' 570 | 'operators': 571 | 'patterns': [ 572 | { 573 | 'match': '(?>=|\\|=' 590 | 'name': 'keyword.operator.assignment.compound.bitwise.c' 591 | } 592 | { 593 | 'match': '<<|>>' 594 | 'name': 'keyword.operator.bitwise.shift.c' 595 | } 596 | { 597 | 'match': '!=|<=|>=|==|<|>' 598 | 'name': 'keyword.operator.comparison.c' 599 | } 600 | { 601 | 'match': '&&|!|\\|\\|' 602 | 'name': 'keyword.operator.logical.c' 603 | } 604 | { 605 | 'match': '&|\\||\\^|~' 606 | 'name': 'keyword.operator.c' 607 | } 608 | { 609 | 'match': '=' 610 | 'name': 'keyword.operator.assignment.c' 611 | } 612 | { 613 | 'match': '%|\\*|/|-|\\+' 614 | 'name': 'keyword.operator.c' 615 | } 616 | { 617 | 'begin': '\\?' 618 | 'beginCaptures': 619 | '0': 620 | 'name': 'keyword.operator.ternary.c' 621 | 'end': ':' 622 | 'applyEndPatternLast': true # To prevent matching C++ namespace access :: 623 | 'endCaptures': 624 | '0': 625 | 'name': 'keyword.operator.ternary.c' 626 | 'patterns': [ 627 | { 628 | 'include': '#access' 629 | } 630 | { 631 | 'include': '#libc' 632 | } 633 | { 634 | 'include': '#c_function_call' 635 | } 636 | { 637 | 'include': '$base' 638 | } 639 | ] 640 | } 641 | ] 642 | 'strings': 643 | 'patterns': [ 644 | { 645 | 'begin': '"' 646 | 'beginCaptures': 647 | '0': 648 | 'name': 'punctuation.definition.string.begin.c' 649 | 'end': '"' 650 | 'endCaptures': 651 | '0': 652 | 'name': 'punctuation.definition.string.end.c' 653 | 'name': 'string.quoted.double.c' 654 | 'patterns': [ 655 | { 656 | 'include': '#string_escaped_char' 657 | } 658 | { 659 | 'include': '#string_placeholder' 660 | } 661 | { 662 | 'include': '#line_continuation_character' 663 | } 664 | ] 665 | } 666 | { 667 | 'begin': '\'' 668 | 'beginCaptures': 669 | '0': 670 | 'name': 'punctuation.definition.string.begin.c' 671 | 'end': '\'' 672 | 'endCaptures': 673 | '0': 674 | 'name': 'punctuation.definition.string.end.c' 675 | 'name': 'string.quoted.single.c' 676 | 'patterns': [ 677 | { 678 | 'include': '#string_escaped_char' 679 | } 680 | { 681 | 'include': '#line_continuation_character' 682 | } 683 | ] 684 | } 685 | ] 686 | 'string_escaped_char': 687 | 'patterns': [ 688 | { 689 | 'match': '''(?x)\\\\ ( 690 | \\\\ | 691 | [abefnprtv'"?] | 692 | [0-3]\\d{,2} | 693 | [4-7]\\d? | 694 | x[a-fA-F0-9]{,2} | 695 | u[a-fA-F0-9]{,4} | 696 | U[a-fA-F0-9]{,8} ) 697 | ''' 698 | 'name': 'constant.character.escape.c' 699 | } 700 | { 701 | 'match': '\\\\.' 702 | 'name': 'invalid.illegal.unknown-escape.c' 703 | } 704 | ] 705 | 'string_placeholder': 706 | 'patterns': [ 707 | { 708 | 'match': '''(?x) % 709 | (\\d+\\$)? # field (argument #) 710 | [#0\\- +']* # flags 711 | [,;:_]? # separator character (AltiVec) 712 | ((-?\\d+)|\\*(-?\\d+\\$)?)? # minimum field width 713 | (\\.((-?\\d+)|\\*(-?\\d+\\$)?)?)? # precision 714 | (hh|h|ll|l|j|t|z|q|L|vh|vl|v|hv|hl)? # length modifier 715 | [diouxXDOUeEfFgGaACcSspn%] # conversion type 716 | ''' 717 | 'name': 'constant.other.placeholder.c' 718 | } 719 | { 720 | 'match': '(%)(?!"\\s*(PRI|SCN))' 721 | 'captures': 722 | '1': 723 | 'name': 'invalid.illegal.placeholder.c' 724 | } 725 | ] 726 | 'storage_types': 727 | 'patterns': [ 728 | { 729 | 'match': '\\b(asm|__asm__|auto|bool|_Bool|char|_Complex|double|enum|float|_Imaginary|int|long|short|signed|struct|typedef|union|unsigned|void)\\b' 730 | 'name': 'storage.type.c' 731 | } 732 | ] 733 | 'vararg_ellipses': 734 | 'match': '(?=+!]+|\\(\\)|\\[\\]))\\s*\\( 1532 | ) 1533 | ''' 1534 | 'end': '(?<=\\))(?!\\w)|(?=+!]+|\\(\\)|\\[\\])) 1645 | ) 1646 | \\s*(\\() 1647 | ''' 1648 | 'beginCaptures': 1649 | '1': 1650 | 'name': 'entity.name.function.c' 1651 | '2': 1652 | 'name': 'punctuation.section.arguments.begin.bracket.round.c' 1653 | 'end': '(\\))|(?=+!]+|\\(\\)|\\[\\])) 1705 | ) 1706 | \\s*(\\() 1707 | ''' 1708 | 'beginCaptures': 1709 | '1': 1710 | 'name': 'entity.name.function.c' 1711 | '2': 1712 | 'name': 'punctuation.section.parameters.begin.bracket.round.c' 1713 | 'end': '\\)' 1714 | 'endCaptures': 1715 | '0': 1716 | 'name': 'punctuation.section.parameters.end.bracket.round.c' 1717 | 'patterns': [ 1718 | { 1719 | 'include': '#function-innards' 1720 | } 1721 | ] 1722 | } 1723 | { 1724 | 'begin': '\\(' 1725 | 'beginCaptures': 1726 | '0': 1727 | 'name': 'punctuation.section.parens.begin.bracket.round.c' 1728 | 'end': '\\)' 1729 | 'endCaptures': 1730 | '0': 1731 | 'name': 'punctuation.section.parens.end.bracket.round.c' 1732 | 'patterns': [ 1733 | { 1734 | 'include': '#function-innards' 1735 | } 1736 | ] 1737 | } 1738 | { 1739 | 'include': '$base' 1740 | } 1741 | ] 1742 | 'function-call-innards': 1743 | 'patterns': [ 1744 | { 1745 | 'include': '#comments' 1746 | } 1747 | { 1748 | 'include': '#storage_types' 1749 | } 1750 | { 1751 | 'include': '#access' 1752 | } 1753 | { 1754 | 'include': '#operators' 1755 | } 1756 | { 1757 | 'begin': '''(?x) 1758 | (?!(?:while|for|do|if|else|switch|catch|enumerate|return|typeid|alignof|alignas|sizeof|[cr]?iterate)\\s*\\() 1759 | ( 1760 | (?:[A-Za-z_][A-Za-z0-9_]*+|::)++ # actual name 1761 | | 1762 | (?:(?<=operator)(?:[-*&<>=+!]+|\\(\\)|\\[\\])) 1763 | ) 1764 | \\s*(\\() 1765 | ''' 1766 | 'beginCaptures': 1767 | '1': 1768 | 'name': 'entity.name.function.c' 1769 | '2': 1770 | 'name': 'punctuation.section.arguments.begin.bracket.round.c' 1771 | 'end': '\\)' 1772 | 'endCaptures': 1773 | '0': 1774 | 'name': 'punctuation.section.arguments.end.bracket.round.c' 1775 | 'patterns': [ 1776 | { 1777 | 'include': '#function-call-innards' 1778 | } 1779 | ] 1780 | } 1781 | { 1782 | 'begin': '\\(' 1783 | 'beginCaptures': 1784 | '0': 1785 | 'name': 'punctuation.section.parens.begin.bracket.round.c' 1786 | 'end': '\\)' 1787 | 'endCaptures': 1788 | '0': 1789 | 'name': 'punctuation.section.parens.end.bracket.round.c' 1790 | 'patterns': [ 1791 | { 1792 | 'include': '#function-call-innards' 1793 | } 1794 | ] 1795 | } 1796 | { 1797 | 'include': '#block_innards' 1798 | } 1799 | ] 1800 | -------------------------------------------------------------------------------- /spec/c-spec.coffee: -------------------------------------------------------------------------------- 1 | TextEditor = null 2 | buildTextEditor = (params) -> 3 | if atom.workspace.buildTextEditor? 4 | atom.workspace.buildTextEditor(params) 5 | else 6 | TextEditor ?= require('atom').TextEditor 7 | new TextEditor(params) 8 | 9 | describe "Language-C", -> 10 | grammar = null 11 | 12 | beforeEach -> 13 | atom.config.set('core.useTreeSitterParsers', false) 14 | 15 | waitsForPromise -> 16 | atom.packages.activatePackage('language-c') 17 | 18 | describe "C", -> 19 | beforeEach -> 20 | grammar = atom.grammars.grammarForScopeName('source.c') 21 | 22 | it "parses the grammar", -> 23 | expect(grammar).toBeTruthy() 24 | expect(grammar.scopeName).toBe 'source.c' 25 | 26 | it "tokenizes punctuation", -> 27 | {tokens} = grammar.tokenizeLine 'hi;' 28 | expect(tokens[1]).toEqual value: ';', scopes: ['source.c', 'punctuation.terminator.statement.c'] 29 | 30 | {tokens} = grammar.tokenizeLine 'a[b]' 31 | expect(tokens[1]).toEqual value: '[', scopes: ['source.c', 'punctuation.definition.begin.bracket.square.c'] 32 | expect(tokens[3]).toEqual value: ']', scopes: ['source.c', 'punctuation.definition.end.bracket.square.c'] 33 | 34 | {tokens} = grammar.tokenizeLine 'a, b' 35 | expect(tokens[1]).toEqual value: ',', scopes: ['source.c', 'punctuation.separator.delimiter.c'] 36 | 37 | it "tokenizes functions", -> 38 | lines = grammar.tokenizeLines ''' 39 | int something(int param) { 40 | return 0; 41 | } 42 | ''' 43 | expect(lines[0][0]).toEqual value: 'int', scopes: ['source.c', 'storage.type.c'] 44 | expect(lines[0][2]).toEqual value: 'something', scopes: ['source.c', 'meta.function.c', 'entity.name.function.c'] 45 | expect(lines[0][3]).toEqual value: '(', scopes: ['source.c', 'meta.function.c', 'punctuation.section.parameters.begin.bracket.round.c'] 46 | expect(lines[0][4]).toEqual value: 'int', scopes: ['source.c', 'meta.function.c', 'storage.type.c'] 47 | expect(lines[0][6]).toEqual value: ')', scopes: ['source.c', 'meta.function.c', 'punctuation.section.parameters.end.bracket.round.c'] 48 | expect(lines[0][8]).toEqual value: '{', scopes: ['source.c', 'meta.block.c', 'punctuation.section.block.begin.bracket.curly.c'] 49 | expect(lines[1][1]).toEqual value: 'return', scopes: ['source.c', 'meta.block.c', 'keyword.control.c'] 50 | expect(lines[1][3]).toEqual value: '0', scopes: ['source.c', 'meta.block.c', 'constant.numeric.c'] 51 | expect(lines[2][0]).toEqual value: '}', scopes: ['source.c', 'meta.block.c', 'punctuation.section.block.end.bracket.curly.c'] 52 | 53 | it "tokenizes varargs ellipses", -> 54 | {tokens} = grammar.tokenizeLine 'void function(...);' 55 | expect(tokens[0]).toEqual value: 'void', scopes: ['source.c', 'storage.type.c'] 56 | expect(tokens[2]).toEqual value: 'function', scopes: ['source.c', 'meta.function.c', 'entity.name.function.c'] 57 | expect(tokens[3]).toEqual value: '(', scopes: ['source.c', 'meta.function.c', 'punctuation.section.parameters.begin.bracket.round.c'] 58 | expect(tokens[4]).toEqual value: '...', scopes: ['source.c', 'meta.function.c', 'punctuation.vararg-ellipses.c'] 59 | expect(tokens[5]).toEqual value: ')', scopes: ['source.c', 'meta.function.c', 'punctuation.section.parameters.end.bracket.round.c'] 60 | 61 | it "tokenizes various _t types", -> 62 | {tokens} = grammar.tokenizeLine 'size_t var;' 63 | expect(tokens[0]).toEqual value: 'size_t', scopes: ['source.c', 'support.type.sys-types.c'] 64 | 65 | {tokens} = grammar.tokenizeLine 'pthread_t var;' 66 | expect(tokens[0]).toEqual value: 'pthread_t', scopes: ['source.c', 'support.type.pthread.c'] 67 | 68 | {tokens} = grammar.tokenizeLine 'int32_t var;' 69 | expect(tokens[0]).toEqual value: 'int32_t', scopes: ['source.c', 'support.type.stdint.c'] 70 | 71 | {tokens} = grammar.tokenizeLine 'myType_t var;' 72 | expect(tokens[0]).toEqual value: 'myType_t', scopes: ['source.c', 'support.type.posix-reserved.c'] 73 | 74 | it "tokenizes 'line continuation' character", -> 75 | {tokens} = grammar.tokenizeLine 'ma' + '\\' + '\n' + 'in(){};' 76 | expect(tokens[0]).toEqual value: 'ma', scopes: ['source.c'] 77 | expect(tokens[1]).toEqual value: '\\', scopes: ['source.c', 'constant.character.escape.line-continuation.c'] 78 | expect(tokens[3]).toEqual value: 'in', scopes: ['source.c', 'meta.function.c', 'entity.name.function.c'] 79 | 80 | describe "strings", -> 81 | it "tokenizes them", -> 82 | delimsByScope = 83 | 'string.quoted.double.c': '"' 84 | 'string.quoted.single.c': '\'' 85 | 86 | for scope, delim of delimsByScope 87 | {tokens} = grammar.tokenizeLine delim + 'a' + delim 88 | expect(tokens[0]).toEqual value: delim, scopes: ['source.c', scope, 'punctuation.definition.string.begin.c'] 89 | expect(tokens[1]).toEqual value: 'a', scopes: ['source.c', scope] 90 | expect(tokens[2]).toEqual value: delim, scopes: ['source.c', scope, 'punctuation.definition.string.end.c'] 91 | 92 | {tokens} = grammar.tokenizeLine delim + 'a' + '\\' + '\n' + 'b' + delim 93 | expect(tokens[0]).toEqual value: delim, scopes: ['source.c', scope, 'punctuation.definition.string.begin.c'] 94 | expect(tokens[1]).toEqual value: 'a', scopes: ['source.c', scope] 95 | expect(tokens[2]).toEqual value: '\\', scopes: ['source.c', scope, 'constant.character.escape.line-continuation.c'] 96 | expect(tokens[4]).toEqual value: 'b', scopes: ['source.c', scope] 97 | expect(tokens[5]).toEqual value: delim, scopes: ['source.c', scope, 'punctuation.definition.string.end.c'] 98 | 99 | {tokens} = grammar.tokenizeLine '"%d"' 100 | expect(tokens[0]).toEqual value: '"', scopes: ['source.c', 'string.quoted.double.c', 'punctuation.definition.string.begin.c'] 101 | expect(tokens[1]).toEqual value: '%d', scopes: ['source.c', 'string.quoted.double.c', 'constant.other.placeholder.c'] 102 | expect(tokens[2]).toEqual value: '"', scopes: ['source.c', 'string.quoted.double.c', 'punctuation.definition.string.end.c'] 103 | 104 | {tokens} = grammar.tokenizeLine '"%"' 105 | expect(tokens[0]).toEqual value: '"', scopes: ['source.c', 'string.quoted.double.c', 'punctuation.definition.string.begin.c'] 106 | expect(tokens[1]).toEqual value: '%', scopes: ['source.c', 'string.quoted.double.c', 'invalid.illegal.placeholder.c'] 107 | expect(tokens[2]).toEqual value: '"', scopes: ['source.c', 'string.quoted.double.c', 'punctuation.definition.string.end.c'] 108 | 109 | {tokens} = grammar.tokenizeLine '"%" PRId32' 110 | expect(tokens[0]).toEqual value: '"', scopes: ['source.c', 'string.quoted.double.c', 'punctuation.definition.string.begin.c'] 111 | expect(tokens[1]).toEqual value: '%', scopes: ['source.c', 'string.quoted.double.c'] 112 | expect(tokens[2]).toEqual value: '"', scopes: ['source.c', 'string.quoted.double.c', 'punctuation.definition.string.end.c'] 113 | 114 | {tokens} = grammar.tokenizeLine '"%" SCNd32' 115 | expect(tokens[0]).toEqual value: '"', scopes: ['source.c', 'string.quoted.double.c', 'punctuation.definition.string.begin.c'] 116 | expect(tokens[1]).toEqual value: '%', scopes: ['source.c', 'string.quoted.double.c'] 117 | expect(tokens[2]).toEqual value: '"', scopes: ['source.c', 'string.quoted.double.c', 'punctuation.definition.string.end.c'] 118 | 119 | describe "comments", -> 120 | it "tokenizes them", -> 121 | {tokens} = grammar.tokenizeLine '/**/' 122 | expect(tokens[0]).toEqual value: '/*', scopes: ['source.c', 'comment.block.c', 'punctuation.definition.comment.begin.c'] 123 | expect(tokens[1]).toEqual value: '*/', scopes: ['source.c', 'comment.block.c', 'punctuation.definition.comment.end.c'] 124 | 125 | {tokens} = grammar.tokenizeLine '/* foo */' 126 | expect(tokens[0]).toEqual value: '/*', scopes: ['source.c', 'comment.block.c', 'punctuation.definition.comment.begin.c'] 127 | expect(tokens[1]).toEqual value: ' foo ', scopes: ['source.c', 'comment.block.c'] 128 | expect(tokens[2]).toEqual value: '*/', scopes: ['source.c', 'comment.block.c', 'punctuation.definition.comment.end.c'] 129 | 130 | {tokens} = grammar.tokenizeLine '*/*' 131 | expect(tokens[0]).toEqual value: '*/*', scopes: ['source.c', 'invalid.illegal.stray-comment-end.c'] 132 | 133 | describe "preprocessor directives", -> 134 | it "tokenizes '#line'", -> 135 | {tokens} = grammar.tokenizeLine '#line 151 "copy.c"' 136 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.line.c', 'punctuation.definition.directive.c'] 137 | expect(tokens[1]).toEqual value: 'line', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.line.c'] 138 | expect(tokens[3]).toEqual value: '151', scopes: ['source.c', 'meta.preprocessor.c', 'constant.numeric.c'] 139 | expect(tokens[5]).toEqual value: '"', scopes: ['source.c', 'meta.preprocessor.c', 'string.quoted.double.c', 'punctuation.definition.string.begin.c'] 140 | expect(tokens[6]).toEqual value: 'copy.c', scopes: ['source.c', 'meta.preprocessor.c', 'string.quoted.double.c'] 141 | expect(tokens[7]).toEqual value: '"', scopes: ['source.c', 'meta.preprocessor.c', 'string.quoted.double.c', 'punctuation.definition.string.end.c'] 142 | 143 | it "tokenizes '#undef'", -> 144 | {tokens} = grammar.tokenizeLine '#undef FOO' 145 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.undef.c', 'punctuation.definition.directive.c'] 146 | expect(tokens[1]).toEqual value: 'undef', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.undef.c'] 147 | expect(tokens[2]).toEqual value: ' ', scopes: ['source.c', 'meta.preprocessor.c'] 148 | expect(tokens[3]).toEqual value: 'FOO', scopes: ['source.c', 'meta.preprocessor.c', 'entity.name.function.preprocessor.c'] 149 | 150 | it "tokenizes '#pragma'", -> 151 | {tokens} = grammar.tokenizeLine '#pragma once' 152 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.pragma.c', 'keyword.control.directive.pragma.c', 'punctuation.definition.directive.c'] 153 | expect(tokens[1]).toEqual value: 'pragma', scopes: ['source.c', 'meta.preprocessor.pragma.c', 'keyword.control.directive.pragma.c'] 154 | expect(tokens[2]).toEqual value: ' ', scopes: ['source.c', 'meta.preprocessor.pragma.c'] 155 | expect(tokens[3]).toEqual value: 'once', scopes: ['source.c', 'meta.preprocessor.pragma.c', 'entity.other.attribute-name.pragma.preprocessor.c'] 156 | 157 | {tokens} = grammar.tokenizeLine '#pragma clang diagnostic ignored "-Wunused-variable"' 158 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.pragma.c', 'keyword.control.directive.pragma.c', 'punctuation.definition.directive.c'] 159 | expect(tokens[1]).toEqual value: 'pragma', scopes: ['source.c', 'meta.preprocessor.pragma.c', 'keyword.control.directive.pragma.c'] 160 | expect(tokens[2]).toEqual value: ' ', scopes: ['source.c', 'meta.preprocessor.pragma.c'] 161 | expect(tokens[3]).toEqual value: 'clang', scopes: ['source.c', 'meta.preprocessor.pragma.c', 'entity.other.attribute-name.pragma.preprocessor.c'] 162 | expect(tokens[5]).toEqual value: 'diagnostic', scopes: ['source.c', 'meta.preprocessor.pragma.c', 'entity.other.attribute-name.pragma.preprocessor.c'] 163 | expect(tokens[7]).toEqual value: 'ignored', scopes: ['source.c', 'meta.preprocessor.pragma.c', 'entity.other.attribute-name.pragma.preprocessor.c'] 164 | expect(tokens[10]).toEqual value: '-Wunused-variable', scopes: ['source.c', 'meta.preprocessor.pragma.c', 'string.quoted.double.c'] 165 | 166 | {tokens} = grammar.tokenizeLine '#pragma mark – Initialization' 167 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.section', 'meta.preprocessor.pragma.c', 'keyword.control.directive.pragma.pragma-mark.c', 'punctuation.definition.directive.c'] 168 | expect(tokens[1]).toEqual value: 'pragma mark', scopes: ['source.c', 'meta.section', 'meta.preprocessor.pragma.c', 'keyword.control.directive.pragma.pragma-mark.c'] 169 | expect(tokens[3]).toEqual value: '– Initialization', scopes: ['source.c', 'meta.section', 'meta.preprocessor.pragma.c', 'entity.name.tag.pragma-mark.c'] 170 | 171 | describe "define", -> 172 | it "tokenizes '#define [identifier name]'", -> 173 | {tokens} = grammar.tokenizeLine '#define _FILE_NAME_H_' 174 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c', 'punctuation.definition.directive.c'] 175 | expect(tokens[1]).toEqual value: 'define', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c'] 176 | expect(tokens[3]).toEqual value: '_FILE_NAME_H_', scopes: ['source.c', 'meta.preprocessor.macro.c', 'entity.name.function.preprocessor.c'] 177 | 178 | it "tokenizes '#define [identifier name] [value]'", -> 179 | {tokens} = grammar.tokenizeLine '#define WIDTH 80' 180 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c', 'punctuation.definition.directive.c'] 181 | expect(tokens[1]).toEqual value: 'define', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c'] 182 | expect(tokens[3]).toEqual value: 'WIDTH', scopes: ['source.c', 'meta.preprocessor.macro.c', 'entity.name.function.preprocessor.c'] 183 | expect(tokens[5]).toEqual value: '80', scopes: ['source.c', 'meta.preprocessor.macro.c', 'constant.numeric.c'] 184 | 185 | {tokens} = grammar.tokenizeLine '#define ABC XYZ(1)' 186 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c', 'punctuation.definition.directive.c'] 187 | expect(tokens[1]).toEqual value: 'define', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c'] 188 | expect(tokens[3]).toEqual value: 'ABC', scopes: ['source.c', 'meta.preprocessor.macro.c', 'entity.name.function.preprocessor.c'] 189 | expect(tokens[4]).toEqual value: ' ', scopes: ['source.c', 'meta.preprocessor.macro.c'] 190 | expect(tokens[5]).toEqual value: 'XYZ', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.function.c', 'entity.name.function.c'] 191 | expect(tokens[6]).toEqual value: '(', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.function.c', 'punctuation.section.arguments.begin.bracket.round.c'] 192 | expect(tokens[7]).toEqual value: '1', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.function.c', 'constant.numeric.c'] 193 | expect(tokens[8]).toEqual value: ')', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.function.c', 'punctuation.section.arguments.end.bracket.round.c'] 194 | 195 | {tokens} = grammar.tokenizeLine '#define PI_PLUS_ONE (3.14 + 1)' 196 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c', 'punctuation.definition.directive.c'] 197 | expect(tokens[1]).toEqual value: 'define', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c'] 198 | expect(tokens[3]).toEqual value: 'PI_PLUS_ONE', scopes: ['source.c', 'meta.preprocessor.macro.c', 'entity.name.function.preprocessor.c'] 199 | expect(tokens[4]).toEqual value: ' ', scopes: ['source.c', 'meta.preprocessor.macro.c'] 200 | expect(tokens[5]).toEqual value: '(', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.section.parens.begin.bracket.round.c'] 201 | expect(tokens[6]).toEqual value: '3.14', scopes: ['source.c', 'meta.preprocessor.macro.c', 'constant.numeric.c'] 202 | expect(tokens[8]).toEqual value: '+', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.operator.c'] 203 | expect(tokens[10]).toEqual value: '1', scopes: ['source.c', 'meta.preprocessor.macro.c', 'constant.numeric.c'] 204 | expect(tokens[11]).toEqual value: ')', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.section.parens.end.bracket.round.c'] 205 | 206 | describe "macros", -> 207 | it "tokenizes them", -> 208 | {tokens} = grammar.tokenizeLine '#define INCREMENT(x) x++' 209 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c', 'punctuation.definition.directive.c'] 210 | expect(tokens[1]).toEqual value: 'define', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c'] 211 | expect(tokens[3]).toEqual value: 'INCREMENT', scopes: ['source.c', 'meta.preprocessor.macro.c', 'entity.name.function.preprocessor.c'] 212 | expect(tokens[4]).toEqual value: '(', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.definition.parameters.begin.c'] 213 | expect(tokens[5]).toEqual value: 'x', scopes: ['source.c', 'meta.preprocessor.macro.c', 'variable.parameter.preprocessor.c'] 214 | expect(tokens[6]).toEqual value: ')', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.definition.parameters.end.c'] 215 | expect(tokens[7]).toEqual value: ' x', scopes: ['source.c', 'meta.preprocessor.macro.c'] 216 | expect(tokens[8]).toEqual value: '++', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.operator.increment.c'] 217 | 218 | {tokens} = grammar.tokenizeLine '#define MULT(x, y) (x) * (y)' 219 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c', 'punctuation.definition.directive.c'] 220 | expect(tokens[1]).toEqual value: 'define', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c'] 221 | expect(tokens[3]).toEqual value: 'MULT', scopes: ['source.c', 'meta.preprocessor.macro.c', 'entity.name.function.preprocessor.c'] 222 | expect(tokens[4]).toEqual value: '(', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.definition.parameters.begin.c'] 223 | expect(tokens[5]).toEqual value: 'x', scopes: ['source.c', 'meta.preprocessor.macro.c', 'variable.parameter.preprocessor.c'] 224 | expect(tokens[6]).toEqual value: ',', scopes: ['source.c', 'meta.preprocessor.macro.c', 'variable.parameter.preprocessor.c', 'punctuation.separator.parameters.c'] 225 | expect(tokens[7]).toEqual value: ' y', scopes: ['source.c', 'meta.preprocessor.macro.c', 'variable.parameter.preprocessor.c'] 226 | expect(tokens[8]).toEqual value: ')', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.definition.parameters.end.c'] 227 | expect(tokens[9]).toEqual value: ' ', scopes: ['source.c', 'meta.preprocessor.macro.c'] 228 | expect(tokens[10]).toEqual value: '(', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.section.parens.begin.bracket.round.c'] 229 | expect(tokens[11]).toEqual value: 'x', scopes: ['source.c', 'meta.preprocessor.macro.c'] 230 | expect(tokens[12]).toEqual value: ')', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.section.parens.end.bracket.round.c'] 231 | expect(tokens[13]).toEqual value: ' ', scopes: ['source.c', 'meta.preprocessor.macro.c'] 232 | expect(tokens[14]).toEqual value: '*', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.operator.c'] 233 | expect(tokens[15]).toEqual value: ' ', scopes: ['source.c', 'meta.preprocessor.macro.c'] 234 | expect(tokens[16]).toEqual value: '(', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.section.parens.begin.bracket.round.c'] 235 | expect(tokens[17]).toEqual value: 'y', scopes: ['source.c', 'meta.preprocessor.macro.c'] 236 | expect(tokens[18]).toEqual value: ')', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.section.parens.end.bracket.round.c'] 237 | 238 | {tokens} = grammar.tokenizeLine '#define SWAP(a, b) do { a ^= b; b ^= a; a ^= b; } while ( 0 )' 239 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c', 'punctuation.definition.directive.c'] 240 | expect(tokens[1]).toEqual value: 'define', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c'] 241 | expect(tokens[3]).toEqual value: 'SWAP', scopes: ['source.c', 'meta.preprocessor.macro.c', 'entity.name.function.preprocessor.c'] 242 | expect(tokens[4]).toEqual value: '(', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.definition.parameters.begin.c'] 243 | expect(tokens[5]).toEqual value: 'a', scopes: ['source.c', 'meta.preprocessor.macro.c', 'variable.parameter.preprocessor.c'] 244 | expect(tokens[6]).toEqual value: ',', scopes: ['source.c', 'meta.preprocessor.macro.c', 'variable.parameter.preprocessor.c', 'punctuation.separator.parameters.c'] 245 | expect(tokens[7]).toEqual value: ' b', scopes: ['source.c', 'meta.preprocessor.macro.c', 'variable.parameter.preprocessor.c'] 246 | expect(tokens[8]).toEqual value: ')', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.definition.parameters.end.c'] 247 | expect(tokens[10]).toEqual value: 'do', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.c'] 248 | expect(tokens[12]).toEqual value: '{', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.section.block.begin.bracket.curly.c'] 249 | expect(tokens[13]).toEqual value: ' a ', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c'] 250 | expect(tokens[14]).toEqual value: '^=', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'keyword.operator.assignment.compound.bitwise.c'] 251 | expect(tokens[15]).toEqual value: ' b', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c'] 252 | expect(tokens[16]).toEqual value: ';', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.terminator.statement.c'] 253 | expect(tokens[17]).toEqual value: ' b ', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c'] 254 | expect(tokens[18]).toEqual value: '^=', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'keyword.operator.assignment.compound.bitwise.c'] 255 | expect(tokens[19]).toEqual value: ' a', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c'] 256 | expect(tokens[20]).toEqual value: ';', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.terminator.statement.c'] 257 | expect(tokens[21]).toEqual value: ' a ', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c'] 258 | expect(tokens[22]).toEqual value: '^=', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'keyword.operator.assignment.compound.bitwise.c'] 259 | expect(tokens[23]).toEqual value: ' b', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c'] 260 | expect(tokens[24]).toEqual value: ';', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.terminator.statement.c'] 261 | expect(tokens[25]).toEqual value: ' ', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c'] 262 | expect(tokens[26]).toEqual value: '}', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.section.block.end.bracket.curly.c'] 263 | expect(tokens[28]).toEqual value: 'while', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.c'] 264 | expect(tokens[29]).toEqual value: ' ', scopes: ['source.c', 'meta.preprocessor.macro.c'] 265 | expect(tokens[30]).toEqual value: '(', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.section.parens.begin.bracket.round.c'] 266 | expect(tokens[32]).toEqual value: '0', scopes: ['source.c', 'meta.preprocessor.macro.c', 'constant.numeric.c'] 267 | expect(tokens[34]).toEqual value: ')', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.section.parens.end.bracket.round.c'] 268 | 269 | it "tokenizes multiline macros", -> 270 | lines = grammar.tokenizeLines ''' 271 | #define max(a,b) (a>b)? \\ 272 | a:b 273 | ''' 274 | expect(lines[0][17]).toEqual value: '\\', scopes: ['source.c', 'meta.preprocessor.macro.c', 'constant.character.escape.line-continuation.c'] 275 | expect(lines[1][0]).toEqual value: ' a', scopes: ['source.c', 'meta.preprocessor.macro.c'] 276 | 277 | lines = grammar.tokenizeLines ''' 278 | #define SWAP(a, b) { \\ 279 | a ^= b; \\ 280 | b ^= a; \\ 281 | a ^= b; \\ 282 | } 283 | ''' 284 | expect(lines[0][0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c', 'punctuation.definition.directive.c'] 285 | expect(lines[0][1]).toEqual value: 'define', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c'] 286 | expect(lines[0][3]).toEqual value: 'SWAP', scopes: ['source.c', 'meta.preprocessor.macro.c', 'entity.name.function.preprocessor.c'] 287 | expect(lines[0][4]).toEqual value: '(', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.definition.parameters.begin.c'] 288 | expect(lines[0][5]).toEqual value: 'a', scopes: ['source.c', 'meta.preprocessor.macro.c', 'variable.parameter.preprocessor.c'] 289 | expect(lines[0][6]).toEqual value: ',', scopes: ['source.c', 'meta.preprocessor.macro.c', 'variable.parameter.preprocessor.c', 'punctuation.separator.parameters.c'] 290 | expect(lines[0][7]).toEqual value: ' b', scopes: ['source.c', 'meta.preprocessor.macro.c', 'variable.parameter.preprocessor.c'] 291 | expect(lines[0][8]).toEqual value: ')', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.definition.parameters.end.c'] 292 | expect(lines[0][10]).toEqual value: '{', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.section.block.begin.bracket.curly.c'] 293 | expect(lines[0][12]).toEqual value: '\\', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'constant.character.escape.line-continuation.c'] 294 | expect(lines[1][1]).toEqual value: '^=', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'keyword.operator.assignment.compound.bitwise.c'] 295 | expect(lines[1][5]).toEqual value: '\\', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'constant.character.escape.line-continuation.c'] 296 | expect(lines[2][1]).toEqual value: '^=', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'keyword.operator.assignment.compound.bitwise.c'] 297 | expect(lines[2][5]).toEqual value: '\\', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'constant.character.escape.line-continuation.c'] 298 | expect(lines[3][1]).toEqual value: '^=', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'keyword.operator.assignment.compound.bitwise.c'] 299 | expect(lines[3][5]).toEqual value: '\\', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'constant.character.escape.line-continuation.c'] 300 | expect(lines[4][0]).toEqual value: '}', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.section.block.end.bracket.curly.c'] 301 | 302 | it "tokenizes complex definitions", -> 303 | lines = grammar.tokenizeLines ''' 304 | #define MakeHook(name) struct HOOK name = {{false, 0L}, \\ 305 | ((HOOKF)(*HookEnt)), ID("hook")} 306 | ''' 307 | expect(lines[0][0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c', 'punctuation.definition.directive.c'] 308 | expect(lines[0][1]).toEqual value: 'define', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c'] 309 | expect(lines[0][3]).toEqual value: 'MakeHook', scopes: ['source.c', 'meta.preprocessor.macro.c', 'entity.name.function.preprocessor.c'] 310 | expect(lines[0][4]).toEqual value: '(', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.definition.parameters.begin.c'] 311 | expect(lines[0][5]).toEqual value: 'name', scopes: ['source.c', 'meta.preprocessor.macro.c', 'variable.parameter.preprocessor.c'] 312 | expect(lines[0][6]).toEqual value: ')', scopes: ['source.c', 'meta.preprocessor.macro.c', 'punctuation.definition.parameters.end.c'] 313 | expect(lines[0][8]).toEqual value: 'struct', scopes: ['source.c', 'meta.preprocessor.macro.c', 'storage.type.c'] 314 | expect(lines[0][10]).toEqual value: '=', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.operator.assignment.c'] 315 | expect(lines[0][12]).toEqual value: '{', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.section.block.begin.bracket.curly.c'] 316 | expect(lines[0][13]).toEqual value: '{', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.section.block.begin.bracket.curly.c'] 317 | expect(lines[0][14]).toEqual value: 'false', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'constant.language.c'] 318 | expect(lines[0][15]).toEqual value: ',', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.separator.delimiter.c'] 319 | expect(lines[0][17]).toEqual value: '0L', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'constant.numeric.c'] 320 | expect(lines[0][18]).toEqual value: '}', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.section.block.end.bracket.curly.c'] 321 | expect(lines[0][19]).toEqual value: ',', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.separator.delimiter.c'] 322 | expect(lines[0][21]).toEqual value: '\\', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'constant.character.escape.line-continuation.c'] 323 | expect(lines[1][0]).toEqual value: '(', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.section.parens.begin.bracket.round.c'] 324 | expect(lines[1][1]).toEqual value: '(', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.section.parens.begin.bracket.round.c'] 325 | expect(lines[1][3]).toEqual value: ')', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.section.parens.end.bracket.round.c'] 326 | expect(lines[1][4]).toEqual value: '(', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.section.parens.begin.bracket.round.c'] 327 | expect(lines[1][5]).toEqual value: '*', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'keyword.operator.c'] 328 | expect(lines[1][7]).toEqual value: ')', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.section.parens.end.bracket.round.c'] 329 | expect(lines[1][8]).toEqual value: ')', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.section.parens.end.bracket.round.c'] 330 | expect(lines[1][9]).toEqual value: ',', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.separator.delimiter.c'] 331 | expect(lines[1][11]).toEqual value: 'ID', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'meta.function.c', 'entity.name.function.c'] 332 | expect(lines[1][12]).toEqual value: '(', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'meta.function.c', 'punctuation.section.arguments.begin.bracket.round.c'] 333 | expect(lines[1][13]).toEqual value: '"', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'meta.function.c', 'string.quoted.double.c', "punctuation.definition.string.begin.c"] 334 | expect(lines[1][14]).toEqual value: 'hook', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'meta.function.c', 'string.quoted.double.c'] 335 | expect(lines[1][15]).toEqual value: '"', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'meta.function.c', 'string.quoted.double.c', "punctuation.definition.string.end.c"] 336 | expect(lines[1][16]).toEqual value: ')', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'meta.function.c', 'punctuation.section.arguments.end.bracket.round.c'] 337 | expect(lines[1][17]).toEqual value: '}', scopes: ['source.c', 'meta.preprocessor.macro.c', 'meta.block.c', 'punctuation.section.block.end.bracket.curly.c'] 338 | 339 | describe "includes", -> 340 | it "tokenizes '#include'", -> 341 | {tokens} = grammar.tokenizeLine '#include ' 342 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.include.c', 'keyword.control.directive.include.c', 'punctuation.definition.directive.c'] 343 | expect(tokens[1]).toEqual value: 'include', scopes: ['source.c', 'meta.preprocessor.include.c', 'keyword.control.directive.include.c'] 344 | expect(tokens[3]).toEqual value: '<', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.other.lt-gt.include.c', 'punctuation.definition.string.begin.c'] 345 | expect(tokens[4]).toEqual value: 'stdio.h', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.other.lt-gt.include.c'] 346 | expect(tokens[5]).toEqual value: '>', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.other.lt-gt.include.c', 'punctuation.definition.string.end.c'] 347 | 348 | {tokens} = grammar.tokenizeLine '#include' 349 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.include.c', 'keyword.control.directive.include.c', 'punctuation.definition.directive.c'] 350 | expect(tokens[1]).toEqual value: 'include', scopes: ['source.c', 'meta.preprocessor.include.c', 'keyword.control.directive.include.c'] 351 | expect(tokens[2]).toEqual value: '<', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.other.lt-gt.include.c', 'punctuation.definition.string.begin.c'] 352 | expect(tokens[3]).toEqual value: 'stdio.h', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.other.lt-gt.include.c'] 353 | expect(tokens[4]).toEqual value: '>', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.other.lt-gt.include.c', 'punctuation.definition.string.end.c'] 354 | 355 | {tokens} = grammar.tokenizeLine '#include_' 356 | expect(tokens[0]).toEqual value: '#include_', scopes: ['source.c'] 357 | 358 | {tokens} = grammar.tokenizeLine '#include "file"' 359 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.include.c', 'keyword.control.directive.include.c', 'punctuation.definition.directive.c'] 360 | expect(tokens[1]).toEqual value: 'include', scopes: ['source.c', 'meta.preprocessor.include.c', 'keyword.control.directive.include.c'] 361 | expect(tokens[3]).toEqual value: '"', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.double.include.c', 'punctuation.definition.string.begin.c'] 362 | expect(tokens[4]).toEqual value: 'file', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.double.include.c'] 363 | expect(tokens[5]).toEqual value: '"', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.double.include.c', 'punctuation.definition.string.end.c'] 364 | 365 | it "tokenizes '#import'", -> 366 | {tokens} = grammar.tokenizeLine '#import "file"' 367 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.include.c', 'keyword.control.directive.import.c', 'punctuation.definition.directive.c'] 368 | expect(tokens[1]).toEqual value: 'import', scopes: ['source.c', 'meta.preprocessor.include.c', 'keyword.control.directive.import.c'] 369 | expect(tokens[3]).toEqual value: '"', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.double.include.c', 'punctuation.definition.string.begin.c'] 370 | expect(tokens[4]).toEqual value: 'file', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.double.include.c'] 371 | expect(tokens[5]).toEqual value: '"', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.double.include.c', 'punctuation.definition.string.end.c'] 372 | 373 | it "tokenizes '#include_next'", -> 374 | {tokens} = grammar.tokenizeLine '#include_next "next.h"' 375 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.include.c', 'keyword.control.directive.include_next.c', 'punctuation.definition.directive.c'] 376 | expect(tokens[1]).toEqual value: 'include_next', scopes: ['source.c', 'meta.preprocessor.include.c', 'keyword.control.directive.include_next.c'] 377 | expect(tokens[3]).toEqual value: '"', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.double.include.c', 'punctuation.definition.string.begin.c'] 378 | expect(tokens[4]).toEqual value: 'next.h', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.double.include.c'] 379 | expect(tokens[5]).toEqual value: '"', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.double.include.c', 'punctuation.definition.string.end.c'] 380 | 381 | describe "diagnostics", -> 382 | it "tokenizes '#error'", -> 383 | {tokens} = grammar.tokenizeLine '#error "C++ compiler required."' 384 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.diagnostic.c', 'keyword.control.directive.diagnostic.error.c', 'punctuation.definition.directive.c'] 385 | expect(tokens[1]).toEqual value: 'error', scopes: ['source.c', 'meta.preprocessor.diagnostic.c', 'keyword.control.directive.diagnostic.error.c'] 386 | expect(tokens[4]).toEqual value: 'C++ compiler required.', scopes: ['source.c', 'meta.preprocessor.diagnostic.c', 'string.quoted.double.c'] 387 | 388 | it "tokenizes '#warning'", -> 389 | {tokens} = grammar.tokenizeLine '#warning "This is a warning."' 390 | expect(tokens[0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.diagnostic.c', 'keyword.control.directive.diagnostic.warning.c', 'punctuation.definition.directive.c'] 391 | expect(tokens[1]).toEqual value: 'warning', scopes: ['source.c', 'meta.preprocessor.diagnostic.c', 'keyword.control.directive.diagnostic.warning.c'] 392 | expect(tokens[4]).toEqual value: 'This is a warning.', scopes: ['source.c', 'meta.preprocessor.diagnostic.c', 'string.quoted.double.c'] 393 | 394 | describe "conditionals", -> 395 | it "tokenizes if-elif-else preprocessor blocks", -> 396 | lines = grammar.tokenizeLines ''' 397 | #if defined(CREDIT) 398 | credit(); 399 | #elif defined(DEBIT) 400 | debit(); 401 | #else 402 | printerror(); 403 | #endif 404 | ''' 405 | expect(lines[0][0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 406 | expect(lines[0][1]).toEqual value: 'if', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 407 | expect(lines[0][3]).toEqual value: 'defined', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 408 | expect(lines[0][5]).toEqual value: 'CREDIT', scopes: ['source.c', 'meta.preprocessor.c', 'entity.name.function.preprocessor.c'] 409 | expect(lines[1][1]).toEqual value: 'credit', scopes: ['source.c', 'meta.function.c', 'entity.name.function.c'] 410 | expect(lines[1][2]).toEqual value: '(', scopes: ['source.c', 'meta.function.c', 'punctuation.section.parameters.begin.bracket.round.c'] 411 | expect(lines[1][3]).toEqual value: ')', scopes: ['source.c', 'meta.function.c', 'punctuation.section.parameters.end.bracket.round.c'] 412 | expect(lines[2][0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 413 | expect(lines[2][1]).toEqual value: 'elif', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 414 | expect(lines[2][3]).toEqual value: 'defined', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 415 | expect(lines[2][5]).toEqual value: 'DEBIT', scopes: ['source.c', 'meta.preprocessor.c', 'entity.name.function.preprocessor.c'] 416 | expect(lines[3][1]).toEqual value: 'debit', scopes: ['source.c', 'meta.function.c', 'entity.name.function.c'] 417 | expect(lines[3][2]).toEqual value: '(', scopes: ['source.c', 'meta.function.c', 'punctuation.section.parameters.begin.bracket.round.c'] 418 | expect(lines[3][3]).toEqual value: ')', scopes: ['source.c', 'meta.function.c', 'punctuation.section.parameters.end.bracket.round.c'] 419 | expect(lines[4][0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 420 | expect(lines[4][1]).toEqual value: 'else', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 421 | expect(lines[5][1]).toEqual value: 'printerror', scopes: ['source.c', 'meta.function.c', 'entity.name.function.c'] 422 | expect(lines[5][2]).toEqual value: '(', scopes: ['source.c', 'meta.function.c', 'punctuation.section.parameters.begin.bracket.round.c'] 423 | expect(lines[5][3]).toEqual value: ')', scopes: ['source.c', 'meta.function.c', 'punctuation.section.parameters.end.bracket.round.c'] 424 | expect(lines[6][0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 425 | expect(lines[6][1]).toEqual value: 'endif', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 426 | 427 | it "tokenizes if-true-else blocks", -> 428 | lines = grammar.tokenizeLines ''' 429 | #if 1 430 | int something() { 431 | #if 1 432 | return 1; 433 | #else 434 | return 0; 435 | #endif 436 | } 437 | #else 438 | int something() { 439 | return 0; 440 | } 441 | #endif 442 | ''' 443 | expect(lines[0][0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 444 | expect(lines[0][1]).toEqual value: 'if', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 445 | expect(lines[0][3]).toEqual value: '1', scopes: ['source.c', 'meta.preprocessor.c', 'constant.numeric.c'] 446 | expect(lines[1][0]).toEqual value: 'int', scopes: ['source.c', 'storage.type.c'] 447 | expect(lines[1][2]).toEqual value: 'something', scopes: ['source.c', 'meta.function.c', 'entity.name.function.c'] 448 | expect(lines[2][1]).toEqual value: '#', scopes: ['source.c', 'meta.block.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 449 | expect(lines[2][2]).toEqual value: 'if', scopes: ['source.c', 'meta.block.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 450 | expect(lines[2][4]).toEqual value: '1', scopes: ['source.c', 'meta.block.c', 'meta.preprocessor.c', 'constant.numeric.c'] 451 | expect(lines[3][1]).toEqual value: 'return', scopes: ['source.c', 'meta.block.c', 'keyword.control.c'] 452 | expect(lines[3][3]).toEqual value: '1', scopes: ['source.c', 'meta.block.c', 'constant.numeric.c'] 453 | expect(lines[4][1]).toEqual value: '#', scopes: ['source.c', 'meta.block.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 454 | expect(lines[4][2]).toEqual value: 'else', scopes: ['source.c', 'meta.block.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 455 | expect(lines[5][0]).toEqual value: ' return 0;', scopes: ['source.c', 'meta.block.c', 'comment.block.preprocessor.else-branch.in-block.c'] 456 | expect(lines[6][1]).toEqual value: '#', scopes: ['source.c', 'meta.block.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 457 | expect(lines[6][2]).toEqual value: 'endif', scopes: ['source.c', 'meta.block.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 458 | expect(lines[8][0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 459 | expect(lines[8][1]).toEqual value: 'else', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 460 | expect(lines[9][0]).toEqual value: 'int something() {', scopes: ['source.c', 'comment.block.preprocessor.else-branch.c'] 461 | expect(lines[12][0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 462 | expect(lines[12][1]).toEqual value: 'endif', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 463 | 464 | it "tokenizes if-false-else blocks", -> 465 | lines = grammar.tokenizeLines ''' 466 | int something() { 467 | #if 0 468 | return 1; 469 | #else 470 | return 0; 471 | #endif 472 | } 473 | ''' 474 | expect(lines[0][0]).toEqual value: 'int', scopes: ['source.c', 'storage.type.c'] 475 | expect(lines[0][2]).toEqual value: 'something', scopes: ['source.c', 'meta.function.c', 'entity.name.function.c'] 476 | expect(lines[1][1]).toEqual value: '#', scopes: ['source.c', 'meta.block.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 477 | expect(lines[1][2]).toEqual value: 'if', scopes: ['source.c', 'meta.block.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 478 | expect(lines[1][4]).toEqual value: '0', scopes: ['source.c', 'meta.block.c', 'meta.preprocessor.c', 'constant.numeric.c'] 479 | expect(lines[2][0]).toEqual value: ' return 1;', scopes: ['source.c', 'meta.block.c', 'comment.block.preprocessor.if-branch.in-block.c'] 480 | expect(lines[3][1]).toEqual value: '#', scopes: ['source.c', 'meta.block.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 481 | expect(lines[3][2]).toEqual value: 'else', scopes: ['source.c', 'meta.block.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 482 | expect(lines[4][1]).toEqual value: 'return', scopes: ['source.c', 'meta.block.c', 'keyword.control.c'] 483 | expect(lines[4][3]).toEqual value: '0', scopes: ['source.c', 'meta.block.c', 'constant.numeric.c'] 484 | expect(lines[5][1]).toEqual value: '#', scopes: ['source.c', 'meta.block.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 485 | expect(lines[5][2]).toEqual value: 'endif', scopes: ['source.c', 'meta.block.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 486 | 487 | lines = grammar.tokenizeLines ''' 488 | #if 0 489 | something(); 490 | #endif 491 | ''' 492 | expect(lines[0][0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 493 | expect(lines[0][1]).toEqual value: 'if', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 494 | expect(lines[0][3]).toEqual value: '0', scopes: ['source.c', 'meta.preprocessor.c', 'constant.numeric.c'] 495 | expect(lines[1][0]).toEqual value: ' something();', scopes: ['source.c', 'comment.block.preprocessor.if-branch.c'] 496 | expect(lines[2][0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 497 | expect(lines[2][1]).toEqual value: 'endif', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 498 | 499 | it "tokenizes ifdef-elif blocks", -> 500 | lines = grammar.tokenizeLines ''' 501 | #ifdef __unix__ /* is defined by compilers targeting Unix systems */ 502 | # include 503 | #elif defined _WIN32 /* is defined by compilers targeting Windows systems */ 504 | # include 505 | #endif 506 | ''' 507 | expect(lines[0][0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 508 | expect(lines[0][1]).toEqual value: 'ifdef', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 509 | expect(lines[0][3]).toEqual value: '__unix__', scopes: ['source.c', 'meta.preprocessor.c', 'entity.name.function.preprocessor.c'] 510 | expect(lines[0][5]).toEqual value: '/*', scopes: ['source.c', 'comment.block.c', 'punctuation.definition.comment.begin.c'] 511 | expect(lines[0][6]).toEqual value: ' is defined by compilers targeting Unix systems ', scopes: ['source.c', 'comment.block.c'] 512 | expect(lines[0][7]).toEqual value: '*/', scopes: ['source.c', 'comment.block.c', 'punctuation.definition.comment.end.c'] 513 | expect(lines[1][1]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.include.c', 'keyword.control.directive.include.c', 'punctuation.definition.directive.c'] 514 | expect(lines[1][2]).toEqual value: ' include', scopes: ['source.c', 'meta.preprocessor.include.c', 'keyword.control.directive.include.c'] 515 | expect(lines[1][4]).toEqual value: '<', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.other.lt-gt.include.c', 'punctuation.definition.string.begin.c'] 516 | expect(lines[1][5]).toEqual value: 'unistd.h', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.other.lt-gt.include.c'] 517 | expect(lines[1][6]).toEqual value: '>', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.other.lt-gt.include.c', 'punctuation.definition.string.end.c'] 518 | expect(lines[2][0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 519 | expect(lines[2][1]).toEqual value: 'elif', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 520 | expect(lines[2][3]).toEqual value: 'defined', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 521 | expect(lines[2][5]).toEqual value: '_WIN32', scopes: ['source.c', 'meta.preprocessor.c', 'entity.name.function.preprocessor.c'] 522 | expect(lines[2][7]).toEqual value: '/*', scopes: ['source.c', 'comment.block.c', 'punctuation.definition.comment.begin.c'] 523 | expect(lines[2][8]).toEqual value: ' is defined by compilers targeting Windows systems ', scopes: ['source.c', 'comment.block.c'] 524 | expect(lines[2][9]).toEqual value: '*/', scopes: ['source.c', 'comment.block.c', 'punctuation.definition.comment.end.c'] 525 | expect(lines[3][1]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.include.c', 'keyword.control.directive.include.c', 'punctuation.definition.directive.c'] 526 | expect(lines[3][2]).toEqual value: ' include', scopes: ['source.c', 'meta.preprocessor.include.c', 'keyword.control.directive.include.c'] 527 | expect(lines[3][4]).toEqual value: '<', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.other.lt-gt.include.c', 'punctuation.definition.string.begin.c'] 528 | expect(lines[3][5]).toEqual value: 'windows.h', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.other.lt-gt.include.c'] 529 | expect(lines[3][6]).toEqual value: '>', scopes: ['source.c', 'meta.preprocessor.include.c', 'string.quoted.other.lt-gt.include.c', 'punctuation.definition.string.end.c'] 530 | expect(lines[4][0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 531 | expect(lines[4][1]).toEqual value: 'endif', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 532 | 533 | it "tokenizes ifndef blocks", -> 534 | lines = grammar.tokenizeLines ''' 535 | #ifndef _INCL_GUARD 536 | #define _INCL_GUARD 537 | #endif 538 | ''' 539 | expect(lines[0][0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 540 | expect(lines[0][1]).toEqual value: 'ifndef', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 541 | expect(lines[0][3]).toEqual value: '_INCL_GUARD', scopes: ['source.c', 'meta.preprocessor.c', 'entity.name.function.preprocessor.c'] 542 | expect(lines[1][1]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c', 'punctuation.definition.directive.c'] 543 | expect(lines[1][2]).toEqual value: 'define', scopes: ['source.c', 'meta.preprocessor.macro.c', 'keyword.control.directive.define.c'] 544 | expect(lines[1][4]).toEqual value: '_INCL_GUARD', scopes: ['source.c', 'meta.preprocessor.macro.c', 'entity.name.function.preprocessor.c'] 545 | expect(lines[2][0]).toEqual value: '#', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 546 | expect(lines[2][1]).toEqual value: 'endif', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 547 | 548 | it "highlights stray elif, else and endif usages as invalid", -> 549 | lines = grammar.tokenizeLines ''' 550 | #if defined SOMEMACRO 551 | #else 552 | #elif //elif not permitted here 553 | #endif 554 | #else //else without if 555 | #endif //endif without if 556 | ''' 557 | expect(lines[2][0]).toEqual value: '#elif', scopes: ['source.c', 'invalid.illegal.stray-elif.c'] 558 | expect(lines[4][0]).toEqual value: '#else', scopes: ['source.c', 'invalid.illegal.stray-else.c'] 559 | expect(lines[5][0]).toEqual value: '#endif', scopes: ['source.c', 'invalid.illegal.stray-endif.c'] 560 | 561 | it "highlights errorneous defined usage as invalid", -> 562 | {tokens} = grammar.tokenizeLine '#if defined == VALUE' 563 | expect(tokens[3]).toEqual value: 'defined', scopes: ['source.c', 'meta.preprocessor.c', 'invalid.illegal.macro-name.c'] 564 | 565 | it "tokenizes multi line conditional queries", -> 566 | lines = grammar.tokenizeLines ''' 567 | #if !defined (MACRO_A) \\ 568 | || !defined MACRO_C 569 | #define MACRO_A TRUE 570 | #elif MACRO_C == (5 + 4 - /* multi line comment */ \\ 571 | SOMEMACRO(TRUE) * 8) // single line comment 572 | #endif 573 | ''' 574 | expect(lines[0][2]).toEqual value: ' ', scopes: ['source.c', 'meta.preprocessor.c'] 575 | expect(lines[0][3]).toEqual value: '!', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.operator.logical.c'] 576 | expect(lines[0][7]).toEqual value: 'MACRO_A', scopes: ['source.c', 'meta.preprocessor.c', 'entity.name.function.preprocessor.c'] 577 | expect(lines[0][10]).toEqual value: '\\', scopes: ['source.c', 'meta.preprocessor.c', 'constant.character.escape.line-continuation.c'] 578 | expect(lines[1][1]).toEqual value: '||', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.operator.logical.c'] 579 | expect(lines[1][3]).toEqual value: '!', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.operator.logical.c'] 580 | expect(lines[1][4]).toEqual value: 'defined', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 581 | expect(lines[1][6]).toEqual value: 'MACRO_C', scopes: ['source.c', 'meta.preprocessor.c', 'entity.name.function.preprocessor.c'] 582 | expect(lines[3][2]).toEqual value: ' ', scopes: ['source.c', 'meta.preprocessor.c'] 583 | expect(lines[3][3]).toEqual value: 'MACRO_C', scopes: ['source.c', 'meta.preprocessor.c', 'entity.name.function.preprocessor.c'] 584 | expect(lines[3][5]).toEqual value: '==', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.operator.comparison.c'] 585 | expect(lines[3][7]).toEqual value: '(', scopes: ['source.c', 'meta.preprocessor.c', 'punctuation.section.parens.begin.bracket.round.c'] 586 | expect(lines[3][8]).toEqual value: '5', scopes: ['source.c', 'meta.preprocessor.c', 'constant.numeric.c'] 587 | expect(lines[3][10]).toEqual value: '+', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.operator.c'] 588 | expect(lines[3][14]).toEqual value: '-', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.operator.c'] 589 | expect(lines[3][16]).toEqual value: '/*', scopes: ['source.c', 'meta.preprocessor.c', 'comment.block.c', 'punctuation.definition.comment.begin.c'] 590 | expect(lines[3][17]).toEqual value: ' multi line comment ', scopes: ['source.c', 'meta.preprocessor.c', 'comment.block.c'] 591 | expect(lines[3][18]).toEqual value: '*/', scopes: ['source.c', 'meta.preprocessor.c', 'comment.block.c', 'punctuation.definition.comment.end.c'] 592 | expect(lines[3][20]).toEqual value: '\\', scopes: ['source.c', 'meta.preprocessor.c', 'constant.character.escape.line-continuation.c'] 593 | expect(lines[4][1]).toEqual value: 'SOMEMACRO', scopes: ['source.c', 'meta.preprocessor.c', 'entity.name.function.preprocessor.c'] 594 | expect(lines[4][3]).toEqual value: 'TRUE', scopes: ['source.c', 'meta.preprocessor.c', 'constant.language.c'] 595 | expect(lines[4][6]).toEqual value: '*', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.operator.c'] 596 | expect(lines[4][9]).toEqual value: ')', scopes: ['source.c', 'meta.preprocessor.c', 'punctuation.section.parens.end.bracket.round.c'] 597 | expect(lines[4][11]).toEqual value: '//', scopes: ['source.c', 'comment.line.double-slash.cpp', 'punctuation.definition.comment.cpp'] 598 | expect(lines[4][12]).toEqual value: ' single line comment', scopes: ['source.c', 'comment.line.double-slash.cpp'] 599 | 600 | it "tokenizes ternary operator usage in preprocessor conditionals", -> 601 | {tokens} = grammar.tokenizeLine '#if defined (__GNU_LIBRARY__) ? defined (__USE_GNU) : !defined (__STRICT_ANSI__)' 602 | expect(tokens[9]).toEqual value: '?', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.operator.ternary.c'] 603 | expect(tokens[11]).toEqual value: 'defined', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 604 | expect(tokens[17]).toEqual value: ':', scopes: ['source.c', 'meta.preprocessor.c', 'keyword.operator.ternary.c'] 605 | 606 | describe "indentation", -> 607 | editor = null 608 | 609 | beforeEach -> 610 | editor = buildTextEditor() 611 | editor.setGrammar(grammar) 612 | 613 | expectPreservedIndentation = (text) -> 614 | editor.setText(text) 615 | editor.autoIndentBufferRows(0, editor.getLineCount() - 1) 616 | 617 | expectedLines = text.split('\n') 618 | actualLines = editor.getText().split('\n') 619 | for actualLine, i in actualLines 620 | expect([ 621 | actualLine, 622 | editor.indentLevelForLine(actualLine) 623 | ]).toEqual([ 624 | expectedLines[i], 625 | editor.indentLevelForLine(expectedLines[i]) 626 | ]) 627 | 628 | it "indents allman-style curly braces", -> 629 | expectPreservedIndentation ''' 630 | if (a) 631 | { 632 | for (;;) 633 | { 634 | do 635 | { 636 | while (b) 637 | { 638 | c(); 639 | } 640 | } 641 | while (d) 642 | } 643 | } 644 | ''' 645 | 646 | it "indents non-allman-style curly braces", -> 647 | expectPreservedIndentation ''' 648 | if (a) { 649 | for (;;) { 650 | do { 651 | while (b) { 652 | c(); 653 | } 654 | } while (d) 655 | } 656 | } 657 | ''' 658 | 659 | it "indents function arguments", -> 660 | expectPreservedIndentation ''' 661 | a( 662 | b, 663 | c( 664 | d 665 | ) 666 | ); 667 | ''' 668 | 669 | it "indents array and struct literals", -> 670 | expectPreservedIndentation ''' 671 | some_t a[3] = { 672 | { .b = c }, 673 | { .b = c, .d = {1, 2} }, 674 | }; 675 | ''' 676 | 677 | it "tokenizes binary literal", -> 678 | {tokens} = grammar.tokenizeLine '0b101010' 679 | expect(tokens[0]).toEqual value: '0b101010', scopes: ['source.c', 'constant.numeric.c'] 680 | 681 | describe "access", -> 682 | it "tokenizes the dot access operator", -> 683 | lines = grammar.tokenizeLines ''' 684 | { 685 | a. 686 | } 687 | ''' 688 | expect(lines[1][0]).toEqual value: ' a', scopes: ['source.c', 'meta.block.c'] 689 | expect(lines[1][1]).toEqual value: '.', scopes: ['source.c', 'meta.block.c', 'punctuation.separator.dot-access.c'] 690 | 691 | lines = grammar.tokenizeLines ''' 692 | { 693 | a.b; 694 | } 695 | ''' 696 | expect(lines[1][0]).toEqual value: ' a', scopes: ['source.c', 'meta.block.c'] 697 | expect(lines[1][1]).toEqual value: '.', scopes: ['source.c', 'meta.block.c', 'punctuation.separator.dot-access.c'] 698 | expect(lines[1][2]).toEqual value: 'b', scopes: ['source.c', 'meta.block.c', 'variable.other.member.c'] 699 | 700 | lines = grammar.tokenizeLines ''' 701 | { 702 | a.b() 703 | } 704 | ''' 705 | expect(lines[1][0]).toEqual value: ' a', scopes: ['source.c', 'meta.block.c'] 706 | expect(lines[1][1]).toEqual value: '.', scopes: ['source.c', 'meta.block.c', 'punctuation.separator.dot-access.c'] 707 | expect(lines[1][2]).toEqual value: 'b', scopes: ['source.c', 'meta.block.c', 'meta.function-call.c', 'entity.name.function.c'] 708 | 709 | lines = grammar.tokenizeLines ''' 710 | { 711 | a. b; 712 | } 713 | ''' 714 | expect(lines[1][1]).toEqual value: '.', scopes: ['source.c', 'meta.block.c', 'punctuation.separator.dot-access.c'] 715 | expect(lines[1][3]).toEqual value: 'b', scopes: ['source.c', 'meta.block.c', 'variable.other.member.c'] 716 | 717 | lines = grammar.tokenizeLines ''' 718 | { 719 | a .b; 720 | } 721 | ''' 722 | expect(lines[1][1]).toEqual value: '.', scopes: ['source.c', 'meta.block.c', 'punctuation.separator.dot-access.c'] 723 | expect(lines[1][2]).toEqual value: 'b', scopes: ['source.c', 'meta.block.c', 'variable.other.member.c'] 724 | 725 | lines = grammar.tokenizeLines ''' 726 | { 727 | a . b; 728 | } 729 | ''' 730 | expect(lines[1][1]).toEqual value: '.', scopes: ['source.c', 'meta.block.c', 'punctuation.separator.dot-access.c'] 731 | expect(lines[1][3]).toEqual value: 'b', scopes: ['source.c', 'meta.block.c', 'variable.other.member.c'] 732 | 733 | it "tokenizes the pointer access operator", -> 734 | lines = grammar.tokenizeLines ''' 735 | { 736 | a->b; 737 | } 738 | ''' 739 | expect(lines[1][1]).toEqual value: '->', scopes: ['source.c', 'meta.block.c', 'punctuation.separator.pointer-access.c'] 740 | expect(lines[1][2]).toEqual value: 'b', scopes: ['source.c', 'meta.block.c', 'variable.other.member.c'] 741 | 742 | lines = grammar.tokenizeLines ''' 743 | { 744 | a->b() 745 | } 746 | ''' 747 | expect(lines[1][0]).toEqual value: ' a', scopes: ['source.c', 'meta.block.c'] 748 | expect(lines[1][1]).toEqual value: '->', scopes: ['source.c', 'meta.block.c', 'punctuation.separator.pointer-access.c'] 749 | 750 | lines = grammar.tokenizeLines ''' 751 | { 752 | a-> b; 753 | } 754 | ''' 755 | expect(lines[1][1]).toEqual value: '->', scopes: ['source.c', 'meta.block.c', 'punctuation.separator.pointer-access.c'] 756 | expect(lines[1][3]).toEqual value: 'b', scopes: ['source.c', 'meta.block.c', 'variable.other.member.c'] 757 | 758 | lines = grammar.tokenizeLines ''' 759 | { 760 | a ->b; 761 | } 762 | ''' 763 | expect(lines[1][1]).toEqual value: '->', scopes: ['source.c', 'meta.block.c', 'punctuation.separator.pointer-access.c'] 764 | expect(lines[1][2]).toEqual value: 'b', scopes: ['source.c', 'meta.block.c', 'variable.other.member.c'] 765 | 766 | lines = grammar.tokenizeLines ''' 767 | { 768 | a -> b; 769 | } 770 | ''' 771 | expect(lines[1][1]).toEqual value: '->', scopes: ['source.c', 'meta.block.c', 'punctuation.separator.pointer-access.c'] 772 | expect(lines[1][3]).toEqual value: 'b', scopes: ['source.c', 'meta.block.c', 'variable.other.member.c'] 773 | 774 | lines = grammar.tokenizeLines ''' 775 | { 776 | a-> 777 | } 778 | ''' 779 | expect(lines[1][0]).toEqual value: ' a', scopes: ['source.c', 'meta.block.c'] 780 | expect(lines[1][1]).toEqual value: '->', scopes: ['source.c', 'meta.block.c', 'punctuation.separator.pointer-access.c'] 781 | 782 | describe "operators", -> 783 | it "tokenizes the sizeof operator", -> 784 | {tokens} = grammar.tokenizeLine('sizeof unary_expression') 785 | expect(tokens[0]).toEqual value: 'sizeof', scopes: ['source.c', 'keyword.operator.sizeof.c'] 786 | expect(tokens[1]).toEqual value: ' unary_expression', scopes: ['source.c'] 787 | 788 | {tokens} = grammar.tokenizeLine('sizeof (int)') 789 | expect(tokens[0]).toEqual value: 'sizeof', scopes: ['source.c', 'keyword.operator.sizeof.c'] 790 | expect(tokens[1]).toEqual value: ' ', scopes: ['source.c'] 791 | expect(tokens[2]).toEqual value: '(', scopes: ['source.c', 'punctuation.section.parens.begin.bracket.round.c'] 792 | expect(tokens[3]).toEqual value: 'int', scopes: ['source.c', 'storage.type.c'] 793 | expect(tokens[4]).toEqual value: ')', scopes: ['source.c', 'punctuation.section.parens.end.bracket.round.c'] 794 | 795 | {tokens} = grammar.tokenizeLine('$sizeof') 796 | expect(tokens[1]).not.toEqual value: 'sizeof', scopes: ['source.c', 'keyword.operator.sizeof.c'] 797 | 798 | {tokens} = grammar.tokenizeLine('sizeof$') 799 | expect(tokens[0]).not.toEqual value: 'sizeof', scopes: ['source.c', 'keyword.operator.sizeof.c'] 800 | 801 | {tokens} = grammar.tokenizeLine('sizeof_') 802 | expect(tokens[0]).not.toEqual value: 'sizeof', scopes: ['source.c', 'keyword.operator.sizeof.c'] 803 | 804 | it "tokenizes the increment operator", -> 805 | {tokens} = grammar.tokenizeLine('i++') 806 | expect(tokens[0]).toEqual value: 'i', scopes: ['source.c'] 807 | expect(tokens[1]).toEqual value: '++', scopes: ['source.c', 'keyword.operator.increment.c'] 808 | 809 | {tokens} = grammar.tokenizeLine('++i') 810 | expect(tokens[0]).toEqual value: '++', scopes: ['source.c', 'keyword.operator.increment.c'] 811 | expect(tokens[1]).toEqual value: 'i', scopes: ['source.c'] 812 | 813 | it "tokenizes the decrement operator", -> 814 | {tokens} = grammar.tokenizeLine('i--') 815 | expect(tokens[0]).toEqual value: 'i', scopes: ['source.c'] 816 | expect(tokens[1]).toEqual value: '--', scopes: ['source.c', 'keyword.operator.decrement.c'] 817 | 818 | {tokens} = grammar.tokenizeLine('--i') 819 | expect(tokens[0]).toEqual value: '--', scopes: ['source.c', 'keyword.operator.decrement.c'] 820 | expect(tokens[1]).toEqual value: 'i', scopes: ['source.c'] 821 | 822 | it "tokenizes logical operators", -> 823 | {tokens} = grammar.tokenizeLine('!a') 824 | expect(tokens[0]).toEqual value: '!', scopes: ['source.c', 'keyword.operator.logical.c'] 825 | expect(tokens[1]).toEqual value: 'a', scopes: ['source.c'] 826 | 827 | operators = ['&&', '||'] 828 | for operator in operators 829 | {tokens} = grammar.tokenizeLine('a ' + operator + ' b') 830 | expect(tokens[0]).toEqual value: 'a ', scopes: ['source.c'] 831 | expect(tokens[1]).toEqual value: operator, scopes: ['source.c', 'keyword.operator.logical.c'] 832 | expect(tokens[2]).toEqual value: ' b', scopes: ['source.c'] 833 | 834 | it "tokenizes comparison operators", -> 835 | operators = ['<=', '>=', '!=', '==', '<', '>' ] 836 | 837 | for operator in operators 838 | {tokens} = grammar.tokenizeLine('a ' + operator + ' b') 839 | expect(tokens[0]).toEqual value: 'a ', scopes: ['source.c'] 840 | expect(tokens[1]).toEqual value: operator, scopes: ['source.c', 'keyword.operator.comparison.c'] 841 | expect(tokens[2]).toEqual value: ' b', scopes: ['source.c'] 842 | 843 | it "tokenizes arithmetic operators", -> 844 | operators = ['+', '-', '*', '/', '%'] 845 | 846 | for operator in operators 847 | {tokens} = grammar.tokenizeLine('a ' + operator + ' b') 848 | expect(tokens[0]).toEqual value: 'a ', scopes: ['source.c'] 849 | expect(tokens[1]).toEqual value: operator, scopes: ['source.c', 'keyword.operator.c'] 850 | expect(tokens[2]).toEqual value: ' b', scopes: ['source.c'] 851 | 852 | it "tokenizes ternary operators", -> 853 | {tokens} = grammar.tokenizeLine('a ? b : c') 854 | expect(tokens[0]).toEqual value: 'a ', scopes: ['source.c'] 855 | expect(tokens[1]).toEqual value: '?', scopes: ['source.c', 'keyword.operator.ternary.c'] 856 | expect(tokens[2]).toEqual value: ' b ', scopes: ['source.c'] 857 | expect(tokens[3]).toEqual value: ':', scopes: ['source.c', 'keyword.operator.ternary.c'] 858 | expect(tokens[4]).toEqual value: ' c', scopes: ['source.c'] 859 | 860 | it "tokenizes ternary operators with member access", -> 861 | {tokens} = grammar.tokenizeLine('a ? b.c : d') 862 | expect(tokens[0]).toEqual value: 'a ', scopes: ['source.c'] 863 | expect(tokens[1]).toEqual value: '?', scopes: ['source.c', 'keyword.operator.ternary.c'] 864 | expect(tokens[2]).toEqual value: ' b', scopes: ['source.c'] 865 | expect(tokens[3]).toEqual value: '.', scopes: ['source.c', 'punctuation.separator.dot-access.c'] 866 | expect(tokens[4]).toEqual value: 'c', scopes: ['source.c', 'variable.other.member.c'] 867 | expect(tokens[5]).toEqual value: ' ', scopes: ['source.c'] 868 | expect(tokens[6]).toEqual value: ':', scopes: ['source.c', 'keyword.operator.ternary.c'] 869 | expect(tokens[7]).toEqual value: ' d', scopes: ['source.c'] 870 | 871 | it "tokenizes ternary operators with pointer dereferencing", -> 872 | {tokens} = grammar.tokenizeLine('a ? b->c : d') 873 | expect(tokens[0]).toEqual value: 'a ', scopes: ['source.c'] 874 | expect(tokens[1]).toEqual value: '?', scopes: ['source.c', 'keyword.operator.ternary.c'] 875 | expect(tokens[2]).toEqual value: ' b', scopes: ['source.c'] 876 | expect(tokens[3]).toEqual value: '->', scopes: ['source.c', 'punctuation.separator.pointer-access.c'] 877 | expect(tokens[4]).toEqual value: 'c', scopes: ['source.c', 'variable.other.member.c'] 878 | expect(tokens[5]).toEqual value: ' ', scopes: ['source.c'] 879 | expect(tokens[6]).toEqual value: ':', scopes: ['source.c', 'keyword.operator.ternary.c'] 880 | expect(tokens[7]).toEqual value: ' d', scopes: ['source.c'] 881 | 882 | it "tokenizes ternary operators with function invocation", -> 883 | {tokens} = grammar.tokenizeLine('a ? f(b) : c') 884 | expect(tokens[0]).toEqual value: 'a ', scopes: ['source.c'] 885 | expect(tokens[1]).toEqual value: '?', scopes: ['source.c', 'keyword.operator.ternary.c'] 886 | expect(tokens[2]).toEqual value: ' ', scopes: ['source.c'] 887 | expect(tokens[3]).toEqual value: 'f', scopes: ['source.c', 'meta.function-call.c', 'entity.name.function.c'] 888 | expect(tokens[4]).toEqual value: '(', scopes: ['source.c', 'meta.function-call.c', 'punctuation.section.arguments.begin.bracket.round.c'] 889 | expect(tokens[5]).toEqual value: 'b', scopes: ['source.c', 'meta.function-call.c'] 890 | expect(tokens[6]).toEqual value: ')', scopes: ['source.c', 'meta.function-call.c', 'punctuation.section.arguments.end.bracket.round.c'] 891 | expect(tokens[7]).toEqual value: ' ', scopes: ['source.c'] 892 | expect(tokens[8]).toEqual value: ':', scopes: ['source.c', 'keyword.operator.ternary.c'] 893 | expect(tokens[9]).toEqual value: ' c', scopes: ['source.c'] 894 | 895 | describe "bitwise", -> 896 | it "tokenizes bitwise 'not'", -> 897 | {tokens} = grammar.tokenizeLine('~a') 898 | expect(tokens[0]).toEqual value: '~', scopes: ['source.c', 'keyword.operator.c'] 899 | expect(tokens[1]).toEqual value: 'a', scopes: ['source.c'] 900 | 901 | it "tokenizes shift operators", -> 902 | {tokens} = grammar.tokenizeLine('>>') 903 | expect(tokens[0]).toEqual value: '>>', scopes: ['source.c', 'keyword.operator.bitwise.shift.c'] 904 | 905 | {tokens} = grammar.tokenizeLine('<<') 906 | expect(tokens[0]).toEqual value: '<<', scopes: ['source.c', 'keyword.operator.bitwise.shift.c'] 907 | 908 | it "tokenizes them", -> 909 | operators = ['|', '^', '&'] 910 | 911 | for operator in operators 912 | {tokens} = grammar.tokenizeLine('a ' + operator + ' b') 913 | expect(tokens[0]).toEqual value: 'a ', scopes: ['source.c'] 914 | expect(tokens[1]).toEqual value: operator, scopes: ['source.c', 'keyword.operator.c'] 915 | expect(tokens[2]).toEqual value: ' b', scopes: ['source.c'] 916 | 917 | describe "assignment", -> 918 | it "tokenizes the assignment operator", -> 919 | {tokens} = grammar.tokenizeLine('a = b') 920 | expect(tokens[0]).toEqual value: 'a ', scopes: ['source.c'] 921 | expect(tokens[1]).toEqual value: '=', scopes: ['source.c', 'keyword.operator.assignment.c'] 922 | expect(tokens[2]).toEqual value: ' b', scopes: ['source.c'] 923 | 924 | it "tokenizes compound assignment operators", -> 925 | operators = ['+=', '-=', '*=', '/=', '%='] 926 | for operator in operators 927 | {tokens} = grammar.tokenizeLine('a ' + operator + ' b') 928 | expect(tokens[0]).toEqual value: 'a ', scopes: ['source.c'] 929 | expect(tokens[1]).toEqual value: operator, scopes: ['source.c', 'keyword.operator.assignment.compound.c'] 930 | expect(tokens[2]).toEqual value: ' b', scopes: ['source.c'] 931 | 932 | it "tokenizes bitwise compound operators", -> 933 | operators = ['<<=', '>>=', '&=', '^=', '|='] 934 | for operator in operators 935 | {tokens} = grammar.tokenizeLine('a ' + operator + ' b') 936 | expect(tokens[0]).toEqual value: 'a ', scopes: ['source.c'] 937 | expect(tokens[1]).toEqual value: operator, scopes: ['source.c', 'keyword.operator.assignment.compound.bitwise.c'] 938 | expect(tokens[2]).toEqual value: ' b', scopes: ['source.c'] 939 | 940 | describe "C++", -> 941 | beforeEach -> 942 | grammar = atom.grammars.grammarForScopeName('source.cpp') 943 | 944 | it "parses the grammar", -> 945 | expect(grammar).toBeTruthy() 946 | expect(grammar.scopeName).toBe 'source.cpp' 947 | 948 | it "tokenizes this with `.this` class", -> 949 | {tokens} = grammar.tokenizeLine 'this.x' 950 | expect(tokens[0]).toEqual value: 'this', scopes: ['source.cpp', 'variable.language.this.cpp'] 951 | 952 | it "tokenizes classes", -> 953 | lines = grammar.tokenizeLines ''' 954 | class Thing { 955 | int x; 956 | } 957 | ''' 958 | expect(lines[0][0]).toEqual value: 'class', scopes: ['source.cpp', 'meta.class-struct-block.cpp', 'storage.type.cpp'] 959 | expect(lines[0][2]).toEqual value: 'Thing', scopes: ['source.cpp', 'meta.class-struct-block.cpp', 'entity.name.type.cpp'] 960 | 961 | it "tokenizes 'extern C'", -> 962 | lines = grammar.tokenizeLines ''' 963 | extern "C" { 964 | #include "legacy_C_header.h" 965 | } 966 | ''' 967 | expect(lines[0][0]).toEqual value: 'extern', scopes: ['source.cpp', 'meta.extern-block.cpp', 'storage.modifier.cpp'] 968 | expect(lines[0][2]).toEqual value: '"', scopes: ['source.cpp', 'meta.extern-block.cpp', 'string.quoted.double.cpp', 'punctuation.definition.string.begin.cpp'] 969 | expect(lines[0][3]).toEqual value: 'C', scopes: ['source.cpp', 'meta.extern-block.cpp', 'string.quoted.double.cpp'] 970 | expect(lines[0][4]).toEqual value: '"', scopes: ['source.cpp', 'meta.extern-block.cpp', 'string.quoted.double.cpp', 'punctuation.definition.string.end.cpp'] 971 | expect(lines[0][6]).toEqual value: '{', scopes: ['source.cpp', 'meta.extern-block.cpp', 'punctuation.section.block.begin.bracket.curly.c'] 972 | expect(lines[1][0]).toEqual value: '#', scopes: ['source.cpp', 'meta.extern-block.cpp', 'meta.preprocessor.include.c', 'keyword.control.directive.include.c', 'punctuation.definition.directive.c'] 973 | expect(lines[1][1]).toEqual value: 'include', scopes: ['source.cpp', 'meta.extern-block.cpp', 'meta.preprocessor.include.c', 'keyword.control.directive.include.c'] 974 | expect(lines[1][3]).toEqual value: '"', scopes: ['source.cpp', 'meta.extern-block.cpp', 'meta.preprocessor.include.c', 'string.quoted.double.include.c', 'punctuation.definition.string.begin.c'] 975 | expect(lines[1][4]).toEqual value: 'legacy_C_header.h', scopes: ['source.cpp', 'meta.extern-block.cpp', 'meta.preprocessor.include.c', 'string.quoted.double.include.c'] 976 | expect(lines[1][5]).toEqual value: '"', scopes: ['source.cpp', 'meta.extern-block.cpp', 'meta.preprocessor.include.c', 'string.quoted.double.include.c', 'punctuation.definition.string.end.c'] 977 | expect(lines[2][0]).toEqual value: '}', scopes: ['source.cpp', 'meta.extern-block.cpp', 'punctuation.section.block.end.bracket.curly.c'] 978 | 979 | lines = grammar.tokenizeLines ''' 980 | #ifdef __cplusplus 981 | extern "C" { 982 | #endif 983 | // legacy C code here 984 | #ifdef __cplusplus 985 | } 986 | #endif 987 | ''' 988 | expect(lines[0][0]).toEqual value: '#', scopes: ['source.cpp', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 989 | expect(lines[0][1]).toEqual value: 'ifdef', scopes: ['source.cpp', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 990 | expect(lines[0][3]).toEqual value: '__cplusplus', scopes: ['source.cpp', 'meta.preprocessor.c', 'entity.name.function.preprocessor.c'] 991 | expect(lines[1][0]).toEqual value: 'extern', scopes: ['source.cpp', 'meta.extern-block.cpp', 'storage.modifier.cpp'] 992 | expect(lines[1][2]).toEqual value: '"', scopes: ['source.cpp', 'meta.extern-block.cpp', 'string.quoted.double.cpp', 'punctuation.definition.string.begin.cpp'] 993 | expect(lines[1][3]).toEqual value: 'C', scopes: ['source.cpp', 'meta.extern-block.cpp', 'string.quoted.double.cpp'] 994 | expect(lines[1][4]).toEqual value: '"', scopes: ['source.cpp', 'meta.extern-block.cpp', 'string.quoted.double.cpp', 'punctuation.definition.string.end.cpp'] 995 | expect(lines[1][6]).toEqual value: '{', scopes: ['source.cpp', 'meta.extern-block.cpp', 'punctuation.section.block.begin.bracket.curly.c'] 996 | expect(lines[2][0]).toEqual value: '#', scopes: ['source.cpp', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 997 | expect(lines[2][1]).toEqual value: 'endif', scopes: ['source.cpp', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 998 | expect(lines[3][1]).toEqual value: '//', scopes: ['source.cpp', 'comment.line.double-slash.cpp', 'punctuation.definition.comment.cpp'] 999 | expect(lines[3][2]).toEqual value: ' legacy C code here', scopes: ['source.cpp', 'comment.line.double-slash.cpp'] 1000 | expect(lines[4][0]).toEqual value: '#', scopes: ['source.cpp', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 1001 | expect(lines[4][1]).toEqual value: 'ifdef', scopes: ['source.cpp', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 1002 | expect(lines[5][0]).toEqual value: '}', scopes: ['source.cpp'] 1003 | expect(lines[6][0]).toEqual value: '#', scopes: ['source.cpp', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c', 'punctuation.definition.directive.c'] 1004 | expect(lines[6][1]).toEqual value: 'endif', scopes: ['source.cpp', 'meta.preprocessor.c', 'keyword.control.directive.conditional.c'] 1005 | 1006 | it "tokenizes UTF string escapes", -> 1007 | lines = grammar.tokenizeLines ''' 1008 | string str = U"\\U01234567\\u0123\\"\\0123\\x123"; 1009 | ''' 1010 | expect(lines[0][0]).toEqual value: 'string str ', scopes: ['source.cpp'] 1011 | expect(lines[0][1]).toEqual value: '=', scopes: ['source.cpp', 'keyword.operator.assignment.c'] 1012 | expect(lines[0][3]).toEqual value: 'U', scopes: ['source.cpp', 'string.quoted.double.cpp', 'punctuation.definition.string.begin.cpp', 'meta.encoding.cpp'] 1013 | expect(lines[0][4]).toEqual value: '"', scopes: ['source.cpp', 'string.quoted.double.cpp', 'punctuation.definition.string.begin.cpp'] 1014 | expect(lines[0][5]).toEqual value: '\\U01234567', scopes: ['source.cpp', 'string.quoted.double.cpp', 'constant.character.escape.cpp'] 1015 | expect(lines[0][6]).toEqual value: '\\u0123', scopes: ['source.cpp', 'string.quoted.double.cpp', 'constant.character.escape.cpp'] 1016 | expect(lines[0][7]).toEqual value: '\\"', scopes: ['source.cpp', 'string.quoted.double.cpp', 'constant.character.escape.cpp'] 1017 | expect(lines[0][8]).toEqual value: '\\012', scopes: ['source.cpp', 'string.quoted.double.cpp', 'constant.character.escape.cpp'] 1018 | expect(lines[0][9]).toEqual value: '3', scopes: ['source.cpp', 'string.quoted.double.cpp'] 1019 | expect(lines[0][10]).toEqual value: '\\x123', scopes: ['source.cpp', 'string.quoted.double.cpp', 'constant.character.escape.cpp'] 1020 | expect(lines[0][11]).toEqual value: '"', scopes: ['source.cpp', 'string.quoted.double.cpp', 'punctuation.definition.string.end.cpp'] 1021 | expect(lines[0][12]).toEqual value: ';', scopes: ['source.cpp', 'punctuation.terminator.statement.c'] 1022 | 1023 | it "tokenizes % format specifiers", -> 1024 | {tokens} = grammar.tokenizeLine '"%d"' 1025 | expect(tokens[0]).toEqual value: '"', scopes: ['source.cpp', 'string.quoted.double.cpp', 'punctuation.definition.string.begin.cpp'] 1026 | expect(tokens[1]).toEqual value: '%d', scopes: ['source.cpp', 'string.quoted.double.cpp', 'constant.other.placeholder.c'] 1027 | expect(tokens[2]).toEqual value: '"', scopes: ['source.cpp', 'string.quoted.double.cpp', 'punctuation.definition.string.end.cpp'] 1028 | 1029 | {tokens} = grammar.tokenizeLine '"%"' 1030 | expect(tokens[0]).toEqual value: '"', scopes: ['source.cpp', 'string.quoted.double.cpp', 'punctuation.definition.string.begin.cpp'] 1031 | expect(tokens[1]).toEqual value: '%', scopes: ['source.cpp', 'string.quoted.double.cpp', 'invalid.illegal.placeholder.c'] 1032 | expect(tokens[2]).toEqual value: '"', scopes: ['source.cpp', 'string.quoted.double.cpp', 'punctuation.definition.string.end.cpp'] 1033 | 1034 | {tokens} = grammar.tokenizeLine '"%" PRId32' 1035 | expect(tokens[0]).toEqual value: '"', scopes: ['source.cpp', 'string.quoted.double.cpp', 'punctuation.definition.string.begin.cpp'] 1036 | expect(tokens[1]).toEqual value: '%', scopes: ['source.cpp', 'string.quoted.double.cpp'] 1037 | expect(tokens[2]).toEqual value: '"', scopes: ['source.cpp', 'string.quoted.double.cpp', 'punctuation.definition.string.end.cpp'] 1038 | 1039 | it "tokenizes raw string literals", -> 1040 | lines = grammar.tokenizeLines ''' 1041 | string str = R"test( 1042 | this is \"a\" test 'string' 1043 | )test"; 1044 | ''' 1045 | expect(lines[0][0]).toEqual value: 'string str ', scopes: ['source.cpp'] 1046 | expect(lines[0][3]).toEqual value: 'R"test(', scopes: ['source.cpp', 'string.quoted.double.raw.cpp', 'punctuation.definition.string.begin.cpp'] 1047 | expect(lines[1][0]).toEqual value: ' this is "a" test \'string\'', scopes: ['source.cpp', 'string.quoted.double.raw.cpp'] 1048 | expect(lines[2][0]).toEqual value: ')test"', scopes: ['source.cpp', 'string.quoted.double.raw.cpp', 'punctuation.definition.string.end.cpp'] 1049 | expect(lines[2][1]).toEqual value: ';', scopes: ['source.cpp', 'punctuation.terminator.statement.c'] 1050 | 1051 | it "errors on long raw string delimiters", -> 1052 | lines = grammar.tokenizeLines ''' 1053 | string str = R"01234567890123456()01234567890123456"; 1054 | ''' 1055 | expect(lines[0][0]).toEqual value: 'string str ', scopes: ['source.cpp'] 1056 | expect(lines[0][3]).toEqual value: 'R"', scopes: ['source.cpp', 'string.quoted.double.raw.cpp', 'punctuation.definition.string.begin.cpp'] 1057 | expect(lines[0][4]).toEqual value: '01234567890123456', scopes: ['source.cpp', 'string.quoted.double.raw.cpp', 'punctuation.definition.string.begin.cpp', 'invalid.illegal.delimiter-too-long.cpp'] 1058 | expect(lines[0][5]).toEqual value: '(', scopes: ['source.cpp', 'string.quoted.double.raw.cpp', 'punctuation.definition.string.begin.cpp'] 1059 | expect(lines[0][6]).toEqual value: ')', scopes: ['source.cpp', 'string.quoted.double.raw.cpp', 'punctuation.definition.string.end.cpp'] 1060 | expect(lines[0][7]).toEqual value: '01234567890123456', scopes: ['source.cpp', 'string.quoted.double.raw.cpp', 'punctuation.definition.string.end.cpp', 'invalid.illegal.delimiter-too-long.cpp'] 1061 | expect(lines[0][8]).toEqual value: '"', scopes: ['source.cpp', 'string.quoted.double.raw.cpp', 'punctuation.definition.string.end.cpp'] 1062 | expect(lines[0][9]).toEqual value: ';', scopes: ['source.cpp', 'punctuation.terminator.statement.c'] 1063 | 1064 | it "tokenizes destructors", -> 1065 | {tokens} = grammar.tokenizeLine('~Foo() {}') 1066 | expect(tokens[0]).toEqual value: '~Foo', scopes: ['source.cpp', 'meta.function.destructor.cpp', 'entity.name.function.cpp'] 1067 | expect(tokens[1]).toEqual value: '(', scopes: ['source.cpp', 'meta.function.destructor.cpp', 'punctuation.definition.parameters.begin.c'] 1068 | expect(tokens[2]).toEqual value: ')', scopes: ['source.cpp', 'meta.function.destructor.cpp', 'punctuation.definition.parameters.end.c'] 1069 | expect(tokens[4]).toEqual value: '{', scopes: ['source.cpp', 'meta.block.c', 'punctuation.section.block.begin.bracket.curly.c'] 1070 | expect(tokens[5]).toEqual value: '}', scopes: ['source.cpp', 'meta.block.c', 'punctuation.section.block.end.bracket.curly.c'] 1071 | 1072 | {tokens} = grammar.tokenizeLine('Foo::~Bar() {}') 1073 | expect(tokens[0]).toEqual value: 'Foo::~Bar', scopes: ['source.cpp', 'meta.function.destructor.cpp', 'entity.name.function.cpp'] 1074 | expect(tokens[1]).toEqual value: '(', scopes: ['source.cpp', 'meta.function.destructor.cpp', 'punctuation.definition.parameters.begin.c'] 1075 | expect(tokens[2]).toEqual value: ')', scopes: ['source.cpp', 'meta.function.destructor.cpp', 'punctuation.definition.parameters.end.c'] 1076 | expect(tokens[4]).toEqual value: '{', scopes: ['source.cpp', 'meta.block.c', 'punctuation.section.block.begin.bracket.curly.c'] 1077 | expect(tokens[5]).toEqual value: '}', scopes: ['source.cpp', 'meta.block.c', 'punctuation.section.block.end.bracket.curly.c'] 1078 | 1079 | describe "digit separators", -> 1080 | it "recognizes numbers with digit separators", -> 1081 | {tokens} = grammar.tokenizeLine "1'000" 1082 | expect(tokens[0]).toEqual value: "1'000", scopes: ['source.cpp', 'constant.numeric.c'] 1083 | 1084 | {tokens} = grammar.tokenizeLine "123'456.500'000e-1'5" 1085 | expect(tokens[0]).toEqual value: "123'456.500'000e-1'5", scopes: ['source.cpp', 'constant.numeric.c'] 1086 | 1087 | {tokens} = grammar.tokenizeLine "0x1234'5678" 1088 | expect(tokens[0]).toEqual value: "0x1234'5678", scopes: ['source.cpp', 'constant.numeric.c'] 1089 | 1090 | {tokens} = grammar.tokenizeLine "0'123'456" 1091 | expect(tokens[0]).toEqual value: "0'123'456", scopes: ['source.cpp', 'constant.numeric.c'] 1092 | 1093 | {tokens} = grammar.tokenizeLine "0b1100'0011'1111'0000" 1094 | expect(tokens[0]).toEqual value: "0b1100'0011'1111'0000", scopes: ['source.cpp', 'constant.numeric.c'] 1095 | 1096 | it "does not tokenize single quotes at the beginning or end of numbers as digit separators", -> 1097 | {tokens} = grammar.tokenizeLine "'1000" 1098 | expect(tokens[0]).toEqual value: "'", scopes: ['source.cpp', 'string.quoted.single.c', 'punctuation.definition.string.begin.c'] 1099 | expect(tokens[1]).toEqual value: "1000", scopes: ['source.cpp', 'string.quoted.single.c'] 1100 | 1101 | {tokens} = grammar.tokenizeLine "1000'" 1102 | expect(tokens[0]).toEqual value: "1000", scopes: ['source.cpp', 'constant.numeric.c'] 1103 | expect(tokens[1]).toEqual value: "'", scopes: ['source.cpp', 'string.quoted.single.c', 'punctuation.definition.string.begin.c'] 1104 | 1105 | describe "comments", -> 1106 | it "tokenizes them", -> 1107 | {tokens} = grammar.tokenizeLine '// comment' 1108 | expect(tokens[0]).toEqual value: '//', scopes: ['source.cpp', 'comment.line.double-slash.cpp', 'punctuation.definition.comment.cpp'] 1109 | expect(tokens[1]).toEqual value: ' comment', scopes: ['source.cpp', 'comment.line.double-slash.cpp'] 1110 | 1111 | lines = grammar.tokenizeLines ''' 1112 | // separated\\ 1113 | comment 1114 | ''' 1115 | expect(lines[0][0]).toEqual value: '//', scopes: ['source.cpp', 'comment.line.double-slash.cpp', 'punctuation.definition.comment.cpp'] 1116 | expect(lines[0][1]).toEqual value: ' separated', scopes: ['source.cpp', 'comment.line.double-slash.cpp'] 1117 | expect(lines[0][2]).toEqual value: '\\', scopes: ['source.cpp', 'comment.line.double-slash.cpp', 'constant.character.escape.line-continuation.c'] 1118 | expect(lines[1][0]).toEqual value: 'comment', scopes: ['source.cpp', 'comment.line.double-slash.cpp'] 1119 | 1120 | lines = grammar.tokenizeLines ''' 1121 | // The space character \x20 is used to prevent stripping trailing whitespace 1122 | // not separated\\\x20 1123 | comment 1124 | ''' 1125 | expect(lines[1][0]).toEqual value: '//', scopes: ['source.cpp', 'comment.line.double-slash.cpp', 'punctuation.definition.comment.cpp'] 1126 | expect(lines[1][1]).toEqual value: ' not separated\\ ', scopes: ['source.cpp', 'comment.line.double-slash.cpp'] 1127 | expect(lines[2][0]).toEqual value: 'comment', scopes: ['source.cpp'] 1128 | 1129 | describe "operators", -> 1130 | it "tokenizes ternary operators with namespace resolution", -> 1131 | {tokens} = grammar.tokenizeLine('a ? ns::b : ns::c') 1132 | expect(tokens[0]).toEqual value: 'a ', scopes: ['source.cpp'] 1133 | expect(tokens[1]).toEqual value: '?', scopes: ['source.cpp', 'keyword.operator.ternary.c'] 1134 | expect(tokens[2]).toEqual value: ' ns', scopes: ['source.cpp'] 1135 | expect(tokens[3]).toEqual value: '::', scopes: ['source.cpp', 'punctuation.separator.namespace.access.cpp'] 1136 | expect(tokens[4]).toEqual value: 'b ', scopes: ['source.cpp'] 1137 | expect(tokens[5]).toEqual value: ':', scopes: ['source.cpp', 'keyword.operator.ternary.c'] 1138 | expect(tokens[6]).toEqual value: ' ns', scopes: ['source.cpp'] 1139 | expect(tokens[7]).toEqual value: '::', scopes: ['source.cpp', 'punctuation.separator.namespace.access.cpp'] 1140 | expect(tokens[8]).toEqual value: 'c', scopes: ['source.cpp'] 1141 | --------------------------------------------------------------------------------