from rpython.rtyper.lltypesystem import lltype, rffi, rstr
from rpython.jit.backend.llsupport.descr import *
from rpython.jit.backend.llsupport import symbolic
from rpython.rlib.objectmodel import Symbolic
from rpython.rtyper.annlowlevel import llhelper
from rpython.jit.metainterp import history
from rpython.jit.codewriter import longlong
import sys, struct, py

def test_get_size_descr():
    c0 = GcCache(False)
    c1 = GcCache(True)
    T = lltype.GcStruct('T')
    S = lltype.GcStruct('S', ('x', lltype.Char),
                             ('y', lltype.Ptr(T)))
    descr_s = get_size_descr(c0, S)
    descr_t = get_size_descr(c0, T)
    assert descr_s.size == symbolic.get_size(S, False)
    assert descr_t.size == symbolic.get_size(T, False)
    assert descr_s.is_immutable() == False
    assert descr_t.is_immutable() == False
    assert descr_t.gc_fielddescrs == []
    assert len(descr_s.gc_fielddescrs) == 1
    assert descr_s == get_size_descr(c0, S)
    assert descr_s != get_size_descr(c1, S)
    #
    descr_s = get_size_descr(c1, S)
    assert isinstance(descr_s.size, Symbolic)
    assert descr_s.is_immutable() == False

    PARENT = lltype.Struct('P', ('x', lltype.Ptr(T)))
    STRUCT = lltype.GcStruct('S', ('parent', PARENT), ('y', lltype.Ptr(T)))
    descr_struct = get_size_descr(c0, STRUCT)
    assert len(descr_struct.gc_fielddescrs) == 2

def test_get_size_descr_immut():
    S = lltype.GcStruct('S', hints={'immutable': True})
    T = lltype.GcStruct('T', ('parent', S),
                        ('x', lltype.Char),
                        hints={'immutable': True})
    U = lltype.GcStruct('U', ('parent', T),
                        ('u', lltype.Ptr(T)),
                        ('v', lltype.Signed),
                        hints={'immutable': True})
    V = lltype.GcStruct('V', ('parent', U),
                        ('miss1', lltype.Void),
                        ('miss2', lltype.Void),
                        hints={'immutable': True})
    for STRUCT in [S, T, U, V]:
        for translated in [False, True]:
            c0 = GcCache(translated)
            descr_s = get_size_descr(c0, STRUCT)
            assert descr_s.is_immutable() == True

def test_get_field_descr():
    U = lltype.Struct('U')
    T = lltype.GcStruct('T')
    S = lltype.GcStruct('S', ('x', lltype.Char),
                             ('y', lltype.Ptr(T)),
                             ('z', lltype.Ptr(U)),
                             ('f', lltype.Float),
                             ('s', lltype.SingleFloat))
    #
    c0 = GcCache(False)
    c1 = GcCache(True)
    assert get_field_descr(c0, S, 'y') == get_field_descr(c0, S, 'y')
    assert get_field_descr(c0, S, 'y') != get_field_descr(c1, S, 'y')
    for tsc in [False, True]:
        c2 = GcCache(tsc)
        descr_x = get_field_descr(c2, S, 'x')
        descr_y = get_field_descr(c2, S, 'y')
        descr_z = get_field_descr(c2, S, 'z')
        descr_f = get_field_descr(c2, S, 'f')
        descr_s = get_field_descr(c2, S, 's')
        assert isinstance(descr_x, FieldDescr)
        assert descr_x.name == 'S.x'
        assert descr_y.name == 'S.y'
        assert descr_z.name == 'S.z'
        assert descr_f.name == 'S.f'
        assert descr_s.name == 'S.s'
        if not tsc:
            assert descr_x.offset < descr_y.offset < descr_z.offset
            assert descr_x.sort_key() < descr_y.sort_key() < descr_z.sort_key()
            assert descr_x.field_size == rffi.sizeof(lltype.Char)
            assert descr_y.field_size == rffi.sizeof(lltype.Ptr(T))
            assert descr_z.field_size == rffi.sizeof(lltype.Ptr(U))
            assert descr_f.field_size == rffi.sizeof(lltype.Float)
            assert descr_s.field_size == rffi.sizeof(lltype.SingleFloat)
        else:
            assert isinstance(descr_x.offset, Symbolic)
            assert isinstance(descr_y.offset, Symbolic)
            assert isinstance(descr_z.offset, Symbolic)
            assert isinstance(descr_f.offset, Symbolic)
            assert isinstance(descr_s.offset, Symbolic)
            assert isinstance(descr_x.field_size, Symbolic)
            assert isinstance(descr_y.field_size, Symbolic)
            assert isinstance(descr_z.field_size, Symbolic)
            assert isinstance(descr_f.field_size, Symbolic)
            assert isinstance(descr_s.field_size, Symbolic)
        assert descr_x.flag == FLAG_UNSIGNED
        assert descr_y.flag == FLAG_POINTER
        assert descr_z.flag == FLAG_UNSIGNED
        assert descr_f.flag == FLAG_FLOAT
        assert descr_s.flag == FLAG_UNSIGNED


def test_get_field_descr_sign():
    for RESTYPE, signed in [(rffi.SIGNEDCHAR, True), (rffi.UCHAR,  False),
                            (rffi.SHORT,      True), (rffi.USHORT, False),
                            (rffi.INT,        True), (rffi.UINT,   False),
                            (rffi.LONG,       True), (rffi.ULONG,  False)]:
        S = lltype.GcStruct('S', ('x', RESTYPE))
        for tsc in [False, True]:
            c2 = GcCache(tsc)
            descr_x = get_field_descr(c2, S, 'x')
            assert descr_x.flag == {False: FLAG_UNSIGNED,
                                    True:  FLAG_SIGNED  }[signed]

def test_get_field_descr_longlong():
    if sys.maxint > 2147483647:
        py.test.skip("long long: for 32-bit only")
    c0 = GcCache(False)
    S = lltype.GcStruct('S', ('y', lltype.UnsignedLongLong))
    descr = get_field_descr(c0, S, 'y')
    assert descr.flag == FLAG_FLOAT
    assert descr.field_size == 8


def test_get_array_descr():
    U = lltype.Struct('U')
    T = lltype.GcStruct('T')
    A1 = lltype.GcArray(lltype.Char)
    A2 = lltype.GcArray(lltype.Ptr(T))
    A3 = lltype.GcArray(lltype.Ptr(U))
    A4 = lltype.GcArray(lltype.Float)
    A5 = lltype.GcArray(lltype.Struct('x', ('v', lltype.Signed),
                                           ('k', lltype.Signed)))
    A6 = lltype.GcArray(lltype.SingleFloat)
    #
    c0 = GcCache(False)
    descr1 = get_array_descr(c0, A1)
    descr2 = get_array_descr(c0, A2)
    descr3 = get_array_descr(c0, A3)
    descr4 = get_array_descr(c0, A4)
    descr5 = get_array_descr(c0, A5)
    descr6 = get_array_descr(c0, A6)
    assert isinstance(descr1, ArrayDescr)
    assert descr1 == get_array_descr(c0, lltype.GcArray(lltype.Char))
    assert descr1.flag == FLAG_UNSIGNED
    assert descr2.flag == FLAG_POINTER