c.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. /*
  2. Language: C
  3. Category: common, system
  4. Website: https://en.wikipedia.org/wiki/C_(programming_language)
  5. */
  6. /** @type LanguageFn */
  7. function c(hljs) {
  8. const regex = hljs.regex;
  9. // added for historic reasons because `hljs.C_LINE_COMMENT_MODE` does
  10. // not include such support nor can we be sure all the grammars depending
  11. // on it would desire this behavior
  12. const C_LINE_COMMENT_MODE = hljs.COMMENT('//', '$', { contains: [ { begin: /\\\n/ } ] });
  13. const DECLTYPE_AUTO_RE = 'decltype\\(auto\\)';
  14. const NAMESPACE_RE = '[a-zA-Z_]\\w*::';
  15. const TEMPLATE_ARGUMENT_RE = '<[^<>]+>';
  16. const FUNCTION_TYPE_RE = '('
  17. + DECLTYPE_AUTO_RE + '|'
  18. + regex.optional(NAMESPACE_RE)
  19. + '[a-zA-Z_]\\w*' + regex.optional(TEMPLATE_ARGUMENT_RE)
  20. + ')';
  21. const TYPES = {
  22. className: 'type',
  23. variants: [
  24. { begin: '\\b[a-z\\d_]*_t\\b' },
  25. { match: /\batomic_[a-z]{3,6}\b/ }
  26. ]
  27. };
  28. // https://en.cppreference.com/w/cpp/language/escape
  29. // \\ \x \xFF \u2837 \u00323747 \374
  30. const CHARACTER_ESCAPES = '\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)';
  31. const STRINGS = {
  32. className: 'string',
  33. variants: [
  34. {
  35. begin: '(u8?|U|L)?"',
  36. end: '"',
  37. illegal: '\\n',
  38. contains: [ hljs.BACKSLASH_ESCAPE ]
  39. },
  40. {
  41. begin: '(u8?|U|L)?\'(' + CHARACTER_ESCAPES + "|.)",
  42. end: '\'',
  43. illegal: '.'
  44. },
  45. hljs.END_SAME_AS_BEGIN({
  46. begin: /(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,
  47. end: /\)([^()\\ ]{0,16})"/
  48. })
  49. ]
  50. };
  51. const NUMBERS = {
  52. className: 'number',
  53. variants: [
  54. { begin: '\\b(0b[01\']+)' },
  55. { begin: '(-?)\\b([\\d\']+(\\.[\\d\']*)?|\\.[\\d\']+)((ll|LL|l|L)(u|U)?|(u|U)(ll|LL|l|L)?|f|F|b|B)' },
  56. { begin: '(-?)(\\b0[xX][a-fA-F0-9\']+|(\\b[\\d\']+(\\.[\\d\']*)?|\\.[\\d\']+)([eE][-+]?[\\d\']+)?)' }
  57. ],
  58. relevance: 0
  59. };
  60. const PREPROCESSOR = {
  61. className: 'meta',
  62. begin: /#\s*[a-z]+\b/,
  63. end: /$/,
  64. keywords: { keyword:
  65. 'if else elif endif define undef warning error line '
  66. + 'pragma _Pragma ifdef ifndef elifdef elifndef include' },
  67. contains: [
  68. {
  69. begin: /\\\n/,
  70. relevance: 0
  71. },
  72. hljs.inherit(STRINGS, { className: 'string' }),
  73. {
  74. className: 'string',
  75. begin: /<.*?>/
  76. },
  77. C_LINE_COMMENT_MODE,
  78. hljs.C_BLOCK_COMMENT_MODE
  79. ]
  80. };
  81. const TITLE_MODE = {
  82. className: 'title',
  83. begin: regex.optional(NAMESPACE_RE) + hljs.IDENT_RE,
  84. relevance: 0
  85. };
  86. const FUNCTION_TITLE = regex.optional(NAMESPACE_RE) + hljs.IDENT_RE + '\\s*\\(';
  87. const C_KEYWORDS = [
  88. "asm",
  89. "auto",
  90. "break",
  91. "case",
  92. "continue",
  93. "default",
  94. "do",
  95. "else",
  96. "enum",
  97. "extern",
  98. "for",
  99. "fortran",
  100. "goto",
  101. "if",
  102. "inline",
  103. "register",
  104. "restrict",
  105. "return",
  106. "sizeof",
  107. "typeof",
  108. "typeof_unqual",
  109. "struct",
  110. "switch",
  111. "typedef",
  112. "union",
  113. "volatile",
  114. "while",
  115. "_Alignas",
  116. "_Alignof",
  117. "_Atomic",
  118. "_Generic",
  119. "_Noreturn",
  120. "_Static_assert",
  121. "_Thread_local",
  122. // aliases
  123. "alignas",
  124. "alignof",
  125. "noreturn",
  126. "static_assert",
  127. "thread_local",
  128. // not a C keyword but is, for all intents and purposes, treated exactly like one.
  129. "_Pragma"
  130. ];
  131. const C_TYPES = [
  132. "float",
  133. "double",
  134. "signed",
  135. "unsigned",
  136. "int",
  137. "short",
  138. "long",
  139. "char",
  140. "void",
  141. "_Bool",
  142. "_BitInt",
  143. "_Complex",
  144. "_Imaginary",
  145. "_Decimal32",
  146. "_Decimal64",
  147. "_Decimal96",
  148. "_Decimal128",
  149. "_Decimal64x",
  150. "_Decimal128x",
  151. "_Float16",
  152. "_Float32",
  153. "_Float64",
  154. "_Float128",
  155. "_Float32x",
  156. "_Float64x",
  157. "_Float128x",
  158. // modifiers
  159. "const",
  160. "static",
  161. "constexpr",
  162. // aliases
  163. "complex",
  164. "bool",
  165. "imaginary"
  166. ];
  167. const KEYWORDS = {
  168. keyword: C_KEYWORDS,
  169. type: C_TYPES,
  170. literal: 'true false NULL',
  171. // TODO: apply hinting work similar to what was done in cpp.js
  172. built_in: 'std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream '
  173. + 'auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set '
  174. + 'unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos '
  175. + 'asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp '
  176. + 'fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper '
  177. + 'isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow '
  178. + 'printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp '
  179. + 'strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan '
  180. + 'vfprintf vprintf vsprintf endl initializer_list unique_ptr',
  181. };
  182. const EXPRESSION_CONTAINS = [
  183. PREPROCESSOR,
  184. TYPES,
  185. C_LINE_COMMENT_MODE,
  186. hljs.C_BLOCK_COMMENT_MODE,
  187. NUMBERS,
  188. STRINGS
  189. ];
  190. const EXPRESSION_CONTEXT = {
  191. // This mode covers expression context where we can't expect a function
  192. // definition and shouldn't highlight anything that looks like one:
  193. // `return some()`, `else if()`, `(x*sum(1, 2))`
  194. variants: [
  195. {
  196. begin: /=/,
  197. end: /;/
  198. },
  199. {
  200. begin: /\(/,
  201. end: /\)/
  202. },
  203. {
  204. beginKeywords: 'new throw return else',
  205. end: /;/
  206. }
  207. ],
  208. keywords: KEYWORDS,
  209. contains: EXPRESSION_CONTAINS.concat([
  210. {
  211. begin: /\(/,
  212. end: /\)/,
  213. keywords: KEYWORDS,
  214. contains: EXPRESSION_CONTAINS.concat([ 'self' ]),
  215. relevance: 0
  216. }
  217. ]),
  218. relevance: 0
  219. };
  220. const FUNCTION_DECLARATION = {
  221. begin: '(' + FUNCTION_TYPE_RE + '[\\*&\\s]+)+' + FUNCTION_TITLE,
  222. returnBegin: true,
  223. end: /[{;=]/,
  224. excludeEnd: true,
  225. keywords: KEYWORDS,
  226. illegal: /[^\w\s\*&:<>.]/,
  227. contains: [
  228. { // to prevent it from being confused as the function title
  229. begin: DECLTYPE_AUTO_RE,
  230. keywords: KEYWORDS,
  231. relevance: 0
  232. },
  233. {
  234. begin: FUNCTION_TITLE,
  235. returnBegin: true,
  236. contains: [ hljs.inherit(TITLE_MODE, { className: "title.function" }) ],
  237. relevance: 0
  238. },
  239. // allow for multiple declarations, e.g.:
  240. // extern void f(int), g(char);
  241. {
  242. relevance: 0,
  243. match: /,/
  244. },
  245. {
  246. className: 'params',
  247. begin: /\(/,
  248. end: /\)/,
  249. keywords: KEYWORDS,
  250. relevance: 0,
  251. contains: [
  252. C_LINE_COMMENT_MODE,
  253. hljs.C_BLOCK_COMMENT_MODE,
  254. STRINGS,
  255. NUMBERS,
  256. TYPES,
  257. // Count matching parentheses.
  258. {
  259. begin: /\(/,
  260. end: /\)/,
  261. keywords: KEYWORDS,
  262. relevance: 0,
  263. contains: [
  264. 'self',
  265. C_LINE_COMMENT_MODE,
  266. hljs.C_BLOCK_COMMENT_MODE,
  267. STRINGS,
  268. NUMBERS,
  269. TYPES
  270. ]
  271. }
  272. ]
  273. },
  274. TYPES,
  275. C_LINE_COMMENT_MODE,
  276. hljs.C_BLOCK_COMMENT_MODE,
  277. PREPROCESSOR
  278. ]
  279. };
  280. return {
  281. name: "C",
  282. aliases: [ 'h' ],
  283. keywords: KEYWORDS,
  284. // Until differentiations are added between `c` and `cpp`, `c` will
  285. // not be auto-detected to avoid auto-detect conflicts between C and C++
  286. disableAutodetect: true,
  287. illegal: '</',
  288. contains: [].concat(
  289. EXPRESSION_CONTEXT,
  290. FUNCTION_DECLARATION,
  291. EXPRESSION_CONTAINS,
  292. [
  293. PREPROCESSOR,
  294. {
  295. begin: hljs.IDENT_RE + '::',
  296. keywords: KEYWORDS
  297. },
  298. {
  299. className: 'class',
  300. beginKeywords: 'enum class struct union',
  301. end: /[{;:<>=]/,
  302. contains: [
  303. { beginKeywords: "final class struct" },
  304. hljs.TITLE_MODE
  305. ]
  306. }
  307. ]),
  308. exports: {
  309. preprocessor: PREPROCESSOR,
  310. strings: STRINGS,
  311. keywords: KEYWORDS
  312. }
  313. };
  314. }
  315. export { c as default };