move a few things away in to-be-integrated/
[myslice.git] / to-be-integrated / third-party / codemirror-3.15 / mode / rust / rust.js
1 CodeMirror.defineMode("rust", function() {
2   var indentUnit = 4, altIndentUnit = 2;
3   var valKeywords = {
4     "if": "if-style", "while": "if-style", "else": "else-style",
5     "do": "else-style", "ret": "else-style", "fail": "else-style",
6     "break": "atom", "cont": "atom", "const": "let", "resource": "fn",
7     "let": "let", "fn": "fn", "for": "for", "alt": "alt", "iface": "iface",
8     "impl": "impl", "type": "type", "enum": "enum", "mod": "mod",
9     "as": "op", "true": "atom", "false": "atom", "assert": "op", "check": "op",
10     "claim": "op", "native": "ignore", "unsafe": "ignore", "import": "else-style",
11     "export": "else-style", "copy": "op", "log": "op", "log_err": "op",
12     "use": "op", "bind": "op", "self": "atom"
13   };
14   var typeKeywords = function() {
15     var keywords = {"fn": "fn", "block": "fn", "obj": "obj"};
16     var atoms = "bool uint int i8 i16 i32 i64 u8 u16 u32 u64 float f32 f64 str char".split(" ");
17     for (var i = 0, e = atoms.length; i < e; ++i) keywords[atoms[i]] = "atom";
18     return keywords;
19   }();
20   var operatorChar = /[+\-*&%=<>!?|\.@]/;
21
22   // Tokenizer
23
24   // Used as scratch variable to communicate multiple values without
25   // consing up tons of objects.
26   var tcat, content;
27   function r(tc, style) {
28     tcat = tc;
29     return style;
30   }
31
32   function tokenBase(stream, state) {
33     var ch = stream.next();
34     if (ch == '"') {
35       state.tokenize = tokenString;
36       return state.tokenize(stream, state);
37     }
38     if (ch == "'") {
39       tcat = "atom";
40       if (stream.eat("\\")) {
41         if (stream.skipTo("'")) { stream.next(); return "string"; }
42         else { return "error"; }
43       } else {
44         stream.next();
45         return stream.eat("'") ? "string" : "error";
46       }
47     }
48     if (ch == "/") {
49       if (stream.eat("/")) { stream.skipToEnd(); return "comment"; }
50       if (stream.eat("*")) {
51         state.tokenize = tokenComment(1);
52         return state.tokenize(stream, state);
53       }
54     }
55     if (ch == "#") {
56       if (stream.eat("[")) { tcat = "open-attr"; return null; }
57       stream.eatWhile(/\w/);
58       return r("macro", "meta");
59     }
60     if (ch == ":" && stream.match(":<")) {
61       return r("op", null);
62     }
63     if (ch.match(/\d/) || (ch == "." && stream.eat(/\d/))) {
64       var flp = false;
65       if (!stream.match(/^x[\da-f]+/i) && !stream.match(/^b[01]+/)) {
66         stream.eatWhile(/\d/);
67         if (stream.eat(".")) { flp = true; stream.eatWhile(/\d/); }
68         if (stream.match(/^e[+\-]?\d+/i)) { flp = true; }
69       }
70       if (flp) stream.match(/^f(?:32|64)/);
71       else stream.match(/^[ui](?:8|16|32|64)/);
72       return r("atom", "number");
73     }
74     if (ch.match(/[()\[\]{}:;,]/)) return r(ch, null);
75     if (ch == "-" && stream.eat(">")) return r("->", null);
76     if (ch.match(operatorChar)) {
77       stream.eatWhile(operatorChar);
78       return r("op", null);
79     }
80     stream.eatWhile(/\w/);
81     content = stream.current();
82     if (stream.match(/^::\w/)) {
83       stream.backUp(1);
84       return r("prefix", "variable-2");
85     }
86     if (state.keywords.propertyIsEnumerable(content))
87       return r(state.keywords[content], content.match(/true|false/) ? "atom" : "keyword");
88     return r("name", "variable");
89   }
90
91   function tokenString(stream, state) {
92     var ch, escaped = false;
93     while (ch = stream.next()) {
94       if (ch == '"' && !escaped) {
95         state.tokenize = tokenBase;
96         return r("atom", "string");
97       }
98       escaped = !escaped && ch == "\\";
99     }
100     // Hack to not confuse the parser when a string is split in
101     // pieces.
102     return r("op", "string");
103   }
104
105   function tokenComment(depth) {
106     return function(stream, state) {
107       var lastCh = null, ch;
108       while (ch = stream.next()) {
109         if (ch == "/" && lastCh == "*") {
110           if (depth == 1) {
111             state.tokenize = tokenBase;
112             break;
113           } else {
114             state.tokenize = tokenComment(depth - 1);
115             return state.tokenize(stream, state);
116           }
117         }
118         if (ch == "*" && lastCh == "/") {
119           state.tokenize = tokenComment(depth + 1);
120           return state.tokenize(stream, state);
121         }
122         lastCh = ch;
123       }
124       return "comment";
125     };
126   }
127
128   // Parser
129
130   var cx = {state: null, stream: null, marked: null, cc: null};
131   function pass() {
132     for (var i = arguments.length - 1; i >= 0; i--) cx.cc.push(arguments[i]);
133   }
134   function cont() {
135     pass.apply(null, arguments);
136     return true;
137   }
138
139   function pushlex(type, info) {
140     var result = function() {
141       var state = cx.state;
142       state.lexical = {indented: state.indented, column: cx.stream.column(),
143                        type: type, prev: state.lexical, info: info};
144     };
145     result.lex = true;
146     return result;
147   }
148   function poplex() {
149     var state = cx.state;
150     if (state.lexical.prev) {
151       if (state.lexical.type == ")")
152         state.indented = state.lexical.indented;
153       state.lexical = state.lexical.prev;
154     }
155   }
156   function typecx() { cx.state.keywords = typeKeywords; }
157   function valcx() { cx.state.keywords = valKeywords; }
158   poplex.lex = typecx.lex = valcx.lex = true;
159
160   function commasep(comb, end) {
161     function more(type) {
162       if (type == ",") return cont(comb, more);
163       if (type == end) return cont();
164       return cont(more);
165     }
166     return function(type) {
167       if (type == end) return cont();
168       return pass(comb, more);
169     };
170   }
171
172   function stat_of(comb, tag) {
173     return cont(pushlex("stat", tag), comb, poplex, block);
174   }
175   function block(type) {
176     if (type == "}") return cont();
177     if (type == "let") return stat_of(letdef1, "let");
178     if (type == "fn") return stat_of(fndef);
179     if (type == "type") return cont(pushlex("stat"), tydef, endstatement, poplex, block);
180     if (type == "enum") return stat_of(enumdef);
181     if (type == "mod") return stat_of(mod);
182     if (type == "iface") return stat_of(iface);
183     if (type == "impl") return stat_of(impl);
184     if (type == "open-attr") return cont(pushlex("]"), commasep(expression, "]"), poplex);
185     if (type == "ignore" || type.match(/[\]\);,]/)) return cont(block);
186     return pass(pushlex("stat"), expression, poplex, endstatement, block);
187   }
188   function endstatement(type) {
189     if (type == ";") return cont();
190     return pass();
191   }
192   function expression(type) {
193     if (type == "atom" || type == "name") return cont(maybeop);
194     if (type == "{") return cont(pushlex("}"), exprbrace, poplex);
195     if (type.match(/[\[\(]/)) return matchBrackets(type, expression);
196     if (type.match(/[\]\)\};,]/)) return pass();
197     if (type == "if-style") return cont(expression, expression);
198     if (type == "else-style" || type == "op") return cont(expression);
199     if (type == "for") return cont(pattern, maybetype, inop, expression, expression);
200     if (type == "alt") return cont(expression, altbody);
201     if (type == "fn") return cont(fndef);
202     if (type == "macro") return cont(macro);
203     return cont();
204   }
205   function maybeop(type) {
206     if (content == ".") return cont(maybeprop);
207     if (content == "::<"){return cont(typarams, maybeop);}
208     if (type == "op" || content == ":") return cont(expression);
209     if (type == "(" || type == "[") return matchBrackets(type, expression);
210     return pass();
211   }
212   function maybeprop() {
213     if (content.match(/^\w+$/)) {cx.marked = "variable"; return cont(maybeop);}
214     return pass(expression);
215   }
216   function exprbrace(type) {
217     if (type == "op") {
218       if (content == "|") return cont(blockvars, poplex, pushlex("}", "block"), block);
219       if (content == "||") return cont(poplex, pushlex("}", "block"), block);
220     }
221     if (content == "mutable" || (content.match(/^\w+$/) && cx.stream.peek() == ":"
222                                  && !cx.stream.match("::", false)))
223       return pass(record_of(expression));
224     return pass(block);
225   }
226   function record_of(comb) {
227     function ro(type) {
228       if (content == "mutable" || content == "with") {cx.marked = "keyword"; return cont(ro);}
229       if (content.match(/^\w*$/)) {cx.marked = "variable"; return cont(ro);}
230       if (type == ":") return cont(comb, ro);
231       if (type == "}") return cont();
232       return cont(ro);
233     }
234     return ro;
235   }
236   function blockvars(type) {
237     if (type == "name") {cx.marked = "def"; return cont(blockvars);}
238     if (type == "op" && content == "|") return cont();
239     return cont(blockvars);
240   }
241
242   function letdef1(type) {
243     if (type.match(/[\]\)\};]/)) return cont();
244     if (content == "=") return cont(expression, letdef2);
245     if (type == ",") return cont(letdef1);
246     return pass(pattern, maybetype, letdef1);
247   }
248   function letdef2(type) {
249     if (type.match(/[\]\)\};,]/)) return pass(letdef1);
250     else return pass(expression, letdef2);
251   }
252   function maybetype(type) {
253     if (type == ":") return cont(typecx, rtype, valcx);
254     return pass();
255   }
256   function inop(type) {
257     if (type == "name" && content == "in") {cx.marked = "keyword"; return cont();}
258     return pass();
259   }
260   function fndef(type) {
261     if (content == "@" || content == "~") {cx.marked = "keyword"; return cont(fndef);}
262     if (type == "name") {cx.marked = "def"; return cont(fndef);}
263     if (content == "<") return cont(typarams, fndef);
264     if (type == "{") return pass(expression);
265     if (type == "(") return cont(pushlex(")"), commasep(argdef, ")"), poplex, fndef);
266     if (type == "->") return cont(typecx, rtype, valcx, fndef);
267     if (type == ";") return cont();
268     return cont(fndef);
269   }
270   function tydef(type) {
271     if (type == "name") {cx.marked = "def"; return cont(tydef);}
272     if (content == "<") return cont(typarams, tydef);
273     if (content == "=") return cont(typecx, rtype, valcx);
274     return cont(tydef);
275   }
276   function enumdef(type) {
277     if (type == "name") {cx.marked = "def"; return cont(enumdef);}
278     if (content == "<") return cont(typarams, enumdef);
279     if (content == "=") return cont(typecx, rtype, valcx, endstatement);
280     if (type == "{") return cont(pushlex("}"), typecx, enumblock, valcx, poplex);
281     return cont(enumdef);
282   }
283   function enumblock(type) {
284     if (type == "}") return cont();
285     if (type == "(") return cont(pushlex(")"), commasep(rtype, ")"), poplex, enumblock);
286     if (content.match(/^\w+$/)) cx.marked = "def";
287     return cont(enumblock);
288   }
289   function mod(type) {
290     if (type == "name") {cx.marked = "def"; return cont(mod);}
291     if (type == "{") return cont(pushlex("}"), block, poplex);
292     return pass();
293   }
294   function iface(type) {
295     if (type == "name") {cx.marked = "def"; return cont(iface);}
296     if (content == "<") return cont(typarams, iface);
297     if (type == "{") return cont(pushlex("}"), block, poplex);
298     return pass();
299   }
300   function impl(type) {
301     if (content == "<") return cont(typarams, impl);
302     if (content == "of" || content == "for") {cx.marked = "keyword"; return cont(rtype, impl);}
303     if (type == "name") {cx.marked = "def"; return cont(impl);}
304     if (type == "{") return cont(pushlex("}"), block, poplex);
305     return pass();
306   }
307   function typarams() {
308     if (content == ">") return cont();
309     if (content == ",") return cont(typarams);
310     if (content == ":") return cont(rtype, typarams);
311     return pass(rtype, typarams);
312   }
313   function argdef(type) {
314     if (type == "name") {cx.marked = "def"; return cont(argdef);}
315     if (type == ":") return cont(typecx, rtype, valcx);
316     return pass();
317   }
318   function rtype(type) {
319     if (type == "name") {cx.marked = "variable-3"; return cont(rtypemaybeparam); }
320     if (content == "mutable") {cx.marked = "keyword"; return cont(rtype);}
321     if (type == "atom") return cont(rtypemaybeparam);
322     if (type == "op" || type == "obj") return cont(rtype);
323     if (type == "fn") return cont(fntype);
324     if (type == "{") return cont(pushlex("{"), record_of(rtype), poplex);
325     return matchBrackets(type, rtype);
326   }
327   function rtypemaybeparam() {
328     if (content == "<") return cont(typarams);
329     return pass();
330   }
331   function fntype(type) {
332     if (type == "(") return cont(pushlex("("), commasep(rtype, ")"), poplex, fntype);
333     if (type == "->") return cont(rtype);
334     return pass();
335   }
336   function pattern(type) {
337     if (type == "name") {cx.marked = "def"; return cont(patternmaybeop);}
338     if (type == "atom") return cont(patternmaybeop);
339     if (type == "op") return cont(pattern);
340     if (type.match(/[\]\)\};,]/)) return pass();
341     return matchBrackets(type, pattern);
342   }
343   function patternmaybeop(type) {
344     if (type == "op" && content == ".") return cont();
345     if (content == "to") {cx.marked = "keyword"; return cont(pattern);}
346     else return pass();
347   }
348   function altbody(type) {
349     if (type == "{") return cont(pushlex("}", "alt"), altblock1, poplex);
350     return pass();
351   }
352   function altblock1(type) {
353     if (type == "}") return cont();
354     if (type == "|") return cont(altblock1);
355     if (content == "when") {cx.marked = "keyword"; return cont(expression, altblock2);}
356     if (type.match(/[\]\);,]/)) return cont(altblock1);
357     return pass(pattern, altblock2);
358   }
359   function altblock2(type) {
360     if (type == "{") return cont(pushlex("}", "alt"), block, poplex, altblock1);
361     else return pass(altblock1);
362   }
363
364   function macro(type) {
365     if (type.match(/[\[\(\{]/)) return matchBrackets(type, expression);
366     return pass();
367   }
368   function matchBrackets(type, comb) {
369     if (type == "[") return cont(pushlex("]"), commasep(comb, "]"), poplex);
370     if (type == "(") return cont(pushlex(")"), commasep(comb, ")"), poplex);
371     if (type == "{") return cont(pushlex("}"), commasep(comb, "}"), poplex);
372     return cont();
373   }
374
375   function parse(state, stream, style) {
376     var cc = state.cc;
377     // Communicate our context to the combinators.
378     // (Less wasteful than consing up a hundred closures on every call.)
379     cx.state = state; cx.stream = stream; cx.marked = null, cx.cc = cc;
380
381     while (true) {
382       var combinator = cc.length ? cc.pop() : block;
383       if (combinator(tcat)) {
384         while(cc.length && cc[cc.length - 1].lex)
385           cc.pop()();
386         return cx.marked || style;
387       }
388     }
389   }
390
391   return {
392     startState: function() {
393       return {
394         tokenize: tokenBase,
395         cc: [],
396         lexical: {indented: -indentUnit, column: 0, type: "top", align: false},
397         keywords: valKeywords,
398         indented: 0
399       };
400     },
401
402     token: function(stream, state) {
403       if (stream.sol()) {
404         if (!state.lexical.hasOwnProperty("align"))
405           state.lexical.align = false;
406         state.indented = stream.indentation();
407       }
408       if (stream.eatSpace()) return null;
409       tcat = content = null;
410       var style = state.tokenize(stream, state);
411       if (style == "comment") return style;
412       if (!state.lexical.hasOwnProperty("align"))
413         state.lexical.align = true;
414       if (tcat == "prefix") return style;
415       if (!content) content = stream.current();
416       return parse(state, stream, style);
417     },
418
419     indent: function(state, textAfter) {
420       if (state.tokenize != tokenBase) return 0;
421       var firstChar = textAfter && textAfter.charAt(0), lexical = state.lexical,
422           type = lexical.type, closing = firstChar == type;
423       if (type == "stat") return lexical.indented + indentUnit;
424       if (lexical.align) return lexical.column + (closing ? 0 : 1);
425       return lexical.indented + (closing ? 0 : (lexical.info == "alt" ? altIndentUnit : indentUnit));
426     },
427
428     electricChars: "{}",
429     blockCommentStart: "/*",
430     blockCommentEnd: "*/",
431     lineComment: "//",
432     fold: "brace"
433   };
434 });
435
436 CodeMirror.defineMIME("text/x-rustsrc", "rust");