#!/usr/bin/env python
# I, Danny Milosavljevic, hereby place this file into the public domain

class Label(object):
    def __init__(self, ID):
        self.ID = ID
        self.bResolved = False # whether it knows "relatively" (to the beginning of the section) where it is
        self.segment = None
        self.addr = 0 # addr relative to beginning of section. The other things are basically not known until link time.
        self.fixups = [] # these contain fixups that the object outputter cares about, too. These will be removed once we don't want anyone to fiddle with them again (i.e. when we derived a relative address and fixed it)
    def resolve(self, segment, addr):
        self.segment = segment
        self.addr = addr
        self.bResolved = True
        i = 0
        while i < len(self.fixups):
            if self.callFixup(self.fixups[i]):
                del self.fixups[i]
            else:
                i += 1
    def callFixup(self, entry):
        addr, size, method, fixup = entry
        return(fixup())
    def addPendingFixup(self, addr, size, method, callback):
        entry = [addr, size, method, callback]
        if not self.bResolved or not self.callFixup(entry):
            self.fixups.append(entry)
    def __repr__(self):
        return(":%s" % self.ID.name)
class Operation(object):
    def __init__(self, operator, operands):
        self.operator = operator
        self.operands = operands
    def __repr__(self):
        return("Operation(%r, %r)" % (self.operator, self.operands))
class SegmentAssembler(object):
    def __init__(self, ID):
        self.ID = ID
        self.data = []
    def addLabelReference(self, label, size, bRelative):
        PC = len(self.data)
        self.add(0, size)
        # make sure it's in the fixup list for the object generator to find (for relocations)
        label.addPendingFixup(PC, size, bRelative, lambda label=label, PC=PC, size=size, bRelative=bRelative: self.fixup(label, PC, size, bRelative))
        #self.addPendingFixup(label, PC, size, bRelative)
    def add(self, value, size = 1):
        assert(isinstance(value, int))
        if size > 1:
            # little endian
            for i in range(size):
                self.data.append(value & 0xFF)
                value = value // 0x100
        else:
            self.data.append(value)
    def getFixupInline(self, label, i, size, bRelative):
        value = label.addr if not bRelative else (label.addr - i - 4)
        return(value)
    def fixup(self, label, i, size, bRelative):
        assert(label.bResolved)
        value = self.getFixupInline(label, i, size, bRelative)
        self.fixupDirectly(i, value, size)
        return(bRelative) # True="fixup worked, so remove task"
    def fixupDirectly(self, PC, value, size):
        i = PC
        for j in range(size):
            self.data[i] = value & 0xFF
            value = value >> 8
            i += 1
class Register(object):
    def __init__(self, ID, code):
        self.ID = ID
        self.code = code
    def __repr__(self):
        return("%%%s" % self.ID.name)
registers = {}
