From 0658187afb830fbcf082950b30f0be6cea4455a0 Mon Sep 17 00:00:00 2001 From: s-ol Date: Sat, 22 May 2021 18:23:57 +0200 Subject: log offending line when errors occur, across all stages --- elf.py | 15 +++++++++------ format.py | 57 ++++++++++++++++++++------------------------------------- pack.py | 2 +- subv.py | 42 ++++++++++++++++++++++++++++++++++++++++++ survey.py | 5 ++--- 5 files changed, 74 insertions(+), 47 deletions(-) diff --git a/elf.py b/elf.py index 4427263..2759679 100755 --- a/elf.py +++ b/elf.py @@ -80,12 +80,11 @@ def write_program_header(segment, c, start): c += wi(align, 4) # p_align return c -if __name__ == "__main__": +@subv.with_parsed_lines +def elf(iter): segments = [] segment = None - for line in sys.stdin: - line = subv.parse(line) - + for line in iter: if line['type'] == 'segment': (name, addr) = line['segment'] segment = { 'name': name, 'addr': addr, 'content': [] } @@ -98,8 +97,6 @@ if __name__ == "__main__": else: raise ValueError("elf input should contain only segments and data!") - cursor = 0 - c = write_elf_header(segments) segment_start = 0x1000 for seg in segments: @@ -110,3 +107,9 @@ if __name__ == "__main__": c = padto(seg['offset'], c) for part in seg['content']: c += wi(part[0], 1) + + yield + +if __name__ == '__main__': + for line in elf(sys.stdin): + pass diff --git a/format.py b/format.py index 419f6df..aa6c8ba 100755 --- a/format.py +++ b/format.py @@ -282,44 +282,27 @@ instr_map = { 'jal': (pack_j, 0x6f), } +@subv.with_parsed_lines def format(iter): - for line_no, raw_line in enumerate(iter, start=1): - try: - line = subv.parse(raw_line) - except AssertionError as e: - message = ''' -failed to format line: -:{} {} -parsed as {} - '''.strip().format(line_no, raw_line.strip()) - raise Exception(message) from e - - try: - if line['type'] == 'instr': - op = line['instr'][0] - assert len(op) == 2, 'instruction without op label: {}'.format(op) - - (op, label) = op - if label not in instr_map: - raise ValueError("unknown instruction label: {}".format(label)) - (formatter, expected) = instr_map[label] - if op != expected: - raise ValueError("opcode {} doesn't match label {} (expected {})" - .format(op, label, expected)) - - formatted = formatter(line['instr']) - formatted[0] = (*formatted[0], label) - line['instr'] = formatted - yield subv.format(line) - else: - yield line['raw'] - except AssertionError as e: - message = ''' -failed to format line: -:{} {} -parsed as {} - '''.strip().format(line_no, raw_line.strip(), subv.dump(line)) - raise Exception(message) from e + for line in iter: + if line['type'] == 'instr': + op = line['instr'][0] + assert len(op) == 2, 'instruction without op label: {}'.format(op) + + (op, label) = op + if label not in instr_map: + raise ValueError("unknown instruction label: {}".format(label)) + (formatter, expected) = instr_map[label] + if op != expected: + raise ValueError("opcode {} doesn't match label {} (expected {})" + .format(op, label, expected)) + + formatted = formatter(line['instr']) + formatted[0] = (*formatted[0], label) + line['instr'] = formatted + line = yield subv.format(line) + else: + line = yield line['raw'] if __name__ == '__main__': import sys diff --git a/pack.py b/pack.py index 13a4971..29949b4 100755 --- a/pack.py +++ b/pack.py @@ -62,6 +62,7 @@ def byteify(word): out.append(byte[:1]) return out +@subv.with_parsed_lines def pack(iter): segment = None @@ -78,7 +79,6 @@ def pack(iter): } for line in iter: - line = subv.parse(line) if line['type'] == 'data': for part in line['data']: buf = bits.concat(buf, bits.from_part(part)) diff --git a/subv.py b/subv.py index 0615159..a280e77 100644 --- a/subv.py +++ b/subv.py @@ -288,3 +288,45 @@ def dump(line): def join_all(gen): res = '\n'.join(gen) return res + + +class SubVException(Exception): + pass + +class LineIterator(object): + def __init__(self, stream): + self.stream = stream + self.iter = enumerate(self.stream, start=1) + self.i, self.raw_line, self.line = 0, None, None + + def __iter__(self): + return self + + def __next__(self): + self.i, self.raw_line = next(self.iter) + self.line = None + try: + self.line = parse(self.raw_line) + except Exception as e: + raise self.exception("failed to parse line") from e + return self.line + + def exception(self, msg): + if self.line: + msg = msg + "\n{}:{}: {}".format(self.stream.name, self.i, format(self.line)) + msg = msg + "\nparsed as {}".format(dump(self.line)) + elif self.raw_line: + msg = msg + "\n{}:{}: {}".format(self.stream.name, self.i, self.raw_line.strip()) + return SubVException(msg) + +def with_parsed_lines(process_fn): + def _wrapped(iter): + iterator = LineIterator(iter) + try: + yield from process_fn(iterator) + except SubVException: + raise + except Exception as e: + raise iterator.exception("failed to {} line".format(process_fn.__name__)) from e + + return _wrapped diff --git a/survey.py b/survey.py index 1420e19..e6beb4b 100755 --- a/survey.py +++ b/survey.py @@ -90,13 +90,12 @@ def observe(part, rel_addr, map): return bits.slice(addr, ref['hi'], ref['lo']) +@subv.with_parsed_lines def survey(iter): queue = [] map = {} - addr = -1 - bits = 0 + addr, bits = -1, 0 for line in iter: - line = subv.parse(line) line['addr'] = addr queue.append(line) -- cgit v1.2.3