aboutsummaryrefslogtreecommitdiff
path: root/js/codemirror/mode/haskell
diff options
context:
space:
mode:
Diffstat (limited to 'js/codemirror/mode/haskell')
-rw-r--r--js/codemirror/mode/haskell/haskell.js242
-rw-r--r--js/codemirror/mode/haskell/index.html60
2 files changed, 302 insertions, 0 deletions
diff --git a/js/codemirror/mode/haskell/haskell.js b/js/codemirror/mode/haskell/haskell.js
new file mode 100644
index 00000000..aac50410
--- /dev/null
+++ b/js/codemirror/mode/haskell/haskell.js
@@ -0,0 +1,242 @@
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 = "comment";
28 if (source.eat('#')) {
29 t = "meta";
30 }
31 return switchState(source, setState, ncomment(t, 1));
32 }
33 return null;
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 "string";
45 }
46 return "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 "qualifier";
57 }
58 return "variable-2";
59 }
60
61 if (smallRE.test(ch)) {
62 source.eatWhile(idRE);
63 return "variable";
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 "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.eat('.')) {
80 t = "number";
81 source.eatWhile(digitRE); // should require at least 1
82 }
83 if (source.eat(/[eE]/)) {
84 t = "number";
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 "comment";
97 }
98 }
99 var t = "variable";
100 if (ch == ':') {
101 t = "variable-2";
102 }
103 source.eatWhile(symbolRE);
104 return t;
105 }
106
107 return "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 var 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 "string";
140 }
141 if (ch == '\\') {
142 if (source.eol() || source.eat(whiteCharRE)) {
143 setState(stringGap);
144 return "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 "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 "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("keyword")(
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("keyword")(
182 "\.\.", ":", "::", "=", "\\", "\"", "<-", "->", "@", "~", "=>");
183
184 setType("builtin")(
185 "!!", "$!", "$", "&&", "+", "++", "-", ".", "/", "/=", "<", "<=", "=<<",
186 "==", ">", ">=", ">>", ">>=", "^", "^^", "||", "*", "**");
187
188 setType("builtin")(
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("builtin")(
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) {
23