Mercurial > lcfOS
comparison python/ppci/common.py @ 312:2c9768114877
Added cool logging formatter
author | Windel Bouwman |
---|---|
date | Mon, 16 Dec 2013 17:58:15 +0100 |
parents | 6aa721e7b10b |
children | 6f4753202b9a |
comparison
equal
deleted
inserted
replaced
311:ff665880a6b0 | 312:2c9768114877 |
---|---|
1 from collections import namedtuple | 1 from collections import namedtuple |
2 import logging | |
2 | 3 |
4 """ | |
5 Error handling routines | |
6 Diagnostic utils | |
7 Source location structures | |
8 """ | |
3 | 9 |
4 # Token is used in the lexical analyzer: | 10 # Token is used in the lexical analyzer: |
5 class Token: | 11 class Token: |
6 def __init__(self, typ, val, loc=None): | 12 def __init__(self, typ, val, loc=None): |
7 self.typ = typ | 13 self.typ = typ |
25 def __repr__(self): | 31 def __repr__(self): |
26 return '{}, {}, {}'.format(self.filename, self.row, self.col) | 32 return '{}, {}, {}'.format(self.filename, self.row, self.col) |
27 | 33 |
28 | 34 |
29 SourceRange = namedtuple('SourceRange', ['p1', 'p2']) | 35 SourceRange = namedtuple('SourceRange', ['p1', 'p2']) |
36 | |
37 | |
38 class CompilerError(Exception): | |
39 def __init__(self, msg, loc=None): | |
40 self.msg = msg | |
41 self.loc = loc | |
42 if loc: | |
43 assert type(loc) is SourceLocation, \ | |
44 '{0} must be SourceLocation'.format(type(loc)) | |
45 self.row = loc.row | |
46 self.col = loc.col | |
47 else: | |
48 self.row = self.col = 0 | |
49 | |
50 def __repr__(self): | |
51 return '"{}"'.format(self.msg) | |
52 | |
53 | |
54 class DiagnosticsManager: | |
55 def __init__(self): | |
56 self.diags = [] | |
57 self.sources = {} | |
58 self.logger = logging.getLogger('diagnostics') | |
59 | |
60 def addSource(self, name, src): | |
61 self.logger.info('Adding source {}'.format(name)) | |
62 self.sources[name] = src | |
63 | |
64 def addDiag(self, d): | |
65 #self.logger.warning(str(d.msg)) | |
66 self.diags.append(d) | |
67 | |
68 def error(self, msg, loc): | |
69 self.addDiag(CompilerError(msg, loc)) | |
70 | |
71 def clear(self): | |
72 del self.diags[:] | |
73 self.sources.clear() | |
74 | |
75 def printErrors(self): | |
76 if len(self.diags) > 0: | |
77 print('{0} Errors'.format(len(self.diags))) | |
78 for d in self.diags: | |
79 self.printError(d) | |
80 | |
81 def printError(self, e): | |
82 def printLine(row, txt): | |
83 print(str(row)+':'+txt) | |
84 print('==============') | |
85 if not e.loc: | |
86 print('Error: {0}'.format(e)) | |
87 else: | |
88 if e.loc.filename not in self.sources: | |
89 print('Error: {0}'.format(e)) | |
90 return | |
91 print("File: {}".format(e.loc.filename)) | |
92 source = self.sources[e.loc.filename] | |
93 lines = source.split('\n') | |
94 ro, co = e.row, e.col | |
95 prerow = ro - 2 | |
96 if prerow < 1: | |
97 prerow = 1 | |
98 afterrow = ro + 3 | |
99 if afterrow > len(lines): | |
100 afterrow = len(lines) | |
101 | |
102 # print preceding source lines: | |
103 for r in range(prerow, ro): | |
104 printLine(r, lines[r-1]) | |
105 # print source line containing error: | |
106 printLine(ro, lines[ro-1]) | |
107 print(' '*(len(str(ro)+':')+co-1) + '^ Error: {0}'.format(e.msg)) | |
108 # print trailing source line: | |
109 for r in range(ro+1, afterrow+1): | |
110 printLine(r, lines[r-1]) | |
111 print('==============') |