[nem-en] Operator ??

Ivan A Eryshov ivan.eryshov at gmail.com
Fri Sep 29 12:03:44 CEST 2006


Hi Michal,

On 26/09/06, Michal Moskal <michal.moskal at gmail.com> wrote:
> As a general remark, it might not be the best idea to follow each and
> every rule. Especially that they are not designed with type inference
> in mind.

Ok. I skip rare cases and add option support. Here is the macro and testes:

// MACRO

namespace Nemerle.Core
{
  macro @?? (exprA, exprB)
  {
    def refEq = System.Type.ReferenceEquals;
    def ref3Eq = (t1,t2,t3) => refEq(t1, t2) || refEq(t1, t3);
    def tnullable = typeof (System.Nullable[_]);
    def toptNone = typeof (Nemerle.Core.option[_].None);
    def toptSome = typeof (Nemerle.Core.option[_].Some);

    def typer = Macros.ImplicitCTX ();
    def hA = typer.TypeExpr (exprA).Type.Hint;
    def hB = typer.TypeExpr (exprB).Type.Hint;
    def tx = (hA, hB);

    match (tx) {
      | (Some (Class (tiA, _)), Some (Class (tiB, _)))
        when tiA.IsValueType && refEq (tiA.SystemType, tnullable)
                && !refEq (tiB.SystemType, tnullable)
             || ref3Eq (tiA.SystemType, toptNone, toptSome)
                && !ref3Eq (tiB.SystemType, toptNone, toptSome) =>

          <[ if ($exprA.HasValue) $exprA.Value else $exprB ]>;

      | (Some (Class (tiA, _)), Some (Class (tiB, _)))
        when tiA.IsValueType && refEq (tiA.SystemType, tnullable)
                && refEq (tiB.SystemType, tnullable) =>

          <[ if ($exprA != null) $exprA else $exprB ]>;

      | (Some (Class (tiA, _)), Some (Class (tiB, _)))
        when ref3Eq (tiA.SystemType, toptNone, toptSome)
                && ref3Eq (tiB.SystemType, toptNone, toptSome) =>

          <[ if ($exprA.IsSome) $exprA else $exprB ]>;

      | (Some (Class (tiA, _)), Some (Class (_, _)))
        when tiA.IsValueType =>

          Message.FatalError (exprA.Location,
                              $"`$tiA' is not a reference or nullable type "
                              "as required by the `??' operator");

      | _ =>
          <[ if ($exprA != null) $exprA else $exprB ]>;
    }
  }
}

// TESTES

using System.Console;



def GetExprType['t] (_ : 't)
{
  typeof ('t)
}



def rn = null;
def r1 = "str1";
def r2 = "str2";

assert (rn ?? r2 == "str2");
assert (GetExprType(rn ?? r2).Equals (typeof (string)));
WriteLine($"$(rn ?? r2)");

assert (r1 ?? r2 == "str1");
assert (GetExprType(r1 ?? r2).Equals (typeof (string)));
WriteLine($"$(r1 ?? r2)");



def dn : double? = null;
def d1 : double? = 0.1;
def d2 : double? = 0.2;

assert ((dn ?? d2).Value == 0.2);
assert (GetExprType(dn ?? d2).Equals (typeof (double?)));
WriteLine($"$(dn ?? d2)");

assert ((d1 ?? d2).Value == 0.1);
assert (GetExprType(d1 ?? d2).Equals (typeof (double?)));
WriteLine($"$(d1 ?? d2)");

assert (dn ?? 0.3 == 0.3);
assert (GetExprType(dn ?? 0.3).Equals (typeof (double)));
WriteLine($"$(dn ?? 0.3)");

assert (d1 ?? 0.3 == 0.1);
assert (GetExprType(d1 ?? 0.3).Equals (typeof (double)));
WriteLine($"$(d1 ?? 0.3)");



def on = None();
def on2 = None();
def o1 = Some(1);
def o2 = Some(2);

assert ((on ?? o2).IsSome);
assert ((on ?? o2).Value == 2);
assert (GetExprType(on ?? o2).Equals (typeof (option[int])));
WriteLine($"$(on ?? o2)");

assert ((o1 ?? o2).Value == 1);
assert (GetExprType(o1 ?? o2).Equals (typeof (option[int].Some)));
WriteLine($"$(o1 ?? o2)");

assert (on ?? 3 == 3);
assert (GetExprType(on ?? 3).Equals (typeof (int)));
WriteLine($"$(on ?? 3)");

assert (o1 ?? 3 == 1);
assert (GetExprType(o1 ?? 3).Equals (typeof (int)));
WriteLine($"$(o1 ?? 3)");

assert ((on ?? on2).IsNone);
assert (GetExprType(on ?? on2).Equals (typeof (option[int].None)));
WriteLine($"$(on ?? on2)");


-- 
Best Regards,
  Ivan A Eryshov.

-= RSDN forever! =-



More information about the devel-en mailing list