1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 '''
31 Tools for logging and tracing.
32 '''
33
34
35
36
37 from lepl.stream.core import s_delta, s_line, s_len
38 from lepl.core.monitor import ActiveMonitor, ValueMonitor, StackMonitor
39 from lepl.support.lib import CircularFifo, LogMixin, sample, fmt, str
40
41
43 '''
44 A basic logger (implemented as a monitor - `MonitorInterface`)
45 that records the flow of control during parsing. It can be controlled by
46 `Trace()`.
47
48 This is a factory that "escapes" the main class via a function to simplify
49 configuration.
50 '''
51 return lambda: _TraceStack(enabled)
52
53
54 -class _TraceStack(ActiveMonitor, ValueMonitor, LogMixin):
55 '''
56 A basic logger (implemented as a monitor - `MonitorInterface`)
57 that records the flow of control during parsing. It can be controlled by
58 `Trace()`.
59 '''
60
62 super(_TraceStack, self).__init__()
63 self.generator = None
64 self.depth = -1
65 self.action = None
66 self.enabled = 1 if enabled else 0
67 self.epoch = 0
68
70 '''
71 Store epoch and stack size.
72 '''
73 self.epoch = epoch
74 self.depth = len(stack)
75
83
85 '''
86 Log when enabled.
87 '''
88 if self.enabled > 0:
89 self._log_result(value, self.fmt_result(value))
90
92 '''
93 Log when enabled.
94 '''
95 if self.enabled > 0:
96 self.generator = generator
97 if type(value) is StopIteration:
98 self.action = fmt('stop -> {0}', generator)
99 else:
100 self.action = fmt('{1!r} -> {0}', generator, value)
101
103 '''
104 Log when enabled.
105 '''
106 if self.enabled > 0:
107 self._log_result(value, self.fmt_result(value))
108
116
118 '''
119 Log when enabled.
120 '''
121 if self.enabled > 0:
122 self._log_result(value, self.fmt_result(value))
123
125 '''
126 Log when enabled.
127 '''
128 if self.enabled > 0:
129 if type(value) is StopIteration:
130 self._log_done(self.fmt_done())
131 else:
132 self._log_error(self.fmt_result(value))
133
135 '''
136 Provide a standard fmt for the results.
137 '''
138 (stream, depth, locn) = self.fmt_stream()
139 return fmt('{0:05d} {1!r:11s} {2} ({3:04d}) {4:03d} '
140 '{5:s} -> {6!r}',
141 self.epoch,
142 stream,
143 locn,
144 depth,
145 self.depth,
146 self.action,
147 value)
148
150 '''
151 Provide a standard fmt for failure.
152 '''
153 (stream, depth, locn) = self.fmt_stream()
154 return fmt('{0:05d} {1!r:11s} {2} ({3:04d}) {4:03d} '
155 '{5:s} -> stop',
156 self.epoch,
157 stream,
158 locn,
159 depth,
160 self.depth,
161 self.action)
162
164 '''
165 Provide a standard fmt for location.
166 '''
167 try:
168 (offset, lineno, char) = s_delta(self.generator.stream)
169 locn = fmt('{0}/{1}.{2}', offset, lineno, char)
170 try:
171 stream = sample('', s_line(self.generator.stream, False)[0], 9)
172 except StopIteration:
173 stream = '<EOS>'
174 return (stream, offset, locn)
175 except StopIteration:
176 return ('<EOS>', -1, '')
177 except TypeError:
178 return (self.generator.stream, -1, '')
179
181 '''
182 Log when enabled.
183 '''
184 if self.enabled > 0:
185 self._info(self.fmt_final_result(value))
186
188 '''
189 Log when enabled.
190 '''
191 if self.enabled > 0:
192 if type(value) is StopIteration:
193 self._info(self.fmt_final_result(fmt('raise {0!r}', value)))
194 else:
195 self._warn(self.fmt_final_result(fmt('raise {0!r}', value)))
196
198 '''
199 Provide a standard fmt for the result.
200 '''
201 return fmt('{0:05d} {1:03d} {2} {3}',
202 self.epoch,
203 self.depth,
204 ' ' * 63,
205 value)
206
208 '''
209 Record a result.
210 '''
211 (self._info if type(value) is tuple else self._debug)(text)
212
214 '''
215 Record an error.
216 '''
217 self._warn(text)
218
220 '''
221 Record a "stop".
222 '''
223 self._debug(text)
224
226 '''
227 Called by the `Trace` matcher to turn this on and off.
228 '''
229 self.enabled += increment
230
231
232 -def RecordDeepest(n_before=6, n_results_after=2, n_done_after=2):
233 '''
234 A logger (implemented as a monitor - `MonitorInterface`)
235 that records the deepest match found during a parse.
236
237 This is a helper function that "escapes" the main class via a function
238 to simplify configuration.
239 '''
240 return lambda: _RecordDeepest(n_before, n_results_after, n_done_after)
241
242
244 '''
245 A logger (implemented as a monitor - `MonitorInterface`)
246 that records the deepest match found during a parse.
247 '''
248
249 - def __init__(self, n_before=6, n_results_after=2, n_done_after=2):
250 super(_RecordDeepest, self).__init__(enabled=True)
251 self.n_before = n_before
252 self.n_results_after = n_results_after
253 self.n_done_after = n_done_after
254 self._limited = CircularFifo(n_before)
255 self._before = []
256 self._results_after = []
257 self._done_after = []
258 self._deepest = -1e99
259 self._countdown_result = 0
260 self._countdown_done = 0
261
263 '''
264 Modify `TraceStack` to record the data.
265 '''
266 if type(value) is tuple:
267 self.record(True, text)
268
270 '''
271 Modify `TraceStack` to record the data.
272 '''
273 self.record(True, text)
274
276 '''
277 Modify `TraceStack` to record the data.
278 '''
279 self.record(False, text)
280
281 - def record(self, is_result, text):
282 '''
283 Record the data.
284 '''
285 try:
286 stream = self.generator.stream
287 try:
288 depth = s_delta(stream)[0]
289 except AttributeError:
290 depth = -1
291 if depth >= self._deepest and is_result:
292 self._deepest = depth
293 self._countdown_result = self.n_results_after
294 self._countdown_done = self.n_done_after
295 self._before = list(self._limited)
296 self._results_after = []
297 self._done_after = []
298 elif is_result and self._countdown_result:
299 self._countdown_result -= 1
300 self._results_after.append(text)
301 elif not is_result and self._countdown_done:
302 self._countdown_done -= 1
303 self._done_after.append(text)
304 self._limited.append(text)
305 except StopIteration:
306 pass
307
309 '''
310 Display the result and reset.
311 '''
312 self._deepest = 0
313 self._limited.clear()
314 self.__display()
315
317 '''
318 Display the result and reset.
319 '''
320 self._deepest = 0
321 self._limited.clear()
322 self.__display()
323
325 '''
326 Display the result.
327 '''
328 self._info(self.__fmt())
329
331 '''
332 fmt the result.
333 '''
334 return fmt(
335 '\nUp to {0} matches before and including longest match:\n{1}\n'
336 'Up to {2} failures following longest match:\n{3}\n'
337 'Up to {4} successful matches following longest match:\n{5}\n',
338 self.n_before, '\n'.join(self._before),
339 self.n_done_after, '\n'.join(self._done_after),
340 self.n_results_after, '\n'.join(self._results_after))
341