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