source: branches/2.2/plugins/LocalFilesEditor/codemirror/mode/haskell/haskell.js @ 10310

Last change on this file since 10310 was 10310, checked in by patdenice, 13 years ago

merge r10307 from trunk to branch 2.2
feature:2262
Replace editarea by Codemirror:
http://codemirror.net

File size: 7.4 KB
Line 
1CodeMirror.defineMode("haskell", function(cmCfg, modeCfg) {
2
3  function switchState(source, setState, f) {
4    setState(f);
5    return f(source, setState);
6  }
7 
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
18   
19  function normal(source, setState) {
20    if (source.eatWhile(whiteCharRE)) {
21      return null;
22    }
23     
24    var ch = source.next();
25    if (specialRE.test(ch)) {
26      if (ch == '{' && source.eat('-')) {
27        var t = "hs-comment";
28        if (source.eat('#')) {
29          t = "hs-pragma";
30        }
31        return switchState(source, setState, ncomment(t, 1));
32      }
33      return "hs-special";
34    }
35   
36    if (ch == '\'') {
37      if (source.eat('\\')) {
38        source.next();  // should handle other escapes here
39      }
40      else {
41        source.next();
42      }
43      if (source.eat('\'')) {
44        return "hs-char";
45      }
46      return "hs-error";
47    }
48   
49    if (ch == '"') {
50      return switchState(source, setState, stringLiteral);
51    }
52     
53    if (largeRE.test(ch)) {
54      source.eatWhile(idRE);
55      if (source.eat('.')) {
56        return "hs-qualifier";
57      }
58      return "hs-conid";
59    }
60     
61    if (smallRE.test(ch)) {
62      source.eatWhile(idRE);
63      return "hs-varid";
64    }
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 "hs-integer";
71        }
72        if (source.eat(/[oO]/)) {
73          source.eatWhile(octitRE); // should require at least 1
74          return "hs-integer";
75        }
76      }
77      source.eatWhile(digitRE);
78      var t = "hs-integer";
79      if (source.eat('.')) {
80        t = "hs-float";
81        source.eatWhile(digitRE); // should require at least 1
82      }
83      if (source.eat(/[eE]/)) {
84        t = "hs-float";
85        source.eat(/[-+]/);
86        source.eatWhile(digitRE); // should require at least 1
87      }
88      return t;
89    }
90     
91    if (symbolRE.test(ch)) {
92      if (ch == '-' && source.eat(/-/)) {
93        source.eatWhile(/-/);
94        if (!source.eat(symbolRE)) {
95          source.skipToEnd();
96          return "hs-comment";
97        }
98      }
99      var t = "hs-varsym";
100      if (ch == ':') {
101        t = "hs-consym";
102      }
103      source.eatWhile(symbolRE);
104      return t;   
105    }
106     
107    return "hs-error";
108  }
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        ch = source.next();
118        if (ch == '{' && source.eat('-')) {
119          ++currNest;
120        }
121        else if (ch == '-' && source.eat('}')) {
122          --currNest;
123          if (currNest == 0) {
124            setState(normal);
125            return type;
126          }
127        }
128      }
129      setState(ncomment(type, currNest));
130      return type;
131    }
132  }
133   
134  function stringLiteral(source, setState) {
135    while (!source.eol()) {
136      var ch = source.next();
137      if (ch == '"') {
138        setState(normal);
139        return "hs-string";
140      }
141      if (ch == '\\') {
142        if (source.eol() || source.eat(whiteCharRE)) {
143          setState(stringGap);
144          return "hs-string";
145        }
146        if (source.eat('&')) {
147        }
148        else {
149          source.next(); // should handle other escapes here
150        }
151      }
152    }
153    setState(normal);
154    return "hs-error";
155  }
156 
157  function stringGap(source, setState) {
158    if (source.eat('\\')) {
159      return switchState(source, setState, stringLiteral);
160    }
161    source.next();
162    setState(normal);
163    return "hs-error";
164  }
165 
166 
167  var wellKnownWords = (function() {
168    var wkw = {};
169    function setType(t) {
170      return function () {
171        for (var i = 0; i < arguments.length; i++)
172          wkw[arguments[i]] = t;
173      }
174    }
175   
176    setType("hs-reservedid")(
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", "_");
180     
181    setType("hs-reservedop")(
182      "\.\.", ":", "::", "=", "\\", "\"", "<-", "->", "@", "~", "=>");
183     
184    setType("hs-prelude-varsym")(
185      "!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<=", "=<<",
186      "==", ">", ">=", ">>", ">>=", "^", "^^", "||", "*", "**");
187     
188    setType("hs-prelude-conid")(
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",
194      "String", "True");
195     
196    setType("hs-prelude-varid")(
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");
223     
224    return wkw;
225  })();
226   
227 
228 
229  return {
230    startState: function ()  { return { f: normal }; },
231    copyState:  function (s) { return { f: s.f }; },
232   
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;
237    }
238  };
239
240});
241
242CodeMirror.defineMIME("text/x-haskell", "haskell");
Note: See TracBrowser for help on using the repository browser.