The ThinkPy interpreter currently fails silently when accessing undefined variables in certain contexts, particularly within enumerate loops. Instead of raising an error, it treats undefined variable names as string literals, leading to confusing runtime errors.
Current Behavior
for score, weight in enumerate(weights):
total = total + (scores[index] * weight) # 'index' is undefined but doesn't raise error
Currently produces a TypeError: list indices must be integers or slices, not str because index is treated as a string literal rather than raising an undefined variable error.
Expected Behavior
The interpreter should raise a clear RuntimeError: Undefined variable: index when attempting to access undefined variables.
Proposed Solution
Implement proper variable scoping in the interpreter:
Add a scope stack to track variables in different contexts
Implement scope push/pop for loops and other block structures
Add proper variable lookup through the scope chain
Maintain ability to handle string literals while catching undefined variables
Implementation Details
class ThinkPyInterpreter:
def __init__(self, explain_mode=False, format_style="default", max_iterations_shown=5):
self.state = {} # Global variable storage
self.scopes = [] # Stack of local scopes
# ... rest of __init__ remains the same ...
def push_scope(self):
"""Create a new local scope"""
self.scopes.append({})
def pop_scope(self):
"""Remove the current local scope"""
if self.scopes:
self.scopes.pop()
def get_variable(self, name):
"""Look up a variable in the current scope chain"""
# Check local scopes from innermost to outermost
for scope in reversed(self.scopes):
if name in scope:
return scope[name]
# Check global scope
if name in self.state:
return self.state[name]
raise RuntimeError(f"Undefined variable: {name}")
def set_variable(self, name, value, is_global=False):
"""Set a variable in the appropriate scope"""
if is_global or not self.scopes:
self.state[name] = value
else:
self.scopes[-1][name] = value
def evaluate_expression(self, expr):
"""Evaluate an expression and return its value"""
if isinstance(expr, (int, float, bool)):
return expr
if isinstance(expr, str):
try:
return self.get_variable(expr)
except RuntimeError:
# If it's not found as a variable, treat it as a string literal
if expr in self.builtins:
return self.builtins[expr]
return expr
if isinstance(expr, dict):
# ... rest of complex expression handling remains the same ...
pass
return expr
def execute_enumerate_loop(self, loop_stmt):
"""Execute an enumerate loop with proper variable scoping"""
index_var = loop_stmt['index']
value_var = loop_stmt['element']
iterable_name = loop_stmt['iterable']
iterable = self.get_variable(iterable_name)
if not hasattr(iterable, '__iter__'):
raise RuntimeError(f"{iterable_name} is not a collection we can enumerate")
self.explain_print("LOOP", f"Starting an enumerate loop over {iterable_name}")
self.explain_print("INFO", f"Total number of items to process: {len(iterable)}")
self.indent_level += 1
self.push_scope() # Create new scope for loop variables
try:
for i, value in enumerate(iterable):
self.set_variable(index_var, i)
self.set_variable(value_var, value)
if self.explain_mode:
if i < self.max_iterations_shown:
self.explain_print("ITERATION",
f"Loop #{i + 1}: {index_var} = {i}, {value_var} = {value}")
elif i == self.max_iterations_shown:
remaining = len(iterable) - self.max_iterations_shown
self.explain_print("INFO",
f"... {remaining} more iterations will be processed ...")
for statement in loop_stmt['body']:
result = self.execute_statement(statement)
if isinstance(result, dict) and result.get('type') == 'return':
return result
finally:
self.pop_scope() # Always clean up the scope
self.indent_level -= 1
if self.explain_mode:
self.explain_print("COMPLETE", f"Loop finished after processing {len(iterable)} items")
Test Cases
Basic undefined variable access
Enumerate loop variable scope
String literal handling
Built-in function access
Nested scope handling
Impact
This change will improve error messaging and catch programming errors earlier in the development process.
Description
The ThinkPy interpreter currently fails silently when accessing undefined variables in certain contexts, particularly within enumerate loops. Instead of raising an error, it treats undefined variable names as string literals, leading to confusing runtime errors.
Current Behavior
Currently produces a
TypeError: list indices must be integers or slices, not str
becauseindex
is treated as a string literal rather than raising an undefined variable error.Expected Behavior
The interpreter should raise a clear
RuntimeError: Undefined variable: index
when attempting to access undefined variables.Proposed Solution
Implement proper variable scoping in the interpreter:
Implementation Details
Test Cases
Impact
This change will improve error messaging and catch programming errors earlier in the development process.