1 CodeMirror.defineMode("haskell", function() {
3 function switchState(source, setState, f) {
5 return f(source, setState);
8 // These should all be Unicode extended, as per the Haskell 2010 report
9 var smallRE = /[a-z_]/;
10 var largeRE = /[A-Z]/;
11 var digitRE = /[0-9]/;
12 var hexitRE = /[0-9A-Fa-f]/;
13 var octitRE = /[0-7]/;
14 var idRE = /[a-z_A-Z0-9']/;
15 var symbolRE = /[-!#$%&*+.\/<=>?@\\^|~:]/;
16 var specialRE = /[(),;[\]`{}]/;
17 var whiteCharRE = /[ \t\v\f]/; // newlines are handled in tokenizer
19 function normal(source, setState) {
20 if (source.eatWhile(whiteCharRE)) {
24 var ch = source.next();
25 if (specialRE.test(ch)) {
26 if (ch == '{' && source.eat('-')) {
28 if (source.eat('#')) {
31 return switchState(source, setState, ncomment(t, 1));
37 if (source.eat('\\')) {
38 source.next(); // should handle other escapes here
43 if (source.eat('\'')) {
50 return switchState(source, setState, stringLiteral);
53 if (largeRE.test(ch)) {
54 source.eatWhile(idRE);
55 if (source.eat('.')) {
61 if (smallRE.test(ch)) {
62 source.eatWhile(idRE);
66 if (digitRE.test(ch)) {
68 if (source.eat(/[xX]/)) {
69 source.eatWhile(hexitRE); // should require at least 1
72 if (source.eat(/[oO]/)) {
73 source.eatWhile(octitRE); // should require at least 1
77 source.eatWhile(digitRE);
79 if (source.eat('.')) {
81 source.eatWhile(digitRE); // should require at least 1
83 if (source.eat(/[eE]/)) {
86 source.eatWhile(digitRE); // should require at least 1
91 if (symbolRE.test(ch)) {
92 if (ch == '-' && source.eat(/-/)) {
94 if (!source.eat(symbolRE)) {
103 source.eatWhile(symbolRE);
110 function ncomment(type, nest) {
114 return function(source, setState) {
116 while (!source.eol()) {
117 var ch = source.next();
118 if (ch == '{' && source.eat('-')) {
121 else if (ch == '-' && source.eat('}')) {
129 setState(ncomment(type, currNest));
134 function stringLiteral(source, setState) {
135 while (!source.eol()) {
136 var ch = source.next();
142 if (source.eol() || source.eat(whiteCharRE)) {
146 if (source.eat('&')) {
149 source.next(); // should handle other escapes here
157 function stringGap(source, setState) {
158 if (source.eat('\\')) {
159 return switchState(source, setState, stringLiteral);
167 var wellKnownWords = (function() {
169 function setType(t) {
171 for (var i = 0; i < arguments.length; i++)
172 wkw[arguments[i]] = t;
177 "case", "class", "data", "default", "deriving", "do", "else", "foreign",
178 "if", "import", "in", "infix", "infixl", "infixr", "instance", "let",
179 "module", "newtype", "of", "then", "type", "where", "_");
182 "\.\.", ":", "::", "=", "\\", "\"", "<-", "->", "@", "~", "=>");
185 "!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<=", "=<<",
186 "==", ">", ">=", ">>", ">>=", "^", "^^", "||", "*", "**");
189 "Bool", "Bounded", "Char", "Double", "EQ", "Either", "Enum", "Eq",
190 "False", "FilePath", "Float", "Floating", "Fractional", "Functor", "GT",
191 "IO", "IOError", "Int", "Integer", "Integral", "Just", "LT", "Left",
192 "Maybe", "Monad", "Nothing", "Num", "Ord", "Ordering", "Rational", "Read",
193 "ReadS", "Real", "RealFloat", "RealFrac", "Right", "Show", "ShowS",
197 "abs", "acos", "acosh", "all", "and", "any", "appendFile", "asTypeOf",
198 "asin", "asinh", "atan", "atan2", "atanh", "break", "catch", "ceiling",
199 "compare", "concat", "concatMap", "const", "cos", "cosh", "curry",
200 "cycle", "decodeFloat", "div", "divMod", "drop", "dropWhile", "either",
201 "elem", "encodeFloat", "enumFrom", "enumFromThen", "enumFromThenTo",
202 "enumFromTo", "error", "even", "exp", "exponent", "fail", "filter",
203 "flip", "floatDigits", "floatRadix", "floatRange", "floor", "fmap",
204 "foldl", "foldl1", "foldr", "foldr1", "fromEnum", "fromInteger",
205 "fromIntegral", "fromRational", "fst", "gcd", "getChar", "getContents",
206 "getLine", "head", "id", "init", "interact", "ioError", "isDenormalized",
207 "isIEEE", "isInfinite", "isNaN", "isNegativeZero", "iterate", "last",
208 "lcm", "length", "lex", "lines", "log", "logBase", "lookup", "map",
209 "mapM", "mapM_", "max", "maxBound", "maximum", "maybe", "min", "minBound",
210 "minimum", "mod", "negate", "not", "notElem", "null", "odd", "or",
211 "otherwise", "pi", "pred", "print", "product", "properFraction",
212 "putChar", "putStr", "putStrLn", "quot", "quotRem", "read", "readFile",
213 "readIO", "readList", "readLn", "readParen", "reads", "readsPrec",
214 "realToFrac", "recip", "rem", "repeat", "replicate", "return", "reverse",
215 "round", "scaleFloat", "scanl", "scanl1", "scanr", "scanr1", "seq",
216 "sequence", "sequence_", "show", "showChar", "showList", "showParen",
217 "showString", "shows", "showsPrec", "significand", "signum", "sin",
218 "sinh", "snd", "span", "splitAt", "sqrt", "subtract", "succ", "sum",
219 "tail", "take", "takeWhile", "tan", "tanh", "toEnum", "toInteger",
220 "toRational", "truncate", "uncurry", "undefined", "unlines", "until",
221 "unwords", "unzip", "unzip3", "userError", "words", "writeFile", "zip",
222 "zip3", "zipWith", "zipWith3");
230 startState: function () { return { f: normal }; },
231 copyState: function (s) { return { f: s.f }; },
233 token: function(stream, state) {
234 var t = state.f(stream, function(s) { state.f = s; });
235 var w = stream.current();
236 return (w in wellKnownWords) ? wellKnownWords[w] : t;
239 blockCommentStart: "{-",
240 blockCommentEnd: "-}",
246 CodeMirror.defineMIME("text/x-haskell", "haskell");