# 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
from dataclasses import dataclass
from typing import List
@dataclass
class Ctor:
symbol: str
subterms: List['Term']
Term = Ctor
def is_variable(t: Term) -> bool:
"""Check if a term represents a variable (begins with uppercase letter)."""
return isinstance(t, Ctor) and t.symbol.isupper()
def is_decoration(t: Term) -> bool:
return isinstance(t, Ctor) and t.symbol.startswith('*')
def render_term(t: Term) -> str:
if isinstance(t, Ctor):
if t.subterms:
return "{}({})".format(t.symbol, ', '.join([render_term(st) for st in t.subterms]))
else:
return t.symbol
else:
raise NotImplementedError(str(t))
def terms_equal(term1: Term, term2: Term) -> bool:
if not isinstance(term1, Ctor) or not isinstance(term2, Ctor):
return False
if term1.symbol != term2.symbol:
return False
if term1.subterms is None and term2.subterms is None:
return True
if term1.subterms is None or term2.subterms is None:
return False
if len(term1.subterms) != len(term2.subterms):
return False
return all(terms_equal(sub1, sub2) for sub1, sub2 in zip(term1.subterms, term2.subterms))
def strip_decorators(term: Term) -> Term:
if not isinstance(term, Ctor):
return term
if is_decoration(term):
return strip_decorators(term.subterms[0])
elif term.subterms:
return Ctor(term.symbol, [strip_decorators(subterm) for subterm in term.subterms])
else:
return term