haskell.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. Language: Haskell
  3. Author: Jeremy Hull <sourdrums@gmail.com>
  4. Contributors: Zena Treep <zena.treep@gmail.com>
  5. Website: https://www.haskell.org
  6. Category: functional
  7. */
  8. function haskell(hljs) {
  9. /* See:
  10. - https://www.haskell.org/onlinereport/lexemes.html
  11. - https://downloads.haskell.org/ghc/9.0.1/docs/html/users_guide/exts/binary_literals.html
  12. - https://downloads.haskell.org/ghc/9.0.1/docs/html/users_guide/exts/numeric_underscores.html
  13. - https://downloads.haskell.org/ghc/9.0.1/docs/html/users_guide/exts/hex_float_literals.html
  14. */
  15. const decimalDigits = '([0-9]_*)+';
  16. const hexDigits = '([0-9a-fA-F]_*)+';
  17. const binaryDigits = '([01]_*)+';
  18. const octalDigits = '([0-7]_*)+';
  19. const ascSymbol = '[!#$%&*+.\\/<=>?@\\\\^~-]';
  20. const uniSymbol = '(\\p{S}|\\p{P})'; // Symbol or Punctuation
  21. const special = '[(),;\\[\\]`|{}]';
  22. const symbol = `(${ascSymbol}|(?!(${special}|[_:"']))${uniSymbol})`;
  23. const COMMENT = { variants: [
  24. // Double dash forms a valid comment only if it's not part of legal lexeme.
  25. // See: Haskell 98 report: https://www.haskell.org/onlinereport/lexemes.html
  26. //
  27. // The commented code does the job, but we can't use negative lookbehind,
  28. // due to poor support by Safari browser.
  29. // > hljs.COMMENT(`(?<!${symbol})--+(?!${symbol})`, '$'),
  30. // So instead, we'll add a no-markup rule before the COMMENT rule in the rules list
  31. // to match the problematic infix operators that contain double dash.
  32. hljs.COMMENT('--+', '$'),
  33. hljs.COMMENT(
  34. /\{-/,
  35. /-\}/,
  36. { contains: [ 'self' ] }
  37. )
  38. ] };
  39. const PRAGMA = {
  40. className: 'meta',
  41. begin: /\{-#/,
  42. end: /#-\}/
  43. };
  44. const PREPROCESSOR = {
  45. className: 'meta',
  46. begin: '^#',
  47. end: '$'
  48. };
  49. const CONSTRUCTOR = {
  50. className: 'type',
  51. begin: '\\b[A-Z][\\w\']*', // TODO: other constructors (build-in, infix).
  52. relevance: 0
  53. };
  54. const LIST = {
  55. begin: '\\(',
  56. end: '\\)',
  57. illegal: '"',
  58. contains: [
  59. PRAGMA,
  60. PREPROCESSOR,
  61. {
  62. className: 'type',
  63. begin: '\\b[A-Z][\\w]*(\\((\\.\\.|,|\\w+)\\))?'
  64. },
  65. hljs.inherit(hljs.TITLE_MODE, { begin: '[_a-z][\\w\']*' }),
  66. COMMENT
  67. ]
  68. };
  69. const RECORD = {
  70. begin: /\{/,
  71. end: /\}/,
  72. contains: LIST.contains
  73. };
  74. const NUMBER = {
  75. className: 'number',
  76. relevance: 0,
  77. variants: [
  78. // decimal floating-point-literal (subsumes decimal-literal)
  79. { match: `\\b(${decimalDigits})(\\.(${decimalDigits}))?` + `([eE][+-]?(${decimalDigits}))?\\b` },
  80. // hexadecimal floating-point-literal (subsumes hexadecimal-literal)
  81. { match: `\\b0[xX]_*(${hexDigits})(\\.(${hexDigits}))?` + `([pP][+-]?(${decimalDigits}))?\\b` },
  82. // octal-literal
  83. { match: `\\b0[oO](${octalDigits})\\b` },
  84. // binary-literal
  85. { match: `\\b0[bB](${binaryDigits})\\b` }
  86. ]
  87. };
  88. return {
  89. name: 'Haskell',
  90. aliases: [ 'hs' ],
  91. keywords:
  92. 'let in if then else case of where do module import hiding '
  93. + 'qualified type data newtype deriving class instance as default '
  94. + 'infix infixl infixr foreign export ccall stdcall cplusplus '
  95. + 'jvm dotnet safe unsafe family forall mdo proc rec',
  96. unicodeRegex: true,
  97. contains: [
  98. // Top-level constructions.
  99. {
  100. beginKeywords: 'module',
  101. end: 'where',
  102. keywords: 'module where',
  103. contains: [
  104. LIST,
  105. COMMENT
  106. ],
  107. illegal: '\\W\\.|;'
  108. },
  109. {
  110. begin: '\\bimport\\b',
  111. end: '$',
  112. keywords: 'import qualified as hiding',
  113. contains: [
  114. LIST,
  115. COMMENT
  116. ],
  117. illegal: '\\W\\.|;'
  118. },
  119. {
  120. className: 'class',
  121. begin: '^(\\s*)?(class|instance)\\b',
  122. end: 'where',
  123. keywords: 'class family instance where',
  124. contains: [
  125. CONSTRUCTOR,
  126. LIST,
  127. COMMENT
  128. ]
  129. },
  130. {
  131. className: 'class',
  132. begin: '\\b(data|(new)?type)\\b',
  133. end: '$',
  134. keywords: 'data family type newtype deriving',
  135. contains: [
  136. PRAGMA,
  137. CONSTRUCTOR,
  138. LIST,
  139. RECORD,
  140. COMMENT
  141. ]
  142. },
  143. {
  144. beginKeywords: 'default',
  145. end: '$',
  146. contains: [
  147. CONSTRUCTOR,
  148. LIST,
  149. COMMENT
  150. ]
  151. },
  152. {
  153. beginKeywords: 'infix infixl infixr',
  154. end: '$',
  155. contains: [
  156. hljs.C_NUMBER_MODE,
  157. COMMENT
  158. ]
  159. },
  160. {
  161. begin: '\\bforeign\\b',
  162. end: '$',
  163. keywords: 'foreign import export ccall stdcall cplusplus jvm '
  164. + 'dotnet safe unsafe',
  165. contains: [
  166. CONSTRUCTOR,
  167. hljs.QUOTE_STRING_MODE,
  168. COMMENT
  169. ]
  170. },
  171. {
  172. className: 'meta',
  173. begin: '#!\\/usr\\/bin\\/env\ runhaskell',
  174. end: '$'
  175. },
  176. // "Whitespaces".
  177. PRAGMA,
  178. PREPROCESSOR,
  179. // Literals and names.
  180. // Single characters.
  181. {
  182. scope: 'string',
  183. begin: /'(?=\\?.')/,
  184. end: /'/,
  185. contains: [
  186. {
  187. scope: 'char.escape',
  188. match: /\\./,
  189. },
  190. ]
  191. },
  192. hljs.QUOTE_STRING_MODE,
  193. NUMBER,
  194. CONSTRUCTOR,
  195. hljs.inherit(hljs.TITLE_MODE, { begin: '^[_a-z][\\w\']*' }),
  196. // No markup, prevents infix operators from being recognized as comments.
  197. { begin: `(?!-)${symbol}--+|--+(?!-)${symbol}`},
  198. COMMENT,
  199. { // No markup, relevance booster
  200. begin: '->|<-' }
  201. ]
  202. };
  203. }
  204. export { haskell as default };