mirror of
https://github.com/catseye/SixtyPical.git
synced 2025-04-07 23:37:23 +00:00
The Type and Ref class hierarchies are now namedtuples.
This commit is contained in:
parent
a0328b8840
commit
8d6e5e090d
@ -184,7 +184,7 @@ class AnalysisContext(object):
|
||||
exception_class = kwargs.get('exception_class', UnmeaningfulReadError)
|
||||
for ref in refs:
|
||||
# statics are always meaningful
|
||||
if self.symtab.fetch_static_ref(self.routine.name, ref.name):
|
||||
if self.symtab.has_static(self.routine.name, ref.name):
|
||||
continue
|
||||
if self.is_constant(ref):
|
||||
pass
|
||||
@ -204,7 +204,7 @@ class AnalysisContext(object):
|
||||
exception_class = kwargs.get('exception_class', ForbiddenWriteError)
|
||||
for ref in refs:
|
||||
# statics are always writeable
|
||||
if self.symtab.fetch_static_ref(self.routine.name, ref.name):
|
||||
if self.symtab.has_static(self.routine.name, ref.name):
|
||||
continue
|
||||
if ref not in self._writeable:
|
||||
message = ref.name
|
||||
@ -505,10 +505,7 @@ class Analyzer(object):
|
||||
|
||||
# if something was touched, then it should have been declared to be writable.
|
||||
for ref in context.each_touched():
|
||||
# FIXME once we have namedtuples, go back to comparing the ref directly!
|
||||
outputs_names = [r.name for r in type_.outputs]
|
||||
trashes_names = [r.name for r in type_.trashes]
|
||||
if ref.name not in outputs_names and ref.name not in trashes_names and not self.symtab.has_static(routine.name, ref.name):
|
||||
if ref not in type_.outputs and ref not in type_.trashes and not self.symtab.has_static(routine.name, ref.name):
|
||||
raise ForbiddenWriteError(routine, ref.name)
|
||||
|
||||
self.exit_contexts = None
|
||||
@ -822,7 +819,7 @@ class Analyzer(object):
|
||||
def analyze_call(self, instr, context):
|
||||
type = self.get_type(instr.location)
|
||||
if not isinstance(type, (RoutineType, VectorType)):
|
||||
raise TypeMismatchError(instr, instr.location)
|
||||
raise TypeMismatchError(instr, instr.location.name)
|
||||
if isinstance(type, VectorType):
|
||||
type = type.of_type
|
||||
for ref in type.inputs:
|
||||
@ -839,7 +836,7 @@ class Analyzer(object):
|
||||
type_ = self.get_type(instr.location)
|
||||
|
||||
if not isinstance(type_, (RoutineType, VectorType)):
|
||||
raise TypeMismatchError(instr, location)
|
||||
raise TypeMismatchError(instr, location.name)
|
||||
|
||||
# assert that the dest routine's inputs are all initialized
|
||||
if isinstance(type_, VectorType):
|
||||
|
@ -1,41 +1,35 @@
|
||||
"""Data/storage model for SixtyPical."""
|
||||
|
||||
|
||||
class Type(object):
|
||||
def __init__(self, name, max_range=None):
|
||||
self.name = name
|
||||
self.max_range = max_range
|
||||
|
||||
def __repr__(self):
|
||||
return 'Type(%r)' % self.name
|
||||
|
||||
def __eq__(self, other):
|
||||
return other.__class__ == self.__class__ and other.name == self.name
|
||||
from collections import namedtuple
|
||||
|
||||
|
||||
TYPE_BIT = Type('bit', max_range=(0, 1))
|
||||
TYPE_BYTE = Type('byte', max_range=(0, 255))
|
||||
TYPE_WORD = Type('word', max_range=(0, 65535))
|
||||
class BitType(namedtuple('BitType', ['typename'])):
|
||||
max_range = (0, 1)
|
||||
def __new__(cls):
|
||||
return super(BitType, cls).__new__(cls, 'bit')
|
||||
TYPE_BIT = BitType()
|
||||
|
||||
|
||||
class RoutineType(Type):
|
||||
class ByteType(namedtuple('ByteType', ['typename'])):
|
||||
max_range = (0, 255)
|
||||
def __new__(cls):
|
||||
return super(ByteType, cls).__new__(cls, 'byte')
|
||||
TYPE_BYTE = ByteType()
|
||||
|
||||
|
||||
class WordType(namedtuple('WordType', ['typename'])):
|
||||
max_range = (0, 65535)
|
||||
def __new__(cls):
|
||||
return super(WordType, cls).__new__(cls, 'word')
|
||||
TYPE_WORD = WordType()
|
||||
|
||||
|
||||
class RoutineType(namedtuple('RoutineType', ['typename', 'inputs', 'outputs', 'trashes'])):
|
||||
"""This memory location contains the code for a routine."""
|
||||
def __init__(self, inputs, outputs, trashes):
|
||||
self.inputs = inputs
|
||||
self.outputs = outputs
|
||||
self.trashes = trashes
|
||||
max_range = (0, 0)
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(inputs=%r, outputs=%r, trashes=%r)' % (
|
||||
self.__class__.__name__, self.inputs, self.outputs, self.trashes
|
||||
)
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, RoutineType) and (
|
||||
other.inputs == self.inputs and
|
||||
other.outputs == self.outputs and
|
||||
other.trashes == self.trashes
|
||||
)
|
||||
def __new__(cls, *args):
|
||||
return super(RoutineType, cls).__new__(cls, 'routine', *args)
|
||||
|
||||
@classmethod
|
||||
def executable_types_compatible(cls_, src, dest):
|
||||
@ -55,34 +49,18 @@ class RoutineType(Type):
|
||||
return False
|
||||
|
||||
|
||||
class VectorType(Type):
|
||||
class VectorType(namedtuple('VectorType', ['typename', 'of_type'])):
|
||||
"""This memory location contains the address of some other type (currently, only RoutineType)."""
|
||||
max_range = (0, 0)
|
||||
max_range = (0, 65535)
|
||||
|
||||
def __init__(self, of_type):
|
||||
self.of_type = of_type
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%r)' % (
|
||||
self.__class__.__name__, self.of_type
|
||||
)
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, VectorType) and self.of_type == other.of_type
|
||||
def __new__(cls, *args):
|
||||
return super(VectorType, cls).__new__(cls, 'vector', *args)
|
||||
|
||||
|
||||
class TableType(Type):
|
||||
def __init__(self, of_type, size):
|
||||
self.of_type = of_type
|
||||
self.size = size
|
||||
class TableType(namedtuple('TableType', ['typename', 'of_type', 'size'])):
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%r, %r)' % (
|
||||
self.__class__.__name__, self.of_type, self.size
|
||||
)
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, TableType) and self.of_type == other.of_type and self.size == other.size
|
||||
def __new__(cls, *args):
|
||||
return super(TableType, cls).__new__(cls, 'table', *args)
|
||||
|
||||
@property
|
||||
def max_range(self):
|
||||
@ -93,94 +71,46 @@ class TableType(Type):
|
||||
return isinstance(x, TableType) and x.of_type == of_type
|
||||
|
||||
|
||||
class PointerType(Type):
|
||||
max_range = (0, 0)
|
||||
class PointerType(namedtuple('PointerType', ['typename'])):
|
||||
max_range = (0, 65535)
|
||||
|
||||
def __init__(self):
|
||||
self.name = 'pointer'
|
||||
|
||||
def __eq__(self, other):
|
||||
return other.__class__ == self.__class__
|
||||
def __new__(cls):
|
||||
return super(PointerType, cls).__new__(cls, 'pointer')
|
||||
|
||||
|
||||
class Ref(object):
|
||||
pass
|
||||
# --------------------------------------------------------
|
||||
|
||||
|
||||
class LocationRef(Ref):
|
||||
def __init__(self, type, name):
|
||||
self.name = name
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.__class__ is other.__class__ and self.name == other.name
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.name)
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%r)' % (self.__class__.__name__, self.name)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
class LocationRef(namedtuple('LocationRef', ['reftype', 'name'])):
|
||||
def __new__(cls, *args):
|
||||
return super(LocationRef, cls).__new__(cls, 'location', *args)
|
||||
|
||||
@classmethod
|
||||
def format_set(cls, location_refs):
|
||||
return '{%s}' % ', '.join([str(loc) for loc in sorted(location_refs, key=lambda x: x.name)])
|
||||
|
||||
|
||||
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)
|
||||
class IndirectRef(namedtuple('IndirectRef', ['reftype', 'ref'])):
|
||||
def __new__(cls, *args):
|
||||
return super(IndirectRef, cls).__new__(cls, 'indirect', *args)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return '[{}]+y'.format(self.ref.name)
|
||||
|
||||
|
||||
class IndexedRef(Ref):
|
||||
def __init__(self, ref, offset, index):
|
||||
self.ref = ref
|
||||
self.offset = offset
|
||||
self.index = index
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, self.__class__) and self.ref == other.ref and self.offset == other.offset and self.index == other.index
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.__class__.name) ^ hash(self.ref) ^ hash(self.offset) ^ hash(self.index)
|
||||
|
||||
def __repr__(self):
|
||||
return '%s(%r, %r, %r)' % (self.__class__.__name__, self.ref, self.offset, self.index)
|
||||
class IndexedRef(namedtuple('IndexedRef', ['reftype', 'ref', 'offset', 'index'])):
|
||||
def __new__(cls, *args):
|
||||
return super(IndexedRef, cls).__new__(cls, 'indexed', *args)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return '{}+{}+{}'.format(self.ref.name, self.offset, self.index.name)
|
||||
|
||||
|
||||
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)
|
||||
class ConstantRef(namedtuple('ConstantRef', ['reftype', 'type', 'value'])):
|
||||
def __new__(cls, *args):
|
||||
return super(ConstantRef, cls).__new__(cls, 'constant', *args)
|
||||
|
||||
def high_byte(self):
|
||||
return (self.value >> 8) & 255
|
||||
@ -207,11 +137,11 @@ class ConstantRef(Ref):
|
||||
return 'constant({})'.format(self.value)
|
||||
|
||||
|
||||
REG_A = LocationRef(TYPE_BYTE, 'a')
|
||||
REG_X = LocationRef(TYPE_BYTE, 'x')
|
||||
REG_Y = LocationRef(TYPE_BYTE, 'y')
|
||||
REG_A = LocationRef('a')
|
||||
REG_X = LocationRef('x')
|
||||
REG_Y = LocationRef('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')
|
||||
FLAG_Z = LocationRef('z')
|
||||
FLAG_C = LocationRef('c')
|
||||
FLAG_N = LocationRef('n')
|
||||
FLAG_V = LocationRef('v')
|
||||
|
@ -54,13 +54,13 @@ class SymbolTable(object):
|
||||
|
||||
def fetch_global_ref(self, name):
|
||||
if name in self.symbols:
|
||||
return LocationRef(self.symbols[name].type_, name)
|
||||
return LocationRef(name)
|
||||
return None
|
||||
|
||||
def fetch_static_ref(self, routine_name, name):
|
||||
routine_statics = self.statics.get(routine_name, {})
|
||||
if name in routine_statics:
|
||||
return LocationRef(routine_statics[name].type_, name)
|
||||
return LocationRef(name)
|
||||
return None
|
||||
|
||||
|
||||
@ -98,22 +98,25 @@ class Parser(object):
|
||||
def resolve_symbols(self, program):
|
||||
# This could stand to be better unified.
|
||||
|
||||
def backpatch_constraint_labels(type_):
|
||||
def resolve(w):
|
||||
if not isinstance(w, ForwardReference):
|
||||
return w
|
||||
return self.lookup(w.name)
|
||||
def resolve(w):
|
||||
return self.lookup(w.name) if isinstance(w, ForwardReference) else w
|
||||
|
||||
def backpatched_type(type_):
|
||||
if isinstance(type_, TableType):
|
||||
backpatch_constraint_labels(type_.of_type)
|
||||
return TableType(backpatched_type(type_.of_type), type_.size)
|
||||
elif isinstance(type_, VectorType):
|
||||
backpatch_constraint_labels(type_.of_type)
|
||||
return VectorType(backpatched_type(type_.of_type))
|
||||
elif isinstance(type_, RoutineType):
|
||||
type_.inputs = set([resolve(w) for w in type_.inputs])
|
||||
type_.outputs = set([resolve(w) for w in type_.outputs])
|
||||
type_.trashes = set([resolve(w) for w in type_.trashes])
|
||||
return RoutineType(
|
||||
frozenset([resolve(w) for w in type_.inputs]),
|
||||
frozenset([resolve(w) for w in type_.outputs]),
|
||||
frozenset([resolve(w) for w in type_.trashes]),
|
||||
)
|
||||
else:
|
||||
return type_
|
||||
|
||||
for name, symentry in self.symtab.symbols.items():
|
||||
backpatch_constraint_labels(symentry.type_)
|
||||
symentry.type_ = backpatched_type(symentry.type_)
|
||||
|
||||
def resolve_fwd_reference(obj, field):
|
||||
field_value = getattr(obj, field, None)
|
||||
@ -265,7 +268,7 @@ class Parser(object):
|
||||
type_ = VectorType(type_)
|
||||
elif self.scanner.consume('routine'):
|
||||
(inputs, outputs, trashes) = self.constraints()
|
||||
type_ = RoutineType(inputs=inputs, outputs=outputs, trashes=trashes)
|
||||
type_ = RoutineType(frozenset(inputs), frozenset(outputs), frozenset(trashes))
|
||||
elif self.scanner.consume('pointer'):
|
||||
type_ = PointerType()
|
||||
else:
|
||||
@ -302,7 +305,7 @@ class Parser(object):
|
||||
def routine(self, name):
|
||||
type_ = self.defn_type()
|
||||
if not isinstance(type_, RoutineType):
|
||||
self.syntax_error("Can only define a routine, not %r" % type_)
|
||||
self.syntax_error("Can only define a routine, not {}".format(repr(type_)))
|
||||
statics = []
|
||||
if self.scanner.consume('@'):
|
||||
self.scanner.check_type('integer literal')
|
||||
|
Loading…
x
Reference in New Issue
Block a user