1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2024-06-18 03:29:32 +00:00
SixtyPical/src/sixtypical/model.py

291 lines
8.1 KiB
Python

"""Data/storage model for SixtyPical."""
class Type(object):
def __init__(self, name):
self.name = name
def __repr__(self):
return 'Type(%r)' % self.name
def __str__(self):
return self.name
def __eq__(self, other):
return isinstance(other, Type) and other.name == self.name
def __hash__(self):
return hash(self.name)
def backpatch_constraint_labels(self, resolver):
if isinstance(self, TableType):
self.of_type.backpatch_constraint_labels(resolver)
elif isinstance(self, VectorType):
self.of_type.backpatch_constraint_labels(resolver)
elif isinstance(self, RoutineType):
self.inputs = set([resolver(w) for w in self.inputs])
self.outputs = set([resolver(w) for w in self.outputs])
self.trashes = set([resolver(w) for w in self.trashes])
TYPE_BIT = Type('bit')
TYPE_BYTE = Type('byte')
TYPE_WORD = Type('word')
class RoutineType(Type):
"""This memory location contains the code for a routine."""
def __init__(self, inputs=None, outputs=None, trashes=None):
self.name = 'routine'
self.inputs = inputs or set()
self.outputs = outputs or set()
self.trashes = trashes or set()
def __repr__(self):
return '%s(%r, inputs=%r, outputs=%r, trashes=%r)' % (
self.__class__.__name__, self.name, self.inputs, self.outputs, self.trashes
)
def __eq__(self, other):
return isinstance(other, RoutineType) and (
other.name == self.name and
other.inputs == self.inputs and
other.outputs == self.outputs and
other.trashes == self.trashes
)
def __hash__(self):
return hash(self.name) ^ hash(self.inputs) ^ hash(self.outputs) ^ hash(self.trashes)
@classmethod
def executable_types_compatible(cls_, src, dest):
"""Returns True iff a value of type `src` can be assigned to a storage location of type `dest`."""
if isinstance(src, VectorType):
src = src.of_type
if isinstance(dest, VectorType):
dest = dest.of_type
if isinstance(src, RoutineType) and isinstance(dest, RoutineType):
# TODO: I'm sure we can replace some of these with subset-containment, but that requires thought
return (
src.inputs == dest.inputs and
src.outputs == dest.outputs and
src.trashes == dest.trashes
)
else:
return False
class VectorType(Type):
"""This memory location contains the address of some other type (currently, only RoutineType)."""
def __init__(self, of_type):
self.name = 'vector'
self.of_type = of_type
def __repr__(self):
return '%s(%r)' % (
self.__class__.__name__, self.of_type
)
def __eq__(self, other):
return self.name == other.name and self.of_type == other.of_type
def __hash__(self):
return hash(self.name) ^ hash(self.of_type)
class TableType(Type):
def __init__(self, of_type, size):
self.of_type = of_type
self.size = size
self.name = '{} table[{}]'.format(self.of_type.name, self.size)
def __repr__(self):
return '%s(%r, %r)' % (
self.__class__.__name__, self.of_type, self.size
)
@classmethod
def is_a_table_type(cls_, x, of_type):
return isinstance(x, TableType) and x.of_type == of_type
class BufferType(Type):
def __init__(self, size):
self.size = size
self.name = 'buffer[%s]' % self.size
class PointerType(Type):
def __init__(self):
self.name = 'pointer'
class Ref(object):
def is_constant(self):
"""read-only means that the program cannot change the value
of a location. constant means that the value of the location
will not change during the lifetime of the program."""
raise NotImplementedError
class LocationRef(Ref):
def __init__(self, type, name):
self.type = type
self.name = name
def __eq__(self, other):
# Ordinarily there will only be one ref with a given name,
# but because we store the type in here and we want to treat
# these objects as immutable, we compare the types, too,
# just to be sure.
equal = isinstance(other, self.__class__) and other.name == self.name
if equal:
assert other.type == self.type
return equal
def __hash__(self):
return hash(self.name + str(self.type))
def __repr__(self):
return '%s(%r, %r)' % (self.__class__.__name__, self.type, self.name)
def __str__(self):
return "{}:{}".format(self.name, self.type)
def is_constant(self):
return isinstance(self.type, RoutineType)
@classmethod
def format_set(cls, location_refs):
return '{%s}' % ', '.join([str(loc) for loc in sorted(location_refs)])
class IndirectRef(Ref):
def __init__(self, ref):
self.ref = ref
def __eq__(self, other):
return isinstance(other, self.__class__) and self.ref == other.ref
def __hash__(self):
return hash(self.__class__.name) ^ hash(self.ref)
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.ref)
@property
def name(self):
return '[{}]+y'.format(self.ref.name)
def is_constant(self):
return False
class IndexedRef(Ref):
def __init__(self, ref, index):
self.ref = ref
self.index = index
def __eq__(self, other):
return isinstance(other, self.__class__) and self.ref == other.ref and self.index == other.index
def __hash__(self):
return hash(self.__class__.name) ^ hash(self.ref) ^ hash(self.index)
def __repr__(self):
return '%s(%r, %r)' % (self.__class__.__name__, self.ref, self.index)
@property
def name(self):
return '{}+{}'.format(self.ref.name, self.index.name)
def is_constant(self):
return False
class AddressRef(Ref):
def __init__(self, ref):
self.ref = ref
def __eq__(self, other):
return self.ref == other.ref
def __hash__(self):
return hash(self.__class__.name) ^ hash(self.ref)
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.ref)
@property
def name(self):
return '^{}'.format(self.ref.name)
def is_constant(self):
return True
class PartRef(Ref):
"""For 'low byte of' location and 'high byte of' location modifiers.
height=0 = low byte, height=1 = high byte.
NOTE: Not actually used yet. Might require more thought before it's usable.
"""
def __init__(self, ref, height):
assert isinstance(ref, Ref)
assert ref.type == TYPE_WORD
self.ref = ref
self.height = height
self.type = TYPE_BYTE
def __eq__(self, other):
return isinstance(other, PartRef) and (
other.height == self.height and other.ref == self.ref
)
def __hash__(self):
return hash(self.ref) ^ hash(self.height) ^ hash(self.type)
def __repr__(self):
return '%s(%r, %r)' % (self.__class__.__name__, self.ref, self.height)
def is_constant(self):
return self.ref.is_constant()
class ConstantRef(Ref):
def __init__(self, type, value):
self.type = type
self.value = value
def __eq__(self, other):
return isinstance(other, ConstantRef) and (
other.type == self.type and other.value == self.value
)
def __hash__(self):
return hash(str(self.value) + str(self.type))
def __repr__(self):
return '%s(%r, %r)' % (self.__class__.__name__, self.type, self.value)
def is_constant(self):
return True
def high_byte(self):
return (self.value >> 8) & 255
def low_byte(self):
return self.value & 255
REG_A = LocationRef(TYPE_BYTE, 'a')
REG_X = LocationRef(TYPE_BYTE, 'x')
REG_Y = LocationRef(TYPE_BYTE, 'y')
FLAG_Z = LocationRef(TYPE_BIT, 'z')
FLAG_C = LocationRef(TYPE_BIT, 'c')
FLAG_N = LocationRef(TYPE_BIT, 'n')
FLAG_V = LocationRef(TYPE_BIT, 'v')