2015-10-16 09:40:38 +00:00
|
|
|
"""Data/storage model for SixtyPical."""
|
|
|
|
|
2017-12-11 10:42:42 +00:00
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
class Type(object):
|
2018-02-14 13:31:03 +00:00
|
|
|
def __init__(self, name, max_range=None):
|
2015-10-16 09:40:38 +00:00
|
|
|
self.name = name
|
2018-02-14 13:31:03 +00:00
|
|
|
self.max_range = max_range
|
2015-10-16 09:40:38 +00:00
|
|
|
|
|
|
|
def __repr__(self):
|
2015-10-18 16:23:01 +00:00
|
|
|
return 'Type(%r)' % self.name
|
2015-10-16 09:40:38 +00:00
|
|
|
|
2015-10-16 22:12:52 +00:00
|
|
|
def __eq__(self, other):
|
2019-04-08 10:50:54 +00:00
|
|
|
return other.__class__ == self.__class__ and other.name == self.name
|
2015-10-16 09:40:38 +00:00
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
|
2018-02-14 13:31:03 +00:00
|
|
|
TYPE_BIT = Type('bit', max_range=(0, 1))
|
|
|
|
TYPE_BYTE = Type('byte', max_range=(0, 255))
|
|
|
|
TYPE_WORD = Type('word', max_range=(0, 65535))
|
2015-10-19 17:18:06 +00:00
|
|
|
|
|
|
|
|
2018-02-05 17:01:25 +00:00
|
|
|
class RoutineType(Type):
|
|
|
|
"""This memory location contains the code for a routine."""
|
2018-09-07 13:51:16 +00:00
|
|
|
def __init__(self, inputs, outputs, trashes):
|
|
|
|
self.inputs = inputs
|
|
|
|
self.outputs = outputs
|
|
|
|
self.trashes = trashes
|
2015-10-19 17:18:06 +00:00
|
|
|
|
|
|
|
def __repr__(self):
|
2019-04-08 10:50:54 +00:00
|
|
|
return '%s(inputs=%r, outputs=%r, trashes=%r)' % (
|
|
|
|
self.__class__.__name__, self.inputs, self.outputs, self.trashes
|
2015-10-19 17:18:06 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
2018-02-05 17:01:25 +00:00
|
|
|
return isinstance(other, RoutineType) and (
|
2015-10-19 17:18:06 +00:00
|
|
|
other.inputs == self.inputs and
|
|
|
|
other.outputs == self.outputs and
|
|
|
|
other.trashes == self.trashes
|
|
|
|
)
|
|
|
|
|
2018-02-05 12:04:28 +00:00
|
|
|
@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`."""
|
2018-02-05 17:01:25 +00:00
|
|
|
if isinstance(src, VectorType):
|
|
|
|
src = src.of_type
|
|
|
|
if isinstance(dest, VectorType):
|
|
|
|
dest = dest.of_type
|
|
|
|
if isinstance(src, RoutineType) and isinstance(dest, RoutineType):
|
2018-02-05 12:04:28 +00:00
|
|
|
# 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
|
|
|
|
|
2015-10-19 17:18:06 +00:00
|
|
|
|
2018-02-05 17:01:25 +00:00
|
|
|
class VectorType(Type):
|
|
|
|
"""This memory location contains the address of some other type (currently, only RoutineType)."""
|
2019-04-10 07:48:33 +00:00
|
|
|
max_range = (0, 0)
|
|
|
|
|
2018-02-05 17:01:25 +00:00
|
|
|
def __init__(self, of_type):
|
|
|
|
self.of_type = of_type
|
2015-10-19 17:18:06 +00:00
|
|
|
|
2018-02-05 17:01:25 +00:00
|
|
|
def __repr__(self):
|
|
|
|
return '%s(%r)' % (
|
|
|
|
self.__class__.__name__, self.of_type
|
|
|
|
)
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
2019-04-08 10:50:54 +00:00
|
|
|
return isinstance(other, VectorType) and self.of_type == other.of_type
|
2015-10-18 16:23:01 +00:00
|
|
|
|
|
|
|
|
2018-02-02 16:31:23 +00:00
|
|
|
class TableType(Type):
|
|
|
|
def __init__(self, of_type, size):
|
|
|
|
self.of_type = of_type
|
|
|
|
self.size = size
|
|
|
|
|
2018-02-02 17:45:07 +00:00
|
|
|
def __repr__(self):
|
|
|
|
return '%s(%r, %r)' % (
|
|
|
|
self.__class__.__name__, self.of_type, self.size
|
|
|
|
)
|
|
|
|
|
2019-04-08 10:50:54 +00:00
|
|
|
def __eq__(self, other):
|
|
|
|
return isinstance(other, TableType) and self.of_type == other.of_type and self.size == other.size
|
|
|
|
|
|
|
|
@property
|
|
|
|
def max_range(self):
|
|
|
|
return (0, self.size - 1)
|
|
|
|
|
2018-02-02 17:05:15 +00:00
|
|
|
@classmethod
|
|
|
|
def is_a_table_type(cls_, x, of_type):
|
|
|
|
return isinstance(x, TableType) and x.of_type == of_type
|
|
|
|
|
2018-02-02 16:31:23 +00:00
|
|
|
|
2017-11-24 11:30:20 +00:00
|
|
|
class PointerType(Type):
|
2019-04-10 07:48:33 +00:00
|
|
|
max_range = (0, 0)
|
|
|
|
|
2017-11-24 11:30:20 +00:00
|
|
|
def __init__(self):
|
|
|
|
self.name = 'pointer'
|
|
|
|
|
2019-04-08 10:50:54 +00:00
|
|
|
def __eq__(self, other):
|
|
|
|
return other.__class__ == self.__class__
|
|
|
|
|
2017-11-24 11:30:20 +00:00
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
class Ref(object):
|
2019-04-10 07:48:33 +00:00
|
|
|
pass
|
2018-02-14 13:31:03 +00:00
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
|
|
|
|
class LocationRef(Ref):
|
|
|
|
def __init__(self, type, name):
|
|
|
|
self.name = name
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
2019-04-10 07:48:33 +00:00
|
|
|
return self.__class__ is other.__class__ and self.name == other.name
|
2015-10-18 16:23:01 +00:00
|
|
|
|
|
|
|
def __hash__(self):
|
2019-04-10 07:48:33 +00:00
|
|
|
return hash(self.name)
|
2015-10-18 16:23:01 +00:00
|
|
|
|
|
|
|
def __repr__(self):
|
2019-04-10 07:48:33 +00:00
|
|
|
return '%s(%r)' % (self.__class__.__name__, self.name)
|
2015-10-18 16:23:01 +00:00
|
|
|
|
2017-12-12 12:45:47 +00:00
|
|
|
def __str__(self):
|
2019-04-10 07:48:33 +00:00
|
|
|
return self.name
|
2018-02-14 13:31:03 +00:00
|
|
|
|
2017-12-12 12:45:47 +00:00
|
|
|
@classmethod
|
|
|
|
def format_set(cls, location_refs):
|
2018-09-06 13:21:29 +00:00
|
|
|
return '{%s}' % ', '.join([str(loc) for loc in sorted(location_refs, key=lambda x: x.name)])
|
2017-12-12 12:45:47 +00:00
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
|
2017-12-01 11:44:40 +00:00
|
|
|
class IndirectRef(Ref):
|
|
|
|
def __init__(self, ref):
|
|
|
|
self.ref = ref
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
2017-12-08 13:41:48 +00:00
|
|
|
return isinstance(other, self.__class__) and self.ref == other.ref
|
2017-12-01 11:44:40 +00:00
|
|
|
|
|
|
|
def __hash__(self):
|
2017-12-01 12:36:58 +00:00
|
|
|
return hash(self.__class__.name) ^ hash(self.ref)
|
2017-12-01 11:44:40 +00:00
|
|
|
|
|
|
|
def __repr__(self):
|
|
|
|
return '%s(%r)' % (self.__class__.__name__, self.ref)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return '[{}]+y'.format(self.ref.name)
|
|
|
|
|
|
|
|
|
2017-12-08 13:41:48 +00:00
|
|
|
class IndexedRef(Ref):
|
2019-04-08 10:50:54 +00:00
|
|
|
def __init__(self, ref, offset, index):
|
2017-12-08 13:41:48 +00:00
|
|
|
self.ref = ref
|
2019-04-08 10:50:54 +00:00
|
|
|
self.offset = offset
|
2017-12-08 13:41:48 +00:00
|
|
|
self.index = index
|
|
|
|
|
|
|
|
def __eq__(self, other):
|
2019-04-08 10:50:54 +00:00
|
|
|
return isinstance(other, self.__class__) and self.ref == other.ref and self.offset == other.offset and self.index == other.index
|
2017-12-08 13:41:48 +00:00
|
|
|
|
|
|
|
def __hash__(self):
|
2019-04-08 10:50:54 +00:00
|
|
|
return hash(self.__class__.name) ^ hash(self.ref) ^ hash(self.offset) ^ hash(self.index)
|
2017-12-08 13:41:48 +00:00
|
|
|
|
|
|
|
def __repr__(self):
|
2019-04-08 10:50:54 +00:00
|
|
|
return '%s(%r, %r, %r)' % (self.__class__.__name__, self.ref, self.offset, self.index)
|
2017-12-08 13:41:48 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
2019-04-08 10:50:54 +00:00
|
|
|
return '{}+{}+{}'.format(self.ref.name, self.offset, self.index.name)
|
2017-12-08 13:41:48 +00:00
|
|
|
|
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
class ConstantRef(Ref):
|
|
|
|
def __init__(self, type, value):
|
|
|
|
self.type = type
|
2015-10-16 09:40:38 +00:00
|
|
|
self.value = value
|
|
|
|
|
2015-10-16 22:12:52 +00:00
|
|
|
def __eq__(self, other):
|
2015-10-18 16:23:01 +00:00
|
|
|
return isinstance(other, ConstantRef) and (
|
|
|
|
other.type == self.type and other.value == self.value
|
|
|
|
)
|
2015-10-16 22:12:52 +00:00
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
def __hash__(self):
|
|
|
|
return hash(str(self.value) + str(self.type))
|
2015-10-16 09:40:38 +00:00
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
def __repr__(self):
|
|
|
|
return '%s(%r, %r)' % (self.__class__.__name__, self.type, self.value)
|
2015-10-16 09:40:38 +00:00
|
|
|
|
2017-12-07 12:48:56 +00:00
|
|
|
def high_byte(self):
|
|
|
|
return (self.value >> 8) & 255
|
|
|
|
|
|
|
|
def low_byte(self):
|
|
|
|
return self.value & 255
|
|
|
|
|
2018-03-14 16:27:33 +00:00
|
|
|
def pred(self):
|
|
|
|
assert self.type == TYPE_BYTE
|
|
|
|
value = self.value - 1
|
|
|
|
while value < 0:
|
|
|
|
value += 256
|
|
|
|
return ConstantRef(self.type, value)
|
|
|
|
|
|
|
|
def succ(self):
|
|
|
|
assert self.type == TYPE_BYTE
|
|
|
|
value = self.value + 1
|
|
|
|
while value > 255:
|
|
|
|
value -= 256
|
|
|
|
return ConstantRef(self.type, value)
|
|
|
|
|
2019-04-08 10:50:54 +00:00
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return 'constant({})'.format(self.value)
|
|
|
|
|
2015-10-16 09:40:38 +00:00
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
REG_A = LocationRef(TYPE_BYTE, 'a')
|
|
|
|
REG_X = LocationRef(TYPE_BYTE, 'x')
|
|
|
|
REG_Y = LocationRef(TYPE_BYTE, 'y')
|
2015-10-16 09:40:38 +00:00
|
|
|
|
2015-10-18 16:23:01 +00:00
|
|
|
FLAG_Z = LocationRef(TYPE_BIT, 'z')
|
|
|
|
FLAG_C = LocationRef(TYPE_BIT, 'c')
|
|
|
|
FLAG_N = LocationRef(TYPE_BIT, 'n')
|
|
|
|
FLAG_V = LocationRef(TYPE_BIT, 'v')
|