From c3a0659058eec41efc8346527e15f05c3af9db88 Mon Sep 17 00:00:00 2001 From: Chris Pressey Date: Fri, 16 Oct 2015 14:01:45 +0100 Subject: [PATCH] Write sufficient tests (I think) for analysis of `if`s. --- README.markdown | 2 +- src/sixtypical/analyzer.py | 8 +++-- src/sixtypical/parser.py | 2 ++ tests/SixtyPical Analysis.md | 57 ++++++++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 3 deletions(-) diff --git a/README.markdown b/README.markdown index 3ebd91e..bdfcc2b 100644 --- a/README.markdown +++ b/README.markdown @@ -31,7 +31,7 @@ TODO For 0.2: -* analyze `if` correctly. +* write a few more tests and clean up spec a bit. For 0.3: diff --git a/src/sixtypical/analyzer.py b/src/sixtypical/analyzer.py index e022ee3..e3d879b 100644 --- a/src/sixtypical/analyzer.py +++ b/src/sixtypical/analyzer.py @@ -22,6 +22,10 @@ class UninitializedOutputError(StaticAnalysisError): pass +class InconsistentInitializationError(StaticAnalysisError): + pass + + class IllegalWriteError(StaticAnalysisError): pass @@ -173,9 +177,9 @@ def analyze_instr(instr, context, routines): analyze_block(instr.block1, context1, routines) analyze_block(instr.block2, context2, routines) for ref in context1.each_initialized(): - context2.assert_initialized(ref) + context2.assert_initialized(ref, exception_class=InconsistentInitializationError) for ref in context2.each_initialized(): - context1.assert_initialized(ref) + context1.assert_initialized(ref, exception_class=InconsistentInitializationError) context.set_from(context1) else: raise NotImplementedError(opcode) diff --git a/src/sixtypical/parser.py b/src/sixtypical/parser.py index 8f04d9d..ac59ac0 100644 --- a/src/sixtypical/parser.py +++ b/src/sixtypical/parser.py @@ -165,6 +165,8 @@ class Parser(object): block2 = None if self.scanner.consume('else'): block2 = self.block() + else: + block2 = Block(instrs=[]) return Instr(opcode='if', dest=None, src=src, block1=block1, block2=block2) elif self.scanner.token in ("ld", "add", "sub", "cmp", "and", "or", "xor"): opcode = self.scanner.token diff --git a/tests/SixtyPical Analysis.md b/tests/SixtyPical Analysis.md index 3c8478e..e1a79f2 100644 --- a/tests/SixtyPical Analysis.md +++ b/tests/SixtyPical Analysis.md @@ -413,3 +413,60 @@ Both blocks of an `if` are analyzed. | } | } = ok + +If a location is initialized in one block, is must be initialized in the other as well. + + | routine foo + | inputs a + | outputs x + | trashes a, z, n, c + | { + | cmp a, 42 + | if z { + | ld x, 7 + | } else { + | ld a, 23 + | } + | } + ? InconsistentInitializationError: x + + | routine foo + | inputs a + | outputs x + | trashes a, z, n, c + | { + | cmp a, 42 + | if z { + | ld a, 6 + | } else { + | ld x, 7 + | } + | } + ? InconsistentInitializationError: x + +An `if` with a single block is analyzed as if it had an empty `else` block. + + | routine foo + | inputs a + | outputs x + | trashes a, z, n, c + | { + | cmp a, 42 + | if z { + | ld x, 7 + | } + | } + ? InconsistentInitializationError: x + + | routine foo + | inputs a + | outputs x + | trashes a, z, n, c + | { + | ld x, 0 + | cmp a, 42 + | if z { + | ld x, 7 + | } + | } + = ok