nac3-spec/toy-impl/lifetime.py

87 lines
2.6 KiB
Python

import ast
from type_def import PrimitiveType
from parse_expr import parse_expr
class Lifetime:
low: int
original: int
def __init__(self, scope):
self.low = self.original = scope
self.parent = None
def fold(self):
while self.parent is not None:
self.low = self.parent.low
self.original = self.parent.original
self.parent = self.parent.parent
return self
def ok(self, other):
self.fold()
if other == None:
return False
other.fold()
return self.low >= other.original and \
(other.original != self.low or self.low != 1)
def __str__(self):
self.fold()
return f'({self.low}, {self.original})'
def assign_expr(
scope: int,
sym_table: dict[str, Lifetime],
expr: ast.expr):
if isinstance(expr, ast.Expression):
body = expr.body
else:
body = expr
if isinstance(body.type, PrimitiveType):
body.lifetime = None
elif isinstance(body, ast.Attribute):
body.lifetime = assign_expr(scope, sym_table, body.value)
elif isinstance(body, ast.Subscript):
body.lifetime = assign_expr(scope, sym_table, body.value)
elif isinstance(body, ast.Name):
if body.id in sym_table:
body.lifetime = sym_table[body.id]
else:
body.lifetime = Lifetime(scope)
sym_table[body.id] = body.lifetime
else:
body.lifetime = Lifetime(scope)
return body.lifetime
def assign_stmt(
scope: int,
sym_table: dict[str, Lifetime],
nodes):
for node in nodes:
if isinstance(node, ast.Assign):
b = assign_expr(scope, sym_table, node.value)
for target in node.targets:
a = assign_expr(scope, sym_table, target)
if a == None and b == None:
continue
if not a.ok(b):
print(ast.unparse(node))
print(f'{a} <- {b}')
assert False
a.low = min(a.low, b.low)
a.original = max(a.original, b.original)
b.parent = a
elif isinstance(node, ast.If) or isinstance(node, ast.While):
assign_stmt(scope + 1, sym_table, node.body)
assign_stmt(scope + 1, sym_table, node.orelse)
elif isinstance(node, ast.Return):
a = assign_expr(scope, sym_table, node.value)
if a != None and a.fold().original > 1:
print(ast.unparse(node))
print(a)
assert False