1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2025-02-19 20:30:45 +00:00

Improve error messaging when constraints are exceeded.

This commit is contained in:
Chris Pressey 2017-12-12 09:42:16 +00:00
parent ec2e051518
commit 82e33ab476
2 changed files with 24 additions and 17 deletions

View File

@ -8,6 +8,7 @@ History of SixtyPical
* Add word to pointer (unchecked for now). * Add word to pointer (unchecked for now).
* Added `word table` type. * Added `word table` type.
* Can `copy` from word storage location to word table and back. * Can `copy` from word storage location to word table and back.
* A `vector` can name itself in its `inputs` and `outputs` or `trashes` sets.
* Implementation: `--debug` shows some extra info during analysis. * Implementation: `--debug` shows some extra info during analysis.
* Fixed bug where `copy`ing literal word into word storage used wrong endianness. * Fixed bug where `copy`ing literal word into word storage used wrong endianness.
* Fixed bug where every memory location was allocated 2 bytes of storage, regardless of type. * Fixed bug where every memory location was allocated 2 bytes of storage, regardless of type.

View File

@ -184,6 +184,19 @@ class Analyzer(object):
(location.name, self.current_routine.name) (location.name, self.current_routine.name)
) )
def assert_affected_within(self, name, affected, limited_to):
def format(loc):
assert isinstance(loc, LocationRef)
return loc.name
if affected <= limited_to:
return
overage = affected - limited_to
overage_s = ', '.join(sorted([format(loc) for loc in overage]))
message = 'affected beyond %s: {%s} in %s' % (name, overage_s, self.current_routine.name)
raise IncompatibleConstraintsError(message)
def analyze_program(self, program): def analyze_program(self, program):
assert isinstance(program, Program) assert isinstance(program, Program)
self.routines = {r.location: r for r in program.routines} self.routines = {r.location: r for r in program.routines}
@ -364,16 +377,10 @@ class Analyzer(object):
elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, LocationRef): elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, LocationRef):
if src.type == dest.type: if src.type == dest.type:
pass pass
elif isinstance(src.type, ExecutableType) and \ elif isinstance(src.type, ExecutableType) and isinstance(dest.type, VectorType):
isinstance(dest.type, VectorType): self.assert_affected_within('inputs', src.type.inputs, dest.type.inputs)
# if dealing with routines and vectors, self.assert_affected_within('outputs', src.type.outputs, dest.type.outputs)
# check that they're not incompatible self.assert_affected_within('trashes', src.type.trashes, dest.type.trashes)
if not (src.type.inputs <= dest.type.inputs):
raise IncompatibleConstraintsError(src.type.inputs - dest.type.inputs)
if not (src.type.outputs <= dest.type.outputs):
raise IncompatibleConstraintsError(src.type.outputs - dest.type.outputs)
if not (src.type.trashes <= dest.type.trashes):
raise IncompatibleConstraintsError(src.type.trashes - dest.type.trashes)
else: else:
raise TypeMismatchError((src, dest)) raise TypeMismatchError((src, dest))
else: else:
@ -409,22 +416,21 @@ class Analyzer(object):
self.analyze_block(instr.block, context) self.analyze_block(instr.block, context)
elif opcode == 'goto': elif opcode == 'goto':
location = instr.location location = instr.location
type = location.type type_ = location.type
if not isinstance(type, ExecutableType): if not isinstance(type_, ExecutableType):
raise TypeMismatchError(location) raise TypeMismatchError(location)
# assert that the dest routine's inputs are all initialized # assert that the dest routine's inputs are all initialized
for ref in type.inputs: for ref in type_.inputs:
context.assert_meaningful(ref) context.assert_meaningful(ref)
# and that this routine's trashes and output constraints are a # and that this routine's trashes and output constraints are a
# superset of the called routine's # superset of the called routine's
current_type = self.current_routine.location.type current_type = self.current_routine.location.type
if not (type.outputs <= current_type.outputs): self.assert_affected_within('outputs', type_.outputs, current_type.outputs)
raise IncompatibleConstraintsError(type.outputs - current_type.outputs) self.assert_affected_within('trashes', type_.trashes, current_type.trashes)
if not (type.trashes <= current_type.trashes):
raise IncompatibleConstraintsError(type.trashes - current_type.trashes)
self.has_encountered_goto = True self.has_encountered_goto = True
else: else:
raise NotImplementedError(opcode) raise NotImplementedError(opcode)