haskell.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. const COMMENT = { variants: [
  10. hljs.COMMENT('--', '$'),
  11. hljs.COMMENT(
  12. /\{-/,
  13. /-\}/,
  14. { contains: [ 'self' ] }
  15. )
  16. ] };
  17. const PRAGMA = {
  18. className: 'meta',
  19. begin: /\{-#/,
  20. end: /#-\}/
  21. };
  22. const PREPROCESSOR = {
  23. className: 'meta',
  24. begin: '^#',
  25. end: '$'
  26. };
  27. const CONSTRUCTOR = {
  28. className: 'type',
  29. begin: '\\b[A-Z][\\w\']*', // TODO: other constructors (build-in, infix).
  30. relevance: 0
  31. };
  32. const LIST = {
  33. begin: '\\(',
  34. end: '\\)',
  35. illegal: '"',
  36. contains: [
  37. PRAGMA,
  38. PREPROCESSOR,
  39. {
  40. className: 'type',
  41. begin: '\\b[A-Z][\\w]*(\\((\\.\\.|,|\\w+)\\))?'
  42. },
  43. hljs.inherit(hljs.TITLE_MODE, { begin: '[_a-z][\\w\']*' }),
  44. COMMENT
  45. ]
  46. };
  47. const RECORD = {
  48. begin: /\{/,
  49. end: /\}/,
  50. contains: LIST.contains
  51. };
  52. /* See:
  53. - https://www.haskell.org/onlinereport/lexemes.html
  54. - https://downloads.haskell.org/ghc/9.0.1/docs/html/users_guide/exts/binary_literals.html
  55. - https://downloads.haskell.org/ghc/9.0.1/docs/html/users_guide/exts/numeric_underscores.html
  56. - https://downloads.haskell.org/ghc/9.0.1/docs/html/users_guide/exts/hex_float_literals.html
  57. */
  58. const decimalDigits = '([0-9]_*)+';
  59. const hexDigits = '([0-9a-fA-F]_*)+';
  60. const binaryDigits = '([01]_*)+';
  61. const octalDigits = '([0-7]_*)+';
  62. const NUMBER = {
  63. className: 'number',
  64. relevance: 0,
  65. variants: [
  66. // decimal floating-point-literal (subsumes decimal-literal)
  67. { match: `\\b(${decimalDigits})(\\.(${decimalDigits}))?` + `([eE][+-]?(${decimalDigits}))?\\b` },
  68. // hexadecimal floating-point-literal (subsumes hexadecimal-literal)
  69. { match: `\\b0[xX]_*(${hexDigits})(\\.(${hexDigits}))?` + `([pP][+-]?(${decimalDigits}))?\\b` },
  70. // octal-literal
  71. { match: `\\b0[oO](${octalDigits})\\b` },
  72. // binary-literal
  73. { match: `\\b0[bB](${binaryDigits})\\b` }
  74. ]
  75. };
  76. return {
  77. name: 'Haskell',
  78. aliases: [ 'hs' ],
  79. keywords:
  80. 'let in if then else case of where do module import hiding '
  81. + 'qualified type data newtype deriving class instance as default '
  82. + 'infix infixl infixr foreign export ccall stdcall cplusplus '
  83. + 'jvm dotnet safe unsafe family forall mdo proc rec',
  84. contains: [
  85. // Top-level constructions.
  86. {
  87. beginKeywords: 'module',
  88. end: 'where',
  89. keywords: 'module where',
  90. contains: [
  91. LIST,
  92. COMMENT
  93. ],
  94. illegal: '\\W\\.|;'
  95. },
  96. {
  97. begin: '\\bimport\\b',
  98. end: '$',
  99. keywords: 'import qualified as hiding',
  100. contains: [
  101. LIST,
  102. COMMENT
  103. ],
  104. illegal: '\\W\\.|;'
  105. },
  106. {
  107. className: 'class',
  108. begin: '^(\\s*)?(class|instance)\\b',
  109. end: 'where',
  110. keywords: 'class family instance where',
  111. contains: [
  112. CONSTRUCTOR,
  113. LIST,
  114. COMMENT
  115. ]
  116. },
  117. {
  118. className: 'class',
  119. begin: '\\b(data|(new)?type)\\b',
  120. end: '$',
  121. keywords: 'data family type newtype deriving',
  122. contains: [
  123. PRAGMA,
  124. CONSTRUCTOR,
  125. LIST,
  126. RECORD,
  127. COMMENT
  128. ]
  129. },
  130. {
  131. beginKeywords: 'default',
  132. end: '$',
  133. contains: [
  134. CONSTRUCTOR,
  135. LIST,
  136. COMMENT
  137. ]
  138. },
  139. {
  140. beginKeywords: 'infix infixl infixr',
  141. end: '$',
  142. contains: [
  143. hljs.C_NUMBER_MODE,
  144. COMMENT
  145. ]
  146. },
  147. {
  148. begin: '\\bforeign\\b',
  149. end: '$',
  150. keywords: 'foreign import export ccall stdcall cplusplus jvm '
  151. + 'dotnet safe unsafe',
  152. contains: [
  153. CONSTRUCTOR,
  154. hljs.QUOTE_STRING_MODE,
  155. COMMENT
  156. ]
  157. },
  158. {
  159. className: 'meta',
  160. begin: '#!\\/usr\\/bin\\/env\ runhaskell',
  161. end: '$'
  162. },
  163. // "Whitespaces".
  164. PRAGMA,
  165. PREPROCESSOR,
  166. // Literals and names.
  167. // Single characters.
  168. {
  169. scope: 'string',
  170. begin: /'(?=\\?.')/,
  171. end: /'/,
  172. contains: [
  173. {
  174. scope: 'char.escape',
  175. match: /\\./,
  176. },
  177. ]
  178. },
  179. hljs.QUOTE_STRING_MODE,
  180. NUMBER,
  181. CONSTRUCTOR,
  182. hljs.inherit(hljs.TITLE_MODE, { begin: '^[_a-z][\\w\']*' }),
  183. COMMENT,
  184. { // No markup, relevance booster
  185. begin: '->|<-' }
  186. ]
  187. };
  188. }
  189. module.exports = haskell;