Skip to content

Commit

Permalink
Implemented UnboundLocalError
Browse files Browse the repository at this point in the history
  • Loading branch information
yryuvraj committed Nov 7, 2023
1 parent 15a5388 commit 8b63969
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 1 deletion.
4 changes: 4 additions & 0 deletions src/interpreted/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ class Constant(Expression):
@dataclass
class Name(Expression):
value: str
ctx: Literal["load", "store"] # Added context


@dataclass
Expand All @@ -47,12 +48,14 @@ class Dict(Expression):
class Attribute(Expression):
value: Expression
attr: str
ctx: Literal["load", "store"]


@dataclass
class Subscript(Expression):
value: Expression
key: Expression
ctx: Literal["load", "store"]


@dataclass
Expand All @@ -73,6 +76,7 @@ class Call(Expression):
@dataclass
class Name(Expression):
id: str
ctx: Literal["load", "store"]


@dataclass
Expand Down
48 changes: 47 additions & 1 deletion src/interpreted/parser.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from __future__ import annotations
from _ast import FunctionDef

import ast
import sys
from keyword import iskeyword
from typing import Any

from interpreted.nodes import (
Assign,
Expand Down Expand Up @@ -686,7 +688,51 @@ def parse_literal(self) -> Expression:

raise ParseError(f"Unexpected token {self.peek().string!r}", self.index)


class ScopeConsistencyChecker(ast.NodeVisitor):
def __init__(self):
self.inconsistent_nodes = []
self.loaded_names = set()

def check_consistency(self, node, variable_name):
if isinstance(node.ctx, nodes.Store):
if variable_name in self.loaded_names:
self.inconsistent_nodes.append(node)

else:
self.loaded_names.add(variable_name)

def visit_Name(self, node):
self.check_consistency(node, node.id)
def visit_Name(self, node):
self.check_consistency(node, node._attributes)

class UnboundLocalErrorChecker(ast.NodeVisitor):

def __init__(self):
self.incosistent_nodes = []

def visit_scope(self, node):
checker = ScopeConsistencyChecker()
checker.visit(node)
self.incosistent_nodes.update(checker.inconsistent_nodes)

def visit_FunctionDef(self, node):
self.visit(node)

def visit_AsyncFunctionDef(self, node):
self.visit(node)

def visit_classDef(self, node):
self.visit(node)

# main driver code for UnboundLocalEerror checker
checker = UnboundLocalErrorChecker()
checker.vist(Module)
if checker.incosistent_nodes:
first_incon = checker.incosistent_nodes[0]
raise ParseError(first_incon.line, first_incon.column)


def assert_expressions_are_targets(expressions: list[Expression], index) -> None:
for target in expressions:
if not isinstance(target, (Name, Subscript)):
Expand Down

0 comments on commit 8b63969

Please sign in to comment.