# Copyright (c) PARRRATE T&V 2021. All rights reserved. from bu4.combinatory.lcombinatory import LCombinatory from bu4.combinatory.lic import LIC from bu4.combinatory.lkc import LKC from bu4.combinatory.lsc import LSC from bu4.linking.constructs.lcall import LCall from bu4.linking.constructs.ldelayed import LDelayed from bu4.linking.constructs.lexception import LException from bu4.linking.constructs.linked import Linked from bu4.linking.constructs.llambda import LLambda from bu4.linking.constructs.lname import LName from bu4.linking.constructs.lnull import LNull from bu4.transform.states.aftertransform import AfterTransform from bu4.transform.states.transformfinished import TransformFinished from bu4.transform.states.transformstart import TransformStart from bu4.transform.states.transformstate import TransformState from bu4.transform.targets.atlambda import ATLambda class LCCall(LCall, LCombinatory): def __init__(self, argument: LCombinatory, lambda_: LCombinatory): super().__init__(argument, lambda_) class LCNull(LNull, LCombinatory): pass class LCException(LException, LCombinatory): pass def is_kks(linked: Linked) -> bool: if not isinstance(linked, LCall): return False if not isinstance(linked.lambda_, LSC): return False linked = linked.argument if not isinstance(linked, LCall): return False if not isinstance(linked.argument, LKC): return False if not isinstance(linked.lambda_, LKC): return False return True def is_ikks(linked: Linked) -> bool: if not isinstance(linked, LCall): return False if not isinstance(linked.argument, LIC): return False return is_kks(linked.lambda_) def is_eta(linked: Linked) -> bool: if not isinstance(linked, LCall): return False if not isinstance(linked.argument, LKC): return False linked = linked.lambda_ if not isinstance(linked, LCall): return False if not isinstance(linked.lambda_, LSC): return False linked = linked.argument if not isinstance(linked, LCall): return False if not isinstance(linked.lambda_, LKC): return False linked = linked.argument if not isinstance(linked, LCall): return False if not isinstance(linked.argument, LIC): return False if not isinstance(linked.lambda_, LSC): return False return True def lccall(argument: Linked, lambda_: Linked) -> TransformState[Linked]: if isinstance(lambda_, LIC): return TransformFinished(argument) elif isinstance(argument, LKC) and isinstance(lambda_, LSC): return TransformFinished(LCCall(LIC(), LKC())) elif isinstance(lambda_, LCall) and isinstance(lambda_.lambda_, LKC): return TransformFinished(lambda_.argument) elif isinstance(argument, LIC) and is_kks(lambda_): return TransformFinished(LKC()) elif isinstance(lambda_, LCall) and is_eta(lambda_.lambda_): lcall = lambda_ return TransformStart(lambda: lccall(lcall.argument, argument)) elif isinstance(argument, LCombinatory) and isinstance(lambda_, LCombinatory): return TransformFinished(LCCall(argument, lambda_)) else: return TransformFinished(LCall.new(argument, lambda_)) def to_combinatory(linked: Linked) -> TransformState[Linked]: if isinstance(linked, LCombinatory): return TransformFinished(linked) elif is_ikks(linked): return TransformFinished(LKC()) elif isinstance(linked, LCall): lcall = linked return AfterTransform( TransformStart(lambda: to_combinatory(lcall.argument)), ATLambda( lambda argument: AfterTransform( TransformStart(lambda: to_combinatory(lcall.lambda_)), ATLambda( lambda lambda_: lccall(argument, lambda_) ) ) ) ) elif isinstance(linked, LDelayed): ldelayed = linked return AfterTransform( TransformStart(lambda: to_combinatory(ldelayed.value)), ATLambda( lambda value: lccall(value, LKC()) ) ) elif isinstance(linked, LLambda): llambda = linked if not llambda.used: return AfterTransform( TransformStart(lambda: to_combinatory(llambda.value)), ATLambda( lambda value: lccall(value, LKC()) ) ) elif isinstance(llambda.value, LName) and llambda.value.name == llambda.name: return TransformFinished(LIC()) elif isinstance(llambda.value, LCall): lcall = llambda.value return AfterTransform( TransformStart(lambda: to_combinatory(LLambda(llambda.name, lcall.argument))), ATLambda( lambda argument: AfterTransform( TransformStart(lambda: to_combinatory(LLambda(llambda.name, lcall.lambda_))), ATLambda( lambda lambda_: AfterTransform( lccall( lambda_, LSC() ), ATLambda( lambda combined: lccall( argument, combined ) ) ) ) ) ) ) else: return AfterTransform( TransformStart(lambda: to_combinatory(llambda.value)), ATLambda( lambda value: to_combinatory(LLambda(llambda.name, value)) ) ) elif isinstance(linked, LNull): return TransformFinished(LCNull()) elif isinstance(linked, LException): return TransformFinished(LCException(linked.name)) else: return TransformFinished(linked)