"""C6T VM assembler pseudo ops.
"""

from copy import deepcopy
from util import Opcode, pop_opcodes, wordlo, wordbytes, stringbytes, ObjSym, symtab, Name
from evaler import evalexpr


class Ds(Opcode):
    """Psuedo op to reserve space.
    """

    def __init__(self):
        super().__init__('.ds')

    def byte_count(self, args: list) -> int:
        if len(args) < 1:
            return 0
        operand = evalexpr(args[0])
        if isinstance(operand, int):
            return operand
        return 0

    def assemble(self, args: list) -> list:
        return [bytes([0]*self.byte_count(args))]


class Dc(Opcode):
    """Pseudo op to save characters.
    """

    def __init__(self):
        super().__init__(".dc")

    def byte_count(self, args: list) -> int:
        return len(args)

    def assemble(self, args: list) -> list:
        out = []
        for elem in map(evalexpr, args):
            if isinstance(elem, int):
                out.append(bytes([wordlo(elem)]))
            elif isinstance(elem, ObjSym):
                new = deepcopy(elem)
                new.hibyte = True
                out.append(new)
        return stringbytes(out)


class Dw(Opcode):
    """Pseudo to save words.
    """

    def __init__(self):
        super().__init__(".dw")

    def byte_count(self, args: list) -> int:
        return len(args)*2

    def assemble(self, args: list) -> list:
        out = []
        for elem in map(evalexpr, args):
            if isinstance(elem, int):
                out.append(wordbytes(elem))
            elif isinstance(elem, ObjSym):
                new = deepcopy(elem)
                new.hibyte = new.lobyte = False
                out.append(new)
        return stringbytes(new)


class Export(Opcode):
    """Pseudo to mark a name as exported.
    """

    def __init__(self):
        super().__init__(".export")

    def byte_count(self, args: list) -> int:
        self.export(args)
        return 0

    def assemble(self, args: list) -> list:
        self.export(args)
        return [bytes()]

    def export(self, args: list) -> None:
        """Export each argument.
        """
        for arg in args:
            if isinstance(arg, Name) and arg.name in symtab:
                symtab[arg.name].exported = True

# TODO: CODE, DATA, BSS, COMMON


def add_pseudos():
    """Add pseudo ops to the opcode table.
    """
    pop_opcodes([Ds(), Dc(), Dw(), Export()])
