### ----------------------------------------------------
### -- Red
### -- Licenses: Artistic-2.0
### -- Authors: Fernando Correa de Oliveira
### -- File: lib/Red/Operators.rakumod
### ----------------------------------------------------
### -- Chunk 1 of 2
use Red::AST;
use Red::AST::Infixes;
use Red::AST::Divisible;
use Red::AST::Value;
use Red::ResultSeq;

=head2 Red::Operators

unit module Red::Operators;

sub __RED_OPERATOR_LOADED__ is export { True }

# TODO: Diferenciate prefix and postfix
#| --X
multi prefix:<-->(Red::Column $a) is export {
    @*UPDATE.push: $a => Red::AST::Sub.new: $a, ast-value 1;
    $a
}

#| ++X
multi prefix:<++>(Red::Column $a) is export {
    @*UPDATE.push: $a => Red::AST::Sum.new: $a, ast-value 1;
    $a
}

#| X--
multi postfix:<-->(Red::Column $a) is export {
    @*UPDATE.push: $a => Red::AST::Sub.new: $a, ast-value 1;
    $a
}

#| X++
multi postfix:<++>(Red::AST $a) is export {
    @*UPDATE.push: $a => Red::AST::Sum.new: $a, ast-value 1;
    $a
}

#| -X
multi prefix:<->(Red::AST $a) is export {
    Red::AST::Mul.new: ast-value(-1), $a
}

#| +X
multi prefix:<+>(Red::AST $a) is export {
    Red::AST::Mul.new: ast-value(1), $a
}

#| X + Y
multi infix:<+>(Red::AST $a, Red::AST $b) is export {
    Red::AST::Sum.new: $a, $b
}

#| X + Y # Where Y is castable to Numeric
multi infix:<+>(Red::AST $a, Numeric() $b) is export {
    Red::AST::Sum.new: $a, ast-value $b
}

#| X + Y # Where X is castable to Numeric
multi infix:<+>(Numeric() $a, Red::AST $b) is export {
    Red::AST::Sum.new: ast-value($a), $b
}

#| X - Y
multi infix:<->(Red::AST $a, Red::AST $b) is export {
    Red::AST::Sub.new: $a, $b
}

#| X - Y # Where Y is castable to Numeric
multi infix:<->(Red::AST $a, Numeric() $b) is export {
    Red::AST::Sub.new: $a, ast-value $b
}

#| X - Y # Where X is castable to Numeric
multi infix:<->(Numeric() $a, Red::AST $b) is export {
    Red::AST::Sub.new: ast-value($a), $b
}

#| X * Y
multi infix:<*>(Red::AST $a, Red::AST $b) is export {
    Red::AST::Mul.new: $a, $b
}

#| X * Y # Where Y is castable to Numeric
multi infix:<*>(Red::AST $a, Numeric() $b) is export {
    Red::AST::Mul.new: $a, ast-value $b
}

#| X * Y
multi infix:<*>(Numeric() $a, Red::AST $b) is export {
    Red::AST::Mul.new: ast-value($a), $b
}

#| X / Y
multi infix:</>(Red::AST $a, Red::AST $b) is export {
    Red::AST::Div.new: $a, $b
}

#| X / Y # Where Y is castable to Numeric and read only
multi infix:</>(Red::AST $a, Numeric() $b is readonly) is export {
    Red::AST::Div.new: $a, ast-value $b
}

#| X / Y # Where X is castable to Numeric and read only
multi infix:</>(Numeric() $a is readonly, Red::AST $b) is export {
    Red::AST::Div.new: ast-value($a), $b
}

#| X / Y # Where Y is castable to Numeric and writable
multi infix:</>(Red::AST $a, Numeric() $b is rw) is export {
    Red::AST::Div.new: $a, ast-value($b), :bind-right
}

#| X / Y # Where X is castable to Numeric and writable
multi infix:</>(Numeric() $a is rw, Red::AST $b) is export {
    Red::AST::Div.new: ast-value($a), $b, :bind-left
}


#| X div Y
multi infix:<div>(Red::AST $a, Red::AST $b) is export {
    Red::AST::IDiv.new: $a, $b
}

#| X div Y # Where Y is castable to Numeric and read only
multi infix:<div>(Red::AST $a, Numeric() $b is readonly) is export {
    Red::AST::IDiv.new: $a, ast-value $b
}

