diff --git a/README.markdown b/README.markdown index 84ee4e6..cc91bcc 100644 --- a/README.markdown +++ b/README.markdown @@ -34,11 +34,16 @@ TODO For 0.6: * `call` vector (generates an JSR to a trampoline that does indirect JMP.) -* `goto` (tail call) a routine or a vector. -* A more involved demo for the C64 — one that sets up an interrupt? +* `goto` (tail call) a a vector. +* add routine name to error messages. +* routines shouldn't need to be listed as inputs. For 0.7: +* A more involved demo for the C64 — one that sets up an interrupt? + +For 0.8: + * `word` type. * `trash` instruction. * zero-page memory locations. @@ -47,7 +52,6 @@ For 0.7: At some point... * `interrupt` routines. -* add line number (or at least routine name) to error messages. * 6502-mnemonic aliases (`sec`, `clc`) * other handy aliases (`eq` for `z`, etc.) * have `copy` instruction able to copy a constant to a user-def mem loc, etc. diff --git a/src/sixtypical/analyzer.py b/src/sixtypical/analyzer.py index b3ba715..70c06cb 100644 --- a/src/sixtypical/analyzer.py +++ b/src/sixtypical/analyzer.py @@ -153,11 +153,12 @@ class Analyzer(object): type = routine.location.type context = Context(type.inputs, type.outputs, type.trashes) self.analyze_block(routine.block, context, routines) - for ref in type.outputs: - context.assert_meaningful(ref, exception_class=UninitializedOutputError) - for ref in context.each_touched(): - if ref not in type.outputs and ref not in type.trashes: - raise IllegalWriteError(ref.name) + if not self.has_encountered_goto: + for ref in type.outputs: + context.assert_meaningful(ref, exception_class=UninitializedOutputError) + for ref in context.each_touched(): + if ref not in type.outputs and ref not in type.trashes: + raise IllegalWriteError(ref.name) self.current_routine = None def analyze_block(self, block, context, routines): diff --git a/tests/SixtyPical Analysis.md b/tests/SixtyPical Analysis.md index 14b9dfb..c4db06a 100644 --- a/tests/SixtyPical Analysis.md +++ b/tests/SixtyPical Analysis.md @@ -1134,7 +1134,7 @@ Indirect call. | } = ok -Calling the vector has indeed trashed stuff etc, +Calling the vector does indeed trash the things the vector says it does. | vector foo trashes x, z, n | @@ -1220,3 +1220,52 @@ Can't `goto` a routine that outputs or trashes more than the current routine. | goto bar | } ? IncompatibleConstraintsError + +Can `goto` a routine that outputs or trashes less than the current routine. + + | routine bar trashes x, z, n { + | ld x, 1 + | } + | + | routine main trashes a, x, z, n { + | ld a, 0 + | ld x, 0 + | goto bar + | } + = ok + +Indirect goto. + + | vector foo outputs x trashes a, z, n + | + | routine bar outputs x trashes a, z, n { + | ld x, 200 + | } + | + | routine main inputs bar outputs x trashes foo, a, z, n { + | copy bar, foo + | goto foo + | } + = ok + +Jumping through the vector does indeed output the things the vector says it does. + + | vector foo trashes a, x, z, n + | + | routine bar trashes a, x, z, n { + | ld x, 200 + | } + | + | routine sub inputs bar trashes foo, a, x, z, n { + | ld x, 0 + | copy bar, foo + | goto foo + | } + | + | routine main inputs bar outputs a trashes z, n { + | call sub + | ld a, x + | } + ? UninitializedOutputError: x + +Ack, I have become a bit confused...