merge
[cython.git] / Cython / Compiler / Errors.py
1 #
2 #   Pyrex - Errors
3 #
4
5 import sys
6 from Cython.Utils import open_new_file
7
8
9 class PyrexError(Exception):
10     pass
11
12 class PyrexWarning(Exception):
13     pass
14
15
16 def context(position):
17     source = position[0]
18     assert not (isinstance(source, unicode) or isinstance(source, str)), (
19         "Please replace filename strings with Scanning.FileSourceDescriptor instances %r" % source)
20     try:
21         F = list(source.get_lines())
22     except UnicodeDecodeError:
23         # file has an encoding problem
24         s = "[unprintable code]\n"
25     else:
26         s =''.join(F[max(0, position[1]-6):position[1]])
27         s = '...\n' + s + ' '*(position[2]-1) + '^\n'
28     s = '-'*60 + '\n' + s + '-'*60 + '\n'
29     return s
30     
31 class CompileError(PyrexError):
32     
33     def __init__(self, position = None, message = ""):
34         self.position = position
35         self.message_only = message
36         self.reported = False
37     # Deprecated and withdrawn in 2.6:
38     #   self.message = message
39         if position:
40             pos_str = "%s:%d:%d: " % (position[0].get_description(), position[1], position[2])
41             cont = context(position)
42         else:
43             pos_str = ""
44             cont = ''
45         Exception.__init__(self, '\nError converting Pyrex file to C:\n' + cont + '\n' + pos_str + message )
46
47 class CompileWarning(PyrexWarning):
48     
49     def __init__(self, position = None, message = ""):
50         self.position = position
51     # Deprecated and withdrawn in 2.6:
52     #   self.message = message
53         if position:
54             pos_str = "%s:%d:%d: " % (position[0].get_description(), position[1], position[2])
55         else:
56             pos_str = ""
57         Exception.__init__(self, pos_str + message)
58
59
60 class InternalError(Exception):
61     # If this is ever raised, there is a bug in the compiler.
62     
63     def __init__(self, message):
64         Exception.__init__(self, "Internal compiler error: %s"
65             % message)
66             
67
68 listing_file = None
69 num_errors = 0
70 echo_file = None
71
72 def open_listing_file(path, echo_to_stderr = 1):
73     # Begin a new error listing. If path is None, no file
74     # is opened, the error counter is just reset.
75     global listing_file, num_errors, echo_file
76     if path is not None:
77         listing_file = open_new_file(path)
78     else:
79         listing_file = None
80     if echo_to_stderr:
81         echo_file = sys.stderr
82     else:
83         echo_file = None
84     num_errors = 0
85
86 def close_listing_file():
87     global listing_file
88     if listing_file:
89         listing_file.close()
90         listing_file = None
91
92 def report_error(err):
93     if error_stack:
94         error_stack[-1].append(err)
95     else:
96         global num_errors
97         # See Main.py for why dual reporting occurs. Quick fix for now.
98         if err.reported: return
99         err.reported = True
100         line = "%s\n" % err
101         if listing_file:
102             listing_file.write(line)
103         if echo_file:
104             echo_file.write(line)
105         num_errors = num_errors + 1
106
107 def error(position, message):
108     #print "Errors.error:", repr(position), repr(message) ###
109     err = CompileError(position, message)
110     #if position is not None: raise Exception(err) # debug
111     report_error(err)
112     return err
113
114 LEVEL=1 # warn about all errors level 1 or higher
115
116 def warning(position, message, level=0):
117     if level < LEVEL:
118         return
119     warn = CompileWarning(position, message)
120     line = "warning: %s\n" % warn
121     if listing_file:
122         listing_file.write(line)
123     if echo_file:
124         echo_file.write(line)
125     return warn
126
127 # These functions can be used to momentarily suppress errors. 
128
129 error_stack = []
130
131 def hold_errors():
132     error_stack.append([])
133
134 def release_errors(ignore=False):
135     held_errors = error_stack.pop()
136     if not ignore:
137         for err in held_errors:
138             report_error(err)
139
140 def held_errors():
141     return error_stack[-1]