tylisp/
ops.rs

1pub mod list;
2pub mod logic;
3pub mod rc;
4pub mod arith;
5#[cfg(feature = "const")] pub mod set;
6
7mod if_impl;
8pub use if_impl::{If,Cond};
9
10use crate::{LispId, engine::*};
11use typenum as tn;
12
13use std::default::Default;
14
15/// TyLisp operator that compares two values for identity
16///
17/// Accepts two parameters that both implement `LispId`.
18/// Returns `True` if both ids are equal and `False` otherwise.
19///
20/// Warning: the current implementation of `LispId` only considers
21/// the base type, so Foo<A> might compare equal to Foo<B>.
22/// This behavior is subject to change in the future.
23
24#[derive(Debug,Default)]
25pub struct Is;
26defun!{ Is {} }
27
28#[cfg(not(feature = "const"))]
29impl<L,R> FunCall< sexpr!{L, R} > for Is
30where L: LispId,
31      R: LispId,
32      L::Id: tn::IsEqual<R::Id>,
33      <L::Id as tn::IsEqual<R::Id>>::Output: Default,
34{
35    type Result = <L::Id as tn::IsEqual<R::Id>>::Output;
36}
37
38#[cfg(feature = "const")]
39impl<L,R> FunCall< sexpr!{L, R} > for Is
40where L:LispId,
41      R:LispId,
42      IdIsEqual<L::Id, R::Id>: AsTypeBool
43{
44    type Result = <IdIsEqual<L::Id, R::Id> as AsTypeBool>::TypeBool;
45}
46
47pub struct IdIsEqual<L,R>(std::marker::PhantomData<(L,R)>);
48
49#[cfg(feature = "const")]
50impl<const LID:u128, const RID:u128> AsTypeBool
51for IdIsEqual<crate::ConstId<LID>, crate::ConstId<RID>>
52where ConstBool<{LID == RID}>: AsTypeBool {
53    type TypeBool = <ConstBool<{LID == RID}> as AsTypeBool>::TypeBool;
54}
55
56pub trait AsTypeBool {
57    type TypeBool: tn::marker_traits::Bit;
58}
59
60impl AsTypeBool for ConstBool<true> {
61    type TypeBool = tn::True;
62}
63
64impl AsTypeBool for ConstBool<false> {
65    type TypeBool = tn::False;
66}
67
68pub struct ConstBool<const X:bool>;
69
70impl<T> FunCalc<T> for Is where Is: FunCall<T>, <Is as FunCall<T>>::Result: Default {
71    type Result = <Is as FunCall<T>>::Result;
72    #[inline(always)]
73    fn calc(self, _:T)->Self::Result { Default::default() }
74}
75
76#[derive(Debug,Default)]
77pub struct IsNot;
78defun_nocalc!{() IsNot {
79    (L,R) {_:L, _:R} => {logic::Not, {Is, @L, @R}};
80}}
81
82#[test]
83fn test_is() {
84    #[derive(Debug,Default)] struct A;
85    #[derive(Debug,Default)] struct B;
86    literal!{A; B}
87
88    let _: eval!{If, {Is, A, B}, A, B } = B;
89    let _: eval!{If, {Is, tn::True, tn::True}, A, B} = A;
90    let _: eval!{If, {Is, A, A}, A, B} = A;
91    let _: eval!{If, {Is, B, B}, A, B} = A;
92
93    fn assert_b<X:LispId>() where sexpr!{If, {Is, @X, B}, A, B}: Eval<Result = A> {
94    }
95
96    assert_b::<B>();
97}
98
99#[test]
100fn test_is_not() {
101    #[derive(Debug,Default)] struct A;
102    #[derive(Debug,Default)] struct B;
103    literal!{A; B}
104
105    let _: eval!{If, {IsNot, A, B}, A, B } = A;
106    let _: eval!{If, {IsNot, tn::True, tn::True}, A, B} = B;
107}
108
109#[test]
110fn test_partial() {
111    #[derive(Debug,Default)] struct A;
112    #[derive(Debug,Default)] struct B;
113    literal!{A; B}
114
115    let _: eval!{If, {{Partial, Is, A}, B}, A, B } = B;
116    let _: eval!{If, {Is, tn::True, tn::True}, A, B} = A;
117}
118/// Function that accepts any number of arguments and returns the first
119///
120/// Useful to specify a constant value where a function call is expected
121
122#[derive(Debug,Default)]
123pub struct Ret;
124literal!{Ret}
125
126impl Call for Ret { type Conv=cc::Func; }
127impl<T,U> FunCall < sexpr!{T; U} > for Ret {
128    type Result = T;
129}
130
131impl<T,U> FunCalc < sexpr!{T; U} > for Ret {
132    type Result = T;
133    fn calc(self, sexpr_pat!{x:T; _:U}: sexpr!{T; U})-> T {
134        x
135    }    
136}
137
138/// Constructs a partial evaluation of a tylisp function.
139///
140/// This allows you to capture some state inside a tylisp callable:
141/// ```raw
142/// {{Partial, Func, A, B}, C, D}
143/// ```
144/// is equivalent to:
145/// ```raw
146/// {Func, A, B, C, D}
147/// ```
148#[derive(Debug,Default)]
149pub struct Partial;
150defmacro!{Partial {
151    (Prefix) {; Prefix} => {Ret, @PartialImpl<Prefix>};
152}}
153impl<Prefix, QPrefix>
154SynCalc< Prefix, QPrefix > for Partial
155{
156    type Result = PartialImpl<Prefix>;
157    #[inline(always)]
158    fn syn_calc(self, _:QPrefix)->Self::Result {
159        PartialImpl(std::marker::PhantomData)
160    }
161}
162
163/// Tylisp macro to perform `evaĺ`-only calculations in a `calc` context
164///
165/// Takes one argument, which is evaluated in an `eval` context.
166/// Returns the evaluation result wrapped in a `PhantomData` object.
167#[derive(Debug,Default)]
168pub struct Phantom;
169defmacro!{Phantom {}}
170
171impl<Arg:Eval> SynCall<sexpr!{Arg}> for Phantom {
172    type Result = std::marker::PhantomData<Arg::Result>;
173}
174
175impl<Arg:Eval,QArg> SynCalc<sexpr!{Arg},QArg> for Phantom {
176    type Result = std::marker::PhantomData<Arg::Result>;
177    #[inline(always)]
178    fn syn_calc(self, _:QArg)->Self::Result { std::marker::PhantomData }
179}
180
181
182
183#[derive(Debug,Default)]
184pub struct Quote;
185defun_nocalc!{() Quote {
186    (Arg) {_:Arg} => {Ret, @crate::Quote<Arg>};
187}}
188
189
190#[derive(Debug)]
191pub struct PartialImpl<Prefix>(std::marker::PhantomData<Prefix>);
192defun_nocalc!{(Prefix) PartialImpl<Prefix> {}}
193
194impl<T> Default for PartialImpl<T> {
195    #[inline(always)]
196    fn default()->Self { PartialImpl(std::marker::PhantomData) }
197}
198
199impl<T> From<()> for PartialImpl<T> {
200    #[inline(always)]
201    fn from(_:())->Self { Default::default() }
202}
203
204impl<Prefix, Tail> FunCall< Tail > for PartialImpl<Prefix>
205where sexpr!{list::Concat, @Prefix, {list::Map, Quote, @Tail}}: Eval,
206    eval!{list::Concat, @Prefix, {list::Map, Quote, @Tail}}: Eval
207{
208    type Result = <eval!{list::Concat, @Prefix, {list::Map, Quote, @Tail}} as Eval>::Result;
209}