git @ Cat's Eye Technologies SixtyPical / 8d6e5e0
The Type and Ref class hierarchies are now namedtuples. Chris Pressey 2 years ago
3 changed file(s) with 78 addition(s) and 148 deletion(s). Raw diff Collapse all Expand all
183183 exception_class = kwargs.get('exception_class', UnmeaningfulReadError)
184184 for ref in refs:
185185 # statics are always meaningful
186 if self.symtab.fetch_static_ref(self.routine.name, ref.name):
186 if self.symtab.has_static(self.routine.name, ref.name):
187187 continue
188188 if self.is_constant(ref):
189189 pass
203203 exception_class = kwargs.get('exception_class', ForbiddenWriteError)
204204 for ref in refs:
205205 # statics are always writeable
206 if self.symtab.fetch_static_ref(self.routine.name, ref.name):
206 if self.symtab.has_static(self.routine.name, ref.name):
207207 continue
208208 if ref not in self._writeable:
209209 message = ref.name
504504
505505 # if something was touched, then it should have been declared to be writable.
506506 for ref in context.each_touched():
507 # FIXME once we have namedtuples, go back to comparing the ref directly!
508 outputs_names = [r.name for r in type_.outputs]
509 trashes_names = [r.name for r in type_.trashes]
510 if ref.name not in outputs_names and ref.name not in trashes_names and not self.symtab.has_static(routine.name, ref.name):
507 if ref not in type_.outputs and ref not in type_.trashes and not self.symtab.has_static(routine.name, ref.name):
511508 raise ForbiddenWriteError(routine, ref.name)
512509
513510 self.exit_contexts = None
821818 def analyze_call(self, instr, context):
822819 type = self.get_type(instr.location)
823820 if not isinstance(type, (RoutineType, VectorType)):
824 raise TypeMismatchError(instr, instr.location)
821 raise TypeMismatchError(instr, instr.location.name)
825822 if isinstance(type, VectorType):
826823 type = type.of_type
827824 for ref in type.inputs:
838835 type_ = self.get_type(instr.location)
839836
840837 if not isinstance(type_, (RoutineType, VectorType)):
841 raise TypeMismatchError(instr, location)
838 raise TypeMismatchError(instr, location.name)
842839
843840 # assert that the dest routine's inputs are all initialized
844841 if isinstance(type_, VectorType):
00 """Data/storage model for SixtyPical."""
11
2
3 class Type(object):
4 def __init__(self, name, max_range=None):
5 self.name = name
6 self.max_range = max_range
7
8 def __repr__(self):
9 return 'Type(%r)' % self.name
10
11 def __eq__(self, other):
12 return other.__class__ == self.__class__ and other.name == self.name
2 from collections import namedtuple
133
144
15 TYPE_BIT = Type('bit', max_range=(0, 1))
16 TYPE_BYTE = Type('byte', max_range=(0, 255))
17 TYPE_WORD = Type('word', max_range=(0, 65535))
5 class BitType(namedtuple('BitType', ['typename'])):
6 max_range = (0, 1)
7 def __new__(cls):
8 return super(BitType, cls).__new__(cls, 'bit')
9 TYPE_BIT = BitType()
1810
1911
20 class RoutineType(Type):
12 class ByteType(namedtuple('ByteType', ['typename'])):
13 max_range = (0, 255)
14 def __new__(cls):
15 return super(ByteType, cls).__new__(cls, 'byte')
16 TYPE_BYTE = ByteType()
17
18
19 class WordType(namedtuple('WordType', ['typename'])):
20 max_range = (0, 65535)
21 def __new__(cls):
22 return super(WordType, cls).__new__(cls, 'word')
23 TYPE_WORD = WordType()
24
25
26 class RoutineType(namedtuple('RoutineType', ['typename', 'inputs', 'outputs', 'trashes'])):
2127 """This memory location contains the code for a routine."""
22 def __init__(self, inputs, outputs, trashes):
23 self.inputs = inputs
24 self.outputs = outputs
25 self.trashes = trashes
28 max_range = (0, 0)
2629
27 def __repr__(self):
28 return '%s(inputs=%r, outputs=%r, trashes=%r)' % (
29 self.__class__.__name__, self.inputs, self.outputs, self.trashes
30 )
31
32 def __eq__(self, other):
33 return isinstance(other, RoutineType) and (
34 other.inputs == self.inputs and
35 other.outputs == self.outputs and
36 other.trashes == self.trashes
37 )
30 def __new__(cls, *args):
31 return super(RoutineType, cls).__new__(cls, 'routine', *args)
3832
3933 @classmethod
4034 def executable_types_compatible(cls_, src, dest):
5448 return False
5549
5650
57 class VectorType(Type):
51 class VectorType(namedtuple('VectorType', ['typename', 'of_type'])):
5852 """This memory location contains the address of some other type (currently, only RoutineType)."""
59 max_range = (0, 0)
53 max_range = (0, 65535)
6054
61 def __init__(self, of_type):
62 self.of_type = of_type
63
64 def __repr__(self):
65 return '%s(%r)' % (
66 self.__class__.__name__, self.of_type
67 )
68
69 def __eq__(self, other):
70 return isinstance(other, VectorType) and self.of_type == other.of_type
55 def __new__(cls, *args):
56 return super(VectorType, cls).__new__(cls, 'vector', *args)
7157
7258
73 class TableType(Type):
74 def __init__(self, of_type, size):
75 self.of_type = of_type
76 self.size = size
59 class TableType(namedtuple('TableType', ['typename', 'of_type', 'size'])):
7760
78 def __repr__(self):
79 return '%s(%r, %r)' % (
80 self.__class__.__name__, self.of_type, self.size
81 )
82
83 def __eq__(self, other):
84 return isinstance(other, TableType) and self.of_type == other.of_type and self.size == other.size
61 def __new__(cls, *args):
62 return super(TableType, cls).__new__(cls, 'table', *args)
8563
8664 @property
8765 def max_range(self):
9270 return isinstance(x, TableType) and x.of_type == of_type
9371
9472
95 class PointerType(Type):
96 max_range = (0, 0)
73 class PointerType(namedtuple('PointerType', ['typename'])):
74 max_range = (0, 65535)
9775
98 def __init__(self):
99 self.name = 'pointer'
100
101 def __eq__(self, other):
102 return other.__class__ == self.__class__
76 def __new__(cls):
77 return super(PointerType, cls).__new__(cls, 'pointer')
10378
10479
105 class Ref(object):
106 pass
80 # --------------------------------------------------------
10781
10882
109 class LocationRef(Ref):
110 def __init__(self, type, name):
111 self.name = name
112
113 def __eq__(self, other):
114 return self.__class__ is other.__class__ and self.name == other.name
115
116 def __hash__(self):
117 return hash(self.name)
118
119 def __repr__(self):
120 return '%s(%r)' % (self.__class__.__name__, self.name)
121
122 def __str__(self):
123 return self.name
83 class LocationRef(namedtuple('LocationRef', ['reftype', 'name'])):
84 def __new__(cls, *args):
85 return super(LocationRef, cls).__new__(cls, 'location', *args)
12486
12587 @classmethod
12688 def format_set(cls, location_refs):
12789 return '{%s}' % ', '.join([str(loc) for loc in sorted(location_refs, key=lambda x: x.name)])
12890
12991
130 class IndirectRef(Ref):
131 def __init__(self, ref):
132 self.ref = ref
133
134 def __eq__(self, other):
135 return isinstance(other, self.__class__) and self.ref == other.ref
136
137 def __hash__(self):
138 return hash(self.__class__.name) ^ hash(self.ref)
139
140 def __repr__(self):
141 return '%s(%r)' % (self.__class__.__name__, self.ref)
92 class IndirectRef(namedtuple('IndirectRef', ['reftype', 'ref'])):
93 def __new__(cls, *args):
94 return super(IndirectRef, cls).__new__(cls, 'indirect', *args)
14295
14396 @property
14497 def name(self):
14598 return '[{}]+y'.format(self.ref.name)
14699
147100
148 class IndexedRef(Ref):
149 def __init__(self, ref, offset, index):
150 self.ref = ref
151 self.offset = offset
152 self.index = index
153
154 def __eq__(self, other):
155 return isinstance(other, self.__class__) and self.ref == other.ref and self.offset == other.offset and self.index == other.index
156
157 def __hash__(self):
158 return hash(self.__class__.name) ^ hash(self.ref) ^ hash(self.offset) ^ hash(self.index)
159
160 def __repr__(self):
161 return '%s(%r, %r, %r)' % (self.__class__.__name__, self.ref, self.offset, self.index)
101 class IndexedRef(namedtuple('IndexedRef', ['reftype', 'ref', 'offset', 'index'])):
102 def __new__(cls, *args):
103 return super(IndexedRef, cls).__new__(cls, 'indexed', *args)
162104
163105 @property
164106 def name(self):
165107 return '{}+{}+{}'.format(self.ref.name, self.offset, self.index.name)
166108
167109
168 class ConstantRef(Ref):
169 def __init__(self, type, value):
170 self.type = type
171 self.value = value
172
173 def __eq__(self, other):
174 return isinstance(other, ConstantRef) and (
175 other.type == self.type and other.value == self.value
176 )
177
178 def __hash__(self):
179 return hash(str(self.value) + str(self.type))
180
181 def __repr__(self):
182 return '%s(%r, %r)' % (self.__class__.__name__, self.type, self.value)
110 class ConstantRef(namedtuple('ConstantRef', ['reftype', 'type', 'value'])):
111 def __new__(cls, *args):
112 return super(ConstantRef, cls).__new__(cls, 'constant', *args)
183113
184114 def high_byte(self):
185115 return (self.value >> 8) & 255
206136 return 'constant({})'.format(self.value)
207137
208138
209 REG_A = LocationRef(TYPE_BYTE, 'a')
210 REG_X = LocationRef(TYPE_BYTE, 'x')
211 REG_Y = LocationRef(TYPE_BYTE, 'y')
139 REG_A = LocationRef('a')
140 REG_X = LocationRef('x')
141 REG_Y = LocationRef('y')
212142
213 FLAG_Z = LocationRef(TYPE_BIT, 'z')
214 FLAG_C = LocationRef(TYPE_BIT, 'c')
215 FLAG_N = LocationRef(TYPE_BIT, 'n')
216 FLAG_V = LocationRef(TYPE_BIT, 'v')
143 FLAG_Z = LocationRef('z')
144 FLAG_C = LocationRef('c')
145 FLAG_N = LocationRef('n')
146 FLAG_V = LocationRef('v')
5353
5454 def fetch_global_ref(self, name):
5555 if name in self.symbols:
56 return LocationRef(self.symbols[name].type_, name)
56 return LocationRef(name)
5757 return None
5858
5959 def fetch_static_ref(self, routine_name, name):
6060 routine_statics = self.statics.get(routine_name, {})
6161 if name in routine_statics:
62 return LocationRef(routine_statics[name].type_, name)
62 return LocationRef(name)
6363 return None
6464
6565
9797 def resolve_symbols(self, program):
9898 # This could stand to be better unified.
9999
100 def backpatch_constraint_labels(type_):
101 def resolve(w):
102 if not isinstance(w, ForwardReference):
103 return w
104 return self.lookup(w.name)
100 def resolve(w):
101 return self.lookup(w.name) if isinstance(w, ForwardReference) else w
102
103 def backpatched_type(type_):
105104 if isinstance(type_, TableType):
106 backpatch_constraint_labels(type_.of_type)
105 return TableType(backpatched_type(type_.of_type), type_.size)
107106 elif isinstance(type_, VectorType):
108 backpatch_constraint_labels(type_.of_type)
107 return VectorType(backpatched_type(type_.of_type))
109108 elif isinstance(type_, RoutineType):
110 type_.inputs = set([resolve(w) for w in type_.inputs])
111 type_.outputs = set([resolve(w) for w in type_.outputs])
112 type_.trashes = set([resolve(w) for w in type_.trashes])
109 return RoutineType(
110 frozenset([resolve(w) for w in type_.inputs]),
111 frozenset([resolve(w) for w in type_.outputs]),
112 frozenset([resolve(w) for w in type_.trashes]),
113 )
114 else:
115 return type_
113116
114117 for name, symentry in self.symtab.symbols.items():
115 backpatch_constraint_labels(symentry.type_)
118 symentry.type_ = backpatched_type(symentry.type_)
116119
117120 def resolve_fwd_reference(obj, field):
118121 field_value = getattr(obj, field, None)
264267 type_ = VectorType(type_)
265268 elif self.scanner.consume('routine'):
266269 (inputs, outputs, trashes) = self.constraints()
267 type_ = RoutineType(inputs=inputs, outputs=outputs, trashes=trashes)
270 type_ = RoutineType(frozenset(inputs), frozenset(outputs), frozenset(trashes))
268271 elif self.scanner.consume('pointer'):
269272 type_ = PointerType()
270273 else:
301304 def routine(self, name):
302305 type_ = self.defn_type()
303306 if not isinstance(type_, RoutineType):
304 self.syntax_error("Can only define a routine, not %r" % type_)
307 self.syntax_error("Can only define a routine, not {}".format(repr(type_)))
305308 statics = []
306309 if self.scanner.consume('@'):
307310 self.scanner.check_type('integer literal')