#pragma warning disable 168 using System; namespace System { public extension Event { public implicit void operator+=(T action) mut { Add(action); } public implicit void operator-=(T action) mut { Remove(action, true); } } } namespace Tests { class Operators { struct FlagsRegister { public bool zero; public bool subtract; public bool half_carry; public bool carry; const uint8 ZERO_FLAG_BYTE_POSITION = 7; const uint8 SUBTRACT_FLAG_BYTE_POSITION = 6; const uint8 HALF_CARRY_FLAG_BYTE_POSITION = 5; const uint8 CARRY_FLAG_BYTE_POSITION = 4; public this(bool z, bool s, bool hc, bool c) { zero = z; subtract = s; half_carry = hc; carry = c; } //Convert flag register to a uint8 public static implicit operator uint8 (FlagsRegister flag) { return (flag.zero ? 1 : 0) << ZERO_FLAG_BYTE_POSITION | (flag.subtract ? 1 : 0) << SUBTRACT_FLAG_BYTE_POSITION | (flag.half_carry ? 1 : 0) << HALF_CARRY_FLAG_BYTE_POSITION | (flag.carry ? 1 : 0) << CARRY_FLAG_BYTE_POSITION; }; } struct StructA { public int mA; public static StructA operator+(StructA lhs, StructA rhs) { StructA res; res.mA = lhs.mA + rhs.mA; return res; } public static StructA operator-(StructA lhs, StructA rhs) { StructA res; res.mA = lhs.mA - rhs.mA; return res; } public static StructA operator++(StructA val) { StructA newVal; newVal.mA = val.mA + 1; return newVal; } [Commutable] public static bool operator<(StructA lhs, StructB rhs) { return lhs.mA < rhs.mB; } } struct StructB { public int mB; public static StructA operator+(StructA sa, StructB sb) { StructA result; result.mA = sa.mA + sb.mB + 1000; return result; } public void operator++() mut { mB++; } } struct StructC { public int mA; public int mB; public this(int a, int b) { mA = a; mB = b; } public static bool operator==(StructC lhs, StructC rhs) { return lhs.mA == rhs.mA; } } struct StructD { int mVal; public this(int val) { mVal = val; } public static implicit operator int(StructD x) { return x.mVal; } public static implicit operator StructD(int x) { return default(StructD); } } struct StructE { float mVal; public this(float val) { mVal = val; } public static implicit operator float(StructE x) { return x.mVal; } public static implicit operator StructE(float x) { return .(x); } public static StructE operator+(StructE lhs, StructE rhs) { return .(1); } public static int operator+(StructE lhs, int rhs) { return 2; } public static int operator+(int lhs, StructE rhs) { return 3; } } struct StructF { public static int operator+(StructF lhs, int rhs) { return 1; } public static int operator+(int lhs, StructF rhs) { return 2; } [Commutable] public static int operator+(StructF lhs, float rhs) { return 3; } } struct StructG : this(int a) { public static StructG operator+(ref StructG lhs, ref StructG rhs) { lhs.a += 1000; rhs.a += 1000; return .(lhs.a + rhs.a); } public static StructG operator-(ref StructG val) { val.a += 1000; return val; } public static implicit operator int(ref StructG val) { return val.a; } } struct StructH { public static int operator+(StructH lhs, int rhs) { return 1; } public static int operator+(int lhs, StructH rhs) { return 2; } [Commutable] public static int operator+(StructH lhs, float rhs) { return 3; } public static int operator&+(StructH lhs, int rhs) { return 4; } public static int operator&+(int lhs, StructH rhs) { return 5; } [Commutable] public static int operator&+(StructH lhs, float rhs) { return 6; } } struct StructOp where T : operator T + T2 { public T DoIt(T val, T2 val2) { return val + val2; } } struct StructOp2 { public T mVal; public static T operator+(StructOp2 lhs, T2 rhs) where T : operator T + T2 { return lhs.mVal + rhs; } public static T operator|(StructOp2 lhs, T2 rhs) where T : operator implicit T2 { T temp = rhs; return temp; } public T GetNeg(T2 val) where T : operator -T2 { return -val; } public T GetInt() where T : Int32 { return mVal; } } enum MyEnum { Case0, Case1, Case2, Case3 } enum MyOtherEnum { case Zero; case One; case Two; case Three; public static explicit operator MyEnum(Self self) { return .Case1; } } struct StructI : int32 { public static int8 operator implicit(Self self) { return 12; } public static int16 operator implicit(Self self) { return 23; } } struct StructJ { public int mVal; public static int8 operator implicit(Self self) { return 12; } public static int16 operator implicit(Self self) { return 23; } public static int32 operator explicit(Self self) { return 34; } public static Self operator explicit(int8 val) { return .(){mVal = 45}; } public static Self operator implicit(int16 val) { return .(){mVal = 56}; } public static Self operator implicit(int32 val) { return .(){mVal = 67}; } } struct StructK : uint64 { public static T operator implicit(Self self) where T : operator explicit uint64 { return (.)(uint64)self; } } /*struct OuterOp { public struct InnerOp where T : operator T + T2 where T : operator -T where T : operator implicit T2 { public static T Op(T val, T2 val2) { return val + val2; } public static T Neg(T val) { return -val; } public static T Cast(T2 val) { return val; } struct InnerOp2 { public static T Op(T val, T2 val2) { return val + val2; } public static T Neg(T val) { return -val; } public static T Cast(T2 val) { return val; } } struct InnerOp3 { public static T Op(T val, T2 val2) { return val + val2; } public static T Neg(T val) { return -val; } public static T Cast(T2 val) { return val; } } } } struct OuterOp2 { public struct InnerOp { } extension InnerOp where T : operator T + T2 where T : operator -T { public static T Op(T val, T2 val2) { return val + val2; } public static T Neg(T val) { return -val; } } }*/ public static T Op(T val, T2 val2) where T : operator T + T2 { return val + val2; } public static T Complex(T val, T2 val2, T3 val3) where T : operator -T where T : operator implicit T2 where T : operator T + T2 where int32 : operator T + T3 { T conv = val2; T result = val + val2; result = -result; int32 iRes = val + val3; return result; } struct StructOp3 where float : operator T + T2 { public float Use(T lhs, T2 rhs) { float f = lhs + rhs; return f; } } public struct Vector2 : this(float x, float y); public static Event sEvent ~ _.Dispose(); // Workaround for the lack of auto-destructor in properties public static ref Event EventProp { get => ref sEvent; set => sEvent = value; }; static int sA = 123; public static ref int RefVal => ref sA; public static int Val { get { return sA; } set { sA = value; } } [Test] public static void TestBasics() { StructA sa0 = default; sa0.mA = 1; StructA sa1 = default; sa1.mA = 2; StructA sa2 = sa0 + sa1; Test.Assert(sa2.mA == 3); StructB sb0; sb0.mB = 11; StructB sb1; sb1.mB = 12; Test.Assert(sa1 < sb0); Test.Assert(!(sa1 >= sb0)); Test.Assert(sb0 > sa1); Test.Assert(!(sb0 <= sa1)); StructA sa3 = sa0 + sb0; Test.Assert(sa3.mA == 1012); StructA sa4 = Op(sa0, sb0); Test.Assert(sa4.mA == 1012); StructA sa6 = sa0++; Test.Assert(sa0.mA == 2); Test.Assert(sa6.mA == 1); sa6 = ++sa0; Test.Assert(sa0.mA == 3); Test.Assert(sa6.mA == 3); StructB sb6 = sb0++; Test.Assert(sb0.mB == 12); Test.Assert(sb6.mB == 11); sb6 = ++sb0; Test.Assert(sb0.mB == 13); Test.Assert(sb6.mB == 13); float val = Op((int32)100, (int16)23); Test.Assert(val == 123); int32 i32res = Complex((int32)100, (int16)23, (int8)4); Test.Assert(i32res == -123); StructOp sOp; let sa5 = sOp.DoIt(sa1, sb1); Test.Assert(sa5.mA == 1014); StructOp2 sOp2; sOp2.mVal = 100; int32 res6 = sOp2 + (int16)40; Test.Assert(res6 == 140); int32 res7 = sOp2.GetInt(); Test.Assert(res7 == 100); Result rsc = .Ok(.(123, 234)); Result rsc2 = .Ok(.(123, 345)); Test.Assert(rsc == rsc2); Test.Assert(rsc !== rsc2); StructOp3 so3 = .(); float f = so3.Use(1, 2); Test.Assert(f == 3); FlagsRegister fr = .(true, false, true, true); Test.Assert(fr == (uint8)0b10110000); StructD sd = .(9); Test.Assert(sd + 10 == 19); Test.Assert(10 + sd == 19); StructE se = .(9); Test.Assert(se + 10 == 2); Test.Assert(10 + se == 3); Test.Assert(se + 1.2f == 1); Test.Assert(1.2f + se == 1); StructF sf = default; Test.Assert(sf + 10 == 1); Test.Assert(10 + sf == 2); Test.Assert(sf + 1.0f == 3); Test.Assert(2.0f + sf == 3); Test.Assert(sf &+ 10 == 1); Test.Assert(10 &+ sf == 2); Test.Assert(sf &+ 1.0f == 3); Test.Assert(2.0f &+ sf == 3); StructH sh = default; Test.Assert(sh + 10 == 1); Test.Assert(10 + sh == 2); Test.Assert(sh + 1.0f == 3); Test.Assert(2.0f + sh == 3); Test.Assert(sh &+ 10 == 4); Test.Assert(10 &+ sh == 5); Test.Assert(sh &+ 1.0f == 6); Test.Assert(2.0f &+ sh == 6); StructG sg = .(100); StructG sg2 = .(200); var sg3 = sg + sg2; var sg4 = -sg3; Test.Assert(sg.a == 1100); Test.Assert(sg2.a == 1200); Test.Assert(sg3.a == 3300); Test.Assert(sg4.a == 3300); /*let oai = OuterOp.InnerOp.Op(1.0f, 100); Test.Assert(oai == 101.0f); let oai2 = OuterOp2.InnerOp.Op(2.0f, 200); Test.Assert(oai2 == 202.0f);*/ const int c0 = 1; const int32 c1 = 1; int i0 = 0; var tVal = Vector2((i0 % c0) * (c1 + c1), 1); int8 a = 123; int32 b = a + 100; Test.Assert(b == 223); MyOtherEnum moe = .Zero; MyEnum me = (MyEnum)moe; Test.Assert(me == .Case1); Test.Assert(moe == 0); moe = .Two; int32 i = (int32)moe; Test.Assert(i == 2); uint32 u = (uint32)moe; Test.Assert(u == 2); // { StructI si = (.)123; int32 i32i = si; int32 i32e = (int32)si; int16 i16i = si; int16 i16e = (int16)si; int8 i8i = si; int8 i8e = (int8)si; float fi = si; float fe = (float)si; Test.Assert(i32i == 23); Test.Assert(i32e == 123); Test.Assert(i16i == 23); Test.Assert(i16e == 23); Test.Assert(i8i == 12); Test.Assert(i8e == 12); Test.Assert(fi == 23); Test.Assert(fe == 123); } /// { StructJ sj = default; int32 i32i = sj; int32 i32e = (int32)sj; int16 i16i = sj; int16 i16e = (int16)sj; int8 i8i = sj; int8 i8e = (int8)sj; float fi = sj; float fe = (float)sj; StructJ sji32i = i32i; StructJ sji32e = (.)i32e; StructJ sji16i = i16i; StructJ sji16e = (.)i16e; StructJ sji8i = i8i; StructJ sji8e = (.)i8e; Test.Assert(i32i == 23); Test.Assert(i32e == 34); Test.Assert(i16i == 23); Test.Assert(i16e == 23); Test.Assert(i8i == 12); Test.Assert(i8e == 12); Test.Assert(fi == 23); Test.Assert(fe == 34); Test.Assert(sji32i.mVal == 67); Test.Assert(sji32e.mVal == 67); Test.Assert(sji16i.mVal == 56); Test.Assert(sji16e.mVal == 56); Test.Assert(sji8i.mVal == 56); Test.Assert(sji8e.mVal == 45); } StructK sk = (.)123; uint64 sku32 = sk; Test.Assert(sku32 == 123); int val2 = 10; void Set() { val2 += 200; } EventProp += new => Set; EventProp(); Test.Assert(val2 == 210); RefVal += 99; Test.Assert(sA == 222); Val += 1000; Test.Assert(sA == 1222); } struct IntStruct { public int mA = 123; public typealias ZaffInt = int; public ZaffInt GetIt() { return 123; } public static implicit operator int(Self val) { return val.mA; } public static implicit operator Self(int val) { IntStruct sVal; sVal.mA = val; return sVal; } public void operator++() mut { mA++; } } [Test] public static void TestCompareWithCastOperator() { IntStruct iVal = .(); Test.Assert(iVal == 123); Test.Assert(iVal == 123.0f); var iVal2 = iVal++; var iVal3 = ++iVal; ++iVal; Test.Assert(iVal == 126); Test.Assert(iVal2 == 123); Test.Assert(iVal3 == 125); } const String cStrD = "D"; const char8* cStrPD = "D"; public static void TestDefaults(StringView sv = "ABC", IntStruct intStruct = 123) { Test.Assert(sv == "ABC"); Test.Assert(intStruct.mA == 123); } [Test] public static void TestStringOp() { const String cStr1 = "A" + "B"; const String cStr2 = cStr1 + "C" + cStrD; Test.Assert(cStr2 == "ABCD"); Test.Assert(cStr2 === "ABCD"); const char8* cStr3 = "A" + "B"; const char8* cStr4 = cStr1 + "C" + cStrPD; Test.Assert(StringView(cStr4) == "ABCD"); TestDefaults(); String strA = scope String("ABCD"); Test.Assert(strA == cStr2); Test.Assert(strA !== cStr1); let strTup = (strA, strA); Test.Assert(strTup == (cStr2, cStr2)); Test.Assert(strTup !== (cStr2, cStr2)); } public static TTo Convert(TFrom val) where TTo : operator explicit TFrom { return (TTo)val; } [Test] public static void TestConversion() { int a = 123; float f = Convert(a); } } }