c.js 8.1 KB

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