aboutsummaryrefslogtreecommitdiff
path: root/js/codemirror/mode/python/python.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/codemirror/mode/python/python.js')
-rw-r--r--js/codemirror/mode/python/python.js321
1 files changed, 321 insertions, 0 deletions
diff --git a/js/codemirror/mode/python/python.js b/js/codemirror/mode/python/python.js
new file mode 100644
index 00000000..baeec03c
--- /dev/null
+++ b/js/codemirror/mode/python/python.js
@@ -0,0 +1,321 @@
1CodeMirror.defineMode("python", function(conf) {
2 var ERRORCLASS = 'error';
3
4 function wordRegexp(words) {
5 return new RegExp("^((" + words.join(")|(") + "))\\b");
6 }
7
8 var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
9 var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
10 var doubleOperators = new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
11 var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
12 var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
13 var 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 commontypes = ['bool', 'classmethod', 'complex', 'dict', 'enumerate',
22 'float', 'frozenset', 'int', 'list', 'object',
23 'property', 'reversed', 'set', 'slice', 'staticmethod',
24 'str', 'super', 'tuple', 'type'];
25 var py2 = {'types': ['basestring', 'buffer', 'file', 'long', 'unicode',
26 'xrange'],
27 'keywords': ['exec', 'print']};
28 var py3 = {'types': ['bytearray', 'bytes', 'filter', 'map', 'memoryview',
29 'open', 'range', 'zip'],
30 'keywords': ['nonlocal']};
31
32 if (!!conf.mode.version && parseInt(conf.mode.version, 10) === 3) {
33 commonkeywords = commonkeywords.concat(py3.keywords);
34 commontypes = commontypes.concat(py3.types);
35 var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i");
36 } else {
37 commonkeywords = commonkeywords.concat(py2.keywords);
38 commontypes = commontypes.concat(py2.types);
39 var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i");
40 }
41 var keywords = wordRegexp(commonkeywords);
42 var types = wordRegexp(commontypes);
43
44 var indentInfo = null;
45
46 // tokenizers
47 function tokenBase(stream, state) {
48 // Handle scope changes
49 if (stream.sol()) {
50 var scopeOffset = state.scopes[0].offset;
51 if (stream.eatSpace()) {
52 var lineOffset = stream.indentation();
53 if (lineOffset > scopeOffset) {
54 indentInfo = 'indent';
55 } else if (lineOffset < scopeOffset) {
56 indentInfo = 'dedent';
57 }
58 return null;
59 } else {
60 if (scopeOffset > 0) {
61 dedent(stream, state);
62 }
63 }
64 }
65 if (stream.eatSpace()) {
66 return null;
67 }
68
69 var ch = stream.peek();
70
71 // Handle Comments
72 if (ch === '#') {
73 stream.skipToEnd();
74 return 'comment';
75 }
76
77 // Handle Number Literals
78 if (stream.match(/^[0-9\.]/, false)) {
79 var floatLiteral = false;
80 // Floats
81 if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; }
82 if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; }
83 if (stream.match(/^\.\d+/)) { floatLiteral = true; }
84 if (floatLiteral) {
85 // Float literals may be "imaginary"
86 stream.eat(/J/i);
87 return 'number';
88 }
89 // Integers
90 var intLiteral = false;
91 // Hex
92 if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; }
93 // Binary
94 if (stream.match(/^0b[01]+/i)) { intLiteral = true; }
95 // Octal
96 if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; }
97 // Decimal
98 if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
99 // Decimal literals may be "imaginary"
100 stream.eat(/J/i);
101 // TODO - Can you have imaginary longs?
102 intLiteral = true;
103 }
104 // Zero by itself with no other piece of number.
105 if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
106 if (intLiteral) {
107 // Integer literals may be "long"
108 stream.eat(/L/i);
109 return 'number';
110 }
111 }
112
113 // Handle Strings
114 if (stream.match(stringPrefixes)) {
115 state.tokenize = tokenStringFactory(stream.current());
116 return state.tokenize(stream, state);
117 }
118
119 // Handle operators and Delimiters
120 if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
121 return null;
122 }
123 if (stream.match(doubleOperators)
124 || stream.match(singleOperators)
125 || stream.match(wordOperators)) {
126 return 'operator';
127 }
128 if (stream.match(singleDelimiters)) {
129 return null;
130 }
131
132 if (stream.match(types)) {
133 return 'builtin';
134 }
135
136 if (stream.match(keywords)) {
137 return 'keyword';
138 }
139
140 if (stream.match(identifiers)) {
141 return 'variable';
142 }
143
144 // Handle non-detected items
145 stream.next();
146 return ERRORCLASS;
147 }
148
149 function tokenStringFactory(delimiter) {
150 while ('rub'.indexOf(delimiter[0].toLowerCase()) >= 0) {
151 delimiter = delimiter.substr(1);
152 }
153 var delim_re = new RegExp(delimiter);
154 var singleline = delimiter.length == 1;
155 var OUTCLASS = 'string';
156
157 return function tokenString(stream, state) {
158 while (!stream.eol()) {
159 stream.eatWhile(/[^'"\\]/);
160 if (stream.eat('\\')) {
161 stream.next();
162 if (singleline && stream.eol()) {
163 return OUTCLASS;
164 }
165 } else if (stream.match(delim_re)) {
166 state.tokenize = tokenBase;
167 return OUTCLASS;
168 } else {
169 stream.eat(/['"]/);
170 }
171 }
172 if (singleline) {
173 if (conf.mode.singleLineStringErrors) {
174 OUTCLASS = ERRORCLASS
175 } else {
176 state.tokenize = tokenBase;
177 }
178 }
179 return OUTCLASS;
180 };
181 }
182
183 function indent(stream, state, type) {
184 type = type || 'py';
185 var indentUnit = 0;
186 if (type === 'py') {
187 for (var i = 0; i < state.scopes.length; ++i) {
188 if (state.scopes[i].type === 'py') {
189 indentUnit = state.scopes[i].offset + conf.indentUnit;
190 break;
191 }
192 }
193 } else {
194 indentUnit = stream.column() + stream.current().length;
195 }
196 state.scopes.unshift({
197 offset: indentUnit,
198 type: type
199 });
200 }
201
202 function dedent(stream, state) {
203 if (state.scopes.length == 1) return;
204 if (state.scopes[0].type === 'py') {
205 var _indent = stream.indentation();
206 var _indent_index = -1;
207 for (var i = 0; i < state.scopes.length; ++i) {
208 if (_indent === state.scopes[i].offset) {
209 _indent_index = i;
210 break;
211 }
212 }
213 if (_indent_index === -1) {
214 return true;
215 }
216 while (state.scopes[0].offset !== _indent) {
217 state.scopes.shift();
218 }
219 return false
220 } else {
221 state.scopes.shift();
222 return false;
223 }
224 }
225
226 function tokenLexer(stream, state) {
227 indentInfo = null;
228 var style = state.tokenize(stream, state);
229 var current = stream.current();
230
231 // Handle '.' connected identifiers