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:
parent
ec2e051518
commit
82e33ab476
@ -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.
|
||||||
|
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user