mirror of
https://github.com/davidhalter/jedi.git
synced 2025-12-08 23:04:48 +08:00
statement parsing
This commit is contained in:
@@ -38,7 +38,7 @@ class Completer(object):
|
|||||||
self.parser = PyFuzzyParser()
|
self.parser = PyFuzzyParser()
|
||||||
|
|
||||||
def evalsource(self, text, line=0):
|
def evalsource(self, text, line=0):
|
||||||
sc = self.parser.parse(text, line)
|
sc = self.parser.parse(text)
|
||||||
self.sc = sc # TODO rm
|
self.sc = sc # TODO rm
|
||||||
src = sc.get_code()
|
src = sc.get_code()
|
||||||
dbg("source: %s" % src)
|
dbg("source: %s" % src)
|
||||||
@@ -208,7 +208,10 @@ print ''
|
|||||||
showdbg()
|
showdbg()
|
||||||
|
|
||||||
print cmpl.parser.top.get_code()
|
print cmpl.parser.top.get_code()
|
||||||
|
#print cmpl.parser.top.subscopes[1].subscopes[0].get_code()
|
||||||
|
|
||||||
|
p = cmpl.parser
|
||||||
|
s = p.top
|
||||||
import code
|
import code
|
||||||
sh = code.InteractiveConsole(locals=locals())
|
sh = code.InteractiveConsole(locals=locals())
|
||||||
#sh.interact("InteractiveConsole")
|
#sh.interact("InteractiveConsole")
|
||||||
|
|||||||
114
pyfuzzyparser.py
114
pyfuzzyparser.py
@@ -8,12 +8,16 @@ import cStringIO
|
|||||||
|
|
||||||
def indent_block(text, indention=" "):
|
def indent_block(text, indention=" "):
|
||||||
""" This function indents a text block with a default of four spaces """
|
""" This function indents a text block with a default of four spaces """
|
||||||
|
temp = ''
|
||||||
|
while text and text[-1] == '\n':
|
||||||
|
temp += text[-1]
|
||||||
|
text = text[:-1]
|
||||||
lines = text.split('\n')
|
lines = text.split('\n')
|
||||||
return '\n'.join(map(lambda s: indention + s, lines))
|
return '\n'.join(map(lambda s: indention + s, lines)) + temp
|
||||||
|
|
||||||
|
|
||||||
class Scope(object):
|
class Scope(object):
|
||||||
def __init__(self, name, indent, docstr=''):
|
def __init__(self, name, indent, line_nr, docstr=''):
|
||||||
self.subscopes = []
|
self.subscopes = []
|
||||||
self.locals = []
|
self.locals = []
|
||||||
self.imports = []
|
self.imports = []
|
||||||
@@ -21,6 +25,7 @@ class Scope(object):
|
|||||||
self.parent = None
|
self.parent = None
|
||||||
self.name = name
|
self.name = name
|
||||||
self.indent = indent
|
self.indent = indent
|
||||||
|
self.line_nr = line_nr
|
||||||
|
|
||||||
def add_scope(self, sub):
|
def add_scope(self, sub):
|
||||||
#print 'push scope: [%s@%s]' % (sub.name, sub.indent)
|
#print 'push scope: [%s@%s]' % (sub.name, sub.indent)
|
||||||
@@ -56,30 +61,30 @@ class Scope(object):
|
|||||||
self.locals.remove(l)
|
self.locals.remove(l)
|
||||||
|
|
||||||
def get_code(self, first_indent=False, indention=" "):
|
def get_code(self, first_indent=False, indention=" "):
|
||||||
str = ""
|
string = ""
|
||||||
if len(self.docstr) > 0:
|
if len(self.docstr) > 0:
|
||||||
str += '"""' + self.docstr + '"""\n'
|
string += '"""' + self.docstr + '"""\n'
|
||||||
for i in self.imports:
|
for i in self.imports:
|
||||||
str += i.get_code() + '\n'
|
string += i.get_code() + '\n'
|
||||||
for sub in self.subscopes:
|
for sub in self.subscopes:
|
||||||
str += sub.get_code(first_indent=True, indention=indention)
|
string += str(sub.line_nr) + sub.get_code(first_indent=True, indention=indention)
|
||||||
for l in self.locals:
|
for l in self.locals:
|
||||||
str += l + '\n'
|
string += l + '\n'
|
||||||
|
|
||||||
if first_indent:
|
if first_indent:
|
||||||
str = indent_block(str, indention=indention)
|
string = indent_block(string, indention=indention)
|
||||||
return "_%s_%s" % (self.indent, str)
|
return string
|
||||||
|
|
||||||
def is_empty(self):
|
def is_empty(self):
|
||||||
"""
|
"""
|
||||||
this function returns true if there are no subscopes, imports, locals.
|
this function returns true if there are no subscopes, imports, locals.
|
||||||
"""
|
"""
|
||||||
return not (self.locals, self.imports, self.subscopes)
|
return not (self.locals or self.imports or self.subscopes)
|
||||||
|
|
||||||
|
|
||||||
class Class(Scope):
|
class Class(Scope):
|
||||||
def __init__(self, name, supers, indent, docstr=''):
|
def __init__(self, name, supers, indent, line_nr, docstr=''):
|
||||||
super(Class, self).__init__(name, indent, docstr)
|
super(Class, self).__init__(name, indent, line_nr, docstr)
|
||||||
self.supers = supers
|
self.supers = supers
|
||||||
|
|
||||||
def get_code(self, first_indent=False, indention=" "):
|
def get_code(self, first_indent=False, indention=" "):
|
||||||
@@ -88,14 +93,15 @@ class Class(Scope):
|
|||||||
str += '(%s)' % ','.join(self.supers)
|
str += '(%s)' % ','.join(self.supers)
|
||||||
str += ':\n'
|
str += ':\n'
|
||||||
str += super(Class, self).get_code(True, indention)
|
str += super(Class, self).get_code(True, indention)
|
||||||
|
print "get_code class %s %i" % (self.name, self.is_empty())
|
||||||
if self.is_empty():
|
if self.is_empty():
|
||||||
str += indent_block("pass\n", indention=indention)
|
str += "pass\n"
|
||||||
return str
|
return str
|
||||||
|
|
||||||
|
|
||||||
class Function(Scope):
|
class Function(Scope):
|
||||||
def __init__(self, name, params, indent, docstr=''):
|
def __init__(self, name, params, indent, line_nr, docstr=''):
|
||||||
Scope.__init__(self, name, indent, docstr)
|
Scope.__init__(self, name, indent, line_nr, docstr)
|
||||||
self.params = params
|
self.params = params
|
||||||
|
|
||||||
def get_code(self, first_indent=False, indention=" "):
|
def get_code(self, first_indent=False, indention=" "):
|
||||||
@@ -104,22 +110,24 @@ class Function(Scope):
|
|||||||
# str += self.childindent()+'"""'+self.docstr+'"""\n'
|
# str += self.childindent()+'"""'+self.docstr+'"""\n'
|
||||||
str += super(Function, self).get_code(True, indention)
|
str += super(Function, self).get_code(True, indention)
|
||||||
if self.is_empty():
|
if self.is_empty():
|
||||||
str += indent_block("pass\n", indention=indention)
|
str += "pass\n"
|
||||||
print "func", self.locals
|
print "func", self.locals
|
||||||
return str
|
return str
|
||||||
|
|
||||||
|
|
||||||
class Import(object):
|
class Import(object):
|
||||||
"""
|
"""
|
||||||
stores the imports of class files
|
stores the imports of any scopes
|
||||||
"""
|
""" # TODO check star?
|
||||||
def __init__(self, namespace, alias='', from_ns='', star=False):
|
def __init__(self, line_nr, namespace, alias='', from_ns='', star=False):
|
||||||
"""
|
"""
|
||||||
|
@param line_nr
|
||||||
@param namespace: the namespace which is imported
|
@param namespace: the namespace which is imported
|
||||||
@param alias: the alias (valid in the current namespace)
|
@param alias: the alias (valid in the current namespace)
|
||||||
@param from_ns: from declaration in an import
|
@param from_ns: from declaration in an import
|
||||||
@param star: if a star is used -> from time import *
|
@param star: if a star is used -> from time import *
|
||||||
"""
|
"""
|
||||||
|
self.line_nr = line_nr
|
||||||
self.namespace = namespace
|
self.namespace = namespace
|
||||||
self.alias = alias
|
self.alias = alias
|
||||||
self.from_ns = from_ns
|
self.from_ns = from_ns
|
||||||
@@ -138,13 +146,56 @@ class Import(object):
|
|||||||
return "test import " + ns_str
|
return "test import " + ns_str
|
||||||
|
|
||||||
|
|
||||||
|
class Statement(object):
|
||||||
|
""" This is the super class for Local and Functions """
|
||||||
|
def __init__(self, line_nr, stmt):
|
||||||
|
"""
|
||||||
|
@param line_nr
|
||||||
|
@param stmt the statement string
|
||||||
|
"""
|
||||||
|
self.line_nr = line_nr
|
||||||
|
self. stmt = stmt
|
||||||
|
|
||||||
|
def get_code(self):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
class Local(object):
|
||||||
|
"""
|
||||||
|
stores locals variables of any scopes
|
||||||
|
"""
|
||||||
|
def __init__(self, line_nr, left, right=None, is_global=False):
|
||||||
|
"""
|
||||||
|
@param line_nr
|
||||||
|
@param left: the left part of the local assignment
|
||||||
|
@param right: the right part of the assignment, must not be set
|
||||||
|
(in case of global)
|
||||||
|
@param is_global: defines a global variable
|
||||||
|
"""
|
||||||
|
self.line_nr = line_nr
|
||||||
|
self.left = left
|
||||||
|
self.right = right
|
||||||
|
|
||||||
|
def get_code(self):
|
||||||
|
if self.alias:
|
||||||
|
ns_str = "%s as %s" % (self.namespace, self.alias)
|
||||||
|
else:
|
||||||
|
ns_str = self.namespace
|
||||||
|
if self.from_ns:
|
||||||
|
if self.star:
|
||||||
|
ns_str = '*'
|
||||||
|
return "test from %s import %s" % (self.from_ns, ns_str)
|
||||||
|
else:
|
||||||
|
return "test import " + ns_str
|
||||||
|
|
||||||
|
|
||||||
class PyFuzzyParser(object):
|
class PyFuzzyParser(object):
|
||||||
"""
|
"""
|
||||||
This class is used to parse a Python file, it then divides them into a
|
This class is used to parse a Python file, it then divides them into a
|
||||||
class structure of differnt scopes.
|
class structure of differnt scopes.
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.top = Scope('global', 0)
|
self.top = Scope('global', 0, 0)
|
||||||
self.scope = self.top
|
self.scope = self.top
|
||||||
|
|
||||||
def _parsedotname(self, pre=None):
|
def _parsedotname(self, pre=None):
|
||||||
@@ -223,7 +274,7 @@ class PyFuzzyParser(object):
|
|||||||
if colon != ':':
|
if colon != ':':
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return Function(fname, params, indent)
|
return Function(fname, params, indent, self.line_nr)
|
||||||
|
|
||||||
def _parseclass(self, indent):
|
def _parseclass(self, indent):
|
||||||
tokentype, cname, ind = self.next()
|
tokentype, cname, ind = self.next()
|
||||||
@@ -237,7 +288,7 @@ class PyFuzzyParser(object):
|
|||||||
elif next != ':':
|
elif next != ':':
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return Class(cname, super, indent)
|
return Class(cname, super, indent, self.line_nr)
|
||||||
|
|
||||||
def _parseassignment(self):
|
def _parseassignment(self):
|
||||||
assign = ''
|
assign = ''
|
||||||
@@ -276,14 +327,11 @@ class PyFuzzyParser(object):
|
|||||||
return "%s" % assign
|
return "%s" % assign
|
||||||
|
|
||||||
def next(self):
|
def next(self):
|
||||||
type, tok, (lineno, indent), end, self.parserline = self.gen.next()
|
type, tok, position, dummy, self.parserline = self.gen.next()
|
||||||
if lineno == self.curline:
|
(self.line_nr, indent) = position
|
||||||
self.currentscope = self.scope
|
|
||||||
return (type, tok, indent)
|
return (type, tok, indent)
|
||||||
|
|
||||||
#p.parse(vim.current.buffer[:], vim.eval("line('.')"))
|
def parse(self, text):
|
||||||
def parse(self, text, curline=0):
|
|
||||||
self.curline = int(curline)
|
|
||||||
buf = cStringIO.StringIO(''.join(text) + '\n')
|
buf = cStringIO.StringIO(''.join(text) + '\n')
|
||||||
self.gen = tokenize.generate_tokens(buf.readline)
|
self.gen = tokenize.generate_tokens(buf.readline)
|
||||||
self.currentscope = self.scope
|
self.currentscope = self.scope
|
||||||
@@ -292,7 +340,8 @@ class PyFuzzyParser(object):
|
|||||||
freshscope = True
|
freshscope = True
|
||||||
while True:
|
while True:
|
||||||
tokentype, tok, indent = self.next()
|
tokentype, tok, indent = self.next()
|
||||||
dbg('main: tok=[%s] indent=[%s]' % (tok, indent))
|
dbg('main: tok=[%s] type=[%s] indent=[%s]'\
|
||||||
|
% (tok, tokentype, indent))
|
||||||
|
|
||||||
if tokentype == tokenize.DEDENT:
|
if tokentype == tokenize.DEDENT:
|
||||||
self.scope = self.scope.parent
|
self.scope = self.scope.parent
|
||||||
@@ -315,7 +364,7 @@ class PyFuzzyParser(object):
|
|||||||
elif tok == 'import':
|
elif tok == 'import':
|
||||||
imports = self._parseimportlist()
|
imports = self._parseimportlist()
|
||||||
for mod, alias in imports:
|
for mod, alias in imports:
|
||||||
self.scope.add_import(Import(mod, alias))
|
self.scope.add_import(Import(self.line_nr, mod, alias))
|
||||||
freshscope = False
|
freshscope = False
|
||||||
elif tok == 'from':
|
elif tok == 'from':
|
||||||
mod, tok = self._parsedotname()
|
mod, tok = self._parsedotname()
|
||||||
@@ -324,7 +373,8 @@ class PyFuzzyParser(object):
|
|||||||
continue
|
continue
|
||||||
names = self._parseimportlist()
|
names = self._parseimportlist()
|
||||||
for name, alias in names:
|
for name, alias in names:
|
||||||
self.scope.add_import(Import(name, alias, mod))
|
i = Import(self.line_nr, name, alias, mod)
|
||||||
|
self.scope.add_import(i)
|
||||||
freshscope = False
|
freshscope = False
|
||||||
elif tokentype == tokenize.STRING:
|
elif tokentype == tokenize.STRING:
|
||||||
if freshscope:
|
if freshscope:
|
||||||
@@ -342,7 +392,7 @@ class PyFuzzyParser(object):
|
|||||||
#except:
|
#except:
|
||||||
# dbg("parse error: %s, %s @ %s" %
|
# dbg("parse error: %s, %s @ %s" %
|
||||||
# (sys.exc_info()[0], sys.exc_info()[1], self.parserline))
|
# (sys.exc_info()[0], sys.exc_info()[1], self.parserline))
|
||||||
return self.top # self._adjustvisibility()
|
return self.top
|
||||||
|
|
||||||
|
|
||||||
def _sanitize(str):
|
def _sanitize(str):
|
||||||
|
|||||||
11
test.py
11
test.py
@@ -10,7 +10,7 @@ from token import OP as OP_TEST, INDENT as INDENT_TEST
|
|||||||
aaa = 6; bbb = 13
|
aaa = 6; bbb = 13
|
||||||
ccc = bbb; d = open("test.py");
|
ccc = bbb; d = open("test.py");
|
||||||
|
|
||||||
class Intro:
|
class Intro(object):
|
||||||
def testing(self, string):
|
def testing(self, string):
|
||||||
return string+","
|
return string+","
|
||||||
|
|
||||||
@@ -20,23 +20,24 @@ class Supi(A, datetime.datetime):
|
|||||||
|
|
||||||
static_var = 0
|
static_var = 0
|
||||||
def __init__():
|
def __init__():
|
||||||
import time
|
|
||||||
pass
|
pass
|
||||||
def test(self):
|
def test(self):
|
||||||
|
import time
|
||||||
print 1
|
print 1
|
||||||
return A()
|
return A()
|
||||||
|
|
||||||
class A():
|
class A():
|
||||||
class B():
|
#class B():
|
||||||
def test(self):
|
def test(self):
|
||||||
return A()
|
return A()
|
||||||
|
|
||||||
class C:
|
|
||||||
a = A()
|
a = A()
|
||||||
|
|
||||||
b = a.test()
|
b = a.test()
|
||||||
|
|
||||||
def blub:
|
class Empty():
|
||||||
|
pass
|
||||||
|
def blub():
|
||||||
|
|
||||||
cdef = 5
|
cdef = 5
|
||||||
def func():
|
def func():
|
||||||
|
|||||||
Reference in New Issue
Block a user