#| X div Y # Where X is castable to Numeric and read only
multi infix:<div>(Numeric() $a is readonly, Red::AST $b) is export {
    Red::AST::IDiv.new: ast-value($a), $b
}

#| X div Y # Where Y is castable to Numeric and writable
multi infix:<div>(Red::AST $a, Numeric() $b is rw) is export {
    Red::AST::IDiv.new: $a, ast-value($b), :bind-right
}

#| X div Y # Where X is castable to Numeric and writable
multi infix:<div>(Numeric() $a is rw, Red::AST $b) is export {
    Red::AST::IDiv.new: ast-value($a), $b, :bind-left
}

#| X eqv Y
multi infix:<eqv>(Red::AST $a, Red::AST $b) is export {
    Red::AST::Eq.new: $a, $b
}

multi infix:<eqv>(Red::AST $a, $b) is export {
    Red::AST::Eq.new: $a, ast-value($b)
}

multi infix:<eqv>($a, Red::AST $b) is export {
    Red::AST::Eq.new: ast-value($a), $b
}

#| X == Y
multi infix:<==>(Red::AST $a, Red::AST $b) is export {
    Red::AST::Eq.new: $a, $b, :cast<num>
}

#| X == Y # Where Y is castable to Numeric and writable
multi infix:<==>(Red::AST $a, Numeric(Str) $b is rw) is default is export {
    Red::AST::Eq.new: $a, ast-value($b), :cast<num>, :bind-right
}

#| X == Y # Where Y is castable to Numeric and read only
multi infix:<==>(Red::AST $a, Numeric(Str) $b is readonly) is default is export {
    Red::AST::Eq.new: $a, ast-value($b), :cast<num>
}

#| X == Y # Where Y is castable to Numeric and writable
multi infix:<==>(Red::AST $a, Numeric() $b is rw) is export {
    Red::AST::Eq.new: $a, ast-value($b), :cast<num>, :bind-right
}

#| X == Y # Where Y is castable to Numeric and read only
multi infix:<==>(Red::AST $a, Numeric() $b is readonly) is export {
    Red::AST::Eq.new: $a, ast-value($b), :cast<num>
}

#| X == Y # Where X is castable to Numeric and writable
multi infix:<==>(Numeric() $a is rw, Red::AST $b) is export {
    Red::AST::Eq.new: ast-value($a), $b, :cast<num>, :bind-left
}

#| X == Y # Where X is castable to Numeric and read only
multi infix:<==>(Numeric() $a is readonly, Red::AST $b) is export {
    Red::AST::Eq.new: ast-value($a), $b, :cast<num>
}

#| X == Y # Where X is castable to Numeric and read only
multi infix:<==>(Red::AST $a where .returns ~~ DateTime, Date $b) is export {
    Red::AST::Eq.new: $a.yyyy-mm-dd, ast-value($b), :cast<num>;
}

#| X == Y # Where LHS is AST and RHS is Enumeration
multi infix:<==>(Red::AST $a, Enumeration $b) is export {
    Red::AST::Eq.new: $a, ast-value($b.value), :cast<num>, :bind-right
}

#| X == Y # Where X is castable to Numeric and writable
multi infix:<==>(Enumeration $a, Red::AST $b) is export {
    Red::AST::Eq.new: ast-value($a), $b, :cast<num>, :bind-left
}

#| X != Y # Where Y is castable to Numeric and read only
multi infix:<!=>(Red::AST $a, Enumeration $b) is export {
    Red::AST::Ne.new: $a, ast-value($b), :cast<num>, :bind-right
}

#| X != Y # Where Y is castable to Numeric and read only
multi infix:<!=>(Red::AST $a, Numeric() $b is rw) is export {
    Red::AST::Ne.new: $a, ast-value($b), :cast<num>, :bind-right
}

#| X != Y # Where Y is castable to Numeric and read only
multi infix:<!=>(Red::AST $a, Numeric() $b is readonly) is export {
    Red::AST::Ne.new: $a, ast-value($b), :cast<num>
}

#| X != Y # Where X is castable to Numeric and writable
multi infix:<!=>(Numeric() $a is rw, Red::AST $b) is export {
    Red::AST::Ne.new: ast-value($a), $b, :cast<num>, :bind-left
}

