2021-05-11 22:07:10 +02:00
|
|
|
import sys
|
|
|
|
from collections import defaultdict
|
|
|
|
from typing import Dict, Callable, List, Final
|
|
|
|
from dataclasses import dataclass
|
2021-05-11 22:15:36 +02:00
|
|
|
from types import FrameType
|
2021-05-11 22:07:10 +02:00
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class ConstantValue:
|
2021-05-11 22:15:36 +02:00
|
|
|
frame: FrameType
|
2021-05-11 22:07:10 +02:00
|
|
|
name: str
|
|
|
|
value: object
|
|
|
|
|
2021-05-11 22:23:48 +02:00
|
|
|
def _traceFun(frame: FrameType, event: str, arg: object) -> None:
|
2021-05-11 22:07:10 +02:00
|
|
|
for constant in constMap[frame]:
|
|
|
|
if constant.name in frame.f_locals and frame.f_locals[constant.name] != constant.value:
|
|
|
|
frame.f_locals[constant.name] = constant.value
|
|
|
|
raise SyntaxError(f"Cannot assign value to constant {repr(constant.name)}")
|
|
|
|
|
|
|
|
class _ConstClass:
|
|
|
|
def __setattr__(self, name, value):
|
|
|
|
"""This is the method called when a new constant is created"""
|
|
|
|
targetFrame = sys._getframe(1)
|
|
|
|
targetFrame.f_trace_lines = False
|
|
|
|
targetFrame.f_trace_opcodes = True
|
|
|
|
targetFrame.f_trace = _traceFun
|
|
|
|
targetFrame.f_locals[name] = value
|
|
|
|
constMap[targetFrame].append(ConstantValue(targetFrame, name, value))
|
|
|
|
|
|
|
|
|
2021-05-11 22:15:36 +02:00
|
|
|
constMap: Dict[FrameType, List[ConstantValue]] = defaultdict(list) # FIXME
|
2021-05-11 22:07:10 +02:00
|
|
|
sys.settrace(lambda frame, event, arg: None)
|
|
|
|
const = _ConstClass()
|