Add specific error for uninit outputs. Sketch `if` analysis.
Chris Pressey
6 years ago
14 | 14 | |
15 | 15 | |
16 | 16 | class UninitializedAccessError(StaticAnalysisError): |
17 | pass | |
18 | ||
19 | ||
20 | class UninitializedOutputError(StaticAnalysisError): | |
17 | 21 | pass |
18 | 22 | |
19 | 23 | |
43 | 47 | self._store.setdefault(ref.name, UNINITIALIZED) |
44 | 48 | self._writeables.add(ref.name) |
45 | 49 | |
46 | def assertInitialized(self, *refs): | |
50 | def assertInitialized(self, *refs, **kwargs): | |
51 | exception_class = kwargs.get('exception_class', UninitializedAccessError) | |
47 | 52 | for ref in refs: |
48 | 53 | if isinstance(ref, ConstantRef): |
49 | 54 | pass |
50 | 55 | elif isinstance(ref, LocationRef): |
51 | 56 | if self.get(ref) != INITIALIZED: |
52 | raise UninitializedAccessError(ref.name) | |
57 | raise exception_class(ref.name) | |
53 | 58 | else: |
54 | 59 | raise ValueError(ref) |
55 | 60 | |
93 | 98 | context = Context(routine.inputs, routine.outputs, routine.trashes) |
94 | 99 | analyze_block(routine.block, context, routines) |
95 | 100 | for ref in routine.outputs: |
96 | context.assertInitialized(ref) | |
101 | context.assertInitialized(ref, exception_class=UninitializedOutputError) | |
97 | 102 | |
98 | 103 | |
99 | 104 | def analyze_block(block, context, routines): |
153 | 158 | context.assertWriteable(ref) |
154 | 159 | context.setUninitialized(ref) |
155 | 160 | elif opcode == 'if': |
156 | pass | |
161 | context1 = context.clone() | |
162 | context2 = context.clone() | |
163 | analyze_block(instr.block1, context1, routines) | |
164 | analyze_block(instr.block2, context2, routines) | |
165 | reconcile_contexts(context1, context2, output=context) | |
157 | 166 | else: |
158 | 167 | raise NotImplementedError |
0 | Sixtypical Analysis | |
0 | SixtyPical Analysis | |
1 | 1 | =================== |
2 | 2 | |
3 | This is a test suite, written in [Falderal][] format, for the Sixtypical | |
3 | This is a test suite, written in [Falderal][] format, for the SixtyPical | |
4 | 4 | static analysis rules. |
5 | 5 | |
6 | 6 | [Falderal]: http://catseye.tc/node/Falderal |
7 | 7 | |
8 | -> Functionality "Analyze Sixtypical program" is implemented by | |
8 | -> Functionality "Analyze SixtyPical program" is implemented by | |
9 | 9 | -> shell command "bin/sixtypical --analyze %(test-body-file)" |
10 | 10 | |
11 | -> Tests for functionality "Analyze Sixtypical program" | |
11 | -> Tests for functionality "Analyze SixtyPical program" | |
12 | 12 | |
13 | 13 | ### Rudiments ### |
14 | 14 | |
41 | 41 | | { |
42 | 42 | | ld x, 0 |
43 | 43 | | } |
44 | ? UninitializedAccessError: a | |
44 | ? UninitializedOutputError: a | |
45 | 45 | |
46 | 46 | | routine main |
47 | 47 | | inputs a |
317 | 317 | | ld x, 0 |
318 | 318 | | call foo |
319 | 319 | | } |
320 | ? UninitializedAccessError: lives | |
320 | ? UninitializedOutputError: lives | |
321 | 321 | |
322 | 322 | ...unless you write to it yourself afterwards. |
323 | 323 | |
401 | 401 | |
402 | 402 | | routine foo |
403 | 403 | | inputs a |
404 | | outputs a | |
405 | | trashes z, n, c | |
404 | | outputs x | |
405 | | trashes a, z, n, c | |
406 | 406 | | { |
407 | 407 | | cmp a, 42 |
408 | 408 | | if z { |
409 | | ld a, 7 | |
409 | | ld x, 7 | |
410 | 410 | | } else { |
411 | | ld a, 23 | |
411 | | ld x, 23 | |
412 | 412 | | } |
413 | 413 | | } |
414 | 414 | = ok |