#| X != Y # Where X is castable to Numeric and read only
multi infix:<!=>(Numeric() $a is readonly, Red::AST $b) is export {
    Red::AST::Ne.new: ast-value($a), $b, :cast<num>
}

#| X != Y # Where X is castable to Numeric and writable
multi infix:<!=>(Enumeration $a, Red::AST $b) is export {
    Red::AST::Ne.new: ast-value($a), $b, :cast<num>, :bind-left
}

#| X == Y
#multi infix:<==>(Red::AST $a, Red::AST $b) is export {
#    Red::AST::Eq.new: $a, $b, :cast<num>
#}

#| X == Y # Where Y is Date and writable
multi infix:<==>(Red::AST $a, Date $b is rw) is export {
    Red::AST::Eq.new: $a, ast-value($b), :cast<num>, :bind-right
}

#| X == Y # Where Y is Date and read only
multi infix:<==>(Red::AST $a, Date $b is readonly) is export {
    Red::AST::Eq.new: $a, ast-value($b), :cast<num>
}

#| X == Y # Where X is Date and writable
multi infix:<==>(Date $a is rw, Red::AST $b) is export {
    Red::AST::Eq.new: ast-value($a), $b, :cast<num>, :bind-left
}

#| X == Y # Where X is Date and read only
multi infix:<==>(Date $a is readonly, Red::AST $b) is export {
    Red::AST::Eq.new: ast-value($a), $b, :cast<num>
}

#| X != Y
multi infix:<!=>(Red::AST $a, Red::AST $b) is export {
    Red::AST::Ne.new: $a, $b, :cast<num>
}

#| X != Y # Where Y is Date and writable
multi infix:<!=>(Red::AST $a, Date $b is rw) is export {
    Red::AST::Ne.new: $a, ast-value($b), :cast<num>, :bind-right
}

#| X != Y # Where Y is Date and read only
multi infix:<!=>(Red::AST $a, Date $b is readonly) is export {
    Red::AST::Ne.new: $a, ast-value($b), :cast<num>
}

#| X != Y # Where X is Date and writable
multi infix:<!=>(Date $a is rw, Red::AST $b) is export {
    Red::AST::Ne.new: ast-value($a), $b, :cast<num>, :bind-left
}

#| X != Y # Where X is Date and read only
multi infix:<!=>(Date $a is readonly, Red::AST $b) is export {
    Red::AST::Ne.new: ast-value($a), $b, :cast<num>
}

#| X eq Y # Where Y is castable to Str and writable
multi infix:<eq>(Red::AST $a, Str() $b is rw) is export {
    Red::AST::Eq.new: $a, ast-value($b), :cast<str>, :bind-right
}

#| X eq Y # Where Y is castable to Str and read only
multi infix:<eq>(Red::AST $a, Str() $b is readonly) is export {
    Red::AST::Eq.new: $a, ast-value($b), :cast<str>
}

#| X eq Y # Where X is castable to Str and writable
multi infix:<eq>(Str() $a is rw, Red::AST $b) is export {
    Red::AST::Eq.new: ast-value($a), $b, :cast<str>, :bind-left
}

#| X eq Y # Where X is castable to Str and read only
multi infix:<eq>(Str() $a is readonly, Red::AST $b) is export {
    Red::AST::Eq.new: ast-value($a), $b, :cast<str>
}

#| X eq Y # Where Y is any Red::AST that returns a DateTime
multi infix:<eq>(Red::AST $a where .returns ~~ DateTime, Date $b) is export {
    Red::AST::Eq.new: $a.yyyy-mm-dd, ast-value($b), :cast<str>;
}

#| X eq Y # Where both are AST that returns Str
multi infix:<eq>(Red::AST $a where .returns ~~ Str, Red::AST $b where .returns ~~ Str) is export {
    Red::AST::Eq.new: $a, $b, :cast<str>;
}

#| X eq Y # Where LHS is an AST and RHS is Enumeration
multi infix:<eq>(Red::AST $a, Enumeration $b) is export {
    Red::AST::Eq.new: $a, ast-value($b.value), :cast<str>, :bind-right
}

multi infix:<eq>(Red::AST $a, Red::AST $b) is export {
    Red::AST::Eq.new: $a, $b, :cast<str>
}

#| X ne Y # Where Y is castable to Str and writable
multi infix:<ne>(Red::AST $a, Str() $b is rw) is export {
    Red::AST::Ne.new: $a, ast-value($b), :cast<str>, :bind-right
}

