Showing the changes to lib/vimfiles/autoload/pythoncomplete.vim (1 of 1336 files). Show all
Unified · Split
| @@ -0,0 +1,599 @@ | ||
| 1 | +"pythoncomplete.vim - Omni Completion for python | |
| 2 | +" Maintainer: Aaron Griffin <aaronmgriffin@gmail.com> | |
| 3 | +" Version: 0.7 | |
| 4 | +" Last Updated: 19 Oct 2006 | |
| 5 | +" | |
| 6 | +" Changes | |
| 7 | +" TODO: | |
| 8 | +" User defined docstrings aren't handled right... | |
| 9 | +" 'info' item output can use some formatting work | |
| 10 | +" Add an "unsafe eval" mode, to allow for return type evaluation | |
| 11 | +" Complete basic syntax along with import statements | |
| 12 | +" i.e. "import url<c-x,c-o>" | |
| 13 | +" Continue parsing on invalid line?? | |
| 14 | +" | |
| 15 | +" v 0.7 | |
| 16 | +" * Fixed function list sorting (_ and __ at the bottom) | |
| 17 | +" * Removed newline removal from docs. It appears vim handles these better in | |
| 18 | +" recent patches | |
| 19 | +" | |
| 20 | +" v 0.6: | |
| 21 | +" * Fixed argument completion | |
| 22 | +" * Removed the 'kind' completions, as they are better indicated | |
| 23 | +" with real syntax | |
| 24 | +" * Added tuple assignment parsing (whoops, that was forgotten) | |
| 25 | +" * Fixed import handling when flattening scope | |
| 26 | +" | |
| 27 | +" v 0.5: | |
| 28 | +" Yeah, I skipped a version number - 0.4 was never public. | |
| 29 | +" It was a bugfix version on top of 0.3. This is a complete | |
| 30 | +" rewrite. | |
| 31 | +" | |
| 32 | + | |
| 33 | +if !has('python') | |
| 34 | + echo "Error: Required vim compiled with +python" | |
| 35 | + finish | |
| 36 | +endif | |
| 37 | + | |
| 38 | +function! pythoncomplete#Complete(findstart, base) | |
| 39 | + "findstart = 1 when we need to get the text length | |
| 40 | + if a:findstart == 1 | |
| 41 | + let line = getline('.') | |
| 42 | + let idx = col('.') | |
| 43 | + while idx > 0 | |
| 44 | + let idx -= 1 | |
| 45 | + let c = line[idx] | |
| 46 | + if c =~ '\w' | |
| 47 | + continue | |
| 48 | + elseif ! c =~ '\.' | |
| 49 | + let idx = -1 | |
| 50 | + break | |
| 51 | + else | |
| 52 | + break | |
| 53 | + endif | |
| 54 | + endwhile | |
| 55 | + | |
| 56 | + return idx | |
| 57 | + "findstart = 0 when we need to return the list of completions | |
| 58 | + else | |
| 59 | + "vim no longer moves the cursor upon completion... fix that | |
| 60 | + let line = getline('.') | |
| 61 | + let idx = col('.') | |
| 62 | + let cword = '' | |
| 63 | + while idx > 0 | |
| 64 | + let idx -= 1 | |
| 65 | + let c = line[idx] | |
| 66 | + if c =~ '\w' || c =~ '\.' || c == '(' | |
| 67 | + let cword = c . cword | |
| 68 | + continue | |
| 69 | + elseif strlen(cword) > 0 || idx == 0 | |
| 70 | + break | |
| 71 | + endif | |
| 72 | + endwhile | |
| 73 | + execute "python vimcomplete('" . cword . "', '" . a:base . "')" | |
| 74 | + return g:pythoncomplete_completions | |
| 75 | + endif | |
| 76 | +endfunction | |
| 77 | + | |
| 78 | +function! s:DefPython() | |
| 79 | +python << PYTHONEOF | |
| 80 | +import sys, tokenize, cStringIO, types | |
| 81 | +from token import NAME, DEDENT, NEWLINE, STRING | |
| 82 | + | |
| 83 | +debugstmts=[] | |
| 84 | +def dbg(s): debugstmts.append(s) | |
| 85 | +def showdbg(): | |
| 86 | + for d in debugstmts: print "DBG: %s " % d | |
| 87 | + | |
| 88 | +def vimcomplete(context,match): | |
| 89 | + global debugstmts | |
| 90 | + debugstmts = [] | |
| 91 | + try: | |
| 92 | + import vim | |
| 93 | + def complsort(x,y): | |
| 94 | + try: | |
| 95 | + xa = x['abbr'] | |
| 96 | + ya = y['abbr'] | |
| 97 | + if xa[0] == '_': | |
| 98 | + if xa[1] == '_' and ya[0:2] == '__': | |
| 99 | + return xa > ya | |
| 100 | + elif ya[0:2] == '__': | |
| 101 | + return -1 | |
| 102 | + elif y[0] == '_': | |
| 103 | + return xa > ya | |
| 104 | + else: | |
| 105 | + return 1 | |
| 106 | + elif ya[0] == '_': | |
| 107 | + return -1 | |
| 108 | + else: | |
| 109 | + return xa > ya | |
| 110 | + except: | |
| 111 | + return 0 | |
| 112 | + cmpl = Completer() | |
| 113 | + cmpl.evalsource('\n'.join(vim.current.buffer),vim.eval("line('.')")) | |
| 114 | + all = cmpl.get_completions(context,match) | |
| 115 | + all.sort(complsort) | |
| 116 | + dictstr = '[' | |
| 117 | + # have to do this for double quoting | |
| 118 | + for cmpl in all: | |
| 119 | + dictstr += '{' | |
| 120 | + for x in cmpl: dictstr += '"%s":"%s",' % (x,cmpl[x]) | |
| 121 | + dictstr += '"icase":0},' | |
| 122 | + if dictstr[-1] == ',': dictstr = dictstr[:-1] | |
| 123 | + dictstr += ']' | |
| 124 | + #dbg("dict: %s" % dictstr) | |
| 125 | + vim.command("silent let g:pythoncomplete_completions = %s" % dictstr) | |
| 126 | + #dbg("Completion dict:\n%s" % all) | |
| 127 | + except vim.error: | |
| 128 | + dbg("VIM Error: %s" % vim.error) | |
| 129 | + | |
| 130 | +class Completer(object): | |
| 131 | + def __init__(self): | |
| 132 | + self.compldict = {} | |
| 133 | + self.parser = PyParser() | |
| 134 | + | |
| 135 | + def evalsource(self,text,line=0): | |
| 136 | + sc = self.parser.parse(text,line) | |
| 137 | + src = sc.get_code() | |
| 138 | + dbg("source: %s" % src) | |
| 139 | + try: exec(src) in self.compldict | |
| 140 | + except: dbg("parser: %s, %s" % (sys.exc_info()[0],sys.exc_info()[1])) | |
| 141 | + for l in sc.locals: | |
| 142 | + try: exec(l) in self.compldict | |
| 143 | + except: dbg("locals: %s, %s [%s]" % (sys.exc_info()[0],sys.exc_info()[1],l)) | |
| 144 | + | |
| 145 | + def _cleanstr(self,doc): | |
| 146 | + return doc.replace('"',' ').replace("'",' ') | |
| 147 | + | |
| 148 | + def get_arguments(self,func_obj): | |
| 149 | + def _ctor(obj): | |
| 150 | + try: return class_ob.__init__.im_func | |
| 151 | + except AttributeError: | |
| 152 | + for base in class_ob.__bases__: | |
| 153 | + rc = _find_constructor(base) | |
| 154 | + if rc is not None: return rc | |
| 155 | + return None | |
| 156 | + | |
| 157 | + arg_offset = 1 | |
| 158 | + if type(func_obj) == types.ClassType: func_obj = _ctor(func_obj) | |
| 159 | + elif type(func_obj) == types.MethodType: func_obj = func_obj.im_func | |
| 160 | + else: arg_offset = 0 | |
| 161 | + | |
| 162 | + arg_text='' | |
| 163 | + if type(func_obj) in [types.FunctionType, types.LambdaType]: | |
| 164 | + try: | |
| 165 | + cd = func_obj.func_code | |
| 166 | + real_args = cd.co_varnames[arg_offset:cd.co_argcount] | |
| 167 | + defaults = func_obj.func_defaults or '' | |
| 168 | + defaults = map(lambda name: "=%s" % name, defaults) | |
| 169 | + defaults = [""] * (len(real_args)-len(defaults)) + defaults | |
| 170 | + items = map(lambda a,d: a+d, real_args, defaults) | |
| 171 | + if func_obj.func_code.co_flags & 0x4: | |
| 172 | + items.append("...") | |
| 173 | + if func_obj.func_code.co_flags & 0x8: | |
| 174 | + items.append("***") | |
| 175 | + arg_text = (','.join(items)) + ')' | |
| 176 | + | |
| 177 | + except: | |
| 178 | + dbg("arg completion: %s: %s" % (sys.exc_info()[0],sys.exc_info()[1])) | |
| 179 | + pass | |
| 180 | + if len(arg_text) == 0: | |
| 181 | + # The doc string sometimes contains the function signature | |
| 182 | + # this works for alot of C modules that are part of the | |
| 183 | + # standard library | |
| 184 | + doc = func_obj.__doc__ | |
| 185 | + if doc: | |
| 186 | + doc = doc.lstrip() | |
| 187 | + pos = doc.find('\n') | |
| 188 | + if pos > 0: | |
| 189 | + sigline = doc[:pos] | |
| 190 | + lidx = sigline.find('(') | |
| 191 | + ridx = sigline.find(')') | |
| 192 | + if lidx > 0 and ridx > 0: | |
| 193 | + arg_text = sigline[lidx+1:ridx] + ')' | |
| 194 | + if len(arg_text) == 0: arg_text = ')' | |
| 195 | + return arg_text | |
| 196 | + | |
| 197 | + def get_completions(self,context,match): | |
| 198 | + dbg("get_completions('%s','%s')" % (context,match)) | |
| 199 | + stmt = '' | |
| 200 | + if context: stmt += str(context) | |
| 201 | + if match: stmt += str(match) | |
| 202 | + try: | |
| 203 | + result = None | |
| 204 | + all = {} | |
| 205 | + ridx = stmt.rfind('.') | |
| 206 | + if len(stmt) > 0 and stmt[-1] == '(': | |
| 207 | + result = eval(_sanitize(stmt[:-1]), self.compldict) | |
| 208 | + doc = result.__doc__ | |
| 209 | + if doc == None: doc = '' | |
| 210 | + args = self.get_arguments(result) | |
| 211 | + return [{'word':self._cleanstr(args),'info':self._cleanstr(doc)}] | |
| 212 | + elif ridx == -1: | |
| 213 | + match = stmt | |
| 214 | + all = self.compldict | |
| 215 | + else: | |
| 216 | + match = stmt[ridx+1:] | |
| 217 | + stmt = _sanitize(stmt[:ridx]) | |
| 218 | + result = eval(stmt, self.compldict) | |
| 219 | + all = dir(result) | |
| 220 | + | |
| 221 | + dbg("completing: stmt:%s" % stmt) | |
| 222 | + completions = [] | |
| 223 | + | |
| 224 | + try: maindoc = result.__doc__ | |
| 225 | + except: maindoc = ' ' | |
| 226 | + if maindoc == None: maindoc = ' ' | |
| 227 | + for m in all: | |
| 228 | + if m == "_PyCmplNoType": continue #this is internal | |
| 229 | + try: | |
| 230 | + dbg('possible completion: %s' % m) | |
| 231 | + if m.find(match) == 0: | |
| 232 | + if result == None: inst = all[m] | |
| 233 | + else: inst = getattr(result,m) | |
| 234 | + try: doc = inst.__doc__ | |
| 235 | + except: doc = maindoc | |
| 236 | + typestr = str(inst) | |
| 237 | + if doc == None or doc == '': doc = maindoc | |
| 238 | + | |
| 239 | + wrd = m[len(match):] | |
| 240 | + c = {'word':wrd, 'abbr':m, 'info':self._cleanstr(doc)} | |
| 241 | + if "function" in typestr: | |
| 242 | + c['word'] += '(' | |
| 243 | + c['abbr'] += '(' + self._cleanstr(self.get_arguments(inst)) | |
| 244 | + elif "method" in typestr: | |
| 245 | + c['word'] += '(' | |
| 246 | + c['abbr'] += '(' + self._cleanstr(self.get_arguments(inst)) | |
| 247 | + elif "module" in typestr: | |
| 248 | + c['word'] += '.' | |
| 249 | + elif "class" in typestr: | |
| 250 | + c['word'] += '(' | |
| 251 | + c['abbr'] += '(' | |
| 252 | + completions.append(c) | |
| 253 | + except: | |
| 254 | + i = sys.exc_info() | |
| 255 | + dbg("inner completion: %s,%s [stmt='%s']" % (i[0],i[1],stmt)) | |
| 256 | + return completions | |
| 257 | + except: | |
| 258 | + i = sys.exc_info() | |
| 259 | + dbg("completion: %s,%s [stmt='%s']" % (i[0],i[1],stmt)) | |
| 260 | + return [] | |
| 261 | + | |
| 262 | +class Scope(object): | |
| 263 | + def __init__(self,name,indent): | |
| 264 | + self.subscopes = [] | |
| 265 | + self.docstr = '' | |
| 266 | + self.locals = [] | |
| 267 | + self.parent = None | |
| 268 | + self.name = name | |
| 269 | + self.indent = indent | |
| 270 | + | |
| 271 | + def add(self,sub): | |
| 272 | + #print 'push scope: [%s@%s]' % (sub.name,sub.indent) | |
| 273 | + sub.parent = self | |
| 274 | + self.subscopes.append(sub) | |
| 275 | + return sub | |
| 276 | + | |
| 277 | + def doc(self,str): | |
| 278 | + """ Clean up a docstring """ | |
| 279 | + d = str.replace('\n',' ') | |
| 280 | + d = d.replace('\t',' ') | |
| 281 | + while d.find(' ') > -1: d = d.replace(' ',' ') | |
| 282 | + while d[0] in '"\'\t ': d = d[1:] | |
| 283 | + while d[-1] in '"\'\t ': d = d[:-1] | |
| 284 | + self.docstr = d | |
| 285 | + | |
| 286 | + def local(self,loc): | |
| 287 | + if not self._hasvaralready(loc): | |
| 288 | + self.locals.append(loc) | |
| 289 | + | |
| 290 | + def copy_decl(self,indent=0): | |
| 291 | + """ Copy a scope's declaration only, at the specified indent level - not local variables """ | |
| 292 | + return Scope(self.name,indent) | |
| 293 | + | |
| 294 | + def _hasvaralready(self,test): | |
| 295 | + "Convienance function... keep out duplicates" | |
| 296 | + if test.find('=') > -1: | |
| 297 | + var = test.split('=')[0].strip() | |
| 298 | + for l in self.locals: | |
| 299 | + if l.find('=') > -1 and var == l.split('=')[0].strip(): | |
| 300 | + return True | |
| 301 | + return False | |
| 302 | + | |
| 303 | + def get_code(self): | |
| 304 | + # we need to start with this, to fix up broken completions | |
| 305 | + # hopefully this name is unique enough... | |
| 306 | + str = '"""'+self.docstr+'"""\n' | |
| 307 | + for l in self.locals: | |
| 308 | + if l.startswith('import'): str += l+'\n' | |
| 309 | + str += 'class _PyCmplNoType:\n def __getattr__(self,name):\n return None\n' | |
| 310 | + for sub in self.subscopes: | |
| 311 | + str += sub.get_code() | |
| 312 | + for l in self.locals: | |
| 313 | + if not l.startswith('import'): str += l+'\n' | |
| 314 | + | |
| 315 | + return str | |
| 316 | + | |
| 317 | + def pop(self,indent): | |
| 318 | + #print 'pop scope: [%s] to [%s]' % (self.indent,indent) | |
| 319 | + outer = self | |
| 320 | + while outer.parent != None and outer.indent >= indent: | |
| 321 | + outer = outer.parent | |
| 322 | + return outer | |
| 323 | + | |
| 324 | + def currentindent(self): | |
| 325 | + #print 'parse current indent: %s' % self.indent | |
| 326 | + return ' '*self.indent | |
| 327 | + | |
| 328 | + def childindent(self): | |
| 329 | + #print 'parse child indent: [%s]' % (self.indent+1) | |
| 330 | + return ' '*(self.indent+1) | |
| 331 | + | |
| 332 | +class Class(Scope): | |
| 333 | + def __init__(self, name, supers, indent): | |
| 334 | + Scope.__init__(self,name,indent) | |
| 335 | + self.supers = supers | |
| 336 | + def copy_decl(self,indent=0): | |
| 337 | + c = Class(self.name,self.supers,indent) | |
| 338 | + for s in self.subscopes: | |
| 339 | + c.add(s.copy_decl(indent+1)) | |
| 340 | + return c | |
| 341 | + def get_code(self): | |
| 342 | + str = '%sclass %s' % (self.currentindent(),self.name) | |
| 343 | + if len(self.supers) > 0: str += '(%s)' % ','.join(self.supers) | |
| 344 | + str += ':\n' | |
| 345 | + if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n' | |
| 346 | + if len(self.subscopes) > 0: | |
| 347 | + for s in self.subscopes: str += s.get_code() | |
| 348 | + else: | |
| 349 | + str += '%spass\n' % self.childindent() | |
| 350 | + return str | |
| 351 | + | |
| 352 | + | |
| 353 | +class Function(Scope): | |
| 354 | + def __init__(self, name, params, indent): | |
| 355 | + Scope.__init__(self,name,indent) | |
| 356 | + self.params = params | |
| 357 | + def copy_decl(self,indent=0): | |
| 358 | + return Function(self.name,self.params,indent) | |
| 359 | + def get_code(self): | |
| 360 | + str = "%sdef %s(%s):\n" % \ | |
| 361 | + (self.currentindent(),self.name,','.join(self.params)) | |
| 362 | + if len(self.docstr) > 0: str += self.childindent()+'"""'+self.docstr+'"""\n' | |
| 363 | + str += "%spass\n" % self.childindent() | |
| 364 | + return str | |
| 365 | + | |
| 366 | +class PyParser: | |
| 367 | + def __init__(self): | |
| 368 | + self.top = Scope('global',0) | |
| 369 | + self.scope = self.top | |
| 370 | + | |
| 371 | + def _parsedotname(self,pre=None): | |
| 372 | + #returns (dottedname, nexttoken) | |
| 373 | + name = [] | |
| 374 | + if pre == None: | |
| 375 | + tokentype, token, indent = self.next() | |
| 376 | + if tokentype != NAME and token != '*': | |
| 377 | + return ('', token) | |
| 378 | + else: token = pre | |
| 379 | + name.append(token) | |
| 380 | + while True: | |
| 381 | + tokentype, token, indent = self.next() | |
| 382 | + if token != '.': break | |
| 383 | + tokentype, token, indent = self.next() | |
| 384 | + if tokentype != NAME: break | |
| 385 | + name.append(token) | |
| 386 | + return (".".join(name), token) | |
| 387 | + | |
| 388 | + def _parseimportlist(self): | |
| 389 | + imports = [] | |
| 390 | + while True: | |
| 391 | + name, token = self._parsedotname() | |
| 392 | + if not name: break | |
| 393 | + name2 = '' | |
| 394 | + if token == 'as': name2, token = self._parsedotname() | |
| 395 | + imports.append((name, name2)) | |
| 396 | + while token != "," and "\n" not in token: | |
| 397 | + tokentype, token, indent = self.next() | |
| 398 | + if token != ",": break | |
| 399 | + return imports | |
| 400 | + | |
| 401 | + def _parenparse(self): | |
| 402 | + name = '' | |
| 403 | + names = [] | |
| 404 | + level = 1 | |
| 405 | + while True: | |
| 406 | + tokentype, token, indent = self.next() | |
| 407 | + if token in (')', ',') and level == 1: | |
| 408 | + names.append(name) | |
| 409 | + name = '' | |
| 410 | + if token == '(': | |
| 411 | + level += 1 | |
| 412 | + elif token == ')': | |
| 413 | + level -= 1 | |
| 414 | + if level == 0: break | |
| 415 | + elif token == ',' and level == 1: | |
| 416 | + pass | |
| 417 | + else: | |
| 418 | + name += str(token) | |
| 419 | + return names | |
| 420 | + | |
| 421 | + def _parsefunction(self,indent): | |
| 422 | + self.scope=self.scope.pop(indent) | |
| 423 | + tokentype, fname, ind = self.next() | |
| 424 | + if tokentype != NAME: return None | |
| 425 | + | |
| 426 | + tokentype, open, ind = self.next() | |
| 427 | + if open != '(': return None | |
| 428 | + params=self._parenparse() | |
| 429 | + | |
| 430 | + tokentype, colon, ind = self.next() | |
| 431 | + if colon != ':': return None | |
| 432 | + | |
| 433 | + return Function(fname,params,indent) | |
| 434 | + | |
| 435 | + def _parseclass(self,indent): | |
| 436 | + self.scope=self.scope.pop(indent) | |
| 437 | + tokentype, cname, ind = self.next() | |
| 438 | + if tokentype != NAME: return None | |
| 439 | + | |
| 440 | + super = [] | |
| 441 | + tokentype, next, ind = self.next() | |
| 442 | + if next == '(': | |
| 443 | + super=self._parenparse() | |
| 444 | + elif next != ':': return None | |
| 445 | + | |
| 446 | + return Class(cname,super,indent) | |
| 447 | + | |
| 448 | + def _parseassignment(self): | |
| 449 | + assign='' | |
| 450 | + tokentype, token, indent = self.next() | |
| 451 | + if tokentype == tokenize.STRING or token == 'str': | |
| 452 | + return '""' | |
| 453 | + elif token == '(' or token == 'tuple': | |
| 454 | + return '()' | |
| 455 | + elif token == '[' or token == 'list': | |
| 456 | + return '[]' | |
| 457 | + elif token == '{' or token == 'dict': | |
| 458 | + return '{}' | |
| 459 | + elif tokentype == tokenize.NUMBER: | |
| 460 | + return '0' | |
| 461 | + elif token == 'open' or token == 'file': | |
| 462 | + return 'file' | |
| 463 | + elif token == 'None': | |
| 464 | + return '_PyCmplNoType()' | |
| 465 | + elif token == 'type': | |
| 466 | + return 'type(_PyCmplNoType)' #only for method resolution | |
| 467 | + else: | |
| 468 | + assign += token | |
| 469 | + level = 0 | |
| 470 | + while True: | |
| 471 | + tokentype, token, indent = self.next() | |
| 472 | + if token in ('(','{','['): | |
| 473 | + level += 1 | |
| 474 | + elif token in (']','}',')'): | |
| 475 | + level -= 1 | |
| 476 | + if level == 0: break | |
| 477 | + elif level == 0: | |
| 478 | + if token in (';','\n'): break | |
| 479 | + assign += token | |
| 480 | + return "%s" % assign | |
| 481 | + | |
| 482 | + def next(self): | |
| 483 | + type, token, (lineno, indent), end, self.parserline = self.gen.next() | |
| 484 | + if lineno == self.curline: | |
| 485 | + #print 'line found [%s] scope=%s' % (line.replace('\n',''),self.scope.name) | |
| 486 | + self.currentscope = self.scope | |
| 487 | + return (type, token, indent) | |
| 488 | + | |
| 489 | + def _adjustvisibility(self): | |
| 490 | + newscope = Scope('result',0) | |
| 491 | + scp = self.currentscope | |
| 492 | + while scp != None: | |
| 493 | + if type(scp) == Function: | |
| 494 | + slice = 0 | |
| 495 | + #Handle 'self' params | |
| 496 | + if scp.parent != None and type(scp.parent) == Class: | |
| 497 | + slice = 1 | |
| 498 | + p = scp.params[0] | |
| 499 | + i = p.find('=') | |
| 500 | + if i != -1: p = p[:i] | |
| 501 | + newscope.local('%s = %s' % (scp.params[0],scp.parent.name)) | |
| 502 | + for p in scp.params[slice:]: | |
| 503 | + i = p.find('=') | |
| 504 | + if i == -1: | |
| 505 | + newscope.local('%s = _PyCmplNoType()' % p) | |
| 506 | + else: | |
| 507 | + newscope.local('%s = %s' % (p[:i],_sanitize(p[i+1]))) | |
| 508 | + | |
| 509 | + for s in scp.subscopes: | |
| 510 | + ns = s.copy_decl(0) | |
| 511 | + newscope.add(ns) | |
| 512 | + for l in scp.locals: newscope.local(l) | |
| 513 | + scp = scp.parent | |
| 514 | + | |
| 515 | + self.currentscope = newscope | |
| 516 | + return self.currentscope | |
| 517 | + | |
| 518 | + #p.parse(vim.current.buffer[:],vim.eval("line('.')")) | |
| 519 | + def parse(self,text,curline=0): | |
| 520 | + self.curline = int(curline) | |
| 521 | + buf = cStringIO.StringIO(''.join(text) + '\n') | |
| 522 | + self.gen = tokenize.generate_tokens(buf.readline) | |
| 523 | + self.currentscope = self.scope | |
| 524 | + | |
| 525 | + try: | |
| 526 | + freshscope=True | |
| 527 | + while True: | |
| 528 | + tokentype, token, indent = self.next() | |
| 529 | + #dbg( 'main: token=[%s] indent=[%s]' % (token,indent)) | |
| 530 | + | |
| 531 | + if tokentype == DEDENT or token == "pass": | |
| 532 | + self.scope = self.scope.pop(indent) | |
| 533 | + elif token == 'def': | |
| 534 | + func = self._parsefunction(indent) | |
| 535 | + if func == None: | |
| 536 | + print "function: syntax error..." | |
| 537 | + continue | |
| 538 | + freshscope = True | |
| 539 | + self.scope = self.scope.add(func) | |
| 540 | + elif token == 'class': | |
| 541 | + cls = self._parseclass(indent) | |
| 542 | + if cls == None: | |
| 543 | + print "class: syntax error..." | |
| 544 | + continue | |
| 545 | + freshscope = True | |
| 546 | + self.scope = self.scope.add(cls) | |
| 547 | + | |
| 548 | + elif token == 'import': | |
| 549 | + imports = self._parseimportlist() | |
| 550 | + for mod, alias in imports: | |
| 551 | + loc = "import %s" % mod | |
| 552 | + if len(alias) > 0: loc += " as %s" % alias | |
| 553 | + self.scope.local(loc) | |
| 554 | + freshscope = False | |
| 555 | + elif token == 'from': | |
| 556 | + mod, token = self._parsedotname() | |
| 557 | + if not mod or token != "import": | |
| 558 | + print "from: syntax error..." | |
| 559 | + continue | |
| 560 | + names = self._parseimportlist() | |
| 561 | + for name, alias in names: | |
| 562 | + loc = "from %s import %s" % (mod,name) | |
| 563 | + if len(alias) > 0: loc += " as %s" % alias | |
| 564 | + self.scope.local(loc) | |
| 565 | + freshscope = False | |
| 566 | + elif tokentype == STRING: | |
| 567 | + if freshscope: self.scope.doc(token) | |
| 568 | + elif tokentype == NAME: | |
| 569 | + name,token = self._parsedotname(token) | |
| 570 | + if token == '=': | |
| 571 | + stmt = self._parseassignment() | |
| 572 | + if stmt != None: | |
| 573 | + self.scope.local("%s = %s" % (name,stmt)) | |
| 574 | + freshscope = False | |
| 575 | + except StopIteration: #thrown on EOF | |
| 576 | + pass | |
| 577 | + except: | |
| 578 | + dbg("parse error: %s, %s @ %s" % | |
| 579 | + (sys.exc_info()[0], sys.exc_info()[1], self.parserline)) | |
| 580 | + return self._adjustvisibility() | |
| 581 | + | |
| 582 | +def _sanitize(str): | |
| 583 | + val = '' | |
| 584 | + level = 0 | |
| 585 | + for c in str: | |
| 586 | + if c in ('(','{','['): | |
| 587 | + level += 1 | |
| 588 | + elif c in (']','}',')'): | |
| 589 | + level -= 1 | |
| 590 | + elif level == 0: | |
| 591 | + val += c | |
| 592 | + return val | |
| 593 | + | |
| 594 | +sys.path.extend(['.','..']) | |
| 595 | +PYTHONEOF | |
| 596 | +endfunction | |
| 597 | + | |
| 598 | +call s:DefPython() | |
| 599 | +" vim: set et ts=4: | |