148
|
1 """
|
|
2 Error handling routines
|
|
3 Diagnostic utils
|
|
4 """
|
|
5
|
|
6 from collections import namedtuple
|
|
7
|
|
8 SourceLocation = namedtuple('SourceLocation', ['row', 'col'])
|
|
9 SourceRange = namedtuple('SourceRange', ['p1', 'p2'])
|
1
|
10
|
|
11 class CompilerException(Exception):
|
148
|
12 def __init__(self, msg, loc):
|
1
|
13 self.msg = msg
|
148
|
14 self.loc = loc
|
1
|
15 def __repr__(self):
|
148
|
16 return 'error {0} at {1}'.format(self.msg, self.loc)
|
1
|
17 def __str__(self):
|
148
|
18 return 'error {0} at {1}'.format(self.msg, self.loc)
|
1
|
19
|
6
|
20 class ErrorNode:
|
|
21 def __init__(self, row, col, msg):
|
|
22 self.row, self.col = row,col
|
|
23 self.msg = msg
|
|
24
|
1
|
25 def Error(msg, node=None):
|
|
26 if node is None:
|
|
27 raise CompilerException(msg)
|
|
28 else:
|
|
29 raise CompilerException(msg, node.row, node.col)
|
|
30
|
|
31 def printError(source, e):
|
|
32 def printLine(row, txt):
|
|
33 print(str(row)+':'+txt)
|
148
|
34 if e.loc.row == 0:
|
1
|
35 print('Error: {0}'.format(e.msg))
|
|
36 else:
|
|
37 lines = source.split('\n')
|
148
|
38 ro, co = e.loc.row, e.loc.col
|
|
39 prerow = ro - 2
|
1
|
40 if prerow < 1:
|
|
41 prerow = 1
|
148
|
42 afterrow = ro + 3
|
1
|
43 if afterrow > len(lines):
|
|
44 afterrow = len(lines)
|
|
45
|
|
46 # print preceding source lines:
|
148
|
47 for r in range(prerow, ro):
|
1
|
48 printLine(r, lines[r-1])
|
|
49 # print source line containing error:
|
148
|
50 printLine(ro, lines[ro-1])
|
|
51 print(' '*(len(str(ro)+':')+co-1) + '^ Error: {0}'.format(e.msg))
|
1
|
52 # print trailing source line:
|
148
|
53 for r in range(ro+1, afterrow+1):
|
1
|
54 printLine(r, lines[r-1])
|
148
|
55
|
|
56 class Diagnostics:
|
|
57 def __init__(self):
|
|
58 self.diags = []
|
|
59 def diag(self, d):
|
|
60 self.diags.append(d)
|
|
61
|