#| X ne Y # Where Y is castable to Str and read only
multi infix:<ne>(Red::AST $a, Str() $b is readonly) is export {
    Red::AST::Ne.new: $a, ast-value($b), :cast<str>
}

#| X ne Y # Where X is castable to Str and writable
multi infix:<ne>(Str() $a is rw, Red::AST $b) is export {
    Red::AST::Ne.new: ast-value($a), $b, :cast<str>, :bind-left
}

#| X ne Y # Where X is castable to Str and read only
multi infix:<ne>(Str() $a is readonly, Red::AST $b) is export {
    Red::AST::Ne.new: ast-value($a), $b, :cast<str>
}

#| X < Y # Where Y is any Red::AST that returns a Numeric
multi infix:<< < >>(Red::AST $a where .returns ~~ Numeric, Red::AST $b) is export is default {
    Red::AST::Lt.new: $a, $b, :cast<num>
}

#| X < Y # Where Y is castable to Numeric and writable
multi infix:<< < >>(Red::AST $a, Numeric() $b is rw) is export {
    Red::AST::Lt.new: $a, ast-value($b), :cast<num>, :bind-right
}

#| X < Y # Where Y is castable to Numeric and read only
multi infix:<< < >>(Red::AST $a, Numeric() $b is readonly) is export {
    Red::AST::Lt.new: $a, ast-value($b), :cast<num>
}

#| X < Y # Where X is castable to Numeric and writable
multi infix:<< < >>(Numeric() $a is rw, Red::AST $b) is export {
    Red::AST::Lt.new: ast-value($a), $b, :cast<num>, :bind-left
}

#| X < Y # Where X is castable to Numeric and read only
multi infix:<< < >>(Numeric() $a is readonly, Red::AST $b) is export {
    Red::AST::Lt.new: ast-value($a), $b, :cast<num>
}

#| X > Y # Where Y is any Red::AST that returns a Numeric
multi infix:<< > >>(Red::AST $a where .returns ~~ Numeric, Red::AST $b) is export is default {
    Red::AST::Gt.new: $a, $b, :cast<num>
}

#| X > Y # Where Y is castable to Numeric and writable
multi infix:<< > >>(Red::AST $a, Numeric() $b is rw) is export {
    Red::AST::Gt.new: $a, ast-value($b), :cast<num>, :bind-right
}

#| X > Y # Where Y is castable to Numeric and read only
multi infix:<< > >>(Red::AST $a, Numeric() $b is readonly) is export {
    Red::AST::Gt.new: $a, ast-value($b), :cast<num>
}

#| X > Y # Where X is castable to Numeric and writable
multi infix:<< > >>(Numeric() $a is rw, Red::AST $b) is export {
    Red::AST::Gt.new: ast-value($a), $b, :cast<num>, :bind-left
}

#| X > Y # Where X is castable to Numeric and read only
multi infix:<< > >>(Numeric() $a is readonly, Red::AST $b) is export {
    Red::AST::Gt.new: ast-value($a), $b, :cast<num>
}

#| X <= Y # Where Y is any Red::AST that returns a Numeric
multi infix:<< <= >>(Red::AST $a where .returns ~~ Numeric, Red::AST $b) is export is default {
    Red::AST::Le.new: $a, $b, :cast<num>
}

#| X <= Y # Where Y is castable to Numeric and read only
multi infix:<< <= >>(Red::AST $a, Numeric() $b is rw) is export {
    Red::AST::Le.new: $a, ast-value($b), :cast<num>, :bind-right
}

#| X <= Y # Where Y is castable to Numeric and read only
multi infix:<< <= >>(Red::AST $a, Numeric() $b is readonly) is export {
    Red::AST::Le.new: $a, ast-value($b), :cast<num>
}

#| X <= Y # Where X is castable to Numeric and writable
multi infix:<< <= >>(Numeric() $a is rw, Red::AST $b) is export {
    Red::AST::Le.new: ast-value($a), $b, :cast<num>, :bind-left
}

#| X <= Y # Where X is castable to Numeric and read only
multi infix:<< <= >>(Numeric() $a is readonly, Red::AST $b) is export {
    Red::AST::Le.new: ast-value($a), $b, :cast<num>
}

