git @ Cat's Eye Technologies SixtyPical / 42cbd73
Show line numbers in static analysis errors (clumsily.) Chris Pressey 4 years ago
1 changed file(s) with 30 addition(s) and 26 deletion(s). Raw diff Collapse all Expand all
99
1010
1111 class StaticAnalysisError(ValueError):
12 pass
12 def __init__(self, line_number, message):
13 super(StaticAnalysisError, self).__init__(line_number, message)
14
15 def __str__(self):
16 return "{} (Line {})".format(self.args[1], self.args[0])
1317
1418
1519 class UnmeaningfulReadError(StaticAnalysisError):
9397
9498 for ref in inputs:
9599 if ref.is_constant():
96 raise ConstantConstraintError('%s in %s' % (ref.name, routine.name))
100 raise ConstantConstraintError(self.routine.line_number, '%s in %s' % (ref.name, routine.name))
97101 self._range[ref] = ref.max_range()
98102 output_names = set()
99103 for ref in outputs:
100104 if ref.is_constant():
101 raise ConstantConstraintError('%s in %s' % (ref.name, routine.name))
105 raise ConstantConstraintError(self.routine.line_number, '%s in %s' % (ref.name, routine.name))
102106 output_names.add(ref.name)
103107 self._writeable.add(ref)
104108 for ref in trashes:
105109 if ref.is_constant():
106 raise ConstantConstraintError('%s in %s' % (ref.name, routine.name))
110 raise ConstantConstraintError(self.routine.line_number, '%s in %s' % (ref.name, routine.name))
107111 if ref.name in output_names:
108 raise InconsistentConstraintsError('%s in %s' % (ref.name, routine.name))
112 raise InconsistentConstraintsError(self.routine.line_number, '%s in %s' % (ref.name, routine.name))
109113 self._writeable.add(ref)
110114
111115 def __str__(self):
141145 message = '%s in %s' % (ref.name, self.routine.name)
142146 if kwargs.get('message'):
143147 message += ' (%s)' % kwargs['message']
144 raise exception_class(message)
148 raise exception_class(self.routine.line_number, message)
145149 elif isinstance(ref, IndexedRef):
146150 self.assert_meaningful(ref.ref, **kwargs)
147151 self.assert_meaningful(ref.index, **kwargs)
158162 message = '%s in %s' % (ref.name, self.routine.name)
159163 if kwargs.get('message'):
160164 message += ' (%s)' % kwargs['message']
161 raise exception_class(message)
165 raise exception_class(self.routine.line_number, message)
162166
163167 def assert_in_range(self, inside, outside):
164168 # FIXME there's a bit of I'm-not-sure-the-best-way-to-do-this-ness, here...
175179 outside_range = (0, outside.type.size-1)
176180
177181 if inside_range[0] < outside_range[0] or inside_range[1] > outside_range[1]:
178 raise RangeExceededError(
182 raise RangeExceededError(self.routine.line_number,
179183 "Possible range of {} {} exceeds acceptable range of {} {}".format(
180184 inside, inside_range, outside, outside_range
181185 )
235239 def assert_type(self, type, *locations):
236240 for location in locations:
237241 if location.type != type:
238 raise TypeMismatchError('%s in %s' %
242 raise TypeMismatchError(self.current_routine.line_number, '%s in %s' %
239243 (location.name, self.current_routine.name)
240244 )
241245
292296 # even if we goto another routine, we can't trash an output.
293297 for ref in trashed:
294298 if ref in type_.outputs:
295 raise UnmeaningfulOutputError('%s in %s' % (ref.name, routine.name))
299 raise UnmeaningfulOutputError(routine.line_number, '%s in %s' % (ref.name, routine.name))
296300
297301 if not self.has_encountered_goto:
298302 for ref in type_.outputs:
300304 for ref in context.each_touched():
301305 if ref not in type_.outputs and ref not in type_.trashes and not routine_has_static(routine, ref):
302306 message = '%s in %s' % (ref.name, routine.name)
303 raise ForbiddenWriteError(message)
307 raise ForbiddenWriteError(routine.line_number, message)
304308 self.current_routine = None
305309
306310 def analyze_block(self, block, context):
333337 if TableType.is_a_table_type(src.ref.type, TYPE_BYTE) and dest.type == TYPE_BYTE:
334338 pass
335339 else:
336 raise TypeMismatchError('%s and %s in %s' %
340 raise TypeMismatchError(instr.line_number, '%s and %s in %s' %
337341 (src.ref.name, dest.name, self.current_routine.name)
338342 )
339343 context.assert_meaningful(src, src.index)
343347 if isinstance(src.ref.type, PointerType) and dest.type == TYPE_BYTE:
344348 pass
345349 else:
346 raise TypeMismatchError((src, dest))
350 raise TypeMismatchError(instr.line_number, (src, dest))
347351 context.assert_meaningful(src.ref, REG_Y)
348352 elif src.type != dest.type:
349 raise TypeMismatchError('%s and %s in %s' %
353 raise TypeMismatchError(instr.line_number, '%s and %s in %s' %
350354 (src.name, dest.name, self.current_routine.name)
351355 )
352356 else:
358362 if src.type == TYPE_BYTE and TableType.is_a_table_type(dest.ref.type, TYPE_BYTE):
359363 pass
360364 else:
361 raise TypeMismatchError((src, dest))
365 raise TypeMismatchError(instr.line_number, (src, dest))
362366 context.assert_meaningful(dest.index)
363367 context.assert_in_range(dest.index, dest.ref)
364368 context.set_written(dest.ref)
367371 if isinstance(dest.ref.type, PointerType) and src.type == TYPE_BYTE:
368372 pass
369373 else:
370 raise TypeMismatchError((src, dest))
374 raise TypeMismatchError(instr.line_number, (src, dest))
371375 context.assert_meaningful(dest.ref, REG_Y)
372376 context.set_written(dest.ref)
373377 elif src.type != dest.type:
374 raise TypeMismatchError('%r and %r in %s' %
378 raise TypeMismatchError(instr.line_number, '%r and %r in %s' %
375379 (src, dest, self.current_routine.name)
376380 )
377381 else:
442446 context.set_unmeaningful(ref)
443447 elif opcode == 'copy':
444448 if dest == REG_A:
445 raise ForbiddenWriteError("{} cannot be used as destination for copy".format(dest))
449 raise ForbiddenWriteError(instr.line_number, "{} cannot be used as destination for copy".format(dest))
446450
447451 # 1. check that their types are compatible
448452
450454 if isinstance(src.ref.type, BufferType) and isinstance(dest.type, PointerType):
451455 pass
452456 else:
453 raise TypeMismatchError((src, dest))
457 raise TypeMismatchError(instr.line_number, (src, dest))
454458 elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, IndirectRef):
455459 if src.type == TYPE_BYTE and isinstance(dest.ref.type, PointerType):
456460 pass
457461 else:
458 raise TypeMismatchError((src, dest))
462 raise TypeMismatchError(instr.line_number, (src, dest))
459463 elif isinstance(src, IndirectRef) and isinstance(dest, LocationRef):
460464 if isinstance(src.ref.type, PointerType) and dest.type == TYPE_BYTE:
461465 pass
462466 else:
463 raise TypeMismatchError((src, dest))
467 raise TypeMismatchError(instr.line_number, (src, dest))
464468
465469 elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, IndexedRef):
466470 if src.type == TYPE_WORD and TableType.is_a_table_type(dest.ref.type, TYPE_WORD):
472476 RoutineType.executable_types_compatible(src.type, dest.ref.type.of_type)):
473477 pass
474478 else:
475 raise TypeMismatchError((src, dest))
479 raise TypeMismatchError(instr.line_number, (src, dest))
476480 context.assert_in_range(dest.index, dest.ref)
477481
478482 elif isinstance(src, IndexedRef) and isinstance(dest, LocationRef):
482486 RoutineType.executable_types_compatible(src.ref.type.of_type, dest.type.of_type)):
483487 pass
484488 else:
485 raise TypeMismatchError((src, dest))
489 raise TypeMismatchError(instr.line_number, (src, dest))
486490 context.assert_in_range(src.index, src.ref)
487491
488492 elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, LocationRef):
493497 self.assert_affected_within('outputs', src.type, dest.type.of_type)
494498 self.assert_affected_within('trashes', src.type, dest.type.of_type)
495499 else:
496 raise TypeMismatchError((src, dest))
500 raise TypeMismatchError(instr.line_number, (src, dest))
497501 else:
498 raise TypeMismatchError((src, dest))
502 raise TypeMismatchError(instr.line_number, (src, dest))
499503
500504 # 2. check that the context is meaningful
501505
527531 type_ = location.type
528532
529533 if not isinstance(type_, (RoutineType, VectorType)):
530 raise TypeMismatchError(location)
534 raise TypeMismatchError(instr.line_number, location)
531535
532536 # assert that the dest routine's inputs are all initialized
533537 if isinstance(type_, VectorType):