Check that the constraints on a routine match those of vector.
Chris Pressey
6 years ago
4 | 4 | ------- |
5 | 5 | |
6 | 6 | * Added `routine` and `vector` types, and `copy` instruction. |
7 | * Both routines and vectors can declare `inputs`, `outputs`, and `trashes`, | |
8 | and these must be compatible to assign a routine or vector to a vector. | |
7 | 9 | |
8 | 10 | 0.5 |
9 | 11 | --- |
32 | 32 | |
33 | 33 | For 0.6: |
34 | 34 | |
35 | * declared `inputs` `outputs` `trashes` on the `vector` type... | |
36 | * we need to get these 3 things onto the type, and also onto routine types | |
35 | * `call` vector (generates an indirect JMP.) | |
37 | 36 | * `goto` (tail call) a routine or a vector. |
38 | * A more involved demo for the C64 — one that sets up an interrupt. | |
37 | * A more involved demo for the C64 — one that sets up an interrupt? | |
39 | 38 | |
40 | 39 | For 0.7: |
41 | 40 |
0 | vector vec | |
1 | inputs y | |
2 | outputs y | |
3 | trashes z, n | |
4 | ||
5 | routine foo | |
6 | inputs x | |
7 | outputs x | |
8 | trashes z, n | |
9 | { | |
10 | inc x | |
11 | } | |
12 | ||
13 | routine main | |
14 | inputs foo | |
15 | outputs vec | |
16 | trashes a, z, n | |
17 | { | |
18 | copy foo, vec | |
19 | } |
2 | 2 | from sixtypical.ast import Program, Routine, Block, Instr |
3 | 3 | from sixtypical.model import ( |
4 | 4 | TYPE_BYTE, TYPE_BYTE_TABLE, |
5 | RoutineType, VectorType, | |
5 | RoutineType, VectorType, ExecutableType, | |
6 | 6 | ConstantRef, LocationRef, |
7 | 7 | REG_A, FLAG_Z, FLAG_N, FLAG_V, FLAG_C |
8 | 8 | ) |
33 | 33 | |
34 | 34 | |
35 | 35 | class TypeMismatchError(StaticAnalysisError): |
36 | pass | |
37 | ||
38 | ||
39 | class IncompatibleConstraintsError(StaticAnalysisError): | |
36 | 40 | pass |
37 | 41 | |
38 | 42 | |
208 | 212 | if instr.block2 is not None: |
209 | 213 | analyze_block(instr.block2, context2, routines) |
210 | 214 | # TODO may we need to deal with touched separately here too? |
215 | # probably not; if it wasn't meaningful in the first place, it | |
216 | # doesn't really matter if you modified it or not, coming out. | |
211 | 217 | for ref in context1.each_meaningful(): |
212 | 218 | context2.assert_meaningful(ref, exception_class=InconsistentInitializationError) |
213 | 219 | for ref in context2.each_meaningful(): |
224 | 230 | |
225 | 231 | # NB I *think* that's enough... but it might not be? |
226 | 232 | elif opcode == 'copy': |
233 | # check that their types are basically compatible | |
227 | 234 | if src.type == dest.type: |
228 | 235 | pass |
229 | elif isinstance(src.type, RoutineType) and isinstance(dest.type, VectorType): | |
236 | elif isinstance(src.type, ExecutableType) and \ | |
237 | isinstance(dest.type, VectorType): | |
230 | 238 | pass |
231 | 239 | else: |
232 | 240 | raise TypeMismatchError((src, dest)) |
241 | ||
242 | # if dealing with routines and vectors, | |
243 | # check that they're not incompatible | |
244 | if isinstance(src.type, ExecutableType) and \ | |
245 | isinstance(dest.type, VectorType): | |
246 | if not (src.type.inputs <= dest.type.inputs): | |
247 | raise IncompatibleConstraintsError(src.type.inputs - dest.type.inputs) | |
248 | if not (src.type.outputs <= dest.type.outputs): | |
249 | raise IncompatibleConstraintsError(src.type.outputs - dest.type.outputs) | |
250 | if not (src.type.trashes <= dest.type.trashes): | |
251 | raise IncompatibleConstraintsError(src.type.trashes - dest.type.trashes) | |
252 | ||
233 | 253 | context.assert_meaningful(src) |
234 | 254 | context.set_written(dest) |
235 | 255 | context.set_touched(REG_A, FLAG_Z, FLAG_N) |
18 | 18 | TYPE_BYTE_TABLE = Type('byte table') |
19 | 19 | |
20 | 20 | |
21 | class InteractionConstrainedType(Type): | |
21 | class ExecutableType(Type): | |
22 | 22 | """Used for routines and vectors.""" |
23 | 23 | def __init__(self, name, inputs=None, outputs=None, trashes=None): |
24 | 24 | self.name = name |
25 | self.inputs = inputs or [] | |
26 | self.outputs = outputs or [] | |
27 | self.trashes = trashes or [] | |
25 | self.inputs = inputs or set() | |
26 | self.outputs = outputs or set() | |
27 | self.trashes = trashes or set() | |
28 | 28 | |
29 | 29 | def __repr__(self): |
30 | 30 | return 'RoutineType(%r, inputs=%r, outputs=%r, trashes=%r)' % ( |
43 | 43 | return hash(self.name) ^ hash(self.inputs) ^ hash(self.outputs) ^ hash(self.trashes) |
44 | 44 | |
45 | 45 | |
46 | class RoutineType(InteractionConstrainedType): | |
46 | class RoutineType(ExecutableType): | |
47 | 47 | """This memory location contains the code for a routine.""" |
48 | 48 | def __init__(self, **kwargs): |
49 | 49 | super(RoutineType, self).__init__('routine', **kwargs) |
50 | 50 | |
51 | 51 | |
52 | class VectorType(InteractionConstrainedType): | |
52 | class VectorType(ExecutableType): | |
53 | 53 | """This memory location contains the address of a routine.""" |
54 | 54 | def __init__(self, **kwargs): |
55 | 55 | super(VectorType, self).__init__('vector', **kwargs) |
148 | 148 | return Defn(name=name, addr=addr, location=location) |
149 | 149 | |
150 | 150 | def constraints(self): |
151 | inputs = [] | |
152 | outputs = [] | |
153 | trashes = [] | |
151 | inputs = set() | |
152 | outputs = set() | |
153 | trashes = set() | |
154 | 154 | if self.scanner.consume('inputs'): |
155 | inputs = self.locexprs() | |
155 | inputs = set(self.locexprs()) | |
156 | 156 | if self.scanner.consume('outputs'): |
157 | outputs = self.locexprs() | |
157 | outputs = set(self.locexprs()) | |
158 | 158 | if self.scanner.consume('trashes'): |
159 | trashes = self.locexprs() | |
159 | trashes = set(self.locexprs()) | |
160 | 160 | return (inputs, outputs, trashes) |
161 | 161 | |
162 | 162 | def routine(self): |
1093 | 1093 | | { |
1094 | 1094 | | copy foo, vec |
1095 | 1095 | | } |
1096 | ? IllegalWriteError | |
1096 | ? IncompatibleConstraintsError | |
1097 | ||
1098 | Routines are read-only. | |
1099 | ||
1100 | | vector vec | |
1101 | | inputs x | |
1102 | | outputs x | |
1103 | | trashes z, n | |
1104 | | | |
1105 | | routine foo | |
1106 | | inputs x | |
1107 | | outputs x | |
1108 | | trashes z, n | |
1109 | | { | |
1110 | | inc x | |
1111 | | } | |
1112 | | | |
1113 | | routine main | |
1114 | | inputs foo | |
1115 | | outputs vec | |
1116 | | trashes a, z, n | |
1117 | | { | |
1118 | | copy vec, foo | |
1119 | | } | |
1120 | ? TypeMismatchError |