22
33import operator
44from abc import ABC
5- from typing import TypeVar, Generic, overload, TYPE_CHECKING, TypeAlias
6- from spellbind.values import Value, OneToOneValue, Constant, SimpleVariable, TwoToOneValue, SelectValue
5+ from typing import TypeVar, Generic, overload, TYPE_CHECKING, TypeAlias, Callable, Iterable
6+
7+ from spellbind.values import Value, OneToOneValue, Constant, SimpleVariable, TwoToOneValue, \
8+ ManyToSameValue, ThreeToOneValue
79
810if TYPE_CHECKING:
911 from spellbind.float_values import FloatValue # pragma: no cover
1618BoolValueLike: TypeAlias = 'BoolValue | bool'
1719
1820_S = TypeVar('_S')
21+ _T = TypeVar('_T')
22+ _U = TypeVar('_U')
23+ _V = TypeVar('_V')
24+
1925
2026BoolLike = bool | Value[bool]
2127IntLike = int | Value[int]
2228FloatLike = float | Value[float]
2329StrLike = str | Value[str]
2430
2531
32+ def _select_function(b: bool, t: _S, f: _S) -> _S:
33+ if b:
34+ return t
35+ return f
36+
37+
2638class BoolValue(Value[bool], ABC):
39+ @property
2740 def logical_not(self) -> BoolValue:
2841 return NotBoolValue(self)
2942
3043 def __and__(self, other: BoolLike) -> BoolValue:
31- return AndBoolValues( self, other)
44+ return BoolValue.derive_from_many(all, self, other, is_associative=True )
3245
3346 def __rand__(self, other: bool) -> BoolValue:
34- return AndBoolValues( other, self)
47+ return BoolValue.derive_from_many(all, other, self, is_associative=True )
3548
3649 def __or__(self, other: BoolLike) -> BoolValue:
37- return OrBoolValues( self, other)
50+ return BoolValue.derive_from_many(any, self, other, is_associative=True )
3851
3952 def __ror__(self, other: bool) -> BoolValue:
40- return OrBoolValues( other, self)
53+ return BoolValue.derive_from_many(any, other, self, is_associative=True )
4154
4255 def __xor__(self, other: BoolLike) -> BoolValue:
43- return XorBoolValues( self, other)
56+ return BoolValue.derive_from_two(operator.xor, self, other)
4457
4558 def __rxor__(self, other: bool) -> BoolValue:
46- return XorBoolValues( other, self)
59+ return BoolValue.derive_from_two(operator.xor, other, self)
4760
4861 @overload
4962 def select(self, if_true: IntValueLike, if_false: IntValueLike) -> IntValue: ...
@@ -61,20 +74,50 @@ def select(self, if_true: BoolValue, if_false: BoolValue) -> BoolValue: ...
6174 def select(self, if_true: Value[_S] | _S, if_false: Value[_S] | _S) -> Value[_S]: ...
6275
6376 def select(self, if_true, if_false):
64- from spellbind.float_values import FloatValue, SelectFloatValue
65- from spellbind.int_values import IntValue, SelectIntValue
66- from spellbind.str_values import StrValue, SelectStrValue
77+ from spellbind.float_values import FloatValue
78+ from spellbind.int_values import IntValue
79+ from spellbind.str_values import StrValue
6780
6881 if isinstance(if_true, (FloatValue, float)) and isinstance(if_false, (FloatValue, float)):
69- return SelectFloatValue( self, if_true, if_false)
82+ return FloatValue.derive_from_three(_select_function, self, if_true, if_false)
7083 elif isinstance(if_true, (StrValue, str)) and isinstance(if_false, (StrValue, str)):
71- return SelectStrValue( self, if_true, if_false)
84+ return StrValue.derive_from_three(_select_function, self, if_true, if_false)
7285 elif isinstance(if_true, (BoolValue, bool)) and isinstance(if_false, (BoolValue, bool)):
73- return SelectBoolValue( self, if_true, if_false)
86+ return BoolValue.derive_from_three(_select_function, self, if_true, if_false)
7487 elif isinstance(if_true, (IntValue, int)) and isinstance(if_false, (IntValue, int)):
75- return SelectIntValue( self, if_true, if_false)
88+ return IntValue.derive_from_three(_select_function, self, if_true, if_false)
7689 else:
77- return SelectValue(self, if_true, if_false)
90+ return Value.derive_three_value(_select_function, self, if_true, if_false)
91+
92+ @classmethod
93+ def derive_from_two(cls, transformer: Callable[[bool, bool], bool],
94+ first: BoolLike, second: BoolLike) -> BoolValue:
95+ return Value.derive_from_two_with_factory(
96+ transformer,
97+ first, second,
98+ create_value=TwoToBoolValue.create,
99+ create_constant=BoolConstant.of,
100+ )
101+
102+ @classmethod
103+ def derive_from_three(cls, transformer: Callable[[_S, _T, _U], bool],
104+ first: _S | Value[_S], second: _T | Value[_T], third: _U | Value[_U]) -> BoolValue:
105+ return Value.derive_from_three_with_factory(
106+ transformer,
107+ first, second, third,
108+ create_value=ThreeToBoolValue.create,
109+ create_constant=BoolConstant.of,
110+ )
111+
112+ @classmethod
113+ def derive_from_many(cls, transformer: Callable[[Iterable[bool]], bool], *values: BoolLike, is_associative: bool = False) -> BoolValue:
114+ return Value.derive_from_many_with_factory(
115+ transformer,
116+ *values,
117+ create_value=ManyBoolToBoolValue.create,
118+ create_constant=BoolConstant.of,
119+ is_associative=is_associative,
120+ )
78121
79122
80123class OneToBoolValue(OneToOneValue[_S, bool], BoolValue, Generic[_S]):
@@ -86,32 +129,44 @@ def __init__(self, value: Value[bool]):
86129 super().__init__(operator.not_, value)
87130
88131
89- class AndBoolValues(TwoToOneValue[bool, bool, bool], BoolValue):
90- def __init__(self, left: BoolLike, right: BoolLike):
91- super().__init__(operator.and_, left, right)
132+ class ManyBoolToBoolValue(ManyToSameValue[bool], BoolValue):
133+ @staticmethod
134+ def create(transformer: Callable[[Iterable[bool]], bool], values: Iterable[BoolLike]) -> BoolValue:
135+ return ManyBoolToBoolValue(transformer, *values)
92136
93137
94- class OrBoolValues(TwoToOneValue[bool, bool, bool], BoolValue):
95- def __init__(self, left: BoolLike, right: BoolLike):
96- super().__init__(operator.or_, left, right)
138+ class BoolConstant(BoolValue, Constant[bool]):
139+ @classmethod
140+ def of(cls, value: bool) -> BoolConstant:
141+ if value:
142+ return TRUE
143+ return FALSE
97144
145+ @property
146+ def logical_not(self) -> BoolConstant:
147+ return BoolConstant.of(not self.value)
98148
99- class XorBoolValues(TwoToOneValue[bool, bool, bool], BoolValue):
100- def __init__ (self, left: BoolLike, right: BoolLike) :
101- super().__init__(operator.xor, left, right)
149+ @property
150+ def constant_value_or_raise (self) -> bool :
151+ return self.value
102152
103153
104- class BoolConstant(BoolValue, Constant [bool]):
154+ class BoolVariable(SimpleVariable [bool], BoolValue ):
105155 pass
106156
107157
108- class BoolVariable(SimpleVariable[bool], BoolValue):
109- pass
158+ class ThreeToBoolValue(ThreeToOneValue[_S, _T, _U, bool], BoolValue):
159+ @staticmethod
160+ def create(transformer: Callable[[_S, _T, _U], bool],
161+ first: _S | Value[_S], second: _T | Value[_T], third: _U | Value[_U]) -> BoolValue:
162+ return ThreeToBoolValue(transformer, first, second, third)
110163
111164
112- class SelectBoolValue(SelectValue[bool], BoolValue):
113- def __init__(self, condition: BoolLike, if_true: BoolLike, if_false: BoolLike):
114- super().__init__(condition, if_true, if_false)
165+ class TwoToBoolValue(TwoToOneValue[_S, _T, bool], BoolValue):
166+ @staticmethod
167+ def create(transformer: Callable[[_S, _T], bool],
168+ first: _S | Value[_S], second: _T | Value[_T]) -> BoolValue:
169+ return TwoToBoolValue(transformer, first, second)
115170
116171
117172TRUE = BoolConstant(True)
0 commit comments