crystal.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. Language: Crystal
  3. Author: TSUYUSATO Kitsune <make.just.on@gmail.com>
  4. Website: https://crystal-lang.org
  5. */
  6. /** @type LanguageFn */
  7. function crystal(hljs) {
  8. var INT_SUFFIX = '(_*[ui](8|16|32|64|128))?';
  9. var FLOAT_SUFFIX = '(_*f(32|64))?';
  10. var CRYSTAL_IDENT_RE = '[a-zA-Z_]\\w*[!?=]?';
  11. var CRYSTAL_METHOD_RE = '[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|[=!]~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~|]|//|//=|&[-+*]=?|&\\*\\*|\\[\\][=?]?';
  12. var CRYSTAL_PATH_RE = '[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?';
  13. var CRYSTAL_KEYWORDS = {
  14. $pattern: CRYSTAL_IDENT_RE,
  15. keyword:
  16. 'abstract alias annotation as as? asm begin break case class def do else elsif end ensure enum extend for fun if ' +
  17. 'include instance_sizeof is_a? lib macro module next nil? of out pointerof private protected rescue responds_to? ' +
  18. 'return require select self sizeof struct super then type typeof union uninitialized unless until verbatim when while with yield ' +
  19. '__DIR__ __END_LINE__ __FILE__ __LINE__',
  20. literal: 'false nil true'
  21. };
  22. var SUBST = {
  23. className: 'subst',
  24. begin: '#{', end: '}',
  25. keywords: CRYSTAL_KEYWORDS
  26. };
  27. var EXPANSION = {
  28. className: 'template-variable',
  29. variants: [
  30. {begin: '\\{\\{', end: '\\}\\}'},
  31. {begin: '\\{%', end: '%\\}'}
  32. ],
  33. keywords: CRYSTAL_KEYWORDS
  34. };
  35. function recursiveParen(begin, end) {
  36. var
  37. contains = [{begin: begin, end: end}];
  38. contains[0].contains = contains;
  39. return contains;
  40. }
  41. var STRING = {
  42. className: 'string',
  43. contains: [hljs.BACKSLASH_ESCAPE, SUBST],
  44. variants: [
  45. {begin: /'/, end: /'/},
  46. {begin: /"/, end: /"/},
  47. {begin: /`/, end: /`/},
  48. {begin: '%[Qwi]?\\(', end: '\\)', contains: recursiveParen('\\(', '\\)')},
  49. {begin: '%[Qwi]?\\[', end: '\\]', contains: recursiveParen('\\[', '\\]')},
  50. {begin: '%[Qwi]?{', end: '}', contains: recursiveParen('{', '}')},
  51. {begin: '%[Qwi]?<', end: '>', contains: recursiveParen('<', '>')},
  52. {begin: '%[Qwi]?\\|', end: '\\|'},
  53. {begin: /<<-\w+$/, end: /^\s*\w+$/},
  54. ],
  55. relevance: 0,
  56. };
  57. var Q_STRING = {
  58. className: 'string',
  59. variants: [
  60. {begin: '%q\\(', end: '\\)', contains: recursiveParen('\\(', '\\)')},
  61. {begin: '%q\\[', end: '\\]', contains: recursiveParen('\\[', '\\]')},
  62. {begin: '%q{', end: '}', contains: recursiveParen('{', '}')},
  63. {begin: '%q<', end: '>', contains: recursiveParen('<', '>')},
  64. {begin: '%q\\|', end: '\\|'},
  65. {begin: /<<-'\w+'$/, end: /^\s*\w+$/},
  66. ],
  67. relevance: 0,
  68. };
  69. var REGEXP = {
  70. begin: '(?!%})(' + hljs.RE_STARTERS_RE + '|\\n|\\b(case|if|select|unless|until|when|while)\\b)\\s*',
  71. keywords: 'case if select unless until when while',
  72. contains: [
  73. {
  74. className: 'regexp',
  75. contains: [hljs.BACKSLASH_ESCAPE, SUBST],
  76. variants: [
  77. {begin: '//[a-z]*', relevance: 0},
  78. {begin: '/(?!\\/)', end: '/[a-z]*'},
  79. ]
  80. }
  81. ],
  82. relevance: 0
  83. };
  84. var REGEXP2 = {
  85. className: 'regexp',
  86. contains: [hljs.BACKSLASH_ESCAPE, SUBST],
  87. variants: [
  88. {begin: '%r\\(', end: '\\)', contains: recursiveParen('\\(', '\\)')},
  89. {begin: '%r\\[', end: '\\]', contains: recursiveParen('\\[', '\\]')},
  90. {begin: '%r{', end: '}', contains: recursiveParen('{', '}')},
  91. {begin: '%r<', end: '>', contains: recursiveParen('<', '>')},
  92. {begin: '%r\\|', end: '\\|'},
  93. ],
  94. relevance: 0
  95. };
  96. var ATTRIBUTE = {
  97. className: 'meta',
  98. begin: '@\\[', end: '\\]',
  99. contains: [
  100. hljs.inherit(hljs.QUOTE_STRING_MODE, {className: 'meta-string'})
  101. ]
  102. };
  103. var CRYSTAL_DEFAULT_CONTAINS = [
  104. EXPANSION,
  105. STRING,
  106. Q_STRING,
  107. REGEXP2,
  108. REGEXP,
  109. ATTRIBUTE,
  110. hljs.HASH_COMMENT_MODE,
  111. {
  112. className: 'class',
  113. beginKeywords: 'class module struct', end: '$|;',
  114. illegal: /=/,
  115. contains: [
  116. hljs.HASH_COMMENT_MODE,
  117. hljs.inherit(hljs.TITLE_MODE, {begin: CRYSTAL_PATH_RE}),
  118. {begin: '<'} // relevance booster for inheritance
  119. ]
  120. },
  121. {
  122. className: 'class',
  123. beginKeywords: 'lib enum union', end: '$|;',
  124. illegal: /=/,
  125. contains: [
  126. hljs.HASH_COMMENT_MODE,
  127. hljs.inherit(hljs.TITLE_MODE, {begin: CRYSTAL_PATH_RE}),
  128. ],
  129. relevance: 10
  130. },
  131. {
  132. beginKeywords: 'annotation', end: '$|;',
  133. illegal: /=/,
  134. contains: [
  135. hljs.HASH_COMMENT_MODE,
  136. hljs.inherit(hljs.TITLE_MODE, {begin: CRYSTAL_PATH_RE}),
  137. ],
  138. relevance: 10
  139. },
  140. {
  141. className: 'function',
  142. beginKeywords: 'def', end: /\B\b/,
  143. contains: [
  144. hljs.inherit(hljs.TITLE_MODE, {
  145. begin: CRYSTAL_METHOD_RE,
  146. endsParent: true
  147. })
  148. ]
  149. },
  150. {
  151. className: 'function',
  152. beginKeywords: 'fun macro', end: /\B\b/,
  153. contains: [
  154. hljs.inherit(hljs.TITLE_MODE, {
  155. begin: CRYSTAL_METHOD_RE,
  156. endsParent: true
  157. })
  158. ],
  159. relevance: 5
  160. },
  161. {
  162. className: 'symbol',
  163. begin: hljs.UNDERSCORE_IDENT_RE + '(\\!|\\?)?:',
  164. relevance: 0
  165. },
  166. {
  167. className: 'symbol',
  168. begin: ':',
  169. contains: [STRING, {begin: CRYSTAL_METHOD_RE}],
  170. relevance: 0
  171. },
  172. {
  173. className: 'number',
  174. variants: [
  175. { begin: '\\b0b([01_]+)' + INT_SUFFIX },
  176. { begin: '\\b0o([0-7_]+)' + INT_SUFFIX },
  177. { begin: '\\b0x([A-Fa-f0-9_]+)' + INT_SUFFIX },
  178. { begin: '\\b([1-9][0-9_]*[0-9]|[0-9])(\\.[0-9][0-9_]*)?([eE]_*[-+]?[0-9_]*)?' + FLOAT_SUFFIX + '(?!_)' },
  179. { begin: '\\b([1-9][0-9_]*|0)' + INT_SUFFIX }
  180. ],
  181. relevance: 0
  182. }
  183. ];
  184. SUBST.contains = CRYSTAL_DEFAULT_CONTAINS;
  185. EXPANSION.contains = CRYSTAL_DEFAULT_CONTAINS.slice(1); // without EXPANSION
  186. return {
  187. name: 'Crystal',
  188. aliases: ['cr'],
  189. keywords: CRYSTAL_KEYWORDS,
  190. contains: CRYSTAL_DEFAULT_CONTAINS
  191. };
  192. }
  193. module.exports = crystal;