git @ Cat's Eye Technologies Lome / master src / lome / checker.py
master

Tree @master (Download .tar.gz)

checker.py @masterraw · history · blame

# Copyright (c) 2025-2026, Chris Pressey, Cat's Eye Technologies.
# This file is distributed under a 2-clause BSD license.  See LICENSES/ dir.
# SPDX-License-Identifier: LicenseRef-BSD-2-Clause-X-Lome

import logging
from dataclasses import dataclass
from typing import List, Union

from .ast import Development, Theorem
from .reduce import ProofSystem, ReductionError, reduce_term
from .term import strip_decorators, terms_equal, render_term


logger = logging.getLogger(__name__)


@dataclass
class OK:
    pass


@dataclass
class Error:
    msg: str


def check_development(development: Development) -> List[Union[OK, Error]]:
    proof_system = ProofSystem()
    for rule in development.rules:
        proof_system.add_rule(rule)
    results = []
    for theorem in development.theorems:
        result = check_theorem(theorem, proof_system)
        results.append(result)
    return results


def check_theorem(theorem: Theorem, proof_system: ProofSystem) -> Union[OK, Error]:
    terms = theorem.terms
    if not terms:
        return Error("Proof has no terms")
    for i in range(1, len(terms)):
        prev_term = terms[i - 1]
        current_term = terms[i]
        try:
            reduced_prev = reduce_term(prev_term, proof_system)
            stripped_current = strip_decorators(current_term)
        except ReductionError as e:
            return Error(str(e))
        logger.debug("previous term: %s", render_term(prev_term))
        logger.debug("current term: %s", render_term(current_term))
        logger.debug("reduced previous: %s", render_term(reduced_prev))
        logger.debug("stripped current: %s", render_term(stripped_current))
        if not terms_equal(reduced_prev, stripped_current):
            return Error(
                f"Step {i+1} is invalid: {render_term(terms[i-1])} "
                f"does not lead to {render_term(terms[i])}"
            )
    if theorem.rule:
        proof_system.add_rule(theorem.rule)
    return OK()