mirror of
https://github.com/davidhalter/parso.git
synced 2025-12-09 06:04:54 +08:00
Add no binding found for nonlocal issue
This commit is contained in:
@@ -100,6 +100,7 @@ class Context(object):
|
|||||||
self._used_name_dict = {}
|
self._used_name_dict = {}
|
||||||
self._global_names = []
|
self._global_names = []
|
||||||
self._nonlocal_names = []
|
self._nonlocal_names = []
|
||||||
|
self._nonlocal_names_in_subscopes = []
|
||||||
self._add_syntax_error = add_syntax_error
|
self._add_syntax_error = add_syntax_error
|
||||||
|
|
||||||
def is_async_funcdef(self):
|
def is_async_funcdef(self):
|
||||||
@@ -125,14 +126,17 @@ class Context(object):
|
|||||||
self._used_name_dict.setdefault(name.value, []).append(name)
|
self._used_name_dict.setdefault(name.value, []).append(name)
|
||||||
|
|
||||||
def finalize(self):
|
def finalize(self):
|
||||||
|
"""
|
||||||
|
Returns a list of nonlocal names that need to be part of that scope.
|
||||||
|
"""
|
||||||
self._analyze_names(self._global_names, 'global')
|
self._analyze_names(self._global_names, 'global')
|
||||||
self._analyze_names(self._nonlocal_names, 'nonlocal')
|
self._analyze_names(self._nonlocal_names, 'nonlocal')
|
||||||
|
|
||||||
# Python2.6 doesn't have dict comprehensions.
|
# Python2.6 doesn't have dict comprehensions.
|
||||||
nonlocal_name_strs = dict((n.value, n) for n in self._nonlocal_names)
|
global_name_strs = dict((n.value, n) for n in self._global_names)
|
||||||
for global_name in self._global_names:
|
for nonlocal_name in self._nonlocal_names:
|
||||||
try:
|
try:
|
||||||
nonlocal_name = nonlocal_name_strs[global_name.value]
|
global_name = global_name_strs[nonlocal_name.value]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -143,6 +147,17 @@ class Context(object):
|
|||||||
error_name = nonlocal_name
|
error_name = nonlocal_name
|
||||||
self._add_syntax_error(message, error_name)
|
self._add_syntax_error(message, error_name)
|
||||||
|
|
||||||
|
nonlocals_not_handled = []
|
||||||
|
for nonlocal_name in self._nonlocal_names_in_subscopes:
|
||||||
|
search = nonlocal_name.value
|
||||||
|
if search in global_name_strs or self.parent_context is None:
|
||||||
|
message = "no binding for nonlocal '%s' found" % nonlocal_name.value
|
||||||
|
self._add_syntax_error(message, nonlocal_name)
|
||||||
|
elif not self.is_function() or \
|
||||||
|
nonlocal_name.value not in self._used_name_dict:
|
||||||
|
nonlocals_not_handled.append(nonlocal_name)
|
||||||
|
return self._nonlocal_names + nonlocals_not_handled
|
||||||
|
|
||||||
def _analyze_names(self, globals_or_nonlocals, type_):
|
def _analyze_names(self, globals_or_nonlocals, type_):
|
||||||
def raise_(message):
|
def raise_(message):
|
||||||
self._add_syntax_error(message % (base_name.value, type_), base_name)
|
self._add_syntax_error(message % (base_name.value, type_), base_name)
|
||||||
@@ -198,7 +213,7 @@ class Context(object):
|
|||||||
def add_context(self, node):
|
def add_context(self, node):
|
||||||
new_context = Context(node, self._add_syntax_error, parent_context=self)
|
new_context = Context(node, self._add_syntax_error, parent_context=self)
|
||||||
yield new_context
|
yield new_context
|
||||||
new_context.finalize()
|
self._nonlocal_names_in_subscopes += new_context.finalize()
|
||||||
|
|
||||||
|
|
||||||
class ErrorFinder(Normalizer):
|
class ErrorFinder(Normalizer):
|
||||||
@@ -627,6 +642,8 @@ class ErrorFinder(Normalizer):
|
|||||||
self._error_dict.setdefault(line, (code, message, node))
|
self._error_dict.setdefault(line, (code, message, node))
|
||||||
|
|
||||||
def finalize(self):
|
def finalize(self):
|
||||||
|
self._context.finalize()
|
||||||
|
|
||||||
for code, message, node in self._error_dict.values():
|
for code, message, node in self._error_dict.values():
|
||||||
self.issues.append(Issue(node, code, message))
|
self.issues.append(Issue(node, code, message))
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ def _all_string_prefixes(version_info):
|
|||||||
if version_info <= (2, 7):
|
if version_info <= (2, 7):
|
||||||
# TODO this is actually not 100% valid. ur is valid in Python 2.7,
|
# TODO this is actually not 100% valid. ur is valid in Python 2.7,
|
||||||
# while ru is not.
|
# while ru is not.
|
||||||
|
# TODO rb is also not valid.
|
||||||
_valid_string_prefixes.append('ur')
|
_valid_string_prefixes.append('ur')
|
||||||
|
|
||||||
# if we add binary f-strings, add: ['fb', 'fbr']
|
# if we add binary f-strings, add: ['fb', 'fbr']
|
||||||
|
|||||||
@@ -47,11 +47,10 @@ except ZeroDivisionError:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class X():
|
|
||||||
nonlocal a
|
|
||||||
|
|
||||||
|
|
||||||
def c():
|
def c():
|
||||||
|
a = 3
|
||||||
|
|
||||||
|
def d():
|
||||||
class X():
|
class X():
|
||||||
nonlocal a
|
nonlocal a
|
||||||
|
|
||||||
|
|||||||
@@ -175,10 +175,30 @@ FAILING_EXAMPLES = [
|
|||||||
'''),
|
'''),
|
||||||
dedent('''
|
dedent('''
|
||||||
def x():
|
def x():
|
||||||
|
a = 4
|
||||||
|
def y():
|
||||||
global a
|
global a
|
||||||
nonlocal a
|
nonlocal a
|
||||||
'''),
|
'''),
|
||||||
# Missing binding of nonlocal
|
# Missing binding of nonlocal
|
||||||
|
dedent('''
|
||||||
|
def x():
|
||||||
|
nonlocal a
|
||||||
|
'''),
|
||||||
|
dedent('''
|
||||||
|
def x():
|
||||||
|
def y():
|
||||||
|
nonlocal a
|
||||||
|
'''),
|
||||||
|
dedent('''
|
||||||
|
def x():
|
||||||
|
a = 4
|
||||||
|
def y():
|
||||||
|
global a
|
||||||
|
print(a)
|
||||||
|
def z():
|
||||||
|
nonlocal a
|
||||||
|
'''),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user