#| X >= Y # Where Y is any Red::AST that returns a Numeric
multi infix:<< >= >>(Red::AST $a where .returns ~~ Numeric, Red::AST $b) is export is default {
    Red::AST::Ge.new: $a, $b, :cast<num>
}

#| X >= Y # Where Y is castable to Numeric and writable
multi infix:<< >= >>(Red::AST $a, Numeric() $b is rw) is export {
    Red::AST::Ge.new: $a, ast-value($b), :cast<num>, :bind-right
}

#| X >= Y # Where Y is castable to Numeric and read only
multi infix:<< >= >>(Red::AST $a, Numeric() $b is readonly) is export {
    Red::AST::Ge.new: $a, ast-value($b), :cast<num>
}

#| X >= Y # Where X is castable to Numeric and writable
multi infix:<< >= >>(Numeric() $a is rw, Red::AST $b) is export {
    Red::AST::Ge.new: ast-value($a), $b, :cast<num>, :bind-left
}

#| X >= Y # Where X is castable to Numeric and read only
multi infix:<< >= >>(Numeric() $a is readonly, Red::AST $b) is export {
    Red::AST::Ge.new: ast-value($a), $b, :cast<num>
}

############################
#| X == Y # Where Y is castable to DateTime and writable
multi infix:<==>(Red::AST $a, DateTime() $b is rw) is export {
    Red::AST::Eq.new: $a, ast-value($b), :cast<datetime>, :bind-right
}

#| X == Y # Where Y is castable to DateTime and read only
multi infix:<==>(Red::AST $a, DateTime() $b is readonly) is export {
    Red::AST::Eq.new: $a, ast-value($b), :cast<datetime>
}

#| X == Y # Where X is castable to DateTime and writable
multi infix:<==>(DateTime() $a is rw, Red::AST $b) is export {
    Red::AST::Eq.new: ast-value($a), $b, :cast<datetime>, :bind-left
}

#| X == Y # Where X is castable to DateTime and read only
multi infix:<==>(DateTime() $a is readonly, Red::AST $b) is export {
    Red::AST::Eq.new: ast-value($a), $b, :cast<datetime>
}

#| X != Y # Where Y is castable to DateTime and read only
multi infix:<!=>(Red::AST $a, DateTime() $b is rw) is export {
    Red::AST::Ne.new: $a, ast-value($b), :cast<datetime>, :bind-right
}

#| X != Y # Where Y is castable to DateTime and read only
multi infix:<!=>(Red::AST $a, DateTime() $b is readonly) is export {
    Red::AST::Ne.new: $a, ast-value($b), :cast<datetime>
}

#| X != Y # Where X is castable to DateTime and writable
multi infix:<!=>(DateTime() $a is rw, Red::AST $b) is export {
    Red::AST::Ne.new: ast-value($a), $b, :cast<datetime>, :bind-left
}

#| X != Y # Where X is castable to DateTime and read only
multi infix:<!=>(DateTime() $a is readonly, Red::AST $b) is export {
    Red::AST::Ne.new: ast-value($a), $b, :cast<datetime>
}

#| X < Y # Where Y is any Red::AST that returns a DateTime
multi infix:<< < >>(Red::AST $a where .returns ~~ DateTime(), Red::AST $b) is export {
    Red::AST::Lt.new: $a, $b, :cast<datetime>
}

#| X < Y # Where Y is DateTime and writable
multi infix:<< < >>(Red::AST $a, DateTime() $b is rw) is export {
    Red::AST::Lt.new: $a, ast-value($b), :cast<datetime>, :bind-right
}

#| X < Y # Where Y is DateTime and read only
multi infix:<< < >>(Red::AST $a, DateTime() $b is readonly) is export {
    Red::AST::Lt.new: $a, ast-value($b), :cast<datetime>
}

#| X < Y # Where X is DateTime and writable
multi infix:<< < >>(DateTime() $a is rw, Red::AST $b) is export {
    Red::AST::Lt.new: ast-value($a), $b, :cast<datetime>, :bind-left
}

#| X < Y # Where X is DateTime and read only
multi infix:<< < >>(DateTime() $a is readonly, Red::AST $b) is export {
    Red::AST::Lt.new: ast-value($a), $b, :cast<datetime>
}

#| X > Y # Where Y is any Red::AST that returns a DateTime
multi infix:<< > >>(Red::AST $a where .returns ~~ DateTime, Red::AST $b) is export {
    Red::AST::Gt.new: $a, $b, :cast<datetime>
}

