mirror of
https://github.com/catseye/SixtyPical.git
synced 2025-01-10 02:29:23 +00:00
Show line numbers in static analysis errors (clumsily.)
This commit is contained in:
parent
e44c802314
commit
42cbd73a20
@ -10,7 +10,11 @@ from sixtypical.model import (
|
||||
|
||||
|
||||
class StaticAnalysisError(ValueError):
|
||||
pass
|
||||
def __init__(self, line_number, message):
|
||||
super(StaticAnalysisError, self).__init__(line_number, message)
|
||||
|
||||
def __str__(self):
|
||||
return "{} (Line {})".format(self.args[1], self.args[0])
|
||||
|
||||
|
||||
class UnmeaningfulReadError(StaticAnalysisError):
|
||||
@ -94,19 +98,19 @@ class Context(object):
|
||||
|
||||
for ref in inputs:
|
||||
if ref.is_constant():
|
||||
raise ConstantConstraintError('%s in %s' % (ref.name, routine.name))
|
||||
raise ConstantConstraintError(self.routine.line_number, '%s in %s' % (ref.name, routine.name))
|
||||
self._range[ref] = ref.max_range()
|
||||
output_names = set()
|
||||
for ref in outputs:
|
||||
if ref.is_constant():
|
||||
raise ConstantConstraintError('%s in %s' % (ref.name, routine.name))
|
||||
raise ConstantConstraintError(self.routine.line_number, '%s in %s' % (ref.name, routine.name))
|
||||
output_names.add(ref.name)
|
||||
self._writeable.add(ref)
|
||||
for ref in trashes:
|
||||
if ref.is_constant():
|
||||
raise ConstantConstraintError('%s in %s' % (ref.name, routine.name))
|
||||
raise ConstantConstraintError(self.routine.line_number, '%s in %s' % (ref.name, routine.name))
|
||||
if ref.name in output_names:
|
||||
raise InconsistentConstraintsError('%s in %s' % (ref.name, routine.name))
|
||||
raise InconsistentConstraintsError(self.routine.line_number, '%s in %s' % (ref.name, routine.name))
|
||||
self._writeable.add(ref)
|
||||
|
||||
def __str__(self):
|
||||
@ -142,7 +146,7 @@ class Context(object):
|
||||
message = '%s in %s' % (ref.name, self.routine.name)
|
||||
if kwargs.get('message'):
|
||||
message += ' (%s)' % kwargs['message']
|
||||
raise exception_class(message)
|
||||
raise exception_class(self.routine.line_number, message)
|
||||
elif isinstance(ref, IndexedRef):
|
||||
self.assert_meaningful(ref.ref, **kwargs)
|
||||
self.assert_meaningful(ref.index, **kwargs)
|
||||
@ -159,7 +163,7 @@ class Context(object):
|
||||
message = '%s in %s' % (ref.name, self.routine.name)
|
||||
if kwargs.get('message'):
|
||||
message += ' (%s)' % kwargs['message']
|
||||
raise exception_class(message)
|
||||
raise exception_class(self.routine.line_number, 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...
|
||||
@ -176,7 +180,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(
|
||||
raise RangeExceededError(self.routine.line_number,
|
||||
"Possible range of {} {} exceeds acceptable range of {} {}".format(
|
||||
inside, inside_range, outside, outside_range
|
||||
)
|
||||
@ -236,7 +240,7 @@ class Analyzer(object):
|
||||
def assert_type(self, type, *locations):
|
||||
for location in locations:
|
||||
if location.type != type:
|
||||
raise TypeMismatchError('%s in %s' %
|
||||
raise TypeMismatchError(self.current_routine.line_number, '%s in %s' %
|
||||
(location.name, self.current_routine.name)
|
||||
)
|
||||
|
||||
@ -293,7 +297,7 @@ 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('%s in %s' % (ref.name, routine.name))
|
||||
raise UnmeaningfulOutputError(routine.line_number, '%s in %s' % (ref.name, routine.name))
|
||||
|
||||
if not self.has_encountered_goto:
|
||||
for ref in type_.outputs:
|
||||
@ -301,7 +305,7 @@ class Analyzer(object):
|
||||
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(message)
|
||||
raise ForbiddenWriteError(routine.line_number, message)
|
||||
self.current_routine = None
|
||||
|
||||
def analyze_block(self, block, context):
|
||||
@ -334,7 +338,7 @@ class Analyzer(object):
|
||||
if TableType.is_a_table_type(src.ref.type, TYPE_BYTE) and dest.type == TYPE_BYTE:
|
||||
pass
|
||||
else:
|
||||
raise TypeMismatchError('%s and %s in %s' %
|
||||
raise TypeMismatchError(instr.line_number, '%s and %s in %s' %
|
||||
(src.ref.name, dest.name, self.current_routine.name)
|
||||
)
|
||||
context.assert_meaningful(src, src.index)
|
||||
@ -344,10 +348,10 @@ class Analyzer(object):
|
||||
if isinstance(src.ref.type, PointerType) and dest.type == TYPE_BYTE:
|
||||
pass
|
||||
else:
|
||||
raise TypeMismatchError((src, dest))
|
||||
raise TypeMismatchError(instr.line_number, (src, dest))
|
||||
context.assert_meaningful(src.ref, REG_Y)
|
||||
elif src.type != dest.type:
|
||||
raise TypeMismatchError('%s and %s in %s' %
|
||||
raise TypeMismatchError(instr.line_number, '%s and %s in %s' %
|
||||
(src.name, dest.name, self.current_routine.name)
|
||||
)
|
||||
else:
|
||||
@ -359,7 +363,7 @@ class Analyzer(object):
|
||||
if src.type == TYPE_BYTE and TableType.is_a_table_type(dest.ref.type, TYPE_BYTE):
|
||||
pass
|
||||
else:
|
||||
raise TypeMismatchError((src, dest))
|
||||
raise TypeMismatchError(instr.line_number, (src, dest))
|
||||
context.assert_meaningful(dest.index)
|
||||
context.assert_in_range(dest.index, dest.ref)
|
||||
context.set_written(dest.ref)
|
||||
@ -368,11 +372,11 @@ class Analyzer(object):
|
||||
if isinstance(dest.ref.type, PointerType) and src.type == TYPE_BYTE:
|
||||
pass
|
||||
else:
|
||||
raise TypeMismatchError((src, dest))
|
||||
raise TypeMismatchError(instr.line_number, (src, dest))
|
||||
context.assert_meaningful(dest.ref, REG_Y)
|
||||
context.set_written(dest.ref)
|
||||
elif src.type != dest.type:
|
||||
raise TypeMismatchError('%r and %r in %s' %
|
||||
raise TypeMismatchError(instr.line_number, '%r and %r in %s' %
|
||||
(src, dest, self.current_routine.name)
|
||||
)
|
||||
else:
|
||||
@ -443,7 +447,7 @@ class Analyzer(object):
|
||||
context.set_unmeaningful(ref)
|
||||
elif opcode == 'copy':
|
||||
if dest == REG_A:
|
||||
raise ForbiddenWriteError("{} cannot be used as destination for copy".format(dest))
|
||||
raise ForbiddenWriteError(instr.line_number, "{} cannot be used as destination for copy".format(dest))
|
||||
|
||||
# 1. check that their types are compatible
|
||||
|
||||
@ -451,17 +455,17 @@ class Analyzer(object):
|
||||
if isinstance(src.ref.type, BufferType) and isinstance(dest.type, PointerType):
|
||||
pass
|
||||
else:
|
||||
raise TypeMismatchError((src, dest))
|
||||
raise TypeMismatchError(instr.line_number, (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((src, dest))
|
||||
raise TypeMismatchError(instr.line_number, (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((src, dest))
|
||||
raise TypeMismatchError(instr.line_number, (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):
|
||||
@ -473,7 +477,7 @@ class Analyzer(object):
|
||||
RoutineType.executable_types_compatible(src.type, dest.ref.type.of_type)):
|
||||
pass
|
||||
else:
|
||||
raise TypeMismatchError((src, dest))
|
||||
raise TypeMismatchError(instr.line_number, (src, dest))
|
||||
context.assert_in_range(dest.index, dest.ref)
|
||||
|
||||
elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef):
|
||||
@ -483,7 +487,7 @@ class Analyzer(object):
|
||||
RoutineType.executable_types_compatible(src.ref.type.of_type, dest.type.of_type)):
|
||||
pass
|
||||
else:
|
||||
raise TypeMismatchError((src, dest))
|
||||
raise TypeMismatchError(instr.line_number, (src, dest))
|
||||
context.assert_in_range(src.index, src.ref)
|
||||
|
||||
elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, LocationRef):
|
||||
@ -494,9 +498,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((src, dest))
|
||||
raise TypeMismatchError(instr.line_number, (src, dest))
|
||||
else:
|
||||
raise TypeMismatchError((src, dest))
|
||||
raise TypeMismatchError(instr.line_number, (src, dest))
|
||||
|
||||
# 2. check that the context is meaningful
|
||||
|
||||
@ -528,7 +532,7 @@ class Analyzer(object):
|
||||
type_ = location.type
|
||||
|
||||
if not isinstance(type_, (RoutineType, VectorType)):
|
||||
raise TypeMismatchError(location)
|
||||
raise TypeMismatchError(instr.line_number, location)
|
||||
|
||||
# assert that the dest routine's inputs are all initialized
|
||||
if isinstance(type_, VectorType):
|
||||
|
Loading…
x
Reference in New Issue
Block a user