haskell.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2. // Distributed under an MIT license: https://codemirror.net/LICENSE
  3. ;(function (mod) {
  4. if (typeof exports == 'object' && typeof module == 'object')
  5. // CommonJS
  6. mod(require('../../lib/codemirror'))
  7. else if (typeof define == 'function' && define.amd)
  8. // AMD
  9. define(['../../lib/codemirror'], mod)
  10. // Plain browser env
  11. else mod(CodeMirror)
  12. })(function (CodeMirror) {
  13. 'use strict'
  14. CodeMirror.defineMode('haskell', function (_config, modeConfig) {
  15. function switchState(source, setState, f) {
  16. setState(f)
  17. return f(source, setState)
  18. }
  19. // These should all be Unicode extended, as per the Haskell 2010 report
  20. var smallRE = /[a-z_]/
  21. var largeRE = /[A-Z]/
  22. var digitRE = /\d/
  23. var hexitRE = /[0-9A-Fa-f]/
  24. var octitRE = /[0-7]/
  25. var idRE = /[a-z_A-Z0-9'\xa1-\uffff]/
  26. var symbolRE = /[-!#$%&*+.\/<=>?@\\^|~:]/
  27. var specialRE = /[(),;[\]`{}]/
  28. var whiteCharRE = /[ \t\v\f]/ // newlines are handled in tokenizer
  29. function normal(source, setState) {
  30. if (source.eatWhile(whiteCharRE)) {
  31. return null
  32. }
  33. var ch = source.next()
  34. if (specialRE.test(ch)) {
  35. if (ch == '{' && source.eat('-')) {
  36. var t = 'comment'
  37. if (source.eat('#')) {
  38. t = 'meta'
  39. }
  40. return switchState(source, setState, ncomment(t, 1))
  41. }
  42. return null
  43. }
  44. if (ch == "'") {
  45. if (source.eat('\\')) {
  46. source.next() // should handle other escapes here
  47. } else {
  48. source.next()
  49. }
  50. if (source.eat("'")) {
  51. return 'string'
  52. }
  53. return 'string error'
  54. }
  55. if (ch == '"') {
  56. return switchState(source, setState, stringLiteral)
  57. }
  58. if (largeRE.test(ch)) {
  59. source.eatWhile(idRE)
  60. if (source.eat('.')) {
  61. return 'qualifier'
  62. }
  63. return 'variable-2'
  64. }
  65. if (smallRE.test(ch)) {
  66. source.eatWhile(idRE)
  67. return 'variable'
  68. }
  69. if (digitRE.test(ch)) {
  70. if (ch == '0') {
  71. if (source.eat(/[xX]/)) {
  72. source.eatWhile(hexitRE) // should require at least 1
  73. return 'integer'
  74. }
  75. if (source.eat(/[oO]/)) {
  76. source.eatWhile(octitRE) // should require at least 1
  77. return 'number'
  78. }
  79. }
  80. source.eatWhile(digitRE)
  81. var t = 'number'
  82. if (source.match(/^\.\d+/)) {
  83. t = 'number'
  84. }
  85. if (source.eat(/[eE]/)) {
  86. t = 'number'
  87. source.eat(/[-+]/)
  88. source.eatWhile(digitRE) // should require at least 1
  89. }
  90. return t
  91. }
  92. if (ch == '.' && source.eat('.')) return 'keyword'
  93. if (symbolRE.test(ch)) {
  94. if (ch == '-' && source.eat(/-/)) {
  95. source.eatWhile(/-/)
  96. if (!source.eat(symbolRE)) {
  97. source.skipToEnd()
  98. return 'comment'
  99. }
  100. }
  101. var t = 'variable'
  102. if (ch == ':') {
  103. t = 'variable-2'
  104. }
  105. source.eatWhile(symbolRE)
  106. return t
  107. }
  108. return 'error'
  109. }
  110. function ncomment(type, nest) {
  111. if (nest == 0) {
  112. return normal
  113. }
  114. return function (source, setState) {
  115. var currNest = nest
  116. while (!source.eol()) {
  117. var ch = source.next()
  118. if (ch == '{' && source.eat('-')) {
  119. ++currNest
  120. } else if (ch == '-' && source.eat('}')) {
  121. --currNest
  122. if (currNest == 0) {
  123. setState(normal)
  124. return type
  125. }
  126. }
  127. }
  128. setState(ncomment(type, currNest))
  129. return type
  130. }
  131. }
  132. function stringLiteral(source, setState) {
  133. while (!source.eol()) {
  134. var ch = source.next()
  135. if (ch == '"') {
  136. setState(normal)
  137. return 'string'
  138. }
  139. if (ch == '\\') {
  140. if (source.eol() || source.eat(whiteCharRE)) {
  141. setState(stringGap)
  142. return 'string'
  143. }
  144. if (source.eat('&')) {
  145. } else {
  146. source.next() // should handle other escapes here
  147. }
  148. }
  149. }
  150. setState(normal)
  151. return 'string error'
  152. }
  153. function stringGap(source, setState) {
  154. if (source.eat('\\')) {
  155. return switchState(source, setState, stringLiteral)
  156. }
  157. source.next()
  158. setState(normal)
  159. return 'error'
  160. }
  161. var wellKnownWords = (function () {
  162. var wkw = {}
  163. function setType(t) {
  164. return function () {
  165. for (var i = 0; i < arguments.length; i++) wkw[arguments[i]] = t
  166. }
  167. }
  168. setType('keyword')(
  169. 'case',
  170. 'class',
  171. 'data',
  172. 'default',
  173. 'deriving',
  174. 'do',
  175. 'else',
  176. 'foreign',
  177. 'if',
  178. 'import',
  179. 'in',
  180. 'infix',
  181. 'infixl',
  182. 'infixr',
  183. 'instance',
  184. 'let',
  185. 'module',
  186. 'newtype',
  187. 'of',
  188. 'then',
  189. 'type',
  190. 'where',
  191. '_'
  192. )
  193. setType('keyword')('..', ':', '::', '=', '\\', '<-', '->', '@', '~', '=>')
  194. setType('builtin')('!!', '$!', '$', '&&', '+', '++', '-', '.', '/', '/=', '<', '<*', '<=', '<$>', '<*>', '=<<', '==', '>', '>=', '>>', '>>=', '^', '^^', '||', '*', '*>', '**')
  195. setType('builtin')(
  196. 'Applicative',
  197. 'Bool',
  198. 'Bounded',
  199. 'Char',
  200. 'Double',
  201. 'EQ',
  202. 'Either',
  203. 'Enum',
  204. 'Eq',
  205. 'False',
  206. 'FilePath',
  207. 'Float',
  208. 'Floating',
  209. 'Fractional',
  210. 'Functor',
  211. 'GT',
  212. 'IO',
  213. 'IOError',
  214. 'Int',
  215. 'Integer',
  216. 'Integral',
  217. 'Just',
  218. 'LT',
  219. 'Left',
  220. 'Maybe',
  221. 'Monad',
  222. 'Nothing',
  223. 'Num',
  224. 'Ord',
  225. 'Ordering',
  226. 'Rational',
  227. 'Read',
  228. 'ReadS',
  229. 'Real',
  230. 'RealFloat',
  231. 'RealFrac',
  232. 'Right',
  233. 'Show',
  234. 'ShowS',
  235. 'String',
  236. 'True'
  237. )
  238. setType('builtin')(
  239. 'abs',
  240. 'acos',
  241. 'acosh',
  242. 'all',
  243. 'and',
  244. 'any',
  245. 'appendFile',
  246. 'asTypeOf',
  247. 'asin',
  248. 'asinh',
  249. 'atan',
  250. 'atan2',
  251. 'atanh',
  252. 'break',
  253. 'catch',
  254. 'ceiling',
  255. 'compare',
  256. 'concat',
  257. 'concatMap',
  258. 'const',
  259. 'cos',
  260. 'cosh',
  261. 'curry',
  262. 'cycle',
  263. 'decodeFloat',
  264. 'div',
  265. 'divMod',
  266. 'drop',
  267. 'dropWhile',
  268. 'either',
  269. 'elem',
  270. 'encodeFloat',
  271. 'enumFrom',
  272. 'enumFromThen',
  273. 'enumFromThenTo',
  274. 'enumFromTo',
  275. 'error',
  276. 'even',
  277. 'exp',
  278. 'exponent',
  279. 'fail',
  280. 'filter',
  281. 'flip',
  282. 'floatDigits',
  283. 'floatRadix',
  284. 'floatRange',
  285. 'floor',
  286. 'fmap',
  287. 'foldl',
  288. 'foldl1',
  289. 'foldr',
  290. 'foldr1',
  291. 'fromEnum',
  292. 'fromInteger',
  293. 'fromIntegral',
  294. 'fromRational',
  295. 'fst',
  296. 'gcd',
  297. 'getChar',
  298. 'getContents',
  299. 'getLine',
  300. 'head',
  301. 'id',
  302. 'init',
  303. 'interact',
  304. 'ioError',
  305. 'isDenormalized',
  306. 'isIEEE',
  307. 'isInfinite',
  308. 'isNaN',
  309. 'isNegativeZero',
  310. 'iterate',
  311. 'last',
  312. 'lcm',
  313. 'length',
  314. 'lex',
  315. 'lines',
  316. 'log',
  317. 'logBase',
  318. 'lookup',
  319. 'map',
  320. 'mapM',
  321. 'mapM_',
  322. 'max',
  323. 'maxBound',
  324. 'maximum',
  325. 'maybe',
  326. 'min',
  327. 'minBound',
  328. 'minimum',
  329. 'mod',
  330. 'negate',
  331. 'not',
  332. 'notElem',
  333. 'null',
  334. 'odd',
  335. 'or',
  336. 'otherwise',
  337. 'pi',
  338. 'pred',
  339. 'print',
  340. 'product',
  341. 'properFraction',
  342. 'pure',
  343. 'putChar',
  344. 'putStr',
  345. 'putStrLn',
  346. 'quot',
  347. 'quotRem',
  348. 'read',
  349. 'readFile',
  350. 'readIO',
  351. 'readList',
  352. 'readLn',
  353. 'readParen',
  354. 'reads',
  355. 'readsPrec',
  356. 'realToFrac',
  357. 'recip',
  358. 'rem',
  359. 'repeat',
  360. 'replicate',
  361. 'return',
  362. 'reverse',
  363. 'round',
  364. 'scaleFloat',
  365. 'scanl',
  366. 'scanl1',
  367. 'scanr',
  368. 'scanr1',
  369. 'seq',
  370. 'sequence',
  371. 'sequence_',
  372. 'show',
  373. 'showChar',
  374. 'showList',
  375. 'showParen',
  376. 'showString',
  377. 'shows',
  378. 'showsPrec',
  379. 'significand',
  380. 'signum',
  381. 'sin',
  382. 'sinh',
  383. 'snd',
  384. 'span',
  385. 'splitAt',
  386. 'sqrt',
  387. 'subtract',
  388. 'succ',
  389. 'sum',
  390. 'tail',
  391. 'take',
  392. 'takeWhile',
  393. 'tan',
  394. 'tanh',
  395. 'toEnum',
  396. 'toInteger',
  397. 'toRational',
  398. 'truncate',
  399. 'uncurry',
  400. 'undefined',
  401. 'unlines',
  402. 'until',
  403. 'unwords',
  404. 'unzip',
  405. 'unzip3',
  406. 'userError',
  407. 'words',
  408. 'writeFile',
  409. 'zip',
  410. 'zip3',
  411. 'zipWith',
  412. 'zipWith3'
  413. )
  414. var override = modeConfig.overrideKeywords
  415. if (override) for (var word in override) if (override.hasOwnProperty(word)) wkw[word] = override[word]
  416. return wkw
  417. })()
  418. return {
  419. startState: function () {
  420. return { f: normal }
  421. },
  422. copyState: function (s) {
  423. return { f: s.f }
  424. },
  425. token: function (stream, state) {
  426. var t = state.f(stream, function (s) {
  427. state.f = s
  428. })
  429. var w = stream.current()
  430. return wellKnownWords.hasOwnProperty(w) ? wellKnownWords[w] : t
  431. },
  432. blockCommentStart: '{-',
  433. blockCommentEnd: '-}',
  434. lineComment: '--',
  435. }
  436. })
  437. CodeMirror.defineMIME('text/x-haskell', 'haskell')
  438. })