#| X > Y # Where Y is DateTime and writable
multi infix:<< > >>(Red::AST $a, DateTime() $b is rw) is export {
    Red::AST::Gt.new: $a, ast-value($b), :cast<datetime>, :bind-right
}

#| X > Y # Where Y is DateTime and read only
multi infix:<< > >>(Red::AST $a, DateTime() $b is readonly) is export {
    Red::AST::Gt.new: $a, ast-value($b), :cast<datetime>
}

#| X > Y # Where X is DateTime and writable
multi infix:<< > >>(DateTime() $a is rw, Red::AST $b) is export {
    Red::AST::Gt.new: ast-value($a), $b, :cast<datetime>, :bind-left
}

#| X > Y # Where X is DateTime and read only
multi infix:<< > >>(DateTime $a is readonly, Red::AST $b) is export {
    Red::AST::Gt.new: ast-value($a), $b, :cast<datetime>
}

#| X <= Y # Where Y is any Red::AST that returns a DateTime
multi infix:<< <= >>(Red::AST $a where .returns ~~ DateTime, Red::AST $b) is export {
    Red::AST::Le.new: $a, $b, :cast<datetime>
}

#| X <= Y # Where Y is DateTime and writable
multi infix:<< <= >>(Red::AST $a, DateTime() $b is rw) is export {
    Red::AST::Le.new: $a, ast-value($b), :cast<datetime>, :bind-right
}

#| X <= Y # Where Y is DateTime and read only
multi infix:<< <= >>(Red::AST $a, DateTime() $b is readonly) is export {
    Red::AST::Le.new: $a, ast-value($b), :cast<datetime>
}

#| X <= Y # Where X is DateTime and writable
multi infix:<< <= >>(DateTime $a is rw, Red::AST $b) is export {
    Red::AST::Le.new: ast-value($a), $b, :cast<datetime>, :bind-left
}

#| X <= Y # Where X is DateTime and read only
multi infix:<< <= >>(DateTime() $a is readonly, Red::AST $b) is export {
    Red::AST::Le.new: ast-value($a), $b, :cast<datetime>
}

#| X >= Y # Where Y is any Red::AST that returns a DateTime
multi infix:<< >= >>(Red::AST $a where .returns ~~ DateTime, Red::AST $b) is export {
    Red::AST::Ge.new: $a, $b, :cast<datetime>
}

#| X >= Y # Where Y is DateTime and writable
multi infix:<< >= >>(Red::AST $a, DateTime() $b is rw) is export {
    Red::AST::Ge.new: $a, ast-value($b), :cast<datetime>, :bind-right
}

#| X >= Y # Where Y is DateTime and read only
multi infix:<< >= >>(Red::AST $a, DateTime() $b is readonly) is export {
    Red::AST::Ge.new: $a, ast-value($b), :cast<datetime>
}

#| X >= Y # Where X is DateTime and writable
multi infix:<< >= >>(DateTime() $a is rw, Red::AST $b) is export {
    Red::AST::Ge.new: ast-value($a), $b, :cast<datetime>, :bind-left
}

#| X >= Y # Where X is DateTime and read only
multi infix:<< >= >>(DateTime() $a is readonly, Red::AST $b) is export {
    Red::AST::Ge.new: ast-value($a), $b, :cast<datetime>
}

############################

#| X == Y # Where Y is castable to Date and writable
multi infix:<==>(Red::AST $a, Date() $b is rw) is export {
    Red::AST::Eq.new: $a, ast-value($b), :cast<date>, :bind-right
}

#| X == Y # Where Y is castable to Date and read only
multi infix:<==>(Red::AST $a, Date() $b is readonly) is export {
    Red::AST::Eq.new: $a, ast-value($b), :cast<date>
}

#| X == Y # Where X is castable to Date and writable
multi infix:<==>(Date() $a is rw, Red::AST $b) is export {
    Red::AST::Eq.new: ast-value($a), $b, :cast<date>, :bind-left
}

#| X == Y # Where X is castable to Date and read only
multi infix:<==>(Date() $a is readonly, Red::AST $b) is export {
    Red::AST::Eq.new: ast-value($a), $b, :cast<date>
}

#| X != Y # Where Y is castable to Date and read only
multi infix:<!=>(Red::AST $a, Date() $b is rw) is export {
    Red::AST::Ne.new: $a, ast-value($b), :cast<date>, :bind-right
}

