@@ -116,20 +116,26 @@ def __init__(self, parent_scope=None):
116116 self ._properties = {}
117117 self ._assignments = {}
118118
119- def names_in_use (self ):
120- names = self .names
121- if self .parent_scope is not None :
122- names = names | self .parent_scope .names_in_use ()
123- return names
119+ def is_name_in_use (self , name : str ) -> bool :
120+ if name in self .names :
121+ return True
122+
123+ if self .parent_scope is None :
124+ return False
125+
126+ return self .parent_scope .is_name_in_use (name )
127+
128+ def is_name_reserved_function_arg (self , name : str ) -> bool :
129+ if name in self ._function_arg_reserved_names :
130+ return True
124131
125- def function_arg_reserved_names (self ):
126- names = self ._function_arg_reserved_names
127- if self .parent_scope is not None :
128- names = names | self .parent_scope .function_arg_reserved_names ()
129- return names
132+ if self .parent_scope is None :
133+ return False
130134
131- def all_reserved_names (self ):
132- return self .names_in_use () | self .function_arg_reserved_names ()
135+ return self .parent_scope .is_name_reserved_function_arg (name )
136+
137+ def is_name_reserved (self , name : str ) -> bool :
138+ return self .is_name_in_use (name ) or self .is_name_reserved_function_arg (name )
133139
134140 def reserve_name (self , requested , function_arg = False , is_builtin = False , properties = None ):
135141 """
@@ -146,10 +152,10 @@ def _add(final):
146152 return final
147153
148154 if function_arg :
149- if requested in self .function_arg_reserved_names ( ):
150- assert requested not in self .names_in_use ( )
155+ if self .is_name_reserved_function_arg ( requested ):
156+ assert not self .is_name_in_use ( requested )
151157 return _add (requested )
152- if requested in self .all_reserved_names ( ):
158+ if self .is_name_reserved ( requested ):
153159 raise AssertionError (f"Cannot use '{ requested } ' as argument name as it is already in use" )
154160
155161 cleaned = cleanup_name (requested )
@@ -159,16 +165,20 @@ def _add(final):
159165 # To avoid shadowing of global names in local scope, we
160166 # take into account parent scope when assigning names.
161167
162- used = self .all_reserved_names ()
163- # We need to also protect against using keywords ('class', 'def' etc.)
164- # i.e. count all keywords as 'used'.
165- # However, some builtins are also keywords (e.g. 'None'), and so
166- # if a builtin is being reserved, don't check against the keyword list
167- if not is_builtin :
168- used = used | set (keyword .kwlist )
169- while attempt in used :
168+ def _is_name_allowed (name : str ) -> bool :
169+ # We need to also protect against using keywords ('class', 'def' etc.)
170+ # i.e. count all keywords as 'used'.
171+ # However, some builtins are also keywords (e.g. 'None'), and so
172+ # if a builtin is being reserved, don't check against the keyword list
173+ if (not is_builtin ) and keyword .iskeyword (name ):
174+ return False
175+
176+ return not self .is_name_reserved (name )
177+
178+ while not _is_name_allowed (attempt ):
170179 attempt = cleaned + str (count )
171180 count += 1
181+
172182 return _add (attempt )
173183
174184 def reserve_function_arg_name (self , name ):
@@ -180,7 +190,7 @@ def reserve_function_arg_name(self, name):
180190 # To keep things simple, and the generated code predictable, we reserve
181191 # names for all function arguments in a separate scope, and insist on
182192 # the exact names
183- if name in self .all_reserved_names ( ):
193+ if self .is_name_reserved ( name ):
184194 raise AssertionError (f"Can't reserve '{ name } ' as function arg name as it is already reserved" )
185195 self ._function_arg_reserved_names .add (name )
186196
@@ -307,7 +317,7 @@ def add_assignment(self, name, value, allow_multiple=False):
307317
308318 x = value
309319 """
310- if name not in self .scope .names_in_use ( ):
320+ if not self .scope .is_name_in_use ( name ):
311321 raise AssertionError (f"Cannot assign to unreserved name '{ name } '" )
312322
313323 if self .scope .has_assignment (name ):
@@ -366,7 +376,7 @@ def __init__(self, name, args=None, parent_scope=None, source=None):
366376 if args is None :
367377 args = ()
368378 for arg in args :
369- if arg in self .names_in_use ( ):
379+ if self .is_name_in_use ( arg ):
370380 raise AssertionError (f"Can't use '{ arg } ' as function argument name because it shadows other names" )
371381 self .reserve_name (arg , function_arg = True )
372382 self .args = args
@@ -663,7 +673,7 @@ class VariableReference(Expression):
663673 child_elements = []
664674
665675 def __init__ (self , name , scope ):
666- if name not in scope .names_in_use ( ):
676+ if not scope .is_name_in_use ( name ):
667677 raise AssertionError (f"Cannot refer to undefined variable '{ name } '" )
668678 self .name = name
669679 self .type = scope .get_name_properties (name ).get (PROPERTY_TYPE , UNKNOWN_TYPE )
@@ -684,7 +694,7 @@ class FunctionCall(Expression):
684694 child_elements = ["args" , "kwargs" ]
685695
686696 def __init__ (self , function_name , args , kwargs , scope , expr_type = UNKNOWN_TYPE ):
687- if function_name not in scope .names_in_use ( ):
697+ if not scope .is_name_in_use ( function_name ):
688698 raise AssertionError (f"Cannot call unknown function '{ function_name } '" )
689699 self .function_name = function_name
690700 self .args = list (args )
0 commit comments