Fix: merge conflict
[myslice.git] / third-party / codemirror-3.15 / mode / python / python.js
1 CodeMirror.defineMode("python", function(conf, parserConf) {
2     var ERRORCLASS = 'error';
3
4     function wordRegexp(words) {
5         return new RegExp("^((" + words.join(")|(") + "))\\b");
6     }
7
8     var singleOperators = parserConf.singleOperators || new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
9     var singleDelimiters = parserConf.singleDelimiters || new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
10     var doubleOperators = parserConf.doubleOperators || new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
11     var doubleDelimiters = parserConf.doubleDelimiters || new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
12     var tripleDelimiters = parserConf.tripleDelimiters || new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
13     var identifiers = parserConf.identifiers|| new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
14
15     var wordOperators = wordRegexp(['and', 'or', 'not', 'is', 'in']);
16     var commonkeywords = ['as', 'assert', 'break', 'class', 'continue',
17                           'def', 'del', 'elif', 'else', 'except', 'finally',
18                           'for', 'from', 'global', 'if', 'import',
19                           'lambda', 'pass', 'raise', 'return',
20                           'try', 'while', 'with', 'yield'];
21     var commonBuiltins = ['abs', 'all', 'any', 'bin', 'bool', 'bytearray', 'callable', 'chr',
22                           'classmethod', 'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod',
23                           'enumerate', 'eval', 'filter', 'float', 'format', 'frozenset',
24                           'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id',
25                           'input', 'int', 'isinstance', 'issubclass', 'iter', 'len',
26                           'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next',
27                           'object', 'oct', 'open', 'ord', 'pow', 'property', 'range',
28                           'repr', 'reversed', 'round', 'set', 'setattr', 'slice',
29                           'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple',
30                           'type', 'vars', 'zip', '__import__', 'NotImplemented',
31                           'Ellipsis', '__debug__'];
32     var py2 = {'builtins': ['apply', 'basestring', 'buffer', 'cmp', 'coerce', 'execfile',
33                             'file', 'intern', 'long', 'raw_input', 'reduce', 'reload',
34                             'unichr', 'unicode', 'xrange', 'False', 'True', 'None'],
35                'keywords': ['exec', 'print']};
36     var py3 = {'builtins': ['ascii', 'bytes', 'exec', 'print'],
37                'keywords': ['nonlocal', 'False', 'True', 'None']};
38
39     if(parserConf.extra_keywords != undefined){
40         commonkeywords = commonkeywords.concat(parserConf.extra_keywords);
41     }
42     if(parserConf.extra_builtins != undefined){
43         commonBuiltins = commonBuiltins.concat(parserConf.extra_builtins);
44     }
45     if (!!parserConf.version && parseInt(parserConf.version, 10) === 3) {
46         commonkeywords = commonkeywords.concat(py3.keywords);
47         commonBuiltins = commonBuiltins.concat(py3.builtins);
48         var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i");
49     } else {
50         commonkeywords = commonkeywords.concat(py2.keywords);
51         commonBuiltins = commonBuiltins.concat(py2.builtins);
52         var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i");
53     }
54     var keywords = wordRegexp(commonkeywords);
55     var builtins = wordRegexp(commonBuiltins);
56
57     var indentInfo = null;
58
59     // tokenizers
60     function tokenBase(stream, state) {
61         // Handle scope changes
62         if (stream.sol()) {
63             var scopeOffset = state.scopes[0].offset;
64             if (stream.eatSpace()) {
65                 var lineOffset = stream.indentation();
66                 if (lineOffset > scopeOffset) {
67                     indentInfo = 'indent';
68                 } else if (lineOffset < scopeOffset) {
69                     indentInfo = 'dedent';
70                 }
71                 return null;
72             } else {
73                 if (scopeOffset > 0) {
74                     dedent(stream, state);
75                 }
76             }
77         }
78         if (stream.eatSpace()) {
79             return null;
80         }
81
82         var ch = stream.peek();
83
84         // Handle Comments
85         if (ch === '#') {
86             stream.skipToEnd();
87             return 'comment';
88         }
89
90         // Handle Number Literals
91         if (stream.match(/^[0-9\.]/, false)) {
92             var floatLiteral = false;
93             // Floats
94             if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; }
95             if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; }
96             if (stream.match(/^\.\d+/)) { floatLiteral = true; }
97             if (floatLiteral) {
98                 // Float literals may be "imaginary"
99                 stream.eat(/J/i);
100                 return 'number';
101             }
102             // Integers
103             var intLiteral = false;
104             // Hex
105             if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; }
106             // Binary
107             if (stream.match(/^0b[01]+/i)) { intLiteral = true; }
108             // Octal
109             if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; }
110             // Decimal
111             if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
112                 // Decimal literals may be "imaginary"
113                 stream.eat(/J/i);
114                 // TODO - Can you have imaginary longs?
115                 intLiteral = true;
116             }
117             // Zero by itself with no other piece of number.
118             if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
119             if (intLiteral) {
120                 // Integer literals may be "long"
121                 stream.eat(/L/i);
122                 return 'number';
123             }
124         }
125
126         // Handle Strings
127         if (stream.match(stringPrefixes)) {
128             state.tokenize = tokenStringFactory(stream.current());
129             return state.tokenize(stream, state);
130         }
131
132         // Handle operators and Delimiters
133         if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
134             return null;
135         }
136         if (stream.match(doubleOperators)
137             || stream.match(singleOperators)
138             || stream.match(wordOperators)) {
139             return 'operator';
140         }
141         if (stream.match(singleDelimiters)) {
142             return null;
143         }
144
145         if (stream.match(keywords)) {
146             return 'keyword';
147         }
148
149         if (stream.match(builtins)) {
150             return 'builtin';
151         }
152
153         if (stream.match(identifiers)) {
154             return 'variable';
155         }
156
157         // Handle non-detected items
158         stream.next();
159         return ERRORCLASS;
160     }
161
162     function tokenStringFactory(delimiter) {
163         while ('rub'.indexOf(delimiter.charAt(0).toLowerCase()) >= 0) {
164             delimiter = delimiter.substr(1);
165         }
166         var singleline = delimiter.length == 1;
167         var OUTCLASS = 'string';
168
169         function tokenString(stream, state) {
170             while (!stream.eol()) {
171                 stream.eatWhile(/[^'"\\]/);
172                 if (stream.eat('\\')) {
173                     stream.next();
174                     if (singleline && stream.eol()) {
175                         return OUTCLASS;
176                     }
177                 } else if (stream.match(delimiter)) {
178                     state.tokenize = tokenBase;
179                     return OUTCLASS;
180                 } else {
181                     stream.eat(/['"]/);
182                 }
183             }
184             if (singleline) {
185                 if (parserConf.singleLineStringErrors) {
186                     return ERRORCLASS;
187                 } else {
188                     state.tokenize = tokenBase;
189                 }
190             }
191             return OUTCLASS;
192         }
193         tokenString.isString = true;
194         return tokenString;
195     }
196
197     function indent(stream, state, type) {
198         type = type || 'py';
199         var indentUnit = 0;
200         if (type === 'py') {
201             if (state.scopes[0].type !== 'py') {
202                 state.scopes[0].offset = stream.indentation();
203                 return;
204             }
205             for (var i = 0; i < state.scopes.length; ++i) {
206                 if (state.scopes[i].type === 'py') {
207                     indentUnit = state.scopes[i].offset + conf.indentUnit;
208                     break;
209                 }
210             }
211         } else {
212             indentUnit = stream.column() + stream.current().length;
213         }
214         state.scopes.unshift({
215             offset: indentUnit,
216             type: type
217         });
218     }
219
220     function dedent(stream, state, type) {
221         type = type || 'py';
222         if (state.scopes.length == 1) return;
223         if (state.scopes[0].type === 'py') {
224             var _indent = stream.indentation();
225             var _indent_index = -1;
226             for (var i = 0; i < state.scopes.length; ++i) {
227                 if (_indent === state.scopes[i].offset) {
228                     _indent_index = i;
229                     break;
230                 }
231             }
232             if (_indent_index === -1) {
233                 return true;
234             }
235             while (state.scopes[0].offset !== _indent) {
236                 state.scopes.shift();
237             }
238             return false;
239         } else {
240             if (type === 'py') {
241                 state.scopes[0].offset = stream.indentation();
242                 return false;
243             } else {
244                 if (state.scopes[0].type != type) {
245                     return true;
246                 }
247                 state.scopes.shift();
248                 return false;
249             }
250         }
251     }
252
253     function tokenLexer(stream, state) {
254         indentInfo = null;
255         var style = state.tokenize(stream, state);
256         var current = stream.current();
257
258         // Handle '.' connected identifiers
259         if (current === '.') {
260             style = stream.match(identifiers, false) ? null : ERRORCLASS;
261             if (style === null && state.lastToken === 'meta') {
262                 // Apply 'meta' style to '.' connected identifiers when
263                 // appropriate.
264                 style = 'meta';
265             }
266             return style;
267         }
268
269         // Handle decorators
270         if (current === '@') {
271             return stream.match(identifiers, false) ? 'meta' : ERRORCLASS;
272         }
273
274         if ((style === 'variable' || style === 'builtin')
275             && state.lastToken === 'meta') {
276             style = 'meta';
277         }
278
279         // Handle scope changes.
280         if (current === 'pass' || current === 'return') {
281             state.dedent += 1;
282         }
283         if (current === 'lambda') state.lambda = true;
284         if ((current === ':' && !state.lambda && state.scopes[0].type == 'py')
285             || indentInfo === 'indent') {
286             indent(stream, state);
287         }
288         var delimiter_index = '[({'.indexOf(current);
289         if (delimiter_index !== -1) {
290             indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1));
291         }
292         if (indentInfo === 'dedent') {
293             if (dedent(stream, state)) {
294                 return ERRORCLASS;
295             }
296         }
297         delimiter_index = '])}'.indexOf(current);
298         if (delimiter_index !== -1) {
299             if (dedent(stream, state, current)) {
300                 return ERRORCLASS;
301             }
302         }
303         if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'py') {
304             if (state.scopes.length > 1) state.scopes.shift();
305             state.dedent -= 1;
306         }
307
308         return style;
309     }
310
311     var external = {
312         startState: function(basecolumn) {
313             return {
314               tokenize: tokenBase,
315               scopes: [{offset:basecolumn || 0, type:'py'}],
316               lastToken: null,
317               lambda: false,
318               dedent: 0
319           };
320         },
321
322         token: function(stream, state) {
323             var style = tokenLexer(stream, state);
324
325             state.lastToken = style;
326
327             if (stream.eol() && state.lambda) {
328                 state.lambda = false;
329             }
330
331             return style;
332         },
333
334         indent: function(state) {
335             if (state.tokenize != tokenBase) {
336                 return state.tokenize.isString ? CodeMirror.Pass : 0;
337             }
338
339             return state.scopes[0].offset;
340         },
341
342         lineComment: "#",
343         fold: "indent"
344     };
345     return external;
346 });
347
348 CodeMirror.defineMIME("text/x-python", "python");
349
350 var words = function(str){return str.split(' ');};
351
352
353 CodeMirror.defineMIME("text/x-cython", {
354   name: "python",
355   extra_keywords: words("by cdef cimport cpdef ctypedef enum except"+
356                         "extern gil include nogil property public"+
357                         "readonly struct union DEF IF ELIF ELSE")
358 });