﻿:: {v:v, g:g, s:s, b:b, d:d, t:t, n:n, r8:r8, r4:r4, i:i, i8:i8, i4:i4, i2:i2, i1:i1, u8:u8, u4:u4, u2:u2, u1:u1}

ToR4(g)
ToR4(s)

ToR4(v)
ToR4(b)
ToR4(d)
ToR4(t)
ToR4(n)
ToR4(r8)
ToR4(r4)
ToR4(i)
ToR4(i8)
ToR4(i4)
ToR4(i2)
ToR4(i1)
ToR4(u8)
ToR4(u4)
ToR4(u2)
ToR4(u1)

:: {o:o, qb:b?, qd:d?, qt:t?, qn:n?, qr8:r8?, qr4:r4?, qi:i?, qi8:i8?, qi4:i4?, qi2:i2?, qi1:i1?, qu8:u8?, qu4:u4?, qu2:u2?, qu1:u1?}

ToR4(o)
ToR4(qb)
ToR4(qd)
ToR4(qt)
ToR4(qn)
ToR4(qr8)
ToR4(qr4)
ToR4(qi)
ToR4(qi8)
ToR4(qi4)
ToR4(qi2)
ToR4(qi1)
ToR4(qu8)
ToR4(qu4)
ToR4(qu2)
ToR4(qu1)

:: {g:g, s:s, v:v, o:o, i:i, qi:i?, r4:r4, qr4:r4?}

ToR4(v)
ToR4(v, v)
ToR4(v, o)
ToR4(v, qi)
ToR4(v, i)

ToR4(i)
ToR4(i, v)
ToR4(i, o)
ToR4(i, qi)
ToR4(i, i)

ToR4(s)
ToR4(s, v)
ToR4(s, o)
ToR4(s, qi)
ToR4(s, i)

ToR4(o)
ToR4(o, v)
ToR4(o, o)
ToR4(o, qi)
ToR4(o, i)

ToR4(qi)
ToR4(qi, v)
ToR4(qi, o)
ToR4(qi, qi)
ToR4(qi, i)

To(g, g)
To(g, qr4)
To(g, r4)

To(v, qr4)
To(v, r4)
To(s, qr4)
To(s, r4)

To(o, qr4)
To(o, r4)

// Lifting.
:: {g:g*, v: v*, s:s*, b:b*, d:d*, n:n*, r8:r8*, r4:r4*, i:i*, i8:i8*, i4:i4*, i2:i2*, i1:i1*, u8:u8*, u4:u4*, u2:u2*, u1:u1*}

ToR4(g)
ToR4(s)

ToR4(v)
ToR4(b)
ToR4(d)
ToR4(n)
ToR4(r8)
ToR4(r4)
ToR4(i)
ToR4(i8)
ToR4(i4)
ToR4(i2)
ToR4(i1)
ToR4(u8)
ToR4(u4)
ToR4(u2)
ToR4(u1)

:: {o:o*, qb:b?*, qd:d?*, qn:n?*, qr8:r8?*, qr4:r4?*, qi:i?*, qi8:i8?*, qi4:i4?*, qi2:i2?*, qi1:i1?*, qu8:u8?*, qu4:u4?*, qu2:u2?*, qu1:u1?*}

ToR4(o)
ToR4(qb)
ToR4(qd)
ToR4(qn)
ToR4(qr8)
ToR4(qr4)
ToR4(qi)
ToR4(qi8)
ToR4(qi4)
ToR4(qi2)
ToR4(qi1)
ToR4(qu8)
ToR4(qu4)
ToR4(qu2)
ToR4(qu1)

// Integer boundaries

ToR4(false)
ToR4(true)

ToR4(-128i1)
ToR4(-32768i2)
ToR4(-2147483648i4)
ToR4(-9223372036854775808i8)

ToR4(255u1)
ToR4(65535u2)
ToR4(4294967295u4)
ToR4(18446744073709551615u8)

// There have been issues with converting integers to double and float. In particular, the standard BigInteger
// to double and float as well as the ulong to double and float are broken. The tests here mostly cover our
// custom implementation of BigInteger to double/float. The ulong to double/float implementation is covered in
// code gen (integer constants are stored as BigInteger during binding/reduction).

9_999_999_999_999_999->CastR8()->CastI8() // Should round up to 10^16.

// Cover u8 to r8.
0x8000_0000_0000_0000u8->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex)
0x8000_0000_0000_0400u8->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round down.
0x8000_0000_0000_0401u8->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round up.
0x8000_0000_0000_0800u8->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex)
0x8000_0000_0000_0BFFu8->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round down.
0x8000_0000_0000_0C00u8->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round up.

0xC123_4567_89AB_C000u8->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex)
0xC123_4567_89AB_C400u8->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round down.
0xC123_4567_89AB_C401u8->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round up.
0xC123_4567_89AB_C800u8->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex)
0xC123_4567_89AB_CBFFu8->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round down.
0xC123_4567_89AB_CC00u8->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round up.

