crystal.js 5.6 KB

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