all repos — NoPaste @ edb00b0ab136a96023b51a3e1c59d21a807d66a2

Resurrected - The PussTheCat.org fork of NoPaste

scripts/CodeMirror/mode/haskell/haskell.js (view raw)

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