0xFFFF_FFFF_FFFF_F800u8->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex)
0xFFFF_FFFF_FFFF_FBFFu8->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round down.
0xFFFF_FFFF_FFFF_FC00u8->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round up.
0xFFFF_FFFF_FFFF_FC00u8->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round up.
0xFFFF_FFFF_FFFF_FFFFu8->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round up.

// Cover u4 to r4. The standard conversion seems to work.
0x8000_0000u4->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex)
0x8000_0080u4->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round down.
0x8000_0081u4->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round up.
0x8000_0100u4->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex)
0x8000_017Fu4->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round down.
0x8000_0180u4->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round up.

// Cover u8 to r4.
0x8000_0000_0000_0000u8->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex)
0x8000_0080_0000_0000u8->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round down.
0x8000_0080_0000_0001u8->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round up.
0x8000_0100_0000_0000u8->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex)
0x8000_017F_FFFF_FFFFu8->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round down.
0x8000_0180_0000_0000u8->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round up.

// Cover ia to r8, just past u8 range.
0x1_0000_0000_0000_0000ia->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex)
0x1_0000_0000_0000_0800ia->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round down.
0x1_0000_0000_0000_0801ia->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round up.
0x1_0000_0000_0000_0900ia->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round up.
0x1_0000_0000_0000_1000ia->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex)
0x1_0000_0000_0000_17FFia->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round down.
0x1_0000_0000_0000_1800ia->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round up.

// Cover ia to r4, just past u8 range.
0x1_0000_0000_0000_0000ia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex)
0x1_0000_0100_0000_0000ia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round down.
0x1_0000_0100_0000_0001ia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round up.
0x1_0000_0101_0000_0000ia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round up.
0x1_0000_0180_0000_0000ia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round up.
0x1_0000_0200_0000_0000ia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex)
0x1_0000_02FF_FFFF_FFFFia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round down.
0x1_0000_0300_0000_0000ia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round up.

// Cover ia to r8, much larger than u8 range.
0x1_0000_0000_0000_0000_0000ia->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex)
0x1_0000_0000_0000_0800_0000ia->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round down.
0x1_0000_0000_0000_0800_0001ia->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round up.
0x1_0000_0000_0000_1000_0000ia->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex)
0x1_0000_0000_0000_17FF_FFFFia->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round down.
0x1_0000_0000_0000_1800_0000ia->(it.Hex, CastR8(it)->CastIA().Hex, CastR8(it).Bits.Hex) // Round up.

// Cover ia to r4, much larger than u8 range.
0x1_0000_0000_0000_0000_0000ia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex)
0x1_0000_0100_0000_0000_0000ia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round down.
0x1_0000_0100_0000_0000_0001ia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round up.
0x1_0000_0200_0000_0000_0000ia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex)
0x1_0000_02FF_FFFF_FFFF_FFFFia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round down.
0x1_0000_0300_0000_0000_0000ia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round up.

// Cover ia to r4, much larger than u8 range.
0x1_0000_0000_0000_0000_0000ia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex)
0x1_0000_0100_0000_0000_0000ia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round down.
0x1_0000_0100_0000_0000_0001ia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round up.
0x1_0000_0200_0000_0000_0000ia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex)
0x1_0000_02FF_FFFF_FFFF_FFFFia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round down.
0x1_0000_0300_0000_0000_0000ia->(it.Hex, CastR4(it)->CastIA().Hex, CastR4(it).Bits.Hex) // Round up.

// Cover ia to r8, near infinity.
(0x8000ia shl 48)->(it - 0x0000ia)->(it shl 961)->(it - 0)->(CastR8(it), CastR8(-it), CastR8(it).Bits.Hex, CastR8(it)->CastIA().Hex[:20] & "...", it.Hex) // Round up to infinity.
(0x8000ia shl 48)->(it - 0x0200ia)->(it shl 961)->(it - 0)->(CastR8(it), CastR8(-it), CastR8(it).Bits.Hex, CastR8(it)->CastIA().Hex[:20] & "...", it.Hex) // Round up to infinity.
(0x8000ia shl 48)->(it - 0x0200ia)->(it shl 961)->(it - 1)->(CastR8(it), CastR8(-it), CastR8(it).Bits.Hex, CastR8(it)->CastIA().Hex[:20] & "...", it.Hex) // Round down.
(0x8000ia shl 48)->(it - 0x0201ia)->(it shl 961)->(it - 0)->(CastR8(it), CastR8(-it), CastR8(it).Bits.Hex, CastR8(it)->CastIA().Hex[:20] & "...", it.Hex) // Round down.
(0x8000ia shl 48)->(it - 0x0400ia)->(it shl 961)->(it - 0)->(CastR8(it), CastR8(-it), CastR8(it).Bits.Hex, CastR8(it)->CastIA().Hex[:20] & "...", it.Hex)

// Cover ia to r4, near infinity.
(0x8000ia shl 16)->(it - 0x0000ia)->(it shl 97)->(it - 0)->(CastR4(it), CastR4(-it), CastR4(it).Bits.Hex, CastR4(it)->CastIA().Hex[:20] & "...", it.Hex) // Round up to infinity.
(0x8000ia shl 16)->(it - 0x0040ia)->(it shl 97)->(it - 0)->(CastR4(it), CastR4(-it), CastR4(it).Bits.Hex, CastR4(it)->CastIA().Hex[:20] & "...", it.Hex) // Round up to infinity.
(0x8000ia shl 16)->(it - 0x0040ia)->(it shl 97)->(it - 1)->(CastR4(it), CastR4(-it), CastR4(it).Bits.Hex, CastR4(it)->CastIA().Hex[:20] & "...", it.Hex) // Round down.
(0x8000ia shl 16)->(it - 0x0041ia)->(it shl 97)->(it - 0)->(CastR4(it), CastR4(-it), CastR4(it).Bits.Hex, CastR4(it)->CastIA().Hex[:20] & "...", it.Hex) // Round down.
(0x8000ia shl 16)->(it - 0x0080ia)->(it shl 97)->(it - 0)->(CastR4(it), CastR4(-it), CastR4(it).Bits.Hex, CastR4(it)->CastIA().Hex[:20] & "...", it.Hex)

// Floating point

ToR4(0.0)
ToR4(-0.0)
ToR4(-1/0)
ToR4(0/0)
ToR4(1/0)

// Floating-point boundaries

ToR8(-CastR4(0x1 * 2.0 ^ -149))
ToR8(-CastR4(0xFFFFFF * 2.0 ^ 104))

CastR4(-0x10000000000000 * 2.0 ^ 76)   = -1/0
CastR4(-0x1FFFFFF0000000 * 2.0 ^ 75)
CastR4(-0x1FFFFFEFFFFFFF * 2.0 ^ 75)
CastR4(-0x1FFFFFE0000000 * 2.0 ^ 75)   > -1/0
CastR4(-0x10000000000000 * 2.0 ^ -201) < -0.0
CastR4(-0x1FFFFFFFFFFFFF * 2.0 ^ -202)
CastR4(-0x10000000000001 * 2.0 ^ -202)
CastR4(-0x10000000000000 * 2.0 ^ -202)
CastR4(-0x1FFFFFFFFFFFFF * 2.0 ^ -203) // expect -0
CastR4(0x1FFFFFFFFFFFFF * 2.0 ^ -203)  // expect 0
CastR4(0x10000000000000 * 2.0 ^ -202)
CastR4(0x10000000000001 * 2.0 ^ -202)
CastR4(0x1FFFFFFFFFFFFF * 2.0 ^ -202)
CastR4(0x10000000000000 * 2.0 ^ -201)  > 0.0
CastR4(0x1FFFFFE0000000 * 2.0 ^ 75)    < 1/0
CastR4(0x1FFFFFEFFFFFFF * 2.0 ^ 75)
CastR4(0x1FFFFFF0000000 * 2.0 ^ 75)
CastR4(0x10000000000000 * 2.0 ^ 76)    = 1/0

// String

ToR4("")
ToR4(" ")
To("", 5r4)
ToR4(" ", 5r4)

ToR4("false")
ToR4("true")
To("false", 0r4)
ToR4("true", 1r4)

ToR8("false")
ToR8("true")
To("false", 0r8)
ToR8("true", 1r8)

ToR4("1_234")
To("1_234", 5r4)

ToR8("1_234")
To("1_234", 5r8)

ToR4("-0")
ToR4("(12.34)")

ToR8("-0")
ToR8("(12.34)")

ToR4("-4 e37")
To("-4 e37", 5r4)

ToR8("-4 e37")
To("-4 e37", 5r8)

ToR4("0")
ToR4("0.0")
ToR4("-0")
ToR4("-0.0")
ToR4("12.34")
ToR4(" 12.34 ")
ToR4("12,345")
ToR4("(123)")
ToR4("2e20")
ToR4("∞")
ToR4("-∞")
ToR4("Infinity")
ToR4("-Infinity")
ToR4("NaN")

ToR8("0")
ToR8("0.0")
ToR8("-0")
ToR8("-0.0")
ToR8("12.34")
ToR8(" 12.34 ")
ToR8("12,345")
ToR8("(123)")
ToR8("2e20")
ToR8("∞")
ToR8("-∞")
ToR8("Infinity")
ToR8("-Infinity")
ToR8("NaN")

// Date and TimeSpan

ToR4(Date(9999, 12, 31))

ToR4(Time(23, 59, 59))
