codex/past-exam-of-the-computer-science-course-of-the-university-of-oxford/2015/compilers-2015-stack-links.py

past-exam-of-the-computer-science-course-of-the-university-of-oxford/2015/compilers-2015-stack-links.py
"""Draw the Oxford 2015 Compilers Q2 activation stack into the current directory.

Tested with Python 3.14.4, Matplotlib 3.10.7 (Debian 3.10.7+dfsg1),
and NumPy 2.3.5, using the dependencies declared in the root pyproject.toml.
"""

from pathlib import Path

import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch, Rectangle


def main():
    fig, ax = plt.subplots(figsize=(9.2, 6.8), dpi=140)
    fig.patch.set_facecolor("white")
    ax.set_facecolor("white")
    ax.set_xlim(-4.5, 4.5)
    ax.set_ylim(-0.7, 6.4)
    ax.axis("off")
    levels = {"main": 0.35, "p": 1.45, "r": 2.55, "s": 3.65, "q": 4.75}
    details = {"main": "oldest activation", "p": "t = 3, x = 3", "r": "", "s": "", "q": "y = 3; executing now"}
    for name, y in levels.items():
        ax.add_patch(Rectangle((-1.25, y - 0.38), 2.5, 0.76,
                               facecolor="#f0f5fa", edgecolor="#263746", linewidth=1.4))
        ax.text(0, y + (0.13 if details[name] else 0), name,
                ha="center", va="center", fontsize=15, weight="bold")
        if details[name]:
            ax.text(0, y - 0.15, details[name], ha="center", va="center", fontsize=10)
    dynamic = [("q", "s"), ("s", "r"), ("r", "p"), ("p", "main")]
    static = [("q", "p"), ("s", "r"), ("r", "p"), ("p", "main")]
    for source, target in dynamic:
        y1, y2 = levels[source], levels[target]
        route = f"angle,angleA=180,angleB=180,rad=0"
        arrow = FancyArrowPatch((-1.25, y1), (-1.25, y2),
                                connectionstyle="arc3,rad=0.8", arrowstyle="-|>",
                                mutation_scale=14, color="#1763a4", linewidth=1.8)
        ax.add_patch(arrow)
    for source, target in static:
        y1, y2 = levels[source], levels[target]
        rad = -0.82 if source == "q" else -0.62
        ax.add_patch(FancyArrowPatch((1.25, y1), (1.25, y2),
                                    connectionstyle=f"arc3,rad={rad}", arrowstyle="-|>",
                                    mutation_scale=14, color="#ae4c20", linewidth=1.8))
    ax.text(-2.8, 5.65, "Dynamic links", color="#1763a4", ha="center", fontsize=14, weight="bold")
    ax.text(-2.8, 5.31, "caller", color="#1763a4", ha="center", fontsize=11)
    ax.text(2.8, 5.65, "Static links", color="#ae4c20", ha="center", fontsize=14, weight="bold")
    ax.text(2.8, 5.31, "lexically enclosing activation", color="#ae4c20", ha="center", fontsize=10)
    ax.text(0, 6.1, "Activation stack while q executes", ha="center", fontsize=16, weight="bold")
    ax.text(-2.75, 2.55, "q → s → r → p → main", rotation=90,
            ha="center", va="center", fontsize=11, color="#1763a4")
    ax.text(3.4, 3.05, "q → p", rotation=90, ha="center", va="center", fontsize=11, color="#ae4c20")
    ax.text(0, -0.38, "main has null caller and enclosing-frame links", ha="center", fontsize=10)
    fig.subplots_adjust(left=0.025, right=0.975, bottom=0.035, top=0.975)
    fig.savefig(Path.cwd() / "compilers-2015-stack-links.png", facecolor="white",
                metadata={"Software": "Matplotlib"})
    plt.close(fig)


if __name__ == "__main__":
    main()