move a few things away in to-be-integrated/
[myslice.git] / to-be-integrated / third-party / codemirror-3.15 / mode / groovy / groovy.js
1 CodeMirror.defineMode("groovy", function(config) {
2   function words(str) {
3     var obj = {}, words = str.split(" ");
4     for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
5     return obj;
6   }
7   var keywords = words(
8     "abstract as assert boolean break byte case catch char class const continue def default " +
9     "do double else enum extends final finally float for goto if implements import in " +
10     "instanceof int interface long native new package private protected public return " +
11     "short static strictfp super switch synchronized threadsafe throw throws transient " +
12     "try void volatile while");
13   var blockKeywords = words("catch class do else finally for if switch try while enum interface def");
14   var atoms = words("null true false this");
15
16   var curPunc;
17   function tokenBase(stream, state) {
18     var ch = stream.next();
19     if (ch == '"' || ch == "'") {
20       return startString(ch, stream, state);
21     }
22     if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
23       curPunc = ch;
24       return null;
25     }
26     if (/\d/.test(ch)) {
27       stream.eatWhile(/[\w\.]/);
28       if (stream.eat(/eE/)) { stream.eat(/\+\-/); stream.eatWhile(/\d/); }
29       return "number";
30     }
31     if (ch == "/") {
32       if (stream.eat("*")) {
33         state.tokenize.push(tokenComment);
34         return tokenComment(stream, state);
35       }
36       if (stream.eat("/")) {
37         stream.skipToEnd();
38         return "comment";
39       }
40       if (expectExpression(state.lastToken)) {
41         return startString(ch, stream, state);
42       }
43     }
44     if (ch == "-" && stream.eat(">")) {
45       curPunc = "->";
46       return null;
47     }
48     if (/[+\-*&%=<>!?|\/~]/.test(ch)) {
49       stream.eatWhile(/[+\-*&%=<>|~]/);
50       return "operator";
51     }
52     stream.eatWhile(/[\w\$_]/);
53     if (ch == "@") { stream.eatWhile(/[\w\$_\.]/); return "meta"; }
54     if (state.lastToken == ".") return "property";
55     if (stream.eat(":")) { curPunc = "proplabel"; return "property"; }
56     var cur = stream.current();
57     if (atoms.propertyIsEnumerable(cur)) { return "atom"; }
58     if (keywords.propertyIsEnumerable(cur)) {
59       if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
60       return "keyword";
61     }
62     return "variable";
63   }
64   tokenBase.isBase = true;
65
66   function startString(quote, stream, state) {
67     var tripleQuoted = false;
68     if (quote != "/" && stream.eat(quote)) {
69       if (stream.eat(quote)) tripleQuoted = true;
70       else return "string";
71     }
72     function t(stream, state) {
73       var escaped = false, next, end = !tripleQuoted;
74       while ((next = stream.next()) != null) {
75         if (next == quote && !escaped) {
76           if (!tripleQuoted) { break; }
77           if (stream.match(quote + quote)) { end = true; break; }
78         }
79         if (quote == '"' && next == "$" && !escaped && stream.eat("{")) {
80           state.tokenize.push(tokenBaseUntilBrace());
81           return "string";
82         }
83         escaped = !escaped && next == "\\";
84       }
85       if (end) state.tokenize.pop();
86       return "string";
87     }
88     state.tokenize.push(t);
89     return t(stream, state);
90   }
91
92   function tokenBaseUntilBrace() {
93     var depth = 1;
94     function t(stream, state) {
95       if (stream.peek() == "}") {
96         depth--;
97         if (depth == 0) {
98           state.tokenize.pop();
99           return state.tokenize[state.tokenize.length-1](stream, state);
100         }
101       } else if (stream.peek() == "{") {
102         depth++;
103       }
104       return tokenBase(stream, state);
105     }
106     t.isBase = true;
107     return t;
108   }
109
110   function tokenComment(stream, state) {
111     var maybeEnd = false, ch;
112     while (ch = stream.next()) {
113       if (ch == "/" && maybeEnd) {
114         state.tokenize.pop();
115         break;
116       }
117       maybeEnd = (ch == "*");
118     }
119     return "comment";
120   }
121
122   function expectExpression(last) {
123     return !last || last == "operator" || last == "->" || /[\.\[\{\(,;:]/.test(last) ||
124       last == "newstatement" || last == "keyword" || last == "proplabel";
125   }
126
127   function Context(indented, column, type, align, prev) {
128     this.indented = indented;
129     this.column = column;
130     this.type = type;
131     this.align = align;
132     this.prev = prev;
133   }
134   function pushContext(state, col, type) {
135     return state.context = new Context(state.indented, col, type, null, state.context);
136   }
137   function popContext(state) {
138     var t = state.context.type;
139     if (t == ")" || t == "]" || t == "}")
140       state.indented = state.context.indented;
141     return state.context = state.context.prev;
142   }
143
144   // Interface
145
146   return {
147     startState: function(basecolumn) {
148       return {
149         tokenize: [tokenBase],
150         context: new Context((basecolumn || 0) - config.indentUnit, 0, "top", false),
151         indented: 0,
152         startOfLine: true,
153         lastToken: null
154       };
155     },
156
157     token: function(stream, state) {
158       var ctx = state.context;
159       if (stream.sol()) {
160         if (ctx.align == null) ctx.align = false;
161         state.indented = stream.indentation();
162         state.startOfLine = true;
163         // Automatic semicolon insertion
164         if (ctx.type == "statement" && !expectExpression(state.lastToken)) {
165           popContext(state); ctx = state.context;
166         }
167       }
168       if (stream.eatSpace()) return null;
169       curPunc = null;
170       var style = state.tokenize[state.tokenize.length-1](stream, state);
171       if (style == "comment") return style;
172       if (ctx.align == null) ctx.align = true;
173
174       if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state);
175       // Handle indentation for {x -> \n ... }
176       else if (curPunc == "->" && ctx.type == "statement" && ctx.prev.type == "}") {
177         popContext(state);
178         state.context.align = false;
179       }
180       else if (curPunc == "{") pushContext(state, stream.column(), "}");
181       else if (curPunc == "[") pushContext(state, stream.column(), "]");
182       else if (curPunc == "(") pushContext(state, stream.column(), ")");
183       else if (curPunc == "}") {
184         while (ctx.type == "statement") ctx = popContext(state);
185         if (ctx.type == "}") ctx = popContext(state);
186         while (ctx.type == "statement") ctx = popContext(state);
187       }
188       else if (curPunc == ctx.type) popContext(state);
189       else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement"))
190         pushContext(state, stream.column(), "statement");
191       state.startOfLine = false;
192       state.lastToken = curPunc || style;
193       return style;
194     },
195
196     indent: function(state, textAfter) {
197       if (!state.tokenize[state.tokenize.length-1].isBase) return 0;
198       var firstChar = textAfter && textAfter.charAt(0), ctx = state.context;
199       if (ctx.type == "statement" && !expectExpression(state.lastToken)) ctx = ctx.prev;
200       var closing = firstChar == ctx.type;
201       if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : config.indentUnit);
202       else if (ctx.align) return ctx.column + (closing ? 0 : 1);
203       else return ctx.indented + (closing ? 0 : config.indentUnit);
204     },
205
206     electricChars: "{}",
207     fold: "brace"
208   };
209 });
210
211 CodeMirror.defineMIME("text/x-groovy", "groovy");