"""Shogoth bootstrap code.

Some utterly trivial functions and types that allow me to begin testing the VM.
Hopefully no "real" interpreter ever uses this code, since it's obviously replaceable.
"""

from ichor import isa
from ichor.assembler import FuncBuilder
from ichor.state import Module, Variant


BOOTSTRAP = Module()

BOOL = BOOTSTRAP.define_type(
    ";bool;true(),false()",
)

TRUE = Variant(BOOL, "true", ())
FALSE = Variant(BOOL, "false", ())

NOT1 = BOOTSTRAP.define_function(
    f";not;{BOOL};{BOOL}",
    [
        # a: Bool
        isa.IDENTIFIERC("bool"),
        isa.TYPEREF(),  # <typeref bool> a
        isa.DUP(),
        isa.IDENTIFIERC("true"),
        isa.ARMREF(), # <variantref true:bool> <typeref bool> a
        isa.DUP(),
        isa.SLOT(0),
        isa.ROT(2),
        isa.ATEST(11),

        isa.ARM(0),
        isa.RETURN(),

        isa.DROP(1),
        isa.IDENTIFIERC("false"),
        isa.ARMREF(),
        isa.ARM(0),
        isa.RETURN(),
    ],
)

_b = FuncBuilder()

# Capture args
_x = _b.mark_argument()
_y = _b.mark_argument()

# Const
_b.write(isa.IDENTIFIERC("bool"))
_b.write(isa.TYPEREF())
_bool_t = _b.mark_slot()

_b.write(isa.SLOT(_bool_t))
_b.write(isa.IDENTIFIERC("true"))
_b.write(isa.ARMREF())
_true_t = _b.mark_slot()

_b.write(isa.SLOT(_bool_t))
_b.write(isa.IDENTIFIERC("false"))
_b.write(isa.ARMREF())
_false_t = _b.mark_slot()

# x: Bool, y: Bool -> Bool
_true_l = _b.make_label()
_b.write(isa.SLOT(_x))
_b.write(isa.SLOT(_true_t))
_b.write(isa.ATEST(_true_l))

_b.write(isa.SLOT(_y))
_b.write(isa.SLOT(_true_t))
_b.write(isa.ATEST(_true_l))

_b.write(isa.SLOT(_false_t))
_b.write(isa.ARM(0))
_b.write(isa.RETURN())

_b.write(_true_l)
_b.write(isa.SLOT(_true_t))
_b.write(isa.ARM(0))
_b.write(isa.RETURN())

OR2 = BOOTSTRAP.define_function(
    f";or;{BOOL},{BOOL};{BOOL}",
    _b.build()
)

_b = FuncBuilder()
# Capture args
_x = _b.mark_argument()
_y = _b.mark_argument()
_z = _b.mark_argument()

# Const
_b.write(isa.IDENTIFIERC("bool"))
_b.write(isa.TYPEREF())
_bool_t = _b.mark_slot()

_b.write(isa.SLOT(_bool_t))
_b.write(isa.IDENTIFIERC("true"))
_b.write(isa.ARMREF())
_true_t = _b.mark_slot()

_b.write(isa.SLOT(_bool_t))
_b.write(isa.IDENTIFIERC("false"))
_b.write(isa.ARMREF())
_false_t = _b.mark_slot()

# x: Bool, y: Bool, z: Bool -> Bool
_true_l = _b.make_label()
_b.write(isa.SLOT(_x))
_b.write(isa.SLOT(_true_t))
_b.write(isa.ATEST(_true_l))

_b.write(isa.SLOT(_y))
_b.write(isa.SLOT(_true_t))
_b.write(isa.ATEST(_true_l))

_b.write(isa.SLOT(_z))
_b.write(isa.SLOT(_true_t))
_b.write(isa.ATEST(_true_l))

_b.write(isa.SLOT(_false_t))
_b.write(isa.ARM(0))
_b.write(isa.RETURN())

_b.write(_true_l)
_b.write(isa.SLOT(_true_t))
_b.write(isa.ARM(0))
_b.write(isa.RETURN())


OR3 = BOOTSTRAP.define_function(
    f";or;{BOOL},{BOOL},{BOOL};{BOOL}",
    _b.build()
)

_b = FuncBuilder()
# Capture args
_x = _b.mark_argument()
_y = _b.mark_argument()

# Const
_b.write(isa.IDENTIFIERC("bool"))
_b.write(isa.TYPEREF())
_bool_t = _b.mark_slot()

_b.write(isa.SLOT(_bool_t))
_b.write(isa.IDENTIFIERC("true"))
_b.write(isa.ARMREF())
_true_t = _b.mark_slot()

_b.write(isa.SLOT(_bool_t))
_b.write(isa.IDENTIFIERC("false"))
_b.write(isa.ARMREF())
_false_t = _b.mark_slot()

# x: Bool, x: Bool -> Bool
_false_l = _b.make_label()
_b.write(isa.SLOT(_x))
_b.write(isa.SLOT(_false_t))
_b.write(isa.ATEST(_false_l))

_b.write(isa.SLOT(_y))
_b.write(isa.SLOT(_false_t))
_b.write(isa.ATEST(_false_l))

_b.write(isa.SLOT(_true_t))
_b.write(isa.ARM(0))
_b.write(isa.RETURN())

_b.write(_false_l)
_b.write(isa.SLOT(_false_t))
_b.write(isa.ARM(0))
_b.write(isa.RETURN())

AND2 = BOOTSTRAP.define_function(
    f";and;{BOOL},{BOOL};{BOOL}",
    _b.build()
)

_b = FuncBuilder()
_b = FuncBuilder()
# Capture args
_x = _b.mark_argument()
_y = _b.mark_argument()
_z = _b.mark_argument()

# Const
_b.write(isa.IDENTIFIERC("bool"))
_b.write(isa.TYPEREF())
_bool_t = _b.mark_slot()

_b.write(isa.SLOT(_bool_t))
_b.write(isa.IDENTIFIERC("true"))
_b.write(isa.ARMREF())
_true_t = _b.mark_slot()

_b.write(isa.SLOT(_bool_t))
_b.write(isa.IDENTIFIERC("false"))
_b.write(isa.ARMREF())
_false_t = _b.mark_slot()

# x: Bool, x: Bool -> Bool
_false_l = _b.make_label()
_b.write(isa.SLOT(_x))
_b.write(isa.SLOT(_false_t))
_b.write(isa.ATEST(_false_l))

_b.write(isa.SLOT(_y))
_b.write(isa.SLOT(_false_t))
_b.write(isa.ATEST(_false_l))

_b.write(isa.SLOT(_z))
_b.write(isa.SLOT(_false_t))
_b.write(isa.ATEST(_false_l))

_b.write(isa.SLOT(_true_t))
_b.write(isa.ARM(0))
_b.write(isa.RETURN())

_b.write(_false_l)
_b.write(isa.SLOT(_false_t))
_b.write(isa.ARM(0))
_b.write(isa.RETURN())

AND3 = BOOTSTRAP.define_function(
    f";and;{BOOL},{BOOL},{BOOL};{BOOL}",
    _b.build()
)

_b = FuncBuilder()
_b.write(isa.BREAK())

XOR2 = BOOTSTRAP.define_function(
    f";xor;{BOOL},{BOOL};{BOOL}",
    _b.build()
)

_b = FuncBuilder()
_b.write(isa.BREAK())

XOR3 = BOOTSTRAP.define_function(
    f";xor;{BOOL},{BOOL},{BOOL};{BOOL}",
    _b.build()
)
