haskell.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. (function(mod) {
  2. if (typeof exports == "object" && typeof module == "object") // CommonJS
  3. mod(require("../../lib/codemirror"));
  4. else if (typeof define == "function" && define.amd) // AMD
  5. define(["../../lib/codemirror"], mod);
  6. else // Plain browser env
  7. mod(CodeMirror);
  8. })(function(CodeMirror) {
  9. "use strict";
  10. CodeMirror.defineMode("haskell", function(_config, modeConfig) {
  11. function switchState(source, setState, f) {
  12. setState(f);
  13. return f(source, setState);
  14. }
  15. // These should all be Unicode extended, as per the Haskell 2010 report
  16. var smallRE = /[a-z_]/;
  17. var largeRE = /[A-Z]/;
  18. var digitRE = /\d/;
  19. var hexitRE = /[0-9A-Fa-f]/;
  20. var octitRE = /[0-7]/;
  21. var idRE = /[a-z_A-Z0-9']/;
  22. var symbolRE = /[-!#$%&*+.\/<=>?@\\^|~:]/;
  23. var specialRE = /[(),;[\]`{}]/;
  24. var whiteCharRE = /[ \t\v\f]/; // newlines are handled in tokenizer
  25. function normal(source, setState) {
  26. if (source.eatWhile(whiteCharRE)) {
  27. return null;
  28. }
  29. var ch = source.next();
  30. if (specialRE.test(ch)) {
  31. if (ch == '{' && source.eat('-')) {
  32. var t = "comment";
  33. if (source.eat('#')) {
  34. t = "meta";
  35. }
  36. return switchState(source, setState, ncomment(t, 1));
  37. }
  38. return null;
  39. }
  40. if (ch == '\'') {
  41. if (source.eat('\\')) {
  42. source.next(); // should handle other escapes here
  43. }
  44. else {
  45. source.next();
  46. }
  47. if (source.eat('\'')) {
  48. return "string";
  49. }
  50. return "error";
  51. }
  52. if (ch == '"') {
  53. return switchState(source, setState, stringLiteral);
  54. }
  55. if (largeRE.test(ch)) {
  56. source.eatWhile(idRE);
  57. if (source.eat('.')) {
  58. return "qualifier";
  59. }
  60. return "variable-2";
  61. }
  62. if (smallRE.test(ch)) {
  63. source.eatWhile(idRE);
  64. return "variable";
  65. }
  66. if (digitRE.test(ch)) {
  67. if (ch == '0') {
  68. if (source.eat(/[xX]/)) {
  69. source.eatWhile(hexitRE); // should require at least 1
  70. return "integer";
  71. }
  72. if (source.eat(/[oO]/)) {
  73. source.eatWhile(octitRE); // should require at least 1
  74. return "number";
  75. }
  76. }
  77. source.eatWhile(digitRE);
  78. var t = "number";
  79. if (source.match(/^\.\d+/)) {
  80. t = "number";
  81. }
  82. if (source.eat(/[eE]/)) {
  83. t = "number";
  84. source.eat(/[-+]/);
  85. source.eatWhile(digitRE); // should require at least 1
  86. }
  87. return t;
  88. }
  89. if (ch == "." && source.eat("."))
  90. return "keyword";
  91. if (symbolRE.test(ch)) {
  92. if (ch == '-' && source.eat(/-/)) {
  93. source.eatWhile(/-/);
  94. if (!source.eat(symbolRE)) {
  95. source.skipToEnd();
  96. return "comment";
  97. }
  98. }
  99. var t = "variable";
  100. if (ch == ':') {
  101. t = "variable-2";
  102. }
  103. source.eatWhile(symbolRE);
  104. return t;
  105. }
  106. return "error";
  107. }
  108. function ncomment(type, nest) {
  109. if (nest == 0) {
  110. return normal;
  111. }
  112. return function(source, setState) {
  113. var currNest = nest;
  114. while (!source.eol()) {
  115. var ch = source.next();
  116. if (ch == '{' && source.eat('-')) {
  117. ++currNest;
  118. }
  119. else if (ch == '-' && source.eat('}')) {
  120. --currNest;
  121. if (currNest == 0) {
  122. setState(normal);
  123. return type;
  124. }
  125. }
  126. }
  127. setState(ncomment(type, currNest));
  128. return type;
  129. };
  130. }
  131. function stringLiteral(source, setState) {
  132. while (!source.eol()) {
  133. var ch = source.next();
  134. if (ch == '"') {
  135. setState(normal);
  136. return "string";
  137. }
  138. if (ch == '\\') {
  139. if (source.eol() || source.eat(whiteCharRE)) {
  140. setState(stringGap);
  141. return "string";
  142. }
  143. if (source.eat('&')) {
  144. }
  145. else {
  146. source.next(); // should handle other escapes here
  147. }
  148. }
  149. }
  150. setState(normal);
  151. return "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++)
  166. wkw[arguments[i]] = t;
  167. };
  168. }
  169. setType("keyword")(
  170. "case", "class", "data", "default", "deriving", "do", "else", "foreign",
  171. "if", "import", "in", "infix", "infixl", "infixr", "instance", "let",
  172. "module", "newtype", "of", "then", "type", "where", "_");
  173. setType("keyword")(
  174. "\.\.", ":", "::", "=", "\\", "\"", "<-", "->", "@", "~", "=>");
  175. setType("builtin")(
  176. "!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<=", "=<<",
  177. "==", ">", ">=", ">>", ">>=", "^", "^^", "||", "*", "**");
  178. setType("builtin")(
  179. "Bool", "Bounded", "Char", "Double", "EQ", "Either", "Enum", "Eq",
  180. "False", "FilePath", "Float", "Floating", "Fractional", "Functor", "GT",
  181. "IO", "IOError", "Int", "Integer", "Integral", "Just", "LT", "Left",
  182. "Maybe", "Monad", "Nothing", "Num", "Ord", "Ordering", "Rational", "Read",
  183. "ReadS", "Real", "RealFloat", "RealFrac", "Right", "Show", "ShowS",
  184. "String", "True");
  185. setType("builtin")(
  186. "abs", "acos", "acosh", "all", "and", "any", "appendFile", "asTypeOf",
  187. "asin", "asinh", "atan", "atan2", "atanh", "break", "catch", "ceiling",
  188. "compare", "concat", "concatMap", "const", "cos", "cosh", "curry",
  189. "cycle", "decodeFloat", "div", "divMod", "drop", "dropWhile", "either",
  190. "elem", "encodeFloat", "enumFrom", "enumFromThen", "enumFromThenTo",
  191. "enumFromTo", "error", "even", "exp", "exponent", "fail", "filter",
  192. "flip", "floatDigits", "floatRadix", "floatRange", "floor", "fmap",
  193. "foldl", "foldl1", "foldr", "foldr1", "fromEnum", "fromInteger",
  194. "fromIntegral", "fromRational", "fst", "gcd", "getChar", "getContents",
  195. "getLine", "head", "id", "init", "interact", "ioError", "isDenormalized",
  196. "isIEEE", "isInfinite", "isNaN", "isNegativeZero", "iterate", "last",
  197. "lcm", "length", "lex", "lines", "log", "logBase", "lookup", "map",
  198. "mapM", "mapM_", "max", "maxBound", "maximum", "maybe", "min", "minBound",
  199. "minimum", "mod", "negate", "not", "notElem", "null", "odd", "or",
  200. "otherwise", "pi", "pred", "print", "product", "properFraction",
  201. "putChar", "putStr", "putStrLn", "quot", "quotRem", "read", "readFile",
  202. "readIO", "readList", "readLn", "readParen", "reads", "readsPrec",
  203. "realToFrac", "recip", "rem", "repeat", "replicate", "return", "reverse",
  204. "round", "scaleFloat", "scanl", "scanl1", "scanr", "scanr1", "seq",
  205. "sequence", "sequence_", "show", "showChar", "showList", "showParen",
  206. "showString", "shows", "showsPrec", "significand", "signum", "sin",
  207. "sinh", "snd", "span", "splitAt", "sqrt", "subtract", "succ", "sum",
  208. "tail", "take", "takeWhile", "tan", "tanh", "toEnum", "toInteger",
  209. "toRational", "truncate", "uncurry", "undefined", "unlines", "until",
  210. "unwords", "unzip", "unzip3", "userError", "words", "writeFile", "zip",
  211. "zip3", "zipWith", "zipWith3");
  212. var override = modeConfig.overrideKeywords;
  213. if (override) for (var word in override) if (override.hasOwnProperty(word))
  214. wkw[word] = override[word];
  215. return wkw;
  216. })();
  217. return {
  218. startState: function () { return { f: normal }; },
  219. copyState: function (s) { return { f: s.f }; },
  220. token: function(stream, state) {
  221. var t = state.f(stream, function(s) { state.f = s; });
  222. var w = stream.current();
  223. return wellKnownWords.hasOwnProperty(w) ? wellKnownWords[w] : t;
  224. },
  225. blockCommentStart: "{-",
  226. blockCommentEnd: "-}",
  227. lineComment: "--"
  228. };
  229. });
  230. CodeMirror.defineMIME("text/x-haskell", "haskell");
  231. });