#| X != Y # Where Y is castable to Date and read only
multi infix:<!=>(Red::AST $a, Date() $b is readonly) is export {
    Red::AST::Ne.new: $a, ast-value($b), :cast<date>
}

#| X != Y # Where X is castable to Date and writable
multi infix:<!=>(Date() $a is rw, Red::AST $b) is export {
    Red::AST::Ne.new: ast-value($a), $b, :cast<date>, :bind-left
}

#| X != Y # Where X is castable to Date and read only
multi infix:<!=>(Date() $a is readonly, Red::AST $b) is export {
    Red::AST::Ne.new: ast-value($a), $b, :cast<date>
}

#| X < Y # Where Y is any Red::AST that returns a Date
multi infix:<< < >>(Red::AST $a where .returns ~~ Date, Red::AST $b) is export {
    Red::AST::Lt.new: $a, $b, :cast<date>
}

#| X < Y # Where Y is Date and writable
multi infix:<< < >>(Red::AST $a, Date $b is rw) is export {
    Red::AST::Lt.new: $a, ast-value($b), :cast<date>, :bind-right
}

#| X < Y # Where Y is Date and read only
multi infix:<< < >>(Red::AST $a, Date $b is readonly) is export {
    Red::AST::Lt.new: $a, ast-value($b), :cast<date>
}

#| X < Y # Where X is Date and writable
multi infix:<< < >>(Date $a is rw, Red::AST $b) is export {
    Red::AST::Lt.new: ast-value($a), $b, :cast<date>, :bind-left
}

#| X < Y # Where X is Date and read only
multi infix:<< < >>(Date $a is readonly, Red::AST $b) is export {
    Red::AST::Lt.new: ast-value($a), $b, :cast<date>
}

#| X > Y # Where Y is any Red::AST that returns a Date
multi infix:<< > >>(Red::AST $a where .returns ~~ Date, Red::AST $b) is export {
    Red::AST::Gt.new: $a, $b, :cast<date>
}

#| X > Y # Where Y is Date and writable
multi infix:<< > >>(Red::AST $a, Date $b is rw) is export {
    Red::AST::Gt.new: $a, ast-value($b), :cast<date>, :bind-right
}

#| X > Y # Where Y is Date and read only
multi infix:<< > >>(Red::AST $a, Date $b is readonly) is export {
    Red::AST::Gt.new: $a, ast-value($b), :cast<date>
}

#| X > Y # Where X is Date and writable
multi infix:<< > >>(Date $a is rw, Red::AST $b) is export {
    Red::AST::Gt.new: ast-value($a), $b, :cast<date>, :bind-left
}

#| X > Y # Where X is Date and read only
multi infix:<< > >>(Date $a is readonly, Red::AST $b) is export {
    Red::AST::Gt.new: ast-value($a), $b, :cast<date>
}

#| X <= Y # Where Y is any Red::AST that returns a Date
multi infix:<< <= >>(Red::AST $a where .returns ~~ Date, Red::AST $b) is export {
    Red::AST::Le.new: $a, $b, :cast<date>
}

#| X <= Y # Where Y is Date and writable
multi infix:<< <= >>(Red::AST $a, Date $b is rw) is export {
    Red::AST::Le.new: $a, ast-value($b), :cast<date>, :bind-right
}

#| X <= Y # Where Y is Date and read only
multi infix:<< <= >>(Red::AST $a, Date $b is readonly) is export {
    Red::AST::Le.new: $a, ast-value($b), :cast<date>
}

#| X <= Y # Where X is Date and read only
multi infix:<< <= >>(Date $a is rw, Red::AST $b) is export {
    Red::AST::Le.new: ast-value($a), $b, :cast<date>, :bind-left
}

#| X <= Y # Where X is Date and read only
multi infix:<< <= >>(Date $a is readonly, Red::AST $b) is export {
    Red::AST::Le.new: ast-value($a), $b, :cast<date>
}

#| X >= Y # Where Y is any Red::AST that returns a Date
multi infix:<< >= >>(Red::AST $a where .returns ~~ Date, Red::AST $b) is export {
    Red::AST::Ge.new: $a, $b, :cast<date>
}

#| X >= Y # Where Y is Date and writable
multi infix:<< >= >>(Red::AST $a, Date