mirror of
https://github.com/catseye/SixtyPical.git
synced 2025-02-19 20:30:45 +00:00
The exception object now contains an AST node, renders name.
This commit is contained in:
parent
7023fb9c1d
commit
1eaec602e3
@ -10,11 +10,16 @@ from sixtypical.model import (
|
||||
|
||||
|
||||
class StaticAnalysisError(ValueError):
|
||||
def __init__(self, line_number, message):
|
||||
super(StaticAnalysisError, self).__init__(line_number, message)
|
||||
def __init__(self, ast, message):
|
||||
super(StaticAnalysisError, self).__init__(ast, message)
|
||||
|
||||
def __str__(self):
|
||||
return "{} (Line {})".format(self.args[1], self.args[0])
|
||||
ast = self.args[0]
|
||||
message = self.args[1]
|
||||
if isinstance(ast, Routine):
|
||||
return "{} (in {}, line {})".format(message, ast.name, ast.line_number)
|
||||
else:
|
||||
return "{} (line {})".format(message, ast.line_number)
|
||||
|
||||
|
||||
class UnmeaningfulReadError(StaticAnalysisError):
|
||||
@ -98,19 +103,19 @@ class Context(object):
|
||||
|
||||
for ref in inputs:
|
||||
if ref.is_constant():
|
||||
raise ConstantConstraintError(self.routine.line_number, '%s in %s' % (ref.name, routine.name))
|
||||
raise ConstantConstraintError(self.routine, ref.name)
|
||||
self._range[ref] = ref.max_range()
|
||||
output_names = set()
|
||||
for ref in outputs:
|
||||
if ref.is_constant():
|
||||
raise ConstantConstraintError(self.routine.line_number, '%s in %s' % (ref.name, routine.name))
|
||||
raise ConstantConstraintError(self.routine, ref.name)
|
||||
output_names.add(ref.name)
|
||||
self._writeable.add(ref)
|
||||
for ref in trashes:
|
||||
if ref.is_constant():
|
||||
raise ConstantConstraintError(self.routine.line_number, '%s in %s' % (ref.name, routine.name))
|
||||
raise ConstantConstraintError(self.routine, ref.name)
|
||||
if ref.name in output_names:
|
||||
raise InconsistentConstraintsError(self.routine.line_number, '%s in %s' % (ref.name, routine.name))
|
||||
raise InconsistentConstraintsError(self.routine, ref.name)
|
||||
self._writeable.add(ref)
|
||||
|
||||
def __str__(self):
|
||||
@ -143,10 +148,10 @@ class Context(object):
|
||||
pass
|
||||
elif isinstance(ref, LocationRef):
|
||||
if ref not in self._range:
|
||||
message = '%s in %s' % (ref.name, self.routine.name)
|
||||
message = ref.name
|
||||
if kwargs.get('message'):
|
||||
message += ' (%s)' % kwargs['message']
|
||||
raise exception_class(self.routine.line_number, message)
|
||||
raise exception_class(self.routine, message)
|
||||
elif isinstance(ref, IndexedRef):
|
||||
self.assert_meaningful(ref.ref, **kwargs)
|
||||
self.assert_meaningful(ref.index, **kwargs)
|
||||
@ -160,10 +165,10 @@ class Context(object):
|
||||
if routine_has_static(self.routine, ref):
|
||||
continue
|
||||
if ref not in self._writeable:
|
||||
message = '%s in %s' % (ref.name, self.routine.name)
|
||||
message = ref.name
|
||||
if kwargs.get('message'):
|
||||
message += ' (%s)' % kwargs['message']
|
||||
raise exception_class(self.routine.line_number, message)
|
||||
raise exception_class(self.routine, message)
|
||||
|
||||
def assert_in_range(self, inside, outside):
|
||||
# FIXME there's a bit of I'm-not-sure-the-best-way-to-do-this-ness, here...
|
||||
@ -180,7 +185,7 @@ class Context(object):
|
||||
outside_range = (0, outside.type.size-1)
|
||||
|
||||
if inside_range[0] < outside_range[0] or inside_range[1] > outside_range[1]:
|
||||
raise RangeExceededError(self.routine.line_number,
|
||||
raise RangeExceededError(self.routine,
|
||||
"Possible range of {} {} exceeds acceptable range of {} {}".format(
|
||||
inside, inside_range, outside, outside_range
|
||||
)
|
||||
@ -240,9 +245,7 @@ class Analyzer(object):
|
||||
def assert_type(self, type, *locations):
|
||||
for location in locations:
|
||||
if location.type != type:
|
||||
raise TypeMismatchError(self.current_routine.line_number, '%s in %s' %
|
||||
(location.name, self.current_routine.name)
|
||||
)
|
||||
raise TypeMismatchError(self.current_routine, location.name)
|
||||
|
||||
def assert_affected_within(self, name, affecting_type, limiting_type):
|
||||
assert name in ('inputs', 'outputs', 'trashes')
|
||||
@ -251,13 +254,13 @@ class Analyzer(object):
|
||||
overage = affected - limited_to
|
||||
if not overage:
|
||||
return
|
||||
message = 'in %s: %s for %s are %s\n\nbut %s affects %s\n\nwhich exceeds it by: %s ' % (
|
||||
self.current_routine.name, name,
|
||||
message = '%s for %s are %s\n\nbut %s affects %s\n\nwhich exceeds it by: %s ' % (
|
||||
name,
|
||||
limiting_type, LocationRef.format_set(limited_to),
|
||||
affecting_type, LocationRef.format_set(affected),
|
||||
LocationRef.format_set(overage)
|
||||
)
|
||||
raise IncompatibleConstraintsError(message)
|
||||
raise IncompatibleConstraintsError(self.current_routine, message)
|
||||
|
||||
def analyze_program(self, program):
|
||||
assert isinstance(program, Program)
|
||||
@ -297,22 +300,21 @@ class Analyzer(object):
|
||||
# even if we goto another routine, we can't trash an output.
|
||||
for ref in trashed:
|
||||
if ref in type_.outputs:
|
||||
raise UnmeaningfulOutputError(routine.line_number, '%s in %s' % (ref.name, routine.name))
|
||||
raise UnmeaningfulOutputError(routine, ref.name)
|
||||
|
||||
if not self.has_encountered_goto:
|
||||
for ref in type_.outputs:
|
||||
context.assert_meaningful(ref, exception_class=UnmeaningfulOutputError)
|
||||
for ref in context.each_touched():
|
||||
if ref not in type_.outputs and ref not in type_.trashes and not routine_has_static(routine, ref):
|
||||
message = '%s in %s' % (ref.name, routine.name)
|
||||
raise ForbiddenWriteError(routine.line_number, message)
|
||||
raise ForbiddenWriteError(routine, ref.name)
|
||||
self.current_routine = None
|
||||
|
||||
def analyze_block(self, block, context):
|
||||
assert isinstance(block, Block)
|
||||
for i in block.instrs:
|
||||
if self.has_encountered_goto:
|
||||
raise IllegalJumpError(i)
|
||||
raise IllegalJumpError(i, i)
|
||||
self.analyze_instr(i, context)
|
||||
|
||||
def analyze_instr(self, instr, context):
|
||||
@ -338,9 +340,7 @@ class Analyzer(object):
|
||||
if TableType.is_a_table_type(src.ref.type, TYPE_BYTE) and dest.type == TYPE_BYTE:
|
||||
pass
|
||||
else:
|
||||
raise TypeMismatchError(instr.line_number, '%s and %s in %s' %
|
||||
(src.ref.name, dest.name, self.current_routine.name)
|
||||
)
|
||||
raise TypeMismatchError(instr, '{} and {}'.format(src.ref.name, dest.name))
|
||||
context.assert_meaningful(src, src.index)
|
||||
context.assert_in_range(src.index, src.ref)
|
||||
elif isinstance(src, IndirectRef):
|
||||
@ -348,12 +348,10 @@ class Analyzer(object):
|
||||
if isinstance(src.ref.type, PointerType) and dest.type == TYPE_BYTE:
|
||||
pass
|
||||
else:
|
||||
raise TypeMismatchError(instr.line_number, (src, dest))
|
||||
raise TypeMismatchError(instr, (src, dest))
|
||||
context.assert_meaningful(src.ref, REG_Y)
|
||||
elif src.type != dest.type:
|
||||
raise TypeMismatchError(instr.line_number, '%s and %s in %s' %
|
||||
(src.name, dest.name, self.current_routine.name)
|
||||
)
|
||||
raise TypeMismatchError(instr, '{} and {}'.format(src.name, dest.name))
|
||||
else:
|
||||
context.assert_meaningful(src)
|
||||
context.copy_range(src, dest)
|
||||
@ -363,7 +361,7 @@ class Analyzer(object):
|
||||
if src.type == TYPE_BYTE and TableType.is_a_table_type(dest.ref.type, TYPE_BYTE):
|
||||
pass
|
||||
else:
|
||||
raise TypeMismatchError(instr.line_number, (src, dest))
|
||||
raise TypeMismatchError(instr, (src, dest))
|
||||
context.assert_meaningful(dest.index)
|
||||
context.assert_in_range(dest.index, dest.ref)
|
||||
context.set_written(dest.ref)
|
||||
@ -372,13 +370,11 @@ class Analyzer(object):
|
||||
if isinstance(dest.ref.type, PointerType) and src.type == TYPE_BYTE:
|
||||
pass
|
||||
else:
|
||||
raise TypeMismatchError(instr.line_number, (src, dest))
|
||||
raise TypeMismatchError(instr, (src, dest))
|
||||
context.assert_meaningful(dest.ref, REG_Y)
|
||||
context.set_written(dest.ref)
|
||||
elif src.type != dest.type:
|
||||
raise TypeMismatchError(instr.line_number, '%r and %r in %s' %
|
||||
(src, dest, self.current_routine.name)
|
||||
)
|
||||
raise TypeMismatchError(instr, '{} and {}'.format(src, name))
|
||||
else:
|
||||
context.set_written(dest)
|
||||
context.assert_meaningful(src)
|
||||
@ -447,7 +443,7 @@ class Analyzer(object):
|
||||
context.set_unmeaningful(ref)
|
||||
elif opcode == 'copy':
|
||||
if dest == REG_A:
|
||||
raise ForbiddenWriteError(instr.line_number, "{} cannot be used as destination for copy".format(dest))
|
||||
raise ForbiddenWriteError(instr, "{} cannot be used as destination for copy".format(dest))
|
||||
|
||||
# 1. check that their types are compatible
|
||||
|
||||
@ -455,17 +451,17 @@ class Analyzer(object):
|
||||
if isinstance(src.ref.type, BufferType) and isinstance(dest.type, PointerType):
|
||||
pass
|
||||
else:
|
||||
raise TypeMismatchError(instr.line_number, (src, dest))
|
||||
raise TypeMismatchError(instr, (src, dest))
|
||||
elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, IndirectRef):
|
||||
if src.type == TYPE_BYTE and isinstance(dest.ref.type, PointerType):
|
||||
pass
|
||||
else:
|
||||
raise TypeMismatchError(instr.line_number, (src, dest))
|
||||
raise TypeMismatchError(instr, (src, dest))
|
||||
elif isinstance(src, IndirectRef) and isinstance(dest, LocationRef):
|
||||
if isinstance(src.ref.type, PointerType) and dest.type == TYPE_BYTE:
|
||||
pass
|
||||
else:
|
||||
raise TypeMismatchError(instr.line_number, (src, dest))
|
||||
raise TypeMismatchError(instr, (src, dest))
|
||||
|
||||
elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, IndexedRef):
|
||||
if src.type == TYPE_WORD and TableType.is_a_table_type(dest.ref.type, TYPE_WORD):
|
||||
@ -477,7 +473,7 @@ class Analyzer(object):
|
||||
RoutineType.executable_types_compatible(src.type, dest.ref.type.of_type)):
|
||||
pass
|
||||
else:
|
||||
raise TypeMismatchError(instr.line_number, (src, dest))
|
||||
raise TypeMismatchError(instr, (src, dest))
|
||||
context.assert_in_range(dest.index, dest.ref)
|
||||
|
||||
elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef):
|
||||
@ -487,7 +483,7 @@ class Analyzer(object):
|
||||
RoutineType.executable_types_compatible(src.ref.type.of_type, dest.type.of_type)):
|
||||
pass
|
||||
else:
|
||||
raise TypeMismatchError(instr.line_number, (src, dest))
|
||||
raise TypeMismatchError(instr, (src, dest))
|
||||
context.assert_in_range(src.index, src.ref)
|
||||
|
||||
elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, LocationRef):
|
||||
@ -498,9 +494,9 @@ class Analyzer(object):
|
||||
self.assert_affected_within('outputs', src.type, dest.type.of_type)
|
||||
self.assert_affected_within('trashes', src.type, dest.type.of_type)
|
||||
else:
|
||||
raise TypeMismatchError(instr.line_number, (src, dest))
|
||||
raise TypeMismatchError(instr, (src, dest))
|
||||
else:
|
||||
raise TypeMismatchError(instr.line_number, (src, dest))
|
||||
raise TypeMismatchError(instr, (src, dest))
|
||||
|
||||
# 2. check that the context is meaningful
|
||||
|
||||
@ -532,7 +528,7 @@ class Analyzer(object):
|
||||
type_ = location.type
|
||||
|
||||
if not isinstance(type_, (RoutineType, VectorType)):
|
||||
raise TypeMismatchError(instr.line_number, location)
|
||||
raise TypeMismatchError(instr, location)
|
||||
|
||||
# assert that the dest routine's inputs are all initialized
|
||||
if isinstance(type_, VectorType):
|
||||
|
@ -42,7 +42,7 @@ If a routine declares it outputs a location, that location should be initialized
|
||||
| {
|
||||
| ld x, 0
|
||||
| }
|
||||
? UnmeaningfulOutputError: a in main
|
||||
? UnmeaningfulOutputError: a
|
||||
|
||||
| routine main
|
||||
| inputs a
|
||||
@ -73,7 +73,7 @@ If a routine modifies a location, it needs to either output it or trash it.
|
||||
| {
|
||||
| ld x, 0
|
||||
| }
|
||||
? ForbiddenWriteError: x in main
|
||||
? ForbiddenWriteError: x
|
||||
|
||||
| routine main
|
||||
| outputs x, z, n
|
||||
@ -96,7 +96,7 @@ This is true regardless of whether it's an input or not.
|
||||
| {
|
||||
| ld x, 0
|
||||
| }
|
||||
? ForbiddenWriteError: x in main
|
||||
? ForbiddenWriteError: x
|
||||
|
||||
| routine main
|
||||
| inputs x
|
||||
@ -127,14 +127,14 @@ If a routine trashes a location, this must be declared.
|
||||
| {
|
||||
| trash x
|
||||
| }
|
||||
? ForbiddenWriteError: x in foo
|
||||
? ForbiddenWriteError: x
|
||||
|
||||
| routine foo
|
||||
| outputs x
|
||||
| {
|
||||
| trash x
|
||||
| }
|
||||
? UnmeaningfulOutputError: x in foo
|
||||
? UnmeaningfulOutputError: x
|
||||
|
||||
If a routine causes a location to be trashed, this must be declared in the caller.
|
||||
|
||||
@ -162,7 +162,7 @@ If a routine causes a location to be trashed, this must be declared in the calle
|
||||
| {
|
||||
| call trash_x
|
||||
| }
|
||||
? ForbiddenWriteError: x in foo
|
||||
? ForbiddenWriteError: x
|
||||
|
||||
| routine trash_x
|
||||
| trashes x, z, n
|
||||
@ -176,7 +176,7 @@ If a routine causes a location to be trashed, this must be declared in the calle
|
||||
| {
|
||||
| call trash_x
|
||||
| }
|
||||
? UnmeaningfulOutputError: x in foo
|
||||
? UnmeaningfulOutputError: x (in foo, line 12)
|
||||
|
||||
If a routine reads or writes a user-define memory location, it needs to declare that too.
|
||||
|
||||
@ -214,7 +214,7 @@ Can't `ld` from a memory location that isn't initialized.
|
||||
| {
|
||||
| ld a, x
|
||||
| }
|
||||
? UnmeaningfulReadError: x in main
|
||||
? UnmeaningfulReadError: x
|
||||
|
||||
Can't `ld` to a memory location that doesn't appear in (outputs ∪ trashes).
|
||||
|
||||
@ -246,14 +246,14 @@ Can't `ld` to a memory location that doesn't appear in (outputs ∪ trashes).
|
||||
| {
|
||||
| ld a, 0
|
||||
| }
|
||||
? ForbiddenWriteError: a in main
|
||||
? ForbiddenWriteError: a
|
||||
|
||||
| routine main
|
||||
| trashes a, n
|
||||
| {
|
||||
| ld a, 0
|
||||
| }
|
||||
? ForbiddenWriteError: z in main
|
||||
? ForbiddenWriteError: z
|
||||
|
||||
Can't `ld` a `word` type.
|
||||
|
||||
@ -265,7 +265,7 @@ Can't `ld` a `word` type.
|
||||
| {
|
||||
| ld a, foo
|
||||
| }
|
||||
? TypeMismatchError: foo and a in main
|
||||
? TypeMismatchError: foo and a
|
||||
|
||||
### st ###
|
||||
|
||||
@ -286,7 +286,7 @@ Can't `st` from a memory location that isn't initialized.
|
||||
| {
|
||||
| st x, lives
|
||||
| }
|
||||
? UnmeaningfulReadError: x in main
|
||||
? UnmeaningfulReadError: x
|
||||
|
||||
Can't `st` to a memory location that doesn't appear in (outputs ∪ trashes).
|
||||
|
||||
@ -312,7 +312,7 @@ Can't `st` to a memory location that doesn't appear in (outputs ∪ trashes).
|
||||
| {
|
||||
| st 0, lives
|
||||
| }
|
||||
? ForbiddenWriteError: lives in main
|
||||
? ForbiddenWriteError: lives
|
||||
|
||||
Can't `st` a `word` type.
|
||||
|
||||
@ -646,7 +646,7 @@ Can't `add` from or to a memory location that isn't initialized.
|
||||
| st off, c
|
||||
| add a, lives
|
||||
| }
|
||||
? UnmeaningfulReadError: lives in main
|
||||
? UnmeaningfulReadError: lives
|
||||
|
||||
| byte lives
|
||||
| routine main
|
||||
@ -657,7 +657,7 @@ Can't `add` from or to a memory location that isn't initialized.
|
||||
| st off, c
|
||||
| add a, lives
|
||||
| }
|
||||
? UnmeaningfulReadError: a in main
|
||||
? UnmeaningfulReadError: a
|
||||
|
||||
Can't `add` to a memory location that isn't writeable.
|
||||
|
||||
@ -668,7 +668,7 @@ Can't `add` to a memory location that isn't writeable.
|
||||
| st off, c
|
||||
| add a, 0
|
||||
| }
|
||||
? ForbiddenWriteError: a in main
|
||||
? ForbiddenWriteError: a
|
||||
|
||||
You can `add` a word constant to a word memory location.
|
||||
|
||||
@ -694,7 +694,7 @@ You can `add` a word constant to a word memory location.
|
||||
| st off, c
|
||||
| add score, 1999
|
||||
| }
|
||||
? UnmeaningfulOutputError: a in main
|
||||
? UnmeaningfulOutputError: a
|
||||
|
||||
To be sure, `add`ing a word constant to a word memory location trashes `a`.
|
||||
|
||||
@ -707,7 +707,7 @@ To be sure, `add`ing a word constant to a word memory location trashes `a`.
|
||||
| st off, c
|
||||
| add score, 1999
|
||||
| }
|
||||
? ForbiddenWriteError: a in main
|
||||
? ForbiddenWriteError: a
|
||||
|
||||
You can `add` a word memory location to another word memory location.
|
||||
|
||||
@ -735,7 +735,7 @@ You can `add` a word memory location to another word memory location.
|
||||
| st off, c
|
||||
| add score, delta
|
||||
| }
|
||||
? ForbiddenWriteError: a in main
|
||||
? ForbiddenWriteError: a
|
||||
|
||||
You can `add` a word memory location, or a constant, to a pointer.
|
||||
|
||||
@ -765,7 +765,7 @@ You can `add` a word memory location, or a constant, to a pointer.
|
||||
| add ptr, delta
|
||||
| add ptr, word 1
|
||||
| }
|
||||
? ForbiddenWriteError: a in main
|
||||
? ForbiddenWriteError: a
|
||||
|
||||
### sub ###
|
||||
|
||||
@ -790,7 +790,7 @@ Can't `sub` from or to a memory location that isn't initialized.
|
||||
| st off, c
|
||||
| sub a, lives
|
||||
| }
|
||||
? UnmeaningfulReadError: lives in main
|
||||
? UnmeaningfulReadError: lives
|
||||
|
||||
| byte lives
|
||||
| routine main
|
||||
@ -801,7 +801,7 @@ Can't `sub` from or to a memory location that isn't initialized.
|
||||
| st off, c
|
||||
| sub a, lives
|
||||
| }
|
||||
? UnmeaningfulReadError: a in main
|
||||
? UnmeaningfulReadError: a
|
||||
|
||||
Can't `sub` to a memory location that isn't writeable.
|
||||
|
||||
@ -812,7 +812,7 @@ Can't `sub` to a memory location that isn't writeable.
|
||||
| st off, c
|
||||
| sub a, 0
|
||||
| }
|
||||
? ForbiddenWriteError: a in main
|
||||
? ForbiddenWriteError: a
|
||||
|
||||
You can `sub` a word constant from a word memory location.
|
||||
|
||||
@ -838,7 +838,7 @@ You can `sub` a word constant from a word memory location.
|
||||
| st on, c
|
||||
| sub score, 1999
|
||||
| }
|
||||
? UnmeaningfulOutputError: a in main
|
||||
? UnmeaningfulOutputError: a
|
||||
|
||||
You can `sub` a word memory location from another word memory location.
|
||||
|
||||
@ -866,7 +866,7 @@ You can `sub` a word memory location from another word memory location.
|
||||
| st off, c
|
||||
| sub score, delta
|
||||
| }
|
||||
? ForbiddenWriteError: a in main
|
||||
? ForbiddenWriteError: a
|
||||
|
||||
### inc ###
|
||||
|
||||
@ -878,7 +878,7 @@ Location must be initialized and writeable.
|
||||
| {
|
||||
| inc x
|
||||
| }
|
||||
? UnmeaningfulReadError: x in main
|
||||
? UnmeaningfulReadError: x
|
||||
|
||||
| routine main
|
||||
| inputs x
|
||||
@ -886,7 +886,7 @@ Location must be initialized and writeable.
|
||||
| {
|
||||
| inc x
|
||||
| }
|
||||
? ForbiddenWriteError: x in main
|
||||
? ForbiddenWriteError: x
|
||||
|
||||
| routine main
|
||||
| inputs x
|
||||
@ -908,7 +908,7 @@ Can't `inc` a `word` type.
|
||||
| {
|
||||
| inc foo
|
||||
| }
|
||||
? TypeMismatchError: foo in main
|
||||
? TypeMismatchError: foo
|
||||
|
||||
### dec ###
|
||||
|
||||
@ -920,7 +920,7 @@ Location must be initialized and writeable.
|
||||
| {
|
||||
| dec x
|
||||
| }
|
||||
? UnmeaningfulReadError: x in main
|
||||
? UnmeaningfulReadError: x
|
||||
|
||||
| routine main
|
||||
| inputs x
|
||||
@ -928,7 +928,7 @@ Location must be initialized and writeable.
|
||||
| {
|
||||
| dec x
|
||||
| }
|
||||
? ForbiddenWriteError: x in main
|
||||
? ForbiddenWriteError: x
|
||||
|
||||
| routine main
|
||||
| inputs x
|
||||
@ -950,7 +950,7 @@ Can't `dec` a `word` type.
|
||||
| {
|
||||
| dec foo
|
||||
| }
|
||||
? TypeMismatchError: foo in main
|
||||
? TypeMismatchError: foo
|
||||
|
||||
### cmp ###
|
||||
|
||||
@ -970,14 +970,14 @@ Some rudimentary tests for cmp.
|
||||
| {
|
||||
| cmp a, 4
|
||||
| }
|
||||
? ForbiddenWriteError: c in main
|
||||
? ForbiddenWriteError: c
|
||||
|
||||
| routine main
|
||||
| trashes z, c, n
|
||||
| {
|
||||
| cmp a, 4
|
||||
| }
|
||||
? UnmeaningfulReadError: a in main
|
||||
? UnmeaningfulReadError: a
|
||||
|
||||
### and ###
|
||||
|
||||
@ -997,14 +997,14 @@ Some rudimentary tests for and.
|
||||
| {
|
||||
| and a, 4
|
||||
| }
|
||||
? ForbiddenWriteError: a in main
|
||||
? ForbiddenWriteError: a
|
||||
|
||||
| routine main
|
||||
| trashes z, n
|
||||
| {
|
||||
| and a, 4
|
||||
| }
|
||||
? UnmeaningfulReadError: a in main
|
||||
? UnmeaningfulReadError: a
|
||||
|
||||
### or ###
|
||||
|
||||
@ -1024,14 +1024,14 @@ Writing unit tests on a train. Wow.
|
||||
| {
|
||||
| or a, 4
|
||||
| }
|
||||
? ForbiddenWriteError: a in main
|
||||
? ForbiddenWriteError: a
|
||||
|
||||
| routine main
|
||||
| trashes z, n
|
||||
| {
|
||||
| or a, 4
|
||||
| }
|
||||
? UnmeaningfulReadError: a in main
|
||||
? UnmeaningfulReadError: a
|
||||
|
||||
### xor ###
|
||||
|
||||
@ -1051,14 +1051,14 @@ Writing unit tests on a train. Wow.
|
||||
| {
|
||||
| xor a, 4
|
||||
| }
|
||||
? ForbiddenWriteError: a in main
|
||||
? ForbiddenWriteError: a
|
||||
|
||||
| routine main
|
||||
| trashes z, n
|
||||
| {
|
||||
| xor a, 4
|
||||
| }
|
||||
? UnmeaningfulReadError: a in main
|
||||
? UnmeaningfulReadError: a
|
||||
|
||||
### shl ###
|
||||
|
||||
@ -1078,7 +1078,7 @@ Some rudimentary tests for shl.
|
||||
| {
|
||||
| shl a
|
||||
| }
|
||||
? ForbiddenWriteError: a in main
|
||||
? ForbiddenWriteError: a
|
||||
|
||||
| routine main
|
||||
| inputs a
|
||||
@ -1086,7 +1086,7 @@ Some rudimentary tests for shl.
|
||||
| {
|
||||
| shl a
|
||||
| }
|
||||
? UnmeaningfulReadError: c in main
|
||||
? UnmeaningfulReadError: c
|
||||
|
||||
### shr ###
|
||||
|
||||
@ -1106,7 +1106,7 @@ Some rudimentary tests for shr.
|
||||
| {
|
||||
| shr a
|
||||
| }
|
||||
? ForbiddenWriteError: a in main
|
||||
? ForbiddenWriteError: a
|
||||
|
||||
| routine main
|
||||
| inputs a
|
||||
@ -1114,7 +1114,7 @@ Some rudimentary tests for shr.
|
||||
| {
|
||||
| shr a
|
||||
| }
|
||||
? UnmeaningfulReadError: c in main
|
||||
? UnmeaningfulReadError: c
|
||||
|
||||
### call ###
|
||||
|
||||
@ -1134,7 +1134,7 @@ initialized.
|
||||
| {
|
||||
| call foo
|
||||
| }
|
||||
? UnmeaningfulReadError: x in main
|
||||
? UnmeaningfulReadError: x
|
||||
|
||||
Note that if you call a routine that trashes a location, you also trash it.
|
||||
|
||||
@ -1153,7 +1153,7 @@ Note that if you call a routine that trashes a location, you also trash it.
|
||||
| ld x, 0
|
||||
| call foo
|
||||
| }
|
||||
? ForbiddenWriteError: lives in main
|
||||
? ForbiddenWriteError: lives
|
||||
|
||||
| byte lives
|
||||
|
|
||||
@ -1190,7 +1190,7 @@ You can't output a value that the thing you called trashed.
|
||||
| ld x, 0
|
||||
| call foo
|
||||
| }
|
||||
? UnmeaningfulOutputError: lives in main
|
||||
? UnmeaningfulOutputError: lives
|
||||
|
||||
...unless you write to it yourself afterwards.
|
||||
|
||||
@ -1241,7 +1241,7 @@ calling it.
|
||||
| call foo
|
||||
| ld a, x
|
||||
| }
|
||||
? UnmeaningfulReadError: x in main
|
||||
? UnmeaningfulReadError: x
|
||||
|
||||
If a routine trashes locations, they are uninitialized in the caller after
|
||||
calling it.
|
||||
@ -1266,7 +1266,7 @@ calling it.
|
||||
| call foo
|
||||
| ld a, x
|
||||
| }
|
||||
? UnmeaningfulReadError: x in main
|
||||
? UnmeaningfulReadError: x
|
||||
|
||||
Calling an extern is just the same as calling a defined routine with the
|
||||
same constraints.
|
||||
@ -1294,7 +1294,7 @@ same constraints.
|
||||
| {
|
||||
| call chrout
|
||||
| }
|
||||
? UnmeaningfulReadError: a in main
|
||||
? UnmeaningfulReadError: a
|
||||
|
||||
| routine chrout
|
||||
| inputs a
|
||||
@ -1308,7 +1308,7 @@ same constraints.
|
||||
| call chrout
|
||||
| ld x, a
|
||||
| }
|
||||
? UnmeaningfulReadError: a in main
|
||||
? UnmeaningfulReadError: a
|
||||
|
||||
### trash ###
|
||||
|
||||
@ -1334,7 +1334,7 @@ Trash does nothing except indicate that we do not care about the value anymore.
|
||||
| ld a, 0
|
||||
| trash a
|
||||
| }
|
||||
? UnmeaningfulOutputError: a in foo
|
||||
? UnmeaningfulOutputError: a
|
||||
|
||||
| routine foo
|
||||
| inputs a
|
||||
@ -1345,7 +1345,7 @@ Trash does nothing except indicate that we do not care about the value anymore.
|
||||
| trash a
|
||||
| st a, x
|
||||
| }
|
||||
? UnmeaningfulReadError: a in foo
|
||||
? UnmeaningfulReadError: a
|
||||
|
||||
### if ###
|
||||
|
||||
@ -1510,7 +1510,7 @@ trashes {`a`, `b`}.
|
||||
| trash x
|
||||
| }
|
||||
| }
|
||||
? ForbiddenWriteError: x in foo
|
||||
? ForbiddenWriteError: x (in foo, line 10)
|
||||
|
||||
| routine foo
|
||||
| inputs a, x, z
|
||||
@ -1522,7 +1522,7 @@ trashes {`a`, `b`}.
|
||||
| trash x
|
||||
| }
|
||||
| }
|
||||
? ForbiddenWriteError: a in foo
|
||||
? ForbiddenWriteError: a (in foo, line 10)
|
||||
|
||||
### repeat ###
|
||||
|
||||
@ -1575,7 +1575,7 @@ initialized at the start.
|
||||
| cmp x, 10
|
||||
| } until z
|
||||
| }
|
||||
? UnmeaningfulReadError: y in main
|
||||
? UnmeaningfulReadError: y
|
||||
|
||||
And if you trash the test expression (i.e. `z` in the below) inside the loop,
|
||||
this is an error too.
|
||||
@ -1592,7 +1592,7 @@ this is an error too.
|
||||
| copy one, two
|
||||
| } until z
|
||||
| }
|
||||
? UnmeaningfulReadError: z in main
|
||||
? UnmeaningfulReadError: z
|
||||
|
||||
The body of `repeat forever` can be empty.
|
||||
|
||||
@ -1624,7 +1624,7 @@ Can't `copy` from a memory location that isn't initialized.
|
||||
| {
|
||||
| copy x, lives
|
||||
| }
|
||||
? UnmeaningfulReadError: x in main
|
||||
? UnmeaningfulReadError: x
|
||||
|
||||
Can't `copy` to a memory location that doesn't appear in (outputs ∪ trashes).
|
||||
|
||||
@ -1652,7 +1652,7 @@ Can't `copy` to a memory location that doesn't appear in (outputs ∪ trashes).
|
||||
| {
|
||||
| copy 0, lives
|
||||
| }
|
||||
? ForbiddenWriteError: lives in main
|
||||
? ForbiddenWriteError: lives
|
||||
|
||||
a, z, and n are trashed, and must be declared as such
|
||||
|
||||
@ -1662,7 +1662,7 @@ a, z, and n are trashed, and must be declared as such
|
||||
| {
|
||||
| copy 0, lives
|
||||
| }
|
||||
? ForbiddenWriteError: n in main
|
||||
? ForbiddenWriteError: n
|
||||
|
||||
a, z, and n are trashed, and must not be declared as outputs.
|
||||
|
||||
@ -1672,7 +1672,7 @@ a, z, and n are trashed, and must not be declared as outputs.
|
||||
| {
|
||||
| copy 0, lives
|
||||
| }
|
||||
? UnmeaningfulOutputError: n in main
|
||||
? UnmeaningfulOutputError: n
|
||||
|
||||
Unless of course you subsequently initialize them.
|
||||
|
||||
@ -1901,7 +1901,7 @@ as an input to, an output of, or as a trashed value of a routine.
|
||||
| {
|
||||
| copy foo, vec
|
||||
| }
|
||||
? ConstantConstraintError: foo in main
|
||||
? ConstantConstraintError: foo
|
||||
|
||||
| vector routine
|
||||
| inputs x
|
||||
@ -1923,7 +1923,7 @@ as an input to, an output of, or as a trashed value of a routine.
|
||||
| {
|
||||
| copy foo, vec
|
||||
| }
|
||||
? ConstantConstraintError: foo in main
|
||||
? ConstantConstraintError: foo
|
||||
|
||||
| vector routine
|
||||
| inputs x
|
||||
@ -1945,7 +1945,7 @@ as an input to, an output of, or as a trashed value of a routine.
|
||||
| {
|
||||
| copy foo, vec
|
||||
| }
|
||||
? ConstantConstraintError: foo in main
|
||||
? ConstantConstraintError: foo
|
||||
|
||||
You can copy the address of a routine into a vector, if that vector is
|
||||
declared appropriately.
|
||||
@ -2074,7 +2074,7 @@ Calling the vector does indeed trash the things the vector says it does.
|
||||
| copy bar, foo
|
||||
| call foo
|
||||
| }
|
||||
? UnmeaningfulOutputError: x in main
|
||||
? UnmeaningfulOutputError: x
|
||||
|
||||
`goto`, if present, must be in tail position (the final instruction in a routine.)
|
||||
|
||||
@ -2200,7 +2200,7 @@ vector says it does.
|
||||
| call sub
|
||||
| ld a, x
|
||||
| }
|
||||
? UnmeaningfulReadError: x in main
|
||||
? UnmeaningfulReadError: x
|
||||
|
||||
| vector routine
|
||||
| outputs x
|
||||
|
Loading…
x
Reference in New Issue
Block a user