1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2024-11-26 14:49:15 +00:00

Add specific error for uninit outputs. Sketch if analysis.

This commit is contained in:
Chris Pressey 2015-10-16 09:38:38 +01:00
parent f92056d640
commit 6192a6a7f8
2 changed files with 23 additions and 14 deletions

View File

@ -18,6 +18,10 @@ class UninitializedAccessError(StaticAnalysisError):
pass pass
class UninitializedOutputError(StaticAnalysisError):
pass
class IllegalWriteError(StaticAnalysisError): class IllegalWriteError(StaticAnalysisError):
pass pass
@ -44,13 +48,14 @@ class Context():
self._store.setdefault(ref.name, UNINITIALIZED) self._store.setdefault(ref.name, UNINITIALIZED)
self._writeables.add(ref.name) self._writeables.add(ref.name)
def assertInitialized(self, *refs): def assertInitialized(self, *refs, **kwargs):
exception_class = kwargs.get('exception_class', UninitializedAccessError)
for ref in refs: for ref in refs:
if isinstance(ref, ConstantRef): if isinstance(ref, ConstantRef):
pass pass
elif isinstance(ref, LocationRef): elif isinstance(ref, LocationRef):
if self.get(ref) != INITIALIZED: if self.get(ref) != INITIALIZED:
raise UninitializedAccessError(ref.name) raise exception_class(ref.name)
else: else:
raise ValueError(ref) raise ValueError(ref)
@ -94,7 +99,7 @@ def analyze_routine(routine, routines):
context = Context(routine.inputs, routine.outputs, routine.trashes) context = Context(routine.inputs, routine.outputs, routine.trashes)
analyze_block(routine.block, context, routines) analyze_block(routine.block, context, routines)
for ref in routine.outputs: for ref in routine.outputs:
context.assertInitialized(ref) context.assertInitialized(ref, exception_class=UninitializedOutputError)
def analyze_block(block, context, routines): def analyze_block(block, context, routines):
@ -154,6 +159,10 @@ def analyze_instr(instr, context, routines):
context.assertWriteable(ref) context.assertWriteable(ref)
context.setUninitialized(ref) context.setUninitialized(ref)
elif opcode == 'if': elif opcode == 'if':
pass context1 = context.clone()
context2 = context.clone()
analyze_block(instr.block1, context1, routines)
analyze_block(instr.block2, context2, routines)
reconcile_contexts(context1, context2, output=context)
else: else:
raise NotImplementedError raise NotImplementedError

View File

@ -1,15 +1,15 @@
Sixtypical Analysis SixtyPical Analysis
=================== ===================
This is a test suite, written in [Falderal][] format, for the Sixtypical This is a test suite, written in [Falderal][] format, for the SixtyPical
static analysis rules. static analysis rules.
[Falderal]: http://catseye.tc/node/Falderal [Falderal]: http://catseye.tc/node/Falderal
-> Functionality "Analyze Sixtypical program" is implemented by -> Functionality "Analyze SixtyPical program" is implemented by
-> shell command "bin/sixtypical --analyze %(test-body-file)" -> shell command "bin/sixtypical --analyze %(test-body-file)"
-> Tests for functionality "Analyze Sixtypical program" -> Tests for functionality "Analyze SixtyPical program"
### Rudiments ### ### Rudiments ###
@ -42,7 +42,7 @@ If a routine declares it outputs a location, that location should be initialized
| { | {
| ld x, 0 | ld x, 0
| } | }
? UninitializedAccessError: a ? UninitializedOutputError: a
| routine main | routine main
| inputs a | inputs a
@ -318,7 +318,7 @@ You can't output a value that the thing you called trashed.
| ld x, 0 | ld x, 0
| call foo | call foo
| } | }
? UninitializedAccessError: lives ? UninitializedOutputError: lives
...unless you write to it yourself afterwards. ...unless you write to it yourself afterwards.
@ -402,14 +402,14 @@ Both blocks of an `if` are analyzed.
| routine foo | routine foo
| inputs a | inputs a
| outputs a | outputs x
| trashes z, n, c | trashes a, z, n, c
| { | {
| cmp a, 42 | cmp a, 42
| if z { | if z {
| ld a, 7 | ld x, 7
| } else { | } else {
| ld a, 23 | ld x, 23
| } | }
| } | }